aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_coerce.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r--src/backend/parser/parse_coerce.c212
1 files changed, 70 insertions, 142 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index af184eca6d1..46d191a9158 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,18 +8,13 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.91 2002/12/12 20:35:13 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.92 2003/02/03 21:15:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
-#include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/indexing.h"
#include "catalog/pg_cast.h"
-#include "catalog/pg_constraint.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@@ -35,7 +30,7 @@
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat);
+ CoercionForm cformat, bool isExplicit);
static Oid PreferredType(CATEGORY category, Oid type);
static Node *build_func_call(Oid funcid, Oid rettype, List *args,
CoercionForm fformat);
@@ -103,7 +98,9 @@ coerce_to_target_type(Node *expr, Oid exprtype,
* as well as a type coercion.
*/
if (expr != NULL)
- expr = coerce_type_typmod(expr, targettype, targettypmod, cformat);
+ expr = coerce_type_typmod(expr, targettype, targettypmod,
+ cformat,
+ (cformat != COERCE_IMPLICIT_CAST));
return expr;
}
@@ -119,7 +116,7 @@ coerce_to_target_type(Node *expr, Oid exprtype,
* No coercion to a typmod (length) is performed here. The caller must
* call coerce_type_typmod as well, if a typmod constraint is wanted.
* (But if the target type is a domain, it may internally contain a
- * typmod constraint, which will be applied inside coerce_type_constraints.)
+ * typmod constraint, which will be applied inside coerce_to_domain.)
*/
Node *
coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
@@ -186,15 +183,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
/* If target is a domain, apply constraints. */
if (targetTyptype == 'd')
- {
- result = coerce_type_constraints(result, targetTypeId,
- cformat);
- /* We might now need a RelabelType. */
- if (exprType(result) != targetTypeId)
- result = (Node *) makeRelabelType((Expr *) result,
- targetTypeId, -1,
- cformat);
- }
+ result = coerce_to_domain(result, InvalidOid, targetTypeId,
+ cformat);
ReleaseSysCache(targetType);
}
@@ -222,17 +212,12 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
cformat);
/*
- * If domain, test against domain constraints and relabel with
+ * If domain, coerce to the domain type and relabel with
* domain type ID
*/
if (targetTypeId != baseTypeId)
- {
- result = coerce_type_constraints(result, targetTypeId,
- cformat);
- result = (Node *) makeRelabelType((Expr *) result,
- targetTypeId, -1,
- cformat);
- }
+ result = coerce_to_domain(result, baseTypeId, targetTypeId,
+ cformat);
/*
* If the input is a constant, apply the type conversion
@@ -257,21 +242,23 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
* higher-level code.
*
* Also, domains may have value restrictions beyond the base type
- * that must be accounted for.
+ * that must be accounted for. If the destination is a domain
+ * then we won't need a RelabelType node.
*/
- result = coerce_type_constraints(node, targetTypeId,
- cformat);
-
- /*
- * 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 (wrong if target is
- * a domain, in any case).
- */
- result = (Node *) makeRelabelType((Expr *) result,
- targetTypeId, -1,
- cformat);
+ result = coerce_to_domain(node, InvalidOid, targetTypeId,
+ cformat);
+ if (result == node)
+ {
+ /*
+ * 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.
+ */
+ result = (Node *) makeRelabelType((Expr *) result,
+ targetTypeId, -1,
+ cformat);
+ }
}
}
else if (typeInheritsFrom(inputTypeId, targetTypeId))
@@ -392,120 +379,61 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
/*
- * Create an expression tree to enforce the constraints (if any)
- * that should be applied by the type. Currently this is only
- * interesting for domain types.
+ * Create an expression tree to represent coercion to a domain type.
+ *
+ * 'arg': input expression
+ * 'baseTypeId': base type of domain, if known (pass InvalidOid if caller
+ * has not bothered to look this up)
+ * 'typeId': target type to coerce to
+ * 'cformat': coercion format
*
- * NOTE: result tree is not guaranteed to show the correct exprType() for
- * the domain; it may show the base type. Caller must relabel if needed.
+ * If the target type isn't a domain, the given 'arg' is returned as-is.
*/
Node *
-coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
+coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, CoercionForm cformat)
{
- char *notNull = NULL;
- int32 typmod = -1;
-
- for (;;)
- {
- HeapTuple tup;
- HeapTuple conTup;
- Form_pg_type typTup;
-
- ScanKeyData key[1];
- int nkeys = 0;
- SysScanDesc scan;
- Relation conRel;
-
- tup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typeId),
- 0, 0, 0);
- if (!HeapTupleIsValid(tup))
- 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 = pstrdup(NameStr(typTup->typname));
-
- /* Add CHECK Constraints to domains */
- conRel = heap_openr(ConstraintRelationName, RowShareLock);
-
- ScanKeyEntryInitialize(&key[nkeys++], 0x0,
- Anum_pg_constraint_contypid, F_OIDEQ,
- ObjectIdGetDatum(typeId));
-
- scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
- SnapshotNow, nkeys, key);
-
- while (HeapTupleIsValid(conTup = systable_getnext(scan)))
- {
- Datum val;
- bool isNull;
- ConstraintTest *r = makeNode(ConstraintTest);
- Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
-
- /* Not expecting conbin to be NULL, but we'll test for it anyway */
- val = fastgetattr(conTup,
- Anum_pg_constraint_conbin,
- conRel->rd_att, &isNull);
-
- if (isNull)
- elog(ERROR, "coerce_type_constraints: domain %s constraint %s has NULL conbin",
- NameStr(typTup->typname), NameStr(c->conname));
-
- r->arg = (Expr *) arg;
- r->testtype = CONSTR_TEST_CHECK;
- r->name = NameStr(c->conname);
- r->domname = NameStr(typTup->typname);
- r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
- val)));
-
- arg = (Node *) r;
- }
-
- systable_endscan(scan);
- heap_close(conRel, RowShareLock);
-
- if (typTup->typtype != 'd')
- {
- /* Not a domain, so done */
- ReleaseSysCache(tup);
- break;
- }
+ CoerceToDomain *result;
+ int32 typmod;
- Assert(typmod < 0);
+ /* Get the base type if it hasn't been supplied */
+ if (baseTypeId == InvalidOid)
+ baseTypeId = getBaseType(typeId);
- typeId = typTup->typbasetype;
- typmod = typTup->typtypmod;
- ReleaseSysCache(tup);
- }
+ /* If it isn't a domain, return the node as it was passed in */
+ if (baseTypeId == typeId)
+ return arg;
/*
- * If domain applies a typmod to its base type, do length coercion.
+ * If the domain applies a typmod to its base type, build the appropriate
+ * coercion step. Mark it implicit for display purposes, because we don't
+ * want it shown separately by ruleutils.c; but the isExplicit flag passed
+ * to the conversion function depends on the manner in which the domain
+ * coercion is invoked, so that the semantics of implicit and explicit
+ * coercion differ. (Is that really the behavior we want?)
+ *
+ * NOTE: because we apply this as part of the fixed expression structure,
+ * ALTER DOMAIN cannot alter the typtypmod. But it's unclear that that
+ * would be safe to do anyway, without lots of knowledge about what the
+ * base type thinks the typmod means.
*/
+ typmod = get_typtypmod(typeId);
if (typmod >= 0)
- arg = coerce_type_typmod(arg, typeId, typmod, cformat);
+ arg = coerce_type_typmod(arg, baseTypeId, typmod,
+ COERCE_IMPLICIT_CAST,
+ (cformat != COERCE_IMPLICIT_CAST));
/*
- * Only need to add one NOT NULL check regardless of how many domains
- * in the stack request it. The topmost domain that requested it is
- * used as the constraint name.
+ * Now build the domain coercion node. This represents run-time checking
+ * of any constraints currently attached to the domain. This also
+ * ensures that the expression is properly labeled as to result type.
*/
- if (notNull)
- {
- ConstraintTest *r = makeNode(ConstraintTest);
-
- r->arg = (Expr *) arg;
- r->testtype = CONSTR_TEST_NOTNULL;
- r->name = "NOT NULL";
- r->domname = notNull;
- r->check_expr = NULL;
-
- arg = (Node *) r;
- }
+ result = makeNode(CoerceToDomain);
+ result->arg = (Expr *) arg;
+ result->resulttype = typeId;
+ result->resulttypmod = -1; /* currently, always -1 for domains */
+ result->coercionformat = cformat;
- return arg;
+ return (Node *) result;
}
@@ -526,7 +454,7 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
*/
static Node *
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat)
+ CoercionForm cformat, bool isExplicit)
{
Oid funcId;
int nargs;
@@ -559,7 +487,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
/* Pass it a boolean isExplicit parameter, too */
cons = makeConst(BOOLOID,
sizeof(bool),
- BoolGetDatum(cformat != COERCE_IMPLICIT_CAST),
+ BoolGetDatum(isExplicit),
false,
true);