Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Functions

domains.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/executor.h"
#include "lib/stringinfo.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for domains.c:

Go to the source code of this file.

Data Structures

struct  DomainIOData

Typedefs

typedef struct DomainIOData DomainIOData

Functions

static void domain_state_setup (DomainIOData *my_extra, Oid domainType, bool binary, MemoryContext mcxt)
static void domain_check_input (Datum value, bool isnull, DomainIOData *my_extra)
Datum domain_in (PG_FUNCTION_ARGS)
Datum domain_recv (PG_FUNCTION_ARGS)
void domain_check (Datum value, bool isnull, Oid domainType, void **extra, MemoryContext mcxt)
int errdatatype (Oid datatypeOid)
int errdomainconstraint (Oid datatypeOid, const char *conname)

Typedef Documentation

typedef struct DomainIOData DomainIOData

Function Documentation

void domain_check ( Datum  value,
bool  isnull,
Oid  domainType,
void **  extra,
MemoryContext  mcxt 
)

Definition at line 319 of file domains.c.

References CurrentMemoryContext, domain_check_input(), domain_state_setup(), DomainIOData::domain_type, MemoryContextAlloc(), and NULL.

Referenced by PLyObject_ToBool(), and PLyObject_ToBytea().

{
    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.
     */
    if (extra)
        my_extra = (DomainIOData *) *extra;
    if (my_extra == NULL)
    {
        my_extra = (DomainIOData *) MemoryContextAlloc(mcxt,
                                                       sizeof(DomainIOData));
        domain_state_setup(my_extra, domainType, true, mcxt);
        if (extra)
            *extra = (void *) my_extra;
    }
    else if (my_extra->domain_type != domainType)
        domain_state_setup(my_extra, domainType, true, mcxt);

    /*
     * Do the necessary checks to ensure it's a valid domain value.
     */
    domain_check_input(value, isnull, my_extra);
}

static void domain_check_input ( Datum  value,
bool  isnull,
DomainIOData my_extra 
) [static]

Definition at line 116 of file domains.c.

References DomainConstraintState::check_expr, DomainIOData::constraint_list, DomainConstraintState::constrainttype, CreateStandaloneExprContext(), DatumGetBool, DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, DomainIOData::domain_type, ExprContext::domainValue_datum, ExprContext::domainValue_isNull, DomainIOData::econtext, elog, ereport, errcode(), errdatatype(), errdomainconstraint(), errmsg(), ERROR, ExecEvalExprSwitchContext(), format_type_be(), lfirst, DomainIOData::mcxt, MemoryContextSwitchTo(), DomainConstraintState::name, NULL, and ReScanExprContext().

Referenced by domain_check(), domain_in(), and domain_recv().

{
    ExprContext *econtext = my_extra->econtext;
    ListCell   *l;

    foreach(l, my_extra->constraint_list)
    {
        DomainConstraintState *con = (DomainConstraintState *) lfirst(l);

        switch (con->constrainttype)
        {
            case DOM_CONSTRAINT_NOTNULL:
                if (isnull)
                    ereport(ERROR,
                            (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)));
                break;
            case DOM_CONSTRAINT_CHECK:
                {
                    Datum       conResult;
                    bool        conIsNull;

                    /* 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 ExecEvalCoerceToDomain, this econtext
                     * couldn't be shared with anything else, so no need to
                     * save and restore fields.
                     */
                    econtext->domainValue_datum = value;
                    econtext->domainValue_isNull = isnull;

                    conResult = ExecEvalExprSwitchContext(con->check_expr,
                                                          econtext,
                                                          &conIsNull, NULL);

                    if (!conIsNull &&
                        !DatumGetBool(conResult))
                        ereport(ERROR,
                                (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)));
                    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.
     */
    if (econtext)
        ReScanExprContext(econtext);
}

Datum domain_in ( PG_FUNCTION_ARGS   ) 

Definition at line 196 of file domains.c.

References domain_check_input(), domain_state_setup(), DomainIOData::domain_type, InputFunctionCall(), MemoryContextAlloc(), NULL, PG_ARGISNULL, PG_GETARG_CSTRING, PG_GETARG_OID, PG_RETURN_DATUM, PG_RETURN_NULL, DomainIOData::proc, DomainIOData::typioparam, DomainIOData::typtypmod, and value.

{
    char       *string;
    Oid         domainType;
    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.
     */
    my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
    if (my_extra == NULL)
    {
        my_extra = (DomainIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                                                       sizeof(DomainIOData));
        domain_state_setup(my_extra, domainType, false,
                           fcinfo->flinfo->fn_mcxt);
        fcinfo->flinfo->fn_extra = (void *) my_extra;
    }
    else if (my_extra->domain_type != domainType)
        domain_state_setup(my_extra, domainType, false,
                           fcinfo->flinfo->fn_mcxt);

    /*
     * Invoke the base type's typinput procedure to convert the data.
     */
    value = InputFunctionCall(&my_extra->proc,
                              string,
                              my_extra->typioparam,
                              my_extra->typtypmod);

    /*
     * Do the necessary checks to ensure it's a valid domain value.
     */
    domain_check_input(value, (string == NULL), my_extra);

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

Datum domain_recv ( PG_FUNCTION_ARGS   ) 

Definition at line 256 of file domains.c.

References buf, domain_check_input(), domain_state_setup(), DomainIOData::domain_type, MemoryContextAlloc(), NULL, PG_ARGISNULL, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, DomainIOData::proc, ReceiveFunctionCall(), DomainIOData::typioparam, DomainIOData::typtypmod, and value.

{
    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.
     */
    my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
    if (my_extra == NULL)
    {
        my_extra = (DomainIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
                                                       sizeof(DomainIOData));
        domain_state_setup(my_extra, domainType, true,
                           fcinfo->flinfo->fn_mcxt);
        fcinfo->flinfo->fn_extra = (void *) my_extra;
    }
    else if (my_extra->domain_type != domainType)
        domain_state_setup(my_extra, domainType, true,
                           fcinfo->flinfo->fn_mcxt);

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

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

static void domain_state_setup ( DomainIOData my_extra,
Oid  domainType,
bool  binary,
MemoryContext  mcxt 
) [static]

Definition at line 68 of file domains.c.

References DomainIOData::constraint_list, DomainIOData::domain_type, DomainIOData::econtext, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), format_type_be(), getBaseTypeAndTypmod(), GetDomainConstraints(), getTypeBinaryInputInfo(), getTypeInputInfo(), DomainIOData::mcxt, MemoryContextSwitchTo(), DomainIOData::proc, DomainIOData::typiofunc, DomainIOData::typioparam, and DomainIOData::typtypmod.

Referenced by domain_check(), domain_in(), and domain_recv().

{
    Oid         baseType;
    MemoryContext oldcontext;

    /* Mark cache invalid */
    my_extra->domain_type = InvalidOid;

    /* Find out the base type */
    my_extra->typtypmod = -1;
    baseType = getBaseTypeAndTypmod(domainType, &my_extra->typtypmod);
    if (baseType == domainType)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("type %s is not a domain",
                        format_type_be(domainType))));

    /* 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 */
    oldcontext = MemoryContextSwitchTo(mcxt);
    my_extra->constraint_list = GetDomainConstraints(domainType);
    MemoryContextSwitchTo(oldcontext);

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

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

int errdatatype ( Oid  datatypeOid  ) 

Definition at line 355 of file domains.c.

References elog, err_generic_string(), ERROR, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum, PG_DIAG_DATATYPE_NAME, PG_DIAG_SCHEMA_NAME, ReleaseSysCache(), SearchSysCache1, and TYPEOID.

Referenced by domain_check_input(), errdomainconstraint(), and ExecEvalCoerceToDomain().

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

int errdomainconstraint ( Oid  datatypeOid,
const char *  conname 
)

Definition at line 379 of file domains.c.

References err_generic_string(), errdatatype(), and PG_DIAG_CONSTRAINT_NAME.

Referenced by domain_check_input(), and ExecEvalCoerceToDomain().

{
    errdatatype(datatypeOid);
    err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname);

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