mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
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.
This commit is contained in:
parent
4e5c2a8d52
commit
316d4e29b2
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user