/*-------------------------------------------------------------------------
*
* 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