*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.105 2002/08/31 19:10:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.106 2002/08/31 22:10:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalConstraint(Constraint *constraint, ExprContext *econtext,
- bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalConstraintTest(ConstraintTest *constraint,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
/*----------
}
}
-/*
- * ExecEvalConstraint
- *
- * Test the constraint against the data provided. If the data fits
- * within the constraint specifications, pass it through (return the
- * datum) otherwise throw an error.
- */
-static Datum
-ExecEvalConstraint(Constraint *constraint, ExprContext *econtext,
- bool *isNull, ExprDoneCond *isDone)
-{
- Datum result;
-
- result = ExecEvalExpr(constraint->raw_expr, econtext, isNull, isDone);
-
- /* Test for the constraint type */
- switch(constraint->contype)
- {
- case CONSTR_NOTNULL:
- if (*isNull)
- {
- elog(ERROR, "Domain %s does not allow NULL values", constraint->name);
- }
- break;
- case CONSTR_CHECK:
-
- elog(ERROR, "ExecEvalConstraint: Domain CHECK Constraints not yet implemented");
- break;
- default:
- elog(ERROR, "ExecEvalConstraint: Constraint type unknown");
- break;
- }
-
- /* If all has gone well (constraint did not fail) return the datum */
- return result;
-}
-
/* ----------------------------------------------------------------
* ExecEvalBooleanTest
*
}
}
+/*
+ * ExecEvalConstraintTest
+ *
+ * Test the constraint against the data provided. If the data fits
+ * within the constraint specifications, pass it through (return the
+ * datum) otherwise throw an error.
+ */
+static Datum
+ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ Datum result;
+
+ result = ExecEvalExpr(constraint->arg, econtext, isNull, isDone);
+
+ switch (constraint->testtype)
+ {
+ case CONSTR_TEST_NOTNULL:
+ if (*isNull)
+ elog(ERROR, "Domain %s does not allow NULL values",
+ constraint->name);
+ break;
+ case CONSTR_TEST_CHECK:
+ /* TODO: Add CHECK Constraints to domains */
+ elog(ERROR, "Domain CHECK Constraints not yet implemented");
+ break;
+ default:
+ elog(ERROR, "ExecEvalConstraintTest: Constraint type unknown");
+ break;
+ }
+
+ /* If all has gone well (constraint did not fail) return the datum */
+ return result;
+}
+
/* ----------------------------------------------------------------
* ExecEvalFieldSelect
*
isNull,
isDone);
break;
- case T_Constraint:
- retDatum = ExecEvalConstraint((Constraint *) expression,
- econtext,
- isNull,
- isDone);
- break;
case T_CaseExpr:
retDatum = ExecEvalCase((CaseExpr *) expression,
econtext,
isNull,
isDone);
break;
+ case T_ConstraintTest:
+ retDatum = ExecEvalConstraintTest((ConstraintTest *) expression,
+ econtext,
+ isNull,
+ isDone);
+ break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.208 2002/08/30 19:23:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.209 2002/08/31 22:10:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
-/* ----------------
- * _copyCaseExpr
- * ----------------
- */
static CaseExpr *
_copyCaseExpr(CaseExpr *from)
{
return newnode;
}
-/* ----------------
- * _copyCaseWhen
- * ----------------
- */
static CaseWhen *
_copyCaseWhen(CaseWhen *from)
{
return newnode;
}
-/* ----------------
- * _copyNullTest
- * ----------------
- */
static NullTest *
_copyNullTest(NullTest *from)
{
return newnode;
}
-/* ----------------
- * _copyBooleanTest
- * ----------------
- */
static BooleanTest *
_copyBooleanTest(BooleanTest *from)
{
return newnode;
}
+static ConstraintTest *
+_copyConstraintTest(ConstraintTest *from)
+{
+ ConstraintTest *newnode = makeNode(ConstraintTest);
+
+ /*
+ * copy remainder of node
+ */
+ Node_Copy(from, newnode, arg);
+ newnode->testtype = from->testtype;
+ if (from->name)
+ newnode->name = pstrdup(from->name);
+ Node_Copy(from, newnode, check_expr);
+
+ return newnode;
+}
+
static ArrayRef *
_copyArrayRef(ArrayRef *from)
{
case T_BooleanTest:
retval = _copyBooleanTest(from);
break;
+ case T_ConstraintTest:
+ retval = _copyConstraintTest(from);
+ break;
case T_FkConstraint:
retval = _copyFkConstraint(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.156 2002/08/30 19:23:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.157 2002/08/31 22:10:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
+{
+ if (!equal(a->arg, b->arg))
+ return false;
+ if (a->testtype != b->testtype)
+ return false;
+ if (!equalstr(a->name, b->name))
+ return false;
+ if (!equal(a->check_expr, b->check_expr))
+ return false;
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
case T_BooleanTest:
retval = _equalBooleanTest(a, b);
break;
+ case T_ConstraintTest:
+ retval = _equalConstraintTest(a, b);
+ break;
case T_FkConstraint:
retval = _equalFkConstraint(a, b);
break;
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.171 2002/08/30 19:23:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.172 2002/08/31 22:10:43 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
{
appendStringInfo(str, " NULLTEST :arg ");
_outNode(str, node->arg);
-
appendStringInfo(str, " :nulltesttype %d ",
(int) node->nulltesttype);
}
{
appendStringInfo(str, " BOOLEANTEST :arg ");
_outNode(str, node->arg);
-
appendStringInfo(str, " :booltesttype %d ",
(int) node->booltesttype);
}
+/*
+ * ConstraintTest
+ */
+static void
+_outConstraintTest(StringInfo str, ConstraintTest *node)
+{
+ appendStringInfo(str, " CONSTRAINTTEST :arg ");
+ _outNode(str, node->arg);
+ appendStringInfo(str, " :testtype %d :name ",
+ (int) node->testtype);
+ _outToken(str, node->name);
+ appendStringInfo(str, " :check_expr ");
+ _outNode(str, node->check_expr);
+}
+
/*
* _outNode -
* converts a Node into ascii string and append it to 'str'
case T_BooleanTest:
_outBooleanTest(str, obj);
break;
+ case T_ConstraintTest:
+ _outConstraintTest(str, obj);
+ break;
case T_FuncCall:
_outFuncCall(str, obj);
break;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.130 2002/08/30 19:23:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.131 2002/08/31 22:10:43 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
return local_node;
}
+/* ----------------
+ * _readConstraintTest
+ *
+ * ConstraintTest is a subclass of Node
+ * ----------------
+ */
+static ConstraintTest *
+_readConstraintTest(void)
+{
+ ConstraintTest *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(ConstraintTest);
+
+ token = pg_strtok(&length); /* eat :arg */
+ local_node->arg = nodeRead(true); /* now read it */
+
+ token = pg_strtok(&length); /* eat :testtype */
+ token = pg_strtok(&length); /* get testtype */
+ local_node->testtype = (ConstraintTestType) atoi(token);
+
+ token = pg_strtok(&length); /* get :name */
+ token = pg_strtok(&length); /* now read it */
+ local_node->name = nullable_string(token, length);
+
+ token = pg_strtok(&length); /* eat :check_expr */
+ local_node->check_expr = nodeRead(true); /* now read it */
+
+ return local_node;
+}
+
/* ----------------
* _readVar
*
return_value = _readNullTest();
else if (length == 11 && strncmp(token, "BOOLEANTEST", length) == 0)
return_value = _readBooleanTest();
+ else if (length == 14 && strncmp(token, "CONSTRAINTTEST", length) == 0)
+ return_value = _readConstraintTest();
else
elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.54 2002/08/02 18:15:06 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.55 2002/08/31 22:10:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/makefuncs.h"
#include "optimizer/prep.h"
#include "parser/parsetree.h"
+#include "parser/parse_coerce.h"
static List *expand_targetlist(List *tlist, int command_type,
*
* For INSERT, generate a NULL constant. (We assume the
* rewriter would have inserted any available default value.)
+ * Also, if the column isn't dropped, apply any domain constraints
+ * that might exist --- this is to catch domain NOT NULL.
*
* For UPDATE, generate a Var reference to the existing value of
* the attribute, so that it gets copied to the new tuple.
att_tup->attbyval,
false, /* not a set */
false);
+ if (!att_tup->attisdropped)
+ new_expr = coerce_type_constraints(NULL, new_expr,
+ atttype, false);
break;
case CMD_UPDATE:
/* Insert NULLs for dropped columns */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.106 2002/07/20 05:16:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.107 2002/08/31 22:10:43 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
return true;
}
break;
- case T_Constraint:
- return walker(((Constraint *) node)->raw_expr, context);
case T_NullTest:
return walker(((NullTest *) node)->arg, context);
case T_BooleanTest:
return walker(((BooleanTest *) node)->arg, context);
+ case T_ConstraintTest:
+ if (walker(((ConstraintTest *) node)->arg, context))
+ return true;
+ return walker(((ConstraintTest *) node)->check_expr, context);
case T_SubLink:
{
SubLink *sublink = (SubLink *) node;
return (Node *) newnode;
}
break;
- case T_Constraint:
- {
- /*
- * Used for confirming domains. Only needed fields
- * within the executor are the name, raw expression
- * and constraint type.
- */
- Constraint *con = (Constraint *) node;
- Constraint *newnode;
-
- FLATCOPY(newnode, con, Constraint);
- MUTATE(newnode->raw_expr, con->raw_expr, Node *);
- return (Node *) newnode;
- }
case T_NullTest:
{
NullTest *ntest = (NullTest *) node;
return (Node *) newnode;
}
break;
+ case T_ConstraintTest:
+ {
+ ConstraintTest *ctest = (ConstraintTest *) node;
+ ConstraintTest *newnode;
+
+ FLATCOPY(newnode, ctest, ConstraintTest);
+ MUTATE(newnode->arg, ctest->arg, Node *);
+ MUTATE(newnode->check_expr, ctest->check_expr, Node *);
+ return (Node *) newnode;
+ }
+ break;
case T_SubLink:
{
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.80 2002/08/22 00:01:42 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.81 2002/08/31 22:10:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static Oid find_coercion_function(Oid targetTypeId, Oid sourceTypeId,
bool isExplicit);
static Oid find_typmod_coercion_function(Oid typeId);
-static Node *TypeConstraints(Node *arg, Oid typeId);
+
/* coerce_type()
* Convert a function argument to a different type.
if (targetTypeId == inputTypeId ||
node == NULL)
{
- /* no conversion needed, but constraints may need to be applied */
+ /* no conversion needed */
result = node;
}
else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
* postpone evaluation of the function call until runtime. But
* there is no way to represent a typinput function call as an
* expression tree, because C-string values are not Datums.
+ * (XXX This *is* possible as of 7.3, do we want to do it?)
*/
Const *con = (Const *) node;
Const *newcon = makeNode(Const);
Type targetType = typeidType(targetTypeId);
- Oid baseTypeId = getBaseType(targetTypeId);
+ char targetTyptype = typeTypType(targetType);
newcon->consttype = targetTypeId;
newcon->constlen = typeLen(targetType);
{
char *val = DatumGetCString(DirectFunctionCall1(unknownout,
con->constvalue));
+
+ /*
+ * If target is a domain, use the typmod it applies to the base
+ * type. Note that we call stringTypeDatum using the domain's
+ * pg_type row, though. This works because the domain row has
+ * the same typinput and typelem as the base type --- ugly...
+ */
+ if (targetTyptype == 'd')
+ atttypmod = getBaseTypeMod(targetTypeId, atttypmod);
+
newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
pfree(val);
}
- ReleaseSysCache(targetType);
-
- /* Test for domain, and apply appropriate constraints */
result = (Node *) newcon;
- if (targetTypeId != baseTypeId)
- result = (Node *) TypeConstraints(result, targetTypeId);
+
+ /*
+ * If target is a domain, apply constraints (except for typmod,
+ * which we assume the input routine took care of).
+ */
+ if (targetTyptype == 'd')
+ result = coerce_type_constraints(pstate, result, targetTypeId,
+ false);
+
+ ReleaseSysCache(targetType);
}
else if (targetTypeId == ANYOID ||
targetTypeId == ANYARRAYOID)
* attach a RelabelType node so that the expression will be seen
* to have the intended type when inspected by higher-level code.
*
+ * Also, domains may have value restrictions beyond the base type
+ * that must be accounted for.
+ */
+ result = coerce_type_constraints(pstate, node, targetTypeId, true);
+ /*
* XXX could we label result with exprTypmod(node) instead of
* default -1 typmod, to save a possible length-coercion later?
* Would work if both types have same interpretation of typmod,
- * which is likely but not certain.
- *
- * Domains may have value restrictions beyond the base type that
- * must be accounted for.
+ * which is likely but not certain (wrong if target is a domain,
+ * in any case).
*/
- Oid baseTypeId = getBaseType(targetTypeId);
- result = node;
- if (targetTypeId != baseTypeId)
- result = (Node *) TypeConstraints(result, targetTypeId);
-
result = (Node *) makeRelabelType(result, targetTypeId, -1);
-
}
else if (typeInheritsFrom(inputTypeId, targetTypeId))
{
*
* For domains, we use the coercion function for the base type.
*/
- Oid funcId;
Oid baseTypeId = getBaseType(targetTypeId);
+ Oid funcId;
funcId = find_coercion_function(baseTypeId,
getBaseType(inputTypeId),
result = build_func_call(funcId, baseTypeId, makeList1(node));
/*
- * If domain, relabel with domain type ID and test against domain
- * constraints
+ * If domain, test against domain constraints and relabel with
+ * domain type ID
*/
if (targetTypeId != baseTypeId)
- result = (Node *) TypeConstraints(result, targetTypeId);
+ {
+ result = coerce_type_constraints(pstate, result, targetTypeId,
+ true);
+ result = (Node *) makeRelabelType(result, targetTypeId, -1);
+ }
/*
* If the input is a constant, apply the type conversion function
* function should be invoked to do that.
*
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
+ *
+ * This mechanism may seem pretty grotty and in need of replacement by
+ * something in pg_cast, but since typmod is only interesting for datatypes
+ * that have special handling in the grammar, there's not really much
+ * percentage in making it any easier to apply such coercions ...
+ *
+ * NOTE: this does not need to work on domain types, because any typmod
+ * coercion for a domain is considered to be part of the type coercion
+ * needed to produce the domain value in the first place.
*/
Node *
coerce_type_typmod(ParseState *pstate, Node *node,
Oid targetTypeId, int32 atttypmod)
{
- Oid baseTypeId;
Oid funcId;
- int32 domainTypMod;
-
- /* If given type is a domain, use base type instead */
- baseTypeId = getBaseTypeTypeMod(targetTypeId, &domainTypMod);
-
-
- /*
- * Use the domain typmod rather than what was supplied if the
- * domain was empty. atttypmod will always be -1 if domains are in use.
- */
- if (baseTypeId != targetTypeId)
- {
- Assert(atttypmod < 0);
- atttypmod = domainTypMod;
- }
/*
* A negative typmod is assumed to mean that no coercion is wanted.
if (atttypmod < 0 || atttypmod == exprTypmod(node))
return node;
- funcId = find_typmod_coercion_function(baseTypeId);
+ funcId = find_typmod_coercion_function(targetTypeId);
+
if (OidIsValid(funcId))
{
Const *cons;
false,
false);
- node = build_func_call(funcId, baseTypeId, makeList2(node, cons));
+ node = build_func_call(funcId, targetTypeId, makeList2(node, cons));
}
return node;
/*
* Create an expression tree to enforce the constraints (if any)
- * which should be applied by the type.
+ * that should be applied by the type. Currently this is only
+ * interesting for domain types.
*/
-static Node *
-TypeConstraints(Node *arg, Oid typeId)
+Node *
+coerce_type_constraints(ParseState *pstate, Node *arg,
+ Oid typeId, bool applyTypmod)
{
char *notNull = NULL;
+ int32 typmod = -1;
for (;;)
{
ObjectIdGetDatum(typeId),
0, 0, 0);
if (!HeapTupleIsValid(tup))
- elog(ERROR, "getBaseType: failed to lookup type %u", typeId);
+ elog(ERROR, "coerce_type_constraints: failed to lookup type %u",
+ typeId);
typTup = (Form_pg_type) GETSTRUCT(tup);
/* Test for NOT NULL Constraint */
if (typTup->typnotnull && notNull == NULL)
- notNull = NameStr(typTup->typname);
+ notNull = pstrdup(NameStr(typTup->typname));
/* TODO: Add CHECK Constraints to domains */
break;
}
+ Assert(typmod < 0);
+
typeId = typTup->typbasetype;
+ typmod = typTup->typtypmod;
ReleaseSysCache(tup);
}
+ /*
+ * If domain applies a typmod to its base type, do length coercion.
+ */
+ if (applyTypmod && typmod >= 0)
+ arg = coerce_type_typmod(pstate, arg, typeId, typmod);
+
/*
* Only need to add one NOT NULL check regardless of how many
- * domains in the tree request it.
+ * domains in the stack request it. The topmost domain that
+ * requested it is used as the constraint name.
*/
- if (notNull != NULL) {
- Constraint *r = makeNode(Constraint);
+ if (notNull)
+ {
+ ConstraintTest *r = makeNode(ConstraintTest);
- r->raw_expr = arg;
- r->contype = CONSTR_NOTNULL;
- r->name = notNull;
+ r->arg = arg;
+ r->testtype = CONSTR_TEST_NOTNULL;
+ r->name = notNull;
+ r->check_expr = NULL;
arg = (Node *) r;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.126 2002/08/26 17:53:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.127 2002/08/31 22:10:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case T_ArrayRef:
case T_FieldSelect:
case T_RelabelType:
+ case T_ConstraintTest:
{
result = (Node *) expr;
break;
case T_CaseWhen:
type = exprType(((CaseWhen *) expr)->result);
break;
- case T_Constraint:
- type = exprType(((Constraint *) expr)->raw_expr);
- break;
case T_NullTest:
type = BOOLOID;
break;
case T_BooleanTest:
type = BOOLOID;
break;
+ case T_ConstraintTest:
+ type = exprType(((ConstraintTest *) expr)->arg);
+ break;
default:
elog(ERROR, "exprType: Do not know how to get type for %d node",
nodeTag(expr));
break;
case T_FieldSelect:
return ((FieldSelect *) expr)->resulttypmod;
- break;
case T_RelabelType:
return ((RelabelType *) expr)->resulttypmod;
- break;
case T_CaseExpr:
{
/*
return typmod;
}
break;
+ case T_ConstraintTest:
+ return exprTypmod(((ConstraintTest *) expr)->arg);
+
default:
break;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.48 2002/08/08 01:22:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.49 2002/08/31 22:10:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return typ->typbyval;
}
+/* given type (as type struct), return the value of its 'typtype' attribute.*/
+char
+typeTypType(Type t)
+{
+ Form_pg_type typ;
+
+ typ = (Form_pg_type) GETSTRUCT(t);
+ return typ->typtype;
+}
+
/* given type (as type struct), return the name of type */
char *
typeTypeName(Type t)
* paranoia is justified since the string might contain anything.
*/
if (length(raw_parsetree_list) != 1)
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
stmt = (SelectStmt *) lfirst(raw_parsetree_list);
if (stmt == NULL ||
!IsA(stmt, SelectStmt) ||
stmt->limitCount != NULL ||
stmt->forUpdate != NIL ||
stmt->op != SETOP_NONE)
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
if (length(stmt->targetList) != 1)
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
restarget = (ResTarget *) lfirst(stmt->targetList);
if (restarget == NULL ||
!IsA(restarget, ResTarget) ||
restarget->name != NULL ||
restarget->indirection != NIL)
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
typecast = (TypeCast *) restarget->val;
if (typecast == NULL ||
!IsA(typecast, TypeCast) ||
typecast->arg == NULL ||
!IsA(typecast->arg, A_Const))
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
typename = typecast->typename;
if (typename == NULL ||
!IsA(typename, TypeName))
- elog(ERROR, "parseTypeString: Invalid type name '%s'", str);
+ elog(ERROR, "Invalid type name '%s'", str);
+
*type_id = typenameTypeId(typename);
*typmod = typename->typmod;
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.119 2002/08/29 01:19:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.120 2002/08/31 22:10:46 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
}
break;
+ case T_ConstraintTest:
+ {
+ ConstraintTest *ctest = (ConstraintTest *) node;
+
+ /*
+ * We assume that the operations of the constraint node
+ * need not be explicitly represented in the output.
+ */
+ get_rule_expr(ctest->arg, context);
+ }
+ break;
+
case T_SubLink:
get_sublink_expr(node, context);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.81 2002/08/29 00:17:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.82 2002/08/31 22:10:47 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
}
/*
- * getBaseTypeTypeMod
- * If the given type is a domain, return its base type;
- * otherwise return the type's own OID. Also return base typmod.
+ * getBaseTypeMod
+ * If the given type is a domain, return the typmod it applies to
+ * its base type; otherwise return the specified original typmod.
*/
-Oid
-getBaseTypeTypeMod(Oid typid, int32 *typmod)
+int32
+getBaseTypeMod(Oid typid, int32 typmod)
{
/*
* We loop to find the bottom base type in a stack of domains.
ObjectIdGetDatum(typid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
- elog(ERROR, "getBaseTypeTypeMod: failed to lookup type %u", typid);
+ elog(ERROR, "getBaseTypeMod: failed to lookup type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
if (typTup->typtype != 'd')
{
break;
}
+ /*
+ * The typmod applied to a domain should always be -1.
+ *
+ * We substitute the domain's typmod as we switch attention to
+ * the base type.
+ */
+ Assert(typmod < 0);
+
typid = typTup->typbasetype;
- *typmod = typTup->typtypmod;
+ typmod = typTup->typtypmod;
ReleaseSysCache(tup);
}
- return typid;
+ return typmod;
}
/*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.117 2002/08/27 04:55:11 tgl Exp $
+ * $Id: nodes.h,v 1.118 2002/08/31 22:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
T_GroupClause,
T_NullTest,
T_BooleanTest,
+ T_ConstraintTest,
T_CaseExpr,
T_CaseWhen,
T_FkConstraint,
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.203 2002/08/30 19:23:20 tgl Exp $
+ * $Id: parsenodes.h,v 1.204 2002/08/31 22:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
NullTestType nulltesttype; /* IS NULL, IS NOT NULL */
} NullTest;
-/* ----------------
+/*
* BooleanTest
*
* BooleanTest represents the operation of determining whether a boolean
* is TRUE, FALSE, or UNKNOWN (ie, NULL). All six meaningful combinations
* are supported. Note that a NULL input does *not* cause a NULL result.
* The appropriate test is performed and returned as a boolean Datum.
- * ----------------
*/
typedef enum BoolTestType
BoolTestType booltesttype; /* test type */
} BooleanTest;
+/*
+ * ConstraintTest
+ *
+ * ConstraintTest represents the operation of testing a value to see whether
+ * it meets a constraint. If so, the input value is returned as the result;
+ * if not, an error is raised.
+ */
+
+typedef enum ConstraintTestType
+{
+ CONSTR_TEST_NOTNULL,
+ CONSTR_TEST_CHECK
+} ConstraintTestType;
+
+typedef struct ConstraintTest
+{
+ NodeTag type;
+ Node *arg; /* input expression */
+ ConstraintTestType testtype; /* test type */
+ char *name; /* name of constraint (for error msgs) */
+ Node *check_expr; /* for CHECK test, a boolean expression */
+} ConstraintTest;
+
/*
* ColumnDef - column definition (used in various creates)
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_coerce.h,v 1.44 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_coerce.h,v 1.45 2002/08/31 22:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Oid targetTypeId, int32 atttypmod, bool isExplicit);
extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
Oid targetTypeId, int32 atttypmod);
+extern Node *coerce_type_constraints(ParseState *pstate, Node *arg,
+ Oid typeId, bool applyTypmod);
extern Node *coerce_to_boolean(Node *node, const char *constructName);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_type.h,v 1.23 2002/06/20 20:29:52 momjian Exp $
+ * $Id: parse_type.h,v 1.24 2002/08/31 22:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Oid typeTypeId(Type tp);
extern int16 typeLen(Type t);
extern bool typeByVal(Type t);
+extern char typeTypType(Type t);
extern char *typeTypeName(Type t);
extern char typeTypeFlag(Type t);
extern Oid typeTypeRelid(Type typ);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lsyscache.h,v 1.60 2002/08/29 00:17:06 tgl Exp $
+ * $Id: lsyscache.h,v 1.61 2002/08/31 22:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
bool *typIsVarlena);
extern Oid getBaseType(Oid typid);
-extern Oid getBaseTypeTypeMod(Oid typid, int32 *typmod);
+extern int32 getBaseTypeMod(Oid typid, int32 typmod);
extern int32 get_typavgwidth(Oid typid, int32 typmod);
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
extern bool get_attstatsslot(HeapTuple statstuple,
(2 rows)
-- check that domains inherit operations from base types
--- XXX shouldn't have to quote the constant here
-select testtext || testvarchar as concat, testnumeric + '42' as sum
+select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest;
concat | sum
-----------+--------
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
-ERROR: ExecInsert: Fail to add null value in not null attribute col3
+ERROR: Domain dnotnull does not allow NULL values
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
ERROR: Domain dnotnull does not allow NULL values
, col5 ddef1 NOT NULL DEFAULT NULL
, col6 ddef2 DEFAULT '88'
, col7 ddef4 DEFAULT 8000
- , col8 ddef5
+ , col8 ddef5
);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'defaulttest_pkey' for table 'defaulttest'
insert into defaulttest default values;
select * from basictest;
-- check that domains inherit operations from base types
--- XXX shouldn't have to quote the constant here
-select testtext || testvarchar as concat, testnumeric + '42' as sum
+select testtext || testvarchar as concat, testnumeric + 42 as sum
from basictest;
drop table basictest;