Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

 domains.c

  Interaktion und
PortierbarkeitC
 

/*-------------------------------------------------------------------------
 *
 * domains.c
 *   I/O functions for domain types.
 *
 * The output functions for a domain type are just the same ones provided
 * by its underlying base type.  The input functions, however, must be
 * prepared to apply any constraints defined by the type.  So, we create
 * special input functions that invoke the base type's input function
 * and then check the constraints.
 *
 * The overhead required for constraint checking can be high, since examining
 * the catalogs to discover the constraints for a given domain is not cheap.
 * We have three mechanisms for minimizing this cost:
 * 1.  We rely on the typcache to keep up-to-date copies of the constraints.
 * 2.  In a nest of domains, we flatten the checking of all the levels
 *  into just one operation (the typcache does this for us).
 * 3.  If there are CHECK constraints, we cache a standalone ExprContext
 *  to evaluate them in.
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/backend/utils/adt/domains.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "lib/stringinfo.h"
#include "utils/builtins.h"
#include "utils/expandeddatum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"

static bool domain_check_internal(Datum value, bool isnull, Oid domainType,
          void **extra, MemoryContext mcxt,
          Node *escontext);

/*
 * structure to cache state across multiple calls
 */

typedef struct DomainIOData
{
 Oid   domain_type;
 /* Data needed to call base type's input function */
 Oid   typiofunc;
 Oid   typioparam;
 int32  typtypmod;
 FmgrInfo proc;
 /* Reference to cached list of constraint items to check */
 DomainConstraintRef constraint_ref;
 /* Context for evaluating CHECK constraints in */
 ExprContext *econtext;
 /* Memory context this cache is in */
 MemoryContext mcxt;
} DomainIOData;


/*
 * domain_state_setup - initialize the cache for a new domain type.
 *
 * Note: we can't re-use the same cache struct for a new domain type,
 * since there's no provision for releasing the DomainConstraintRef.
 * If a call site needs to deal with a new domain type, we just leak
 * the old struct for the duration of the query.
 */

static DomainIOData *
domain_state_setup(Oid domainType, bool binary, MemoryContext mcxt)
{
 DomainIOData *my_extra;
 TypeCacheEntry *typentry;
 Oid   baseType;

 my_extra = (DomainIOData *) MemoryContextAlloc(mcxt, sizeof(DomainIOData));

 /*
  * Verify that domainType represents a valid domain type.  We need to be
  * careful here because domain_in and domain_recv can be called from SQL,
  * possibly with incorrect arguments.  We use lookup_type_cache mainly
  * because it will throw a clean user-facing error for a bad OID; but also
  * it can cache the underlying base type info.
 */

 typentry = lookup_type_cache(domainType, TYPECACHE_DOMAIN_BASE_INFO);
 if (typentry->typtype != TYPTYPE_DOMAIN)
  ereport(ERROR,
    (errcode(ERRCODE_DATATYPE_MISMATCH),
     errmsg("type %s is not a domain",
      format_type_be(domainType))));

 /* Find out the base type */
 baseType = typentry->domainBaseType;
 my_extra->typtypmod = typentry->domainBaseTypmod;

 /* Look up underlying I/O function */
 if (binary)
  getTypeBinaryInputInfo(baseType,
          &my_extra->typiofunc,
          &my_extra->typioparam);
 else
  getTypeInputInfo(baseType,
       &my_extra->typiofunc,
       &my_extra->typioparam);
 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, mcxt);

 /* Look up constraints for domain */
 InitDomainConstraintRef(domainType, &my_extra->constraint_ref, mcxt, true);

 /* We don't make an ExprContext until needed */
 my_extra->econtext = NULL;
 my_extra->mcxt = mcxt;

 /* Mark cache valid */
 my_extra->domain_type = domainType;

 return my_extra;
}

/*
 * domain_check_input - apply the cached checks.
 *
 * This is roughly similar to the handling of CoerceToDomain nodes in
 * execExpr*.c, but we execute each constraint separately, rather than
 * compiling them in-line within a larger expression.
 *
 * If escontext points to an ErrorSaveContext, any failures are reported
 * there, otherwise they are ereport'ed.  Note that we do not attempt to do
 * soft reporting of errors raised during execution of CHECK constraints.
 */

static void
domain_check_input(Datum value, bool isnull, DomainIOData *my_extra,
       Node *escontext)
{
 ExprContext *econtext = my_extra->econtext;
 ListCell   *l;

 /* Make sure we have up-to-date constraints */
 UpdateDomainConstraintRef(&my_extra->constraint_ref);

 foreach(l, my_extra->constraint_ref.constraints)
 {
  DomainConstraintState *con = (DomainConstraintState *) lfirst(l);

  switch (con->constrainttype)
  {
   case DOM_CONSTRAINT_NOTNULL:
    if (isnull)
    {
     errsave(escontext,
       (errcode(ERRCODE_NOT_NULL_VIOLATION),
        errmsg("domain %s does not allow null values",
         format_type_be(my_extra->domain_type)),
        errdatatype(my_extra->domain_type)));
     goto fail;
    }
    break;
   case DOM_CONSTRAINT_CHECK:
    {
     /* Make the econtext if we didn't already */
     if (econtext == NULL)
     {
      MemoryContext oldcontext;

      oldcontext = MemoryContextSwitchTo(my_extra->mcxt);
      econtext = CreateStandaloneExprContext();
      MemoryContextSwitchTo(oldcontext);
      my_extra->econtext = econtext;
     }

     /*
      * Set up value to be returned by CoerceToDomainValue
      * nodes.  Unlike in the generic expression case, this
      * econtext couldn't be shared with anything else, so no
      * need to save and restore fields.  But we do need to
      * protect the passed-in value against being changed by
      * called functions.  (It couldn't be a R/W expanded
      * object for most uses, but that seems possible for
      * domain_check().)
 */

     econtext->domainValue_datum =
      MakeExpandedObjectReadOnly(value, isnull,
               my_extra->constraint_ref.tcache->typlen);
     econtext->domainValue_isNull = isnull;

     if (!ExecCheck(con->check_exprstate, econtext))
     {
      errsave(escontext,
        (errcode(ERRCODE_CHECK_VIOLATION),
         errmsg("value for domain %s violates check constraint \"%s\"",
          format_type_be(my_extra->domain_type),
          con->name),
         errdomainconstraint(my_extra->domain_type,
              con->name)));
      goto fail;
     }
     break;
    }
   default:
    elog(ERROR, "unrecognized constraint type: %d",
      (int) con->constrainttype);
    break;
  }
 }

 /*
  * Before exiting, call any shutdown callbacks and reset econtext's
  * per-tuple memory.  This avoids leaking non-memory resources, if
  * anything in the expression(s) has any.
 */

fail:
 if (econtext)
  ReScanExprContext(econtext);
}


/*
 * domain_in  - input routine for any domain type.
 */

Datum
domain_in(PG_FUNCTION_ARGS)
{
 char    *string;
 Oid   domainType;
 Node    *escontext = fcinfo->context;
 DomainIOData *my_extra;
 Datum  value;

 /*
  * Since domain_in is not strict, we have to check for null inputs. The
  * typioparam argument should never be null in normal system usage, but it
  * could be null in a manual invocation --- if so, just return null.
 */

 if (PG_ARGISNULL(0))
  string = NULL;
 else
  string = PG_GETARG_CSTRING(0);
 if (PG_ARGISNULL(1))
  PG_RETURN_NULL();
 domainType = PG_GETARG_OID(1);

 /*
  * We arrange to look up the needed info just once per series of calls,
  * assuming the domain type doesn't change underneath us (which really
  * shouldn't happen, but cope if it does).
 */

 my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
 if (my_extra == NULL || my_extra->domain_type != domainType)
 {
  my_extra = domain_state_setup(domainType, false,
           fcinfo->flinfo->fn_mcxt);
  fcinfo->flinfo->fn_extra = my_extra;
 }

 /*
  * Invoke the base type's typinput procedure to convert the data.
 */

 if (!InputFunctionCallSafe(&my_extra->proc,
          string,
          my_extra->typioparam,
          my_extra->typtypmod,
          escontext,
          &value))
  PG_RETURN_NULL();

 /*
  * Do the necessary checks to ensure it's a valid domain value.
 */

 domain_check_input(value, (string == NULL), my_extra, escontext);

 if (string == NULL)
  PG_RETURN_NULL();
 else
  PG_RETURN_DATUM(value);
}

/*
 * domain_recv  - binary input routine for any domain type.
 */

Datum
domain_recv(PG_FUNCTION_ARGS)
{
 StringInfo buf;
 Oid   domainType;
 DomainIOData *my_extra;
 Datum  value;

 /*
  * Since domain_recv is not strict, we have to check for null inputs. The
  * typioparam argument should never be null in normal system usage, but it
  * could be null in a manual invocation --- if so, just return null.
 */

 if (PG_ARGISNULL(0))
  buf = NULL;
 else
  buf = (StringInfo) PG_GETARG_POINTER(0);
 if (PG_ARGISNULL(1))
  PG_RETURN_NULL();
 domainType = PG_GETARG_OID(1);

 /*
  * We arrange to look up the needed info just once per series of calls,
  * assuming the domain type doesn't change underneath us (which really
  * shouldn't happen, but cope if it does).
 */

 my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
 if (my_extra == NULL || my_extra->domain_type != domainType)
 {
  my_extra = domain_state_setup(domainType, true,
           fcinfo->flinfo->fn_mcxt);
  fcinfo->flinfo->fn_extra = my_extra;
 }

 /*
  * Invoke the base type's typreceive procedure to convert the data.
 */

 value = ReceiveFunctionCall(&my_extra->proc,
        buf,
        my_extra->typioparam,
        my_extra->typtypmod);

 /*
  * Do the necessary checks to ensure it's a valid domain value.
 */

 domain_check_input(value, (buf == NULL), my_extra, NULL);

 if (buf == NULL)
  PG_RETURN_NULL();
 else
  PG_RETURN_DATUM(value);
}

/*
 * domain_check - check that a datum satisfies the constraints of a
 * domain.  extra and mcxt can be passed if they are available from,
 * say, a FmgrInfo structure, or they can be NULL, in which case the
 * setup is repeated for each call.
 */

void
domain_check(Datum value, bool isnull, Oid domainType,
    void **extra, MemoryContext mcxt)
{
 (void) domain_check_internal(value, isnull, domainType, extra, mcxt,
         NULL);
}

/* Error-safe variant of domain_check(). */
bool
domain_check_safe(Datum value, bool isnull, Oid domainType,
      void **extra, MemoryContext mcxt,
      Node *escontext)
{
 return domain_check_internal(value, isnull, domainType, extra, mcxt,
         escontext);
}

/*
 * domain_check_internal
 *   Workhorse for domain_check() and domain_check_safe()
 *
 * Returns false if an error occurred in domain_check_input() and 'escontext'
 * points to an ErrorSaveContext, true otherwise.
 */

static bool
domain_check_internal(Datum value, bool isnull, Oid domainType,
       void **extra, MemoryContext mcxt,
       Node *escontext)
{
 DomainIOData *my_extra = NULL;

 if (mcxt == NULL)
  mcxt = CurrentMemoryContext;

 /*
  * We arrange to look up the needed info just once per series of calls,
  * assuming the domain type doesn't change underneath us (which really
  * shouldn't happen, but cope if it does).
 */

 if (extra)
  my_extra = (DomainIOData *) *extra;
 if (my_extra == NULL || my_extra->domain_type != domainType)
 {
  my_extra = domain_state_setup(domainType, true, mcxt);
  if (extra)
   *extra = my_extra;
 }

 /*
  * Do the necessary checks to ensure it's a valid domain value.
 */

 domain_check_input(value, isnull, my_extra, escontext);

 return !SOFT_ERROR_OCCURRED(escontext);
}

/*
 * errdatatype --- stores schema_name and datatype_name of a datatype
 * within the current errordata.
 */

int
errdatatype(Oid datatypeOid)
{
 HeapTuple tup;
 Form_pg_type typtup;

 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(datatypeOid));
 if (!HeapTupleIsValid(tup))
  elog(ERROR, "cache lookup failed for type %u", datatypeOid);
 typtup = (Form_pg_type) GETSTRUCT(tup);

 err_generic_string(PG_DIAG_SCHEMA_NAME,
        get_namespace_name(typtup->typnamespace));
 err_generic_string(PG_DIAG_DATATYPE_NAME, NameStr(typtup->typname));

 ReleaseSysCache(tup);

 return 0;     /* return value does not matter */
}

/*
 * errdomainconstraint --- stores schema_name, datatype_name and
 * constraint_name of a domain-related constraint within the current errordata.
 */

int
errdomainconstraint(Oid datatypeOid, const char *conname)
{
 errdatatype(datatypeOid);
 err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname);

 return 0;     /* return value does not matter */
}

Messung V0.5 in Prozent
C=94 H=93 G=93

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.139Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002