aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_node.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-07-19 00:26:20 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-07-19 00:26:20 +0000
commit7f76eab140e703b7847b107245a669e2010886c0 (patch)
tree8c9d01c654aa8de0e14c0d446817ba60c33d0199 /src/backend/parser/parse_node.c
parentc9814427722798751fa5bf254f597d722d76b5e3 (diff)
downloadpostgresql-7f76eab140e703b7847b107245a669e2010886c0.tar.gz
postgresql-7f76eab140e703b7847b107245a669e2010886c0.zip
Rewrite parser's handling of INSERT ... SELECT so that processing
of the SELECT part of the statement is just like a plain SELECT. All INSERT-specific processing happens after the SELECT parsing is done. This eliminates many problems, e.g. INSERT ... SELECT ... GROUP BY using the wrong column labels. Ensure that DEFAULT clauses are coerced to the target column type, whether or not stored clause produces the right type. Substantial cleanup of parser's array support.
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r--src/backend/parser/parse_node.c245
1 files changed, 133 insertions, 112 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 53c756670c3..80a8543d5a5 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.28 1999/07/17 20:17:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.29 1999/07/19 00:26:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,6 +24,7 @@
#include "parser/parse_node.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -222,164 +223,184 @@ make_var(ParseState *pstate, Oid relid, char *refname,
}
/*
- * make_array_ref() -- Make an array reference node.
+ * transformArraySubscripts()
+ * Transform array subscripting. This is used for both
+ * array fetch and array assignment.
*
- * Array references can hang off of arbitrary nested dot (or
- * function invocation) expressions. This routine takes a
- * tree generated by ParseFunc() and an array index and
- * generates a new array reference tree. We do some simple
- * typechecking to be sure the dereference is valid in the
- * type system, but we don't do any bounds checking here.
+ * In an array fetch, we are given a source array value and we produce an
+ * expression that represents the result of extracting a single array element
+ * or an array slice.
*
- * indirection is a list of A_Indices
+ * In an array assignment, we are given a destination array value plus a
+ * source value that is to be assigned to a single element or a slice of
+ * that array. We produce an expression that represents the new array value
+ * with the source data inserted into the right part of the array.
+ *
+ * pstate Parse state
+ * arrayBase Already-transformed expression for the array as a whole
+ * indirection Untransformed list of subscripts (must not be NIL)
+ * forceSlice If true, treat subscript as array slice in all cases
+ * assignFrom NULL for array fetch, else transformed expression for source.
*/
-ArrayRef *
-make_array_ref(Node *expr,
- List *indirection)
+ArrayRef *
+transformArraySubscripts(ParseState *pstate,
+ Node *arrayBase,
+ List *indirection,
+ bool forceSlice,
+ Node *assignFrom)
{
- Oid typearray;
+ Oid typearray,
+ typeelement,
+ typeresult;
HeapTuple type_tuple;
Form_pg_type type_struct_array,
type_struct_element;
- ArrayRef *aref;
- Oid reftype;
+ bool isSlice = forceSlice;
List *upperIndexpr = NIL;
List *lowerIndexpr = NIL;
+ List *idx;
+ ArrayRef *aref;
- typearray = exprType(expr);
+ /* Get the type tuple for the array */
+ typearray = exprType(arrayBase);
type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(typearray),
0, 0, 0);
-
if (!HeapTupleIsValid(type_tuple))
- elog(ERROR, "make_array_ref: Cache lookup failed for type %u\n",
+ elog(ERROR, "transformArraySubscripts: Cache lookup failed for array type %u",
typearray);
-
- /* get the array type struct from the type tuple */
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple);
- if (type_struct_array->typelem == InvalidOid)
- elog(ERROR, "make_array_ref: type %s is not an array",
+ typeelement = type_struct_array->typelem;
+ if (typeelement == InvalidOid)
+ elog(ERROR, "transformArraySubscripts: type %s is not an array",
type_struct_array->typname);
- /* get the type tuple for the element type */
+ /* Get the type tuple for the array element type */
type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_struct_array->typelem),
+ ObjectIdGetDatum(typeelement),
0, 0, 0);
if (!HeapTupleIsValid(type_tuple))
- elog(ERROR, "make_array_ref: Cache lookup failed for type %u\n",
- typearray);
-
+ elog(ERROR, "transformArraySubscripts: Cache lookup failed for array element type %u",
+ typeelement);
type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple);
- while (indirection != NIL)
+ /*
+ * A list containing only single subscripts refers to a single array
+ * element. If any of the items are double subscripts (lower:upper),
+ * then the subscript expression means an array slice operation.
+ * In this case, we supply a default lower bound of 1 for any items
+ * that contain only a single subscript.
+ * The forceSlice parameter forces us to treat the operation as a
+ * slice, even if no lower bounds are mentioned. Otherwise,
+ * we have to prescan the indirection list to see if there are any
+ * double subscripts.
+ */
+ if (! isSlice)
{
- A_Indices *ind = lfirst(indirection);
-
- if (ind->lidx)
-
- /*
- * XXX assumes all lower indices non null in this case
- */
- lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
-
- upperIndexpr = lappend(upperIndexpr, ind->uidx);
- indirection = lnext(indirection);
+ foreach (idx, indirection)
+ {
+ A_Indices *ai = (A_Indices *) lfirst(idx);
+ if (ai->lidx != NULL)
+ {
+ isSlice = true;
+ break;
+ }
+ }
}
- aref = makeNode(ArrayRef);
- aref->refattrlength = type_struct_array->typlen;
- aref->refelemlength = type_struct_element->typlen;
- aref->refelemtype = type_struct_array->typelem;
- aref->refelembyval = type_struct_element->typbyval;
- aref->refupperindexpr = upperIndexpr;
- aref->reflowerindexpr = lowerIndexpr;
- aref->refexpr = expr;
- aref->refassgnexpr = NULL;
- if (lowerIndexpr == NIL) /* accessing a single array element */
- reftype = aref->refelemtype;
+ /* The type represented by the subscript expression is the element type
+ * if we are fetching a single element, but it is the same as the array
+ * type if we are fetching a slice or storing.
+ */
+ if (isSlice || assignFrom != NULL)
+ typeresult = typearray;
else
-/* request to clip a part of the array, the result is another array */
- reftype = typearray;
+ typeresult = typeelement;
/*
- * we change it to reflect the true type; since the original
- * refelemtype doesn't seem to get used anywhere. - ay 10/94
+ * Transform the subscript expressions.
*/
- aref->refelemtype = reftype;
-
- return aref;
-}
-
-
-/* make_array_set()
- */
-ArrayRef *
-make_array_set(Expr *target_expr,
- List *upperIndexpr,
- List *lowerIndexpr,
- Expr *expr)
-{
- Oid typearray;
- HeapTuple type_tuple;
- Form_pg_type type_struct_array;
- Form_pg_type type_struct_element;
- ArrayRef *aref;
- Oid reftype;
-
- typearray = exprType((Node *) target_expr);
-
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typearray),
- 0, 0, 0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(ERROR, "make_array_ref: Cache lookup failed for type %u\n",
- typearray);
-
- /* get the array type struct from the type tuple */
- type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple);
+ foreach (idx, indirection)
+ {
+ A_Indices *ai = (A_Indices *) lfirst(idx);
+ Node *subexpr;
- if (type_struct_array->typelem == InvalidOid)
- elog(ERROR, "make_array_ref: type %s is not an array",
- type_struct_array->typname);
- /* get the type tuple for the element type */
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_struct_array->typelem),
- 0, 0, 0);
+ if (isSlice)
+ {
+ if (ai->lidx)
+ {
+ subexpr = transformExpr(pstate, ai->lidx, EXPR_COLUMN_FIRST);
+ /* If it's not int4 already, try to coerce */
+ subexpr = CoerceTargetExpr(pstate, subexpr,
+ exprType(subexpr), INT4OID);
+ if (subexpr == NULL)
+ elog(ERROR, "array index expressions must be integers");
+ }
+ else
+ {
+ /* Make a constant 1 */
+ subexpr = (Node *) makeConst(INT4OID,
+ sizeof(int32),
+ Int32GetDatum(1),
+ false,
+ true, /* pass by value */
+ false,
+ false);
+ }
+ lowerIndexpr = lappend(lowerIndexpr, subexpr);
+ }
+ subexpr = transformExpr(pstate, ai->uidx, EXPR_COLUMN_FIRST);
+ /* If it's not int4 already, try to coerce */
+ subexpr = CoerceTargetExpr(pstate, subexpr,
+ exprType(subexpr), INT4OID);
+ if (subexpr == NULL)
+ elog(ERROR, "array index expressions must be integers");
+ upperIndexpr = lappend(upperIndexpr, subexpr);
+ }
- if (!HeapTupleIsValid(type_tuple))
- elog(ERROR, "make_array_ref: Cache lookup failed for type %u\n",
- typearray);
+ /*
+ * If doing an array store, coerce the source value to the right type.
+ */
+ if (assignFrom != NULL)
+ {
+ Oid typesource = exprType(assignFrom);
+ Oid typeneeded = isSlice ? typearray : typeelement;
- type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple);
+ if (typesource != InvalidOid)
+ {
+ if (typesource != typeneeded)
+ {
+ assignFrom = CoerceTargetExpr(pstate, assignFrom,
+ typesource, typeneeded);
+ if (assignFrom == NULL)
+ elog(ERROR, "Array assignment requires type '%s'"
+ " but expression is of type '%s'"
+ "\n\tYou will need to rewrite or cast the expression",
+ typeidTypeName(typeneeded),
+ typeidTypeName(typesource));
+ }
+ }
+ }
+ /*
+ * Ready to build the ArrayRef node.
+ */
aref = makeNode(ArrayRef);
aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->typlen;
- aref->refelemtype = type_struct_array->typelem;
+ aref->refelemtype = typeresult; /* XXX should save element type too */
aref->refelembyval = type_struct_element->typbyval;
aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr;
- aref->refexpr = (Node *) target_expr;
- aref->refassgnexpr = (Node *) expr;
-
- /* accessing a single array element? */
- if (lowerIndexpr == NIL)
- reftype = aref->refelemtype;
-
- /* otherwise, request to set a part of the array, by another array */
- else
- reftype = typearray;
-
- aref->refelemtype = reftype;
+ aref->refexpr = arrayBase;
+ aref->refassgnexpr = assignFrom;
return aref;
}
/*
- *
* make_const -
*
* - takes a lispvalue, (as returned to the yacc routine by the lexer)