summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/parse_coerce.c131
-rw-r--r--src/backend/parser/parse_expr.c14
-rw-r--r--src/backend/parser/parse_type.c25
3 files changed, 105 insertions, 65 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 1016c782d29..397bd4b8b07 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -35,7 +35,7 @@ static Node *build_func_call(Oid funcid, Oid rettype, List *args);
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.
@@ -49,7 +49,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
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))
@@ -69,11 +69,12 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
* 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);
@@ -85,16 +86,31 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
{
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)
@@ -109,21 +125,18 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
* 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))
{
@@ -144,8 +157,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
*
* 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),
@@ -157,11 +170,15 @@ coerce_type(ParseState *pstate, Node *node, Oid 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
@@ -306,28 +323,21 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
* 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.
@@ -335,7 +345,8 @@ coerce_type_typmod(ParseState *pstate, Node *node,
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;
@@ -348,7 +359,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
false,
false);
- node = build_func_call(funcId, baseTypeId, makeList2(node, cons));
+ node = build_func_call(funcId, targetTypeId, makeList2(node, cons));
}
return node;
@@ -869,12 +880,15 @@ build_func_call(Oid funcid, Oid rettype, List *args)
/*
* 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 (;;)
{
@@ -885,12 +899,13 @@ TypeConstraints(Node *arg, Oid typeId)
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 */
@@ -901,20 +916,32 @@ TypeConstraints(Node *arg, Oid typeId)
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;
}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 1a7acd22527..de07d39b4d0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -640,6 +640,7 @@ transformExpr(ParseState *pstate, Node *expr)
case T_ArrayRef:
case T_FieldSelect:
case T_RelabelType:
+ case T_ConstraintTest:
{
result = (Node *) expr;
break;
@@ -919,15 +920,15 @@ exprType(Node *expr)
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));
@@ -978,10 +979,8 @@ exprTypmod(Node *expr)
break;
case T_FieldSelect:
return ((FieldSelect *) expr)->resulttypmod;
- break;
case T_RelabelType:
return ((RelabelType *) expr)->resulttypmod;
- break;
case T_CaseExpr:
{
/*
@@ -1013,6 +1012,9 @@ exprTypmod(Node *expr)
return typmod;
}
break;
+ case T_ConstraintTest:
+ return exprTypmod(((ConstraintTest *) expr)->arg);
+
default:
break;
}
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 0eb29045b1f..e75c193eff5 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -277,6 +277,16 @@ typeByVal(Type t)
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)
@@ -434,7 +444,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
* 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) ||
@@ -450,25 +460,26 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
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;