aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_node.c
diff options
context:
space:
mode:
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)