aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_node.c
diff options
context:
space:
mode:
authorThomas G. Lockhart <lockhart@fourpalms.org>1998-05-09 23:31:34 +0000
committerThomas G. Lockhart <lockhart@fourpalms.org>1998-05-09 23:31:34 +0000
commit3ace5fd08247726756d695156e8ccb075d5f76d5 (patch)
tree640d4b580e65f500f0894a7c9b65bb5d8bd974c7 /src/backend/parser/parse_node.c
parent54b5577cb6822d35256e2e3a36b6c59e7fda1409 (diff)
downloadpostgresql-3ace5fd08247726756d695156e8ccb075d5f76d5.tar.gz
postgresql-3ace5fd08247726756d695156e8ccb075d5f76d5.zip
Add capabilities for automatic type conversion.
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r--src/backend/parser/parse_node.c157
1 files changed, 115 insertions, 42 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 3a36fcd576c..140ca3df47e 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.14 1998/02/26 04:33:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.15 1998/05/09 23:29:53 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,7 +39,7 @@ make_operand(char *opname,
/*
* make_parsestate() --
* allocate and initialize a new ParseState.
- * the CALLERS is responsible for freeing the ParseState* returned
+ * the CALLER is responsible for freeing the ParseState* returned
*
*/
@@ -57,6 +57,15 @@ make_parsestate(ParseState *parentParseState)
return (pstate);
}
+
+extern
+Node *
+coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId);
+
+
+/* make_operand()
+ * Ensure argument type match by forcing conversion of constants.
+ */
static Node *
make_operand(char *opname,
Node *tree,
@@ -65,35 +74,33 @@ make_operand(char *opname,
{
Node *result;
Type true_type;
+#if FALSE
Datum val;
Oid infunc;
+#endif
+#ifdef PARSEDEBUG
+printf("make_operand: constructing operand for '%s' %s->%s\n",
+ opname, typeidTypeName(orig_typeId), typeidTypeName(true_typeId));
+#endif
if (tree != NULL)
{
result = tree;
true_type = typeidType(true_typeId);
disallow_setop(opname, true_type, result);
+
+ /* must coerce? */
if (true_typeId != orig_typeId)
- { /* must coerce */
- Const *con = (Const *) result;
-
- Assert(nodeTag(result) == T_Const);
- val = (Datum) textout((struct varlena *)
- con->constvalue);
- infunc = typeidInfunc(true_typeId);
- con = makeNode(Const);
- con->consttype = true_typeId;
- con->constlen = typeLen(true_type);
- con->constvalue = (Datum) fmgr(infunc,
- val,
- typeidTypElem(true_typeId),
- -1 /* for varchar() type */ );
- con->constisnull = false;
- con->constbyval = true;
- con->constisset = false;
- result = (Node *) con;
+ {
+#ifdef PARSEDEBUG
+printf("make_operand: try to convert node from %s to %s\n",
+ typeidTypeName(orig_typeId), typeidTypeName(true_typeId));
+#endif
+ result = coerce_type(NULL, tree, orig_typeId, true_typeId);
}
}
+
+ /* otherwise, this is a NULL value */
else
{
Const *con = makeNode(Const);
@@ -108,7 +115,7 @@ make_operand(char *opname,
}
return result;
-}
+} /* make_operand() */
static void
@@ -119,13 +126,49 @@ disallow_setop(char *op, Type optype, Node *operand)
if (nodeTag(operand) == T_Iter)
{
- elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
- op, typeTypeName(optype));
- elog(ERROR, "but '%s' takes single values, not sets.",
- op);
+ elog(ERROR, "An operand to the '%s' operator returns a set of %s,"
+ "\n\tbut '%s' takes single values, not sets.",
+ op, typeTypeName(optype), op);
}
}
+
+/* CoerceType()
+ * Try to force type of node.
+ */
+Oid CoerceType(Oid typeId, Node *node);
+
+Oid
+CoerceType(Oid typeId, Node *node)
+{
+ switch (nodeTag(node))
+ {
+ case T_Const:
+ {
+ Const *con = (Const *) node;
+
+#ifdef PARSEDEBUG
+printf( "Convert node %d to text\n", nodeTag(node));
+#endif
+
+ typeId = TEXTOID;
+ con->consttype = typeId;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return typeId;
+} /* CoerceType() */
+
+
+/* make_op()
+ * Operator construction.
+ *
+ * Transform operator expression ensuring type compatibility.
+ * This is where some type conversion happens.
+ */
Expr *
make_op(char *opname, Node *ltree, Node *rtree)
{
@@ -138,10 +181,9 @@ make_op(char *opname, Node *ltree, Node *rtree)
*right;
Expr *result;
+ /* right operator? */
if (rtree == NULL)
{
-
- /* right operator */
ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
temp = right_oper(opname, ltypeId);
opform = (OperatorTupleForm) GETSTRUCT(temp);
@@ -149,25 +191,29 @@ make_op(char *opname, Node *ltree, Node *rtree)
right = NULL;
}
+
+ /* left operator? */
else if (ltree == NULL)
{
-
- /* left operator */
rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
temp = left_oper(opname, rtypeId);
+#ifdef PARSEDEBUG
+printf("make_op: returned from left_oper() with structure at %p\n", (void *)temp);
+#endif
opform = (OperatorTupleForm) GETSTRUCT(temp);
+#ifdef PARSEDEBUG
+printf("make_op: calling make_operand()\n");
+#endif
right = make_operand(opname, rtree, rtypeId, opform->oprright);
left = NULL;
}
+
+ /* otherwise, binary operator */
else
{
- char *outstr;
- Oid infunc,
- outfunc;
- Type newtype;
-#define CONVERTABLE_TYPE(t) ( (t) == INT2OID || \
+#define CONVERTIBLE_TYPE(t) ( (t) == INT2OID || \
(t) == INT4OID || \
(t) == OIDOID || \
(t) == FLOAT4OID || \
@@ -178,12 +224,32 @@ make_op(char *opname, Node *ltree, Node *rtree)
ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
+#if FALSE
+ /* Both operands of unknown type?
+ * Then they are strings and we should force at least one to text
+ * - thomas 1998-03-16
+ */
+ ltypeId = exprType(ltree);
+ rtypeId = exprType(rtree);
+
+ if ((ltypeId == UNKNOWNOID)
+ && (rtypeId == UNKNOWNOID))
+ {
+#ifdef PARSEDEBUG
+printf( "Convert left-hand constant to text for node %d\n", nodeTag(ltree));
+#endif
+
+ ltypeId = CoerceType(TEXTOID, ltree);
+ }
+#endif
+
+#if FALSE
/*
* convert constant when using a const of a numeric type and a
* non-const of another numeric type
*/
- if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
- CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
+ if (CONVERTIBLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
+ CONVERTIBLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
!((Const *) rtree)->constiscast)
{
outfunc = typeidOutfunc(rtypeId);
@@ -197,8 +263,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
((Const *) rtree)->constbyval = typeByVal(newtype);
}
- if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
- CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
+ if (CONVERTIBLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
+ CONVERTIBLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
!((Const *) ltree)->constiscast)
{
outfunc = typeidOutfunc(ltypeId);
@@ -211,6 +277,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
((Const *) ltree)->constlen = typeLen(newtype);
((Const *) ltree)->constbyval = typeByVal(newtype);
}
+#endif
temp = oper(opname, ltypeId, rtypeId, false);
opform = (OperatorTupleForm) GETSTRUCT(temp);
@@ -219,8 +286,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
}
newop = makeOper(oprid(temp), /* opno */
- InvalidOid,/* opid */
- opform->oprresult, /* operator result type */
+ InvalidOid, /* opid */
+ opform->oprresult, /* operator result type */
0,
NULL);
@@ -239,6 +306,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
return result;
}
+
Var *
make_var(ParseState *pstate, Oid relid, char *refname,
char *attrname)
@@ -356,6 +424,9 @@ make_array_ref(Node *expr,
return aref;
}
+
+/* make_array_set()
+ */
ArrayRef *
make_array_set(Expr *target_expr,
List *upperIndexpr,
@@ -406,10 +477,12 @@ make_array_set(Expr *target_expr,
aref->refexpr = (Node *) target_expr;
aref->refassgnexpr = (Node *) expr;
- if (lowerIndexpr == NIL) /* accessing a single array element */
+ /* accessing a single array element? */
+ if (lowerIndexpr == NIL)
reftype = aref->refelemtype;
+
+ /* otherwise, request to set a part of the array, by another array */
else
-/* request to set a part of the array, by another array */
reftype = typearray;
aref->refelemtype = reftype;