From: Tom Lane Date: Fri, 20 Sep 2002 16:56:02 +0000 (+0000) Subject: Code review for check-domain-constraints-in-COPY patch. Do correct thing X-Git-Tag: REL7_3~438 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=316d4e29b2a1ba5c70eb6fba3e820b971157c025;p=postgresql Code review for check-domain-constraints-in-COPY patch. Do correct thing when default expression for a domain is being used. Avoid repetitive catalog lookups. --- diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index becb66d7fc..b4de718eae 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.174 2002/09/20 15:43:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.175 2002/09/20 16:56:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,6 +43,7 @@ #include "utils/lsyscache.h" #include "utils/syscache.h" + #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) #define OCTVALUE(c) ((c) - '0') @@ -746,8 +747,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, num_defaults; FmgrInfo *in_functions; Oid *elements; - bool *isDomain; - bool hasDomain = false; + Node **constraintexprs; + Const **constraintconsts; + bool hasConstraints = false; int i; List *cur; Oid in_func_oid; @@ -792,15 +794,18 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ExecSetSlotDescriptor(slot, tupDesc, false); /* - * pick up the input function and default expression (if any) for each - * attribute in the relation. (We don't actually use the input - * function if it's a binary copy.) + * Pick up the required catalog information for each attribute in the + * relation, including the input function, the element type (to pass + * to the input function), and info about defaults and constraints. + * (We don't actually use the input function if it's a binary copy.) */ - defmap = (int *) palloc(sizeof(int) * num_phys_attrs); - defexprs = (Node **) palloc(sizeof(Node *) * num_phys_attrs); in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid)); - isDomain = (bool *) palloc(num_phys_attrs * sizeof(bool)); + defmap = (int *) palloc(num_phys_attrs * sizeof(int)); + defexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *)); + constraintexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *)); + constraintconsts = (Const **) palloc(num_phys_attrs * sizeof(Const *)); + MemSet(constraintexprs, 0, num_phys_attrs * sizeof(Node *)); for (i = 0; i < num_phys_attrs; i++) { @@ -808,20 +813,12 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, if (attr[i]->attisdropped) continue; - /* Test for the base type */ - if (getBaseType(attr[i]->atttypid) != attr[i]->atttypid) - { - hasDomain = true; - isDomain[i] = true; - } - else - isDomain[i] = false; - /* Fetch the input function */ in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); fmgr_info(in_func_oid, &in_functions[i]); elements[i] = GetTypeElement(attr[i]->atttypid); + /* Get default info if needed */ if (intMember(i + 1, attnumlist)) { /* attribute is to be copied */ @@ -839,6 +836,45 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, num_defaults++; } } + + /* If it's a domain type, get info on domain constraints */ + if (get_typtype(attr[i]->atttypid) == 'd') + { + Const *con; + Node *node; + + /* + * Easiest way to do this is to use parse_coerce.c to set up + * an expression that checks the constraints. (At present, + * the expression might contain a length-coercion-function call + * and/or ConstraintTest nodes.) The bottom of the expression + * is a Const node that we fill in with the actual datum during + * the data input loop. + * + * XXX to prevent premature constant folding in parse_coerce, + * pass in a NULL constant to start with. See the comments in + * coerce_type; this should be changed someday to use some sort + * of Param node instead of a Const. + */ + con = makeConst(attr[i]->atttypid, + attr[i]->attlen, + (Datum) 0, + true, /* is null */ + attr[i]->attbyval, + false, /* not a set */ + false); /* not coerced */ + + node = coerce_type_constraints((Node *) con, attr[i]->atttypid, + COERCE_IMPLICIT_CAST); + + /* check whether any constraints actually found */ + if (node != (Node *) con) + { + constraintexprs[i] = node; + constraintconsts[i] = con; + hasConstraints = true; + } + } } if (!binary) @@ -1090,52 +1126,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, } } - /* Deal with domains */ - if (hasDomain) - { - ParseState *pstate; - pstate = make_parsestate(NULL); - - foreach(cur, attnumlist) - { - int attnum = lfirsti(cur); - int m = attnum - 1; - - Const *con; - Node *node; - bool isNull = (nulls[m] == 'n'); - - /* This is not a domain, so lets skip it */ - if (!isDomain[m]) - continue; - - /* - * This is a domain. As such, we must process it's input - * function and coerce_type_constraints. The simplest way - * of doing that is to allow coerce_type to accomplish its - * job from an unknown constant - */ - - /* Create a constant */ - con = makeConst(attr[m]->atttypid, - attr[m]->attlen, - values[m], - isNull, - attr[m]->attbyval, - false, /* not a set */ - false); /* not coerced */ - - /* Process constraints */ - node = coerce_type_constraints((Node *) con, attr[m]->atttypid, - COERCE_IMPLICIT_CAST); - - values[m] = ExecEvalExpr(node, econtext, - &isNull, NULL); - - nulls[m] = isNull ? 'n' : ' '; - } - } - /* * Now compute and insert any defaults available for the columns * not provided by the input data. Anything not processed here or @@ -1151,6 +1141,36 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, nulls[defmap[i]] = ' '; } + /* + * Next apply any domain constraints + */ + if (hasConstraints) + { + for (i = 0; i < num_phys_attrs; i++) + { + Node *node = constraintexprs[i]; + Const *con; + bool isnull; + + if (node == NULL) + continue; /* no constraint for this attr */ + + /* Insert current row's value into the Const node */ + con = constraintconsts[i]; + con->constvalue = values[i]; + con->constisnull = (nulls[i] == 'n'); + + /* + * Execute the constraint expression. Allow the expression + * to replace the value (consider e.g. a timestamp precision + * restriction). + */ + values[i] = ExecEvalExpr(node, econtext, + &isnull, NULL); + nulls[i] = isnull ? 'n' : ' '; + } + } + /* * And now we can form the input tuple. */