Commit 7f76eab1 authored by Tom Lane's avatar Tom Lane

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.
parent c9814427
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.57 1999/07/17 20:16:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.58 1999/07/19 00:26:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -86,31 +86,44 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -86,31 +86,44 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
bool *isNull, bool *isNull,
bool *isDone) bool *isDone)
{ {
bool dummy;
int i = 0,
j = 0;
ArrayType *array_scanner; ArrayType *array_scanner;
List *upperIndexpr,
*lowerIndexpr;
Node *assgnexpr;
List *elt; List *elt;
int i = 0,
j = 0;
IntArray upper, IntArray upper,
lower; lower;
int *lIndex; int *lIndex;
char *dataPtr; bool dummy;
*isNull = false; *isNull = false;
array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr,
econtext,
isNull,
isDone);
if (*isNull)
return (Datum) NULL;
upperIndexpr = arrayRef->refupperindexpr; if (arrayRef->refexpr != NULL)
{
array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr,
econtext,
isNull,
isDone);
if (*isNull)
return (Datum) NULL;
}
else
{
/* Null refexpr indicates we are doing an INSERT into an array column.
* For now, we just take the refassgnexpr (which the parser will have
* ensured is an array value) and return it as-is, ignoring any
* subscripts that may have been supplied in the INSERT column list.
* This is a kluge, but it's not real clear what the semantics ought
* to be...
*/
array_scanner = NULL;
}
foreach(elt, upperIndexpr) foreach(elt, arrayRef->refupperindexpr)
{ {
if (i >= MAXDIM)
elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
MAXDIM);
upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt), upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
econtext, econtext,
isNull, isNull,
...@@ -119,12 +132,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -119,12 +132,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
return (Datum) NULL; return (Datum) NULL;
} }
lowerIndexpr = arrayRef->reflowerindexpr; if (arrayRef->reflowerindexpr != NIL)
lIndex = NULL;
if (lowerIndexpr != NIL)
{ {
foreach(elt, lowerIndexpr) foreach(elt, arrayRef->reflowerindexpr)
{ {
if (j >= MAXDIM)
elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
MAXDIM);
lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt), lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
econtext, econtext,
isNull, isNull,
...@@ -137,30 +152,42 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -137,30 +152,42 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
"ExecEvalArrayRef: upper and lower indices mismatch"); "ExecEvalArrayRef: upper and lower indices mismatch");
lIndex = lower.indx; lIndex = lower.indx;
} }
else
{
lIndex = NULL;
}
assgnexpr = arrayRef->refassgnexpr; if (arrayRef->refassgnexpr != NULL)
if (assgnexpr != NULL)
{ {
dataPtr = (char *) ExecEvalExpr((Node *) Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
assgnexpr, econtext, econtext,
isNull, &dummy); isNull,
&dummy);
if (*isNull) if (*isNull)
return (Datum) NULL; return (Datum) NULL;
execConstByVal = arrayRef->refelembyval; execConstByVal = arrayRef->refelembyval;
execConstLen = arrayRef->refelemlength; execConstLen = arrayRef->refelemlength;
if (array_scanner == NULL)
return sourceData; /* XXX do something else? */
if (lIndex == NULL) if (lIndex == NULL)
return (Datum) array_set(array_scanner, i, upper.indx, dataPtr, return (Datum) array_set(array_scanner, i, upper.indx,
(char *) sourceData,
arrayRef->refelembyval, arrayRef->refelembyval,
arrayRef->refelemlength, arrayRef->refelemlength,
arrayRef->refattrlength, isNull); arrayRef->refattrlength, isNull);
return (Datum) array_assgn(array_scanner, i, upper.indx, return (Datum) array_assgn(array_scanner, i, upper.indx,
lower.indx, lower.indx,
(ArrayType *) dataPtr, (ArrayType *) sourceData,
arrayRef->refelembyval, arrayRef->refelembyval,
arrayRef->refelemlength, isNull); arrayRef->refelemlength, isNull);
} }
execConstByVal = arrayRef->refelembyval; execConstByVal = arrayRef->refelembyval;
execConstLen = arrayRef->refelemlength; execConstLen = arrayRef->refelemlength;
if (lIndex == NULL) if (lIndex == NULL)
return (Datum) array_ref(array_scanner, i, upper.indx, return (Datum) array_ref(array_scanner, i, upper.indx,
arrayRef->refelembyval, arrayRef->refelembyval,
......
This diff is collapsed.
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.54 1999/07/17 20:17:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.55 1999/07/19 00:26:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,7 +30,7 @@ static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod); ...@@ -30,7 +30,7 @@ static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence); static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence); static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
static Node *transformIndirection(ParseState *pstate, Node *basenode, static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection, int precedence); List *indirection);
/* /*
* transformExpr - * transformExpr -
...@@ -81,7 +81,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -81,7 +81,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
param->paramtype = (Oid) toid; param->paramtype = (Oid) toid;
param->param_tlist = (List *) NULL; param->param_tlist = (List *) NULL;
result = transformIndirection(pstate, (Node *) param, result = transformIndirection(pstate, (Node *) param,
pno->indirection, precedence); pno->indirection);
break; break;
} }
case T_A_Expr: case T_A_Expr:
...@@ -467,37 +467,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -467,37 +467,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
} }
static Node * static Node *
transformIndirection(ParseState *pstate, Node *basenode, transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
List *indirection, int precedence)
{ {
List *idx;
if (indirection == NIL) if (indirection == NIL)
return basenode; return basenode;
foreach (idx, indirection) return (Node *) transformArraySubscripts(pstate, basenode,
{ indirection, false, NULL);
A_Indices *ai = (A_Indices *) lfirst(idx);
Node *lexpr = NULL,
*uexpr;
/* uidx is always present, but lidx might be null */
if (ai->lidx != NULL)
{
lexpr = transformExpr(pstate, ai->lidx, precedence);
if (exprType(lexpr) != INT4OID)
elog(ERROR, "array index expressions must be int4's");
}
uexpr = transformExpr(pstate, ai->uidx, precedence);
if (exprType(uexpr) != INT4OID)
elog(ERROR, "array index expressions must be int4's");
ai->lidx = lexpr;
ai->uidx = uexpr;
/*
* note we reuse the list of A_Indices nodes, make sure
* we don't free them! Otherwise, make a new list here
*/
}
return (Node *) make_array_ref(basenode, indirection);
} }
static Node * static Node *
...@@ -505,11 +480,9 @@ transformAttr(ParseState *pstate, Attr *att, int precedence) ...@@ -505,11 +480,9 @@ transformAttr(ParseState *pstate, Attr *att, int precedence)
{ {
Node *basenode; Node *basenode;
/* what if att->attrs == "*"? */
basenode = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno, basenode = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,
precedence); precedence);
return transformIndirection(pstate, basenode, return transformIndirection(pstate, basenode, att->indirection);
att->indirection, precedence);
} }
static Node * static Node *
...@@ -555,7 +528,7 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence) ...@@ -555,7 +528,7 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
Oid Oid
exprType(Node *expr) exprType(Node *expr)
{ {
Oid type = (Oid) 0; Oid type = (Oid) InvalidOid;
if (!expr) if (!expr)
return type; return type;
...@@ -622,6 +595,42 @@ exprType(Node *expr) ...@@ -622,6 +595,42 @@ exprType(Node *expr)
return type; return type;
} }
/*
* exprTypmod -
* returns the type-specific attrmod of the expression, if it can be
* determined. In most cases, it can't and we return -1.
*/
int32
exprTypmod(Node *expr)
{
if (!expr)
return -1;
switch (nodeTag(expr))
{
case T_Var:
return ((Var *) expr)->vartypmod;
case T_Const:
{
/* Be smart about string constants... */
Const *con = (Const *) expr;
switch (con->consttype)
{
case BPCHAROID:
if (! con->constisnull)
return VARSIZE(DatumGetPointer(con->constvalue));
break;
default:
break;
}
}
break;
default:
break;
}
return -1;
}
static Node * static Node *
parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -24,6 +24,7 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
#include "parser/parse_oper.h" #include "parser/parse_oper.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -222,164 +223,184 @@ make_var(ParseState *pstate, Oid relid, char *refname, ...@@ -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 * In an array fetch, we are given a source array value and we produce an
* function invocation) expressions. This routine takes a * expression that represents the result of extracting a single array element
* tree generated by ParseFunc() and an array index and * or an array slice.
* 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.
* *
* 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 * ArrayRef *
make_array_ref(Node *expr, transformArraySubscripts(ParseState *pstate,
List *indirection) Node *arrayBase,
List *indirection,
bool forceSlice,
Node *assignFrom)
{ {
Oid typearray; Oid typearray,
typeelement,
typeresult;
HeapTuple type_tuple; HeapTuple type_tuple;
Form_pg_type type_struct_array, Form_pg_type type_struct_array,
type_struct_element; type_struct_element;
ArrayRef *aref; bool isSlice = forceSlice;
Oid reftype;
List *upperIndexpr = NIL; List *upperIndexpr = NIL;
List *lowerIndexpr = 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, type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(typearray), ObjectIdGetDatum(typearray),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(type_tuple)) 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); typearray);
/* get the array type struct from the type tuple */
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple); type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple);
if (type_struct_array->typelem == InvalidOid) typeelement = type_struct_array->typelem;
elog(ERROR, "make_array_ref: type %s is not an array", if (typeelement == InvalidOid)
elog(ERROR, "transformArraySubscripts: type %s is not an array",
type_struct_array->typname); 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, type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(type_struct_array->typelem), ObjectIdGetDatum(typeelement),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(type_tuple)) if (!HeapTupleIsValid(type_tuple))
elog(ERROR, "make_array_ref: Cache lookup failed for type %u\n", elog(ERROR, "transformArraySubscripts: Cache lookup failed for array element type %u",
typearray); typeelement);
type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple); 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); foreach (idx, indirection)
{
if (ind->lidx) A_Indices *ai = (A_Indices *) lfirst(idx);
if (ai->lidx != NULL)
/* {
* XXX assumes all lower indices non null in this case isSlice = true;
*/ break;
lowerIndexpr = lappend(lowerIndexpr, ind->lidx); }
}
upperIndexpr = lappend(upperIndexpr, ind->uidx);
indirection = lnext(indirection);
} }
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 */ /* The type represented by the subscript expression is the element type
reftype = aref->refelemtype; * 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 else
/* request to clip a part of the array, the result is another array */ typeresult = typeelement;
reftype = typearray;
/* /*
* we change it to reflect the true type; since the original * Transform the subscript expressions.
* refelemtype doesn't seem to get used anywhere. - ay 10/94
*/ */
aref->refelemtype = reftype; foreach (idx, indirection)
{
return aref; A_Indices *ai = (A_Indices *) lfirst(idx);
} Node *subexpr;
/* 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);
if (type_struct_array->typelem == InvalidOid) if (isSlice)
elog(ERROR, "make_array_ref: type %s is not an array", {
type_struct_array->typname); if (ai->lidx)
/* get the type tuple for the element type */ {
type_tuple = SearchSysCacheTuple(TYPOID, subexpr = transformExpr(pstate, ai->lidx, EXPR_COLUMN_FIRST);
ObjectIdGetDatum(type_struct_array->typelem), /* If it's not int4 already, try to coerce */
0, 0, 0); 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", * If doing an array store, coerce the source value to the right type.
typearray); */
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 = makeNode(ArrayRef);
aref->refattrlength = type_struct_array->typlen; aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->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->refelembyval = type_struct_element->typbyval;
aref->refupperindexpr = upperIndexpr; aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr; aref->reflowerindexpr = lowerIndexpr;
aref->refexpr = (Node *) target_expr; aref->refexpr = arrayBase;
aref->refassgnexpr = (Node *) expr; aref->refassgnexpr = assignFrom;
/* 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;
return aref; return aref;
} }
/* /*
*
* make_const - * make_const -
* *
* - takes a lispvalue, (as returned to the yacc routine by the lexer) * - takes a lispvalue, (as returned to the yacc routine by the lexer)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.25 1999/07/17 20:17:25 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.26 1999/07/19 00:26:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,10 +25,8 @@ ...@@ -25,10 +25,8 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
static void checkTargetTypes(ParseState *pstate, char *target_colname,
char *refname, char *colname);
struct static struct
{ {
char *field; char *field;
int code; int code;
...@@ -97,7 +95,6 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up) ...@@ -97,7 +95,6 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
int index; int index;
List *temp; List *temp;
if (sublevels_up) if (sublevels_up)
*sublevels_up = 0; *sublevels_up = 0;
...@@ -175,7 +172,7 @@ colnameRangeTableEntry(ParseState *pstate, char *colname) ...@@ -175,7 +172,7 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
/* /*
* put new entry in pstate p_rtable structure, or return pointer * put new entry in pstate p_rtable structure, or return pointer
* if pstate null * if pstate null
*/ */
RangeTblEntry * RangeTblEntry *
addRangeTableEntry(ParseState *pstate, addRangeTableEntry(ParseState *pstate,
char *relname, char *relname,
...@@ -239,38 +236,31 @@ addRangeTableEntry(ParseState *pstate, ...@@ -239,38 +236,31 @@ addRangeTableEntry(ParseState *pstate,
List * List *
expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
{ {
List *te_list = NIL;
RangeTblEntry *rte;
Relation rel; Relation rel;
List *te_tail = NIL,
*te_head = NIL;
Var *varnode;
int varattno, int varattno,
maxattrs; maxattrs;
RangeTblEntry *rte;
rte = refnameRangeTableEntry(pstate, refname); rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL) if (rte == NULL)
rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE); rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
rel = heap_open(rte->relid); rel = heap_open(rte->relid);
if (rel == NULL) if (rel == NULL)
elog(ERROR, "Unable to expand all -- heap_open failed on %s", elog(ERROR, "Unable to expand all -- heap_open failed on %s",
rte->refname); rte->refname);
maxattrs = RelationGetNumberOfAttributes(rel); maxattrs = RelationGetNumberOfAttributes(rel);
for (varattno = 0; varattno <= maxattrs - 1; varattno++) for (varattno = 0; varattno < maxattrs; varattno++)
{ {
char *attrname; char *attrname;
char *resname = NULL; Var *varnode;
TargetEntry *te = makeNode(TargetEntry); TargetEntry *te = makeNode(TargetEntry);
attrname = pstrdup((rel->rd_att->attrs[varattno]->attname).data); attrname = pstrdup(rel->rd_att->attrs[varattno]->attname.data);
varnode = (Var *) make_var(pstate, rte->relid, refname, attrname); varnode = make_var(pstate, rte->relid, refname, attrname);
handleTargetColname(pstate, &resname, refname, attrname);
if (resname != NULL)
attrname = resname;
/* /*
* Even if the elements making up a set are complex, the set * Even if the elements making up a set are complex, the set
...@@ -285,15 +275,12 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) ...@@ -285,15 +275,12 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
(Oid) 0, (Oid) 0,
false); false);
te->expr = (Node *) varnode; te->expr = (Node *) varnode;
if (te_head == NIL) te_list = lappend(te_list, te);
te_head = te_tail = lcons(te, NIL);
else
te_tail = lappend(te_tail, te);
} }
heap_close(rel); heap_close(rel);
return te_head; return te_list;
} }
/* /*
...@@ -378,102 +365,3 @@ attnumTypeId(Relation rd, int attid) ...@@ -378,102 +365,3 @@ attnumTypeId(Relation rd, int attid)
*/ */
return rd->rd_att->attrs[attid - 1]->atttypid; return rd->rd_att->attrs[attid - 1]->atttypid;
} }
/* handleTargetColname()
* Use column names from insert.
*/
void
handleTargetColname(ParseState *pstate, char **resname,
char *refname, char *colname)
{
if (pstate->p_is_insert)
{
if (pstate->p_insert_columns != NIL)
{
Ident *id = lfirst(pstate->p_insert_columns);
*resname = id->name;
pstate->p_insert_columns = lnext(pstate->p_insert_columns);
}
else
elog(ERROR, "INSERT has more expressions than target columns");
}
if (pstate->p_is_insert || pstate->p_is_update)
checkTargetTypes(pstate, *resname, refname, colname);
}
/* checkTargetTypes()
* Checks value and target column types.
*/
static void
checkTargetTypes(ParseState *pstate, char *target_colname,
char *refname, char *colname)
{
Oid attrtype_id,
attrtype_target;
int resdomno_id,
resdomno_target;
RangeTblEntry *rte;
if (target_colname == NULL || colname == NULL)
return;
if (refname != NULL)
rte = refnameRangeTableEntry(pstate, refname);
else
{
rte = colnameRangeTableEntry(pstate, colname);
if (rte == (RangeTblEntry *) NULL)
elog(ERROR, "Attribute %s not found", colname);
refname = rte->refname;
}
/*
if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
elog(ERROR, "'%s' not available in this context", colname);
*/
resdomno_id = get_attnum(rte->relid, colname);
attrtype_id = get_atttype(rte->relid, resdomno_id);
resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
#ifdef NOT_USED
if ((attrtype_id != attrtype_target)
|| (get_atttypmod(rte->relid, resdomno_id) !=
get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target)))
{
if (can_coerce_type(1, &attrtype_id, &attrtype_target))
{
Node *expr = coerce_type(pstate, expr, attrtype_id,
attrtype_target,
get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
elog(ERROR, "Type %s(%d) can be coerced to match target column %s(%d)",
colname, get_atttypmod(rte->relid, resdomno_id),
target_colname, get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
}
else
{
elog(ERROR, "Type or size of %s(%d) does not match target column %s(%d)",
colname, get_atttypmod(rte->relid, resdomno_id),
target_colname, get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
}
}
#else
if (attrtype_id != attrtype_target)
elog(ERROR, "Type of '%s' does not match target column '%s'",
colname, target_colname);
if (attrtype_id == BPCHAROID &&
get_atttypmod(rte->relid, resdomno_id) !=
get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target))
elog(ERROR, "Length of '%s' is not equal to the length of target column '%s'",
colname, target_colname);
if (attrtype_id == VARCHAROID &&
get_atttypmod(rte->relid, resdomno_id) >
get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target))
elog(ERROR, "Length of '%s' is longer than length of target column '%s'",
colname, target_colname);
#endif
}
This diff is collapsed.
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_clause.h,v 1.11 1999/07/15 23:04:01 momjian Exp $ * $Id: parse_clause.h,v 1.12 1999/07/19 00:26:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
extern void makeRangeTable(ParseState *pstate, char *relname, List *frmList, Node **qual); extern void makeRangeTable(ParseState *pstate, List *frmList, Node **qual);
extern Node *transformWhereClause(ParseState *pstate, Node *where, Node *using); extern void setTargetTable(ParseState *pstate, char *relname);
extern Node *transformWhereClause(ParseState *pstate, Node *where,
Node *using);
extern List *transformGroupClause(ParseState *pstate, List *grouplist, extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist); List *targetlist);
extern List *transformSortClause(ParseState *pstate, extern List *transformSortClause(ParseState *pstate,
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* parse_exer.h * parse_expr.h
* *
* *
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_expr.h,v 1.13 1999/07/15 23:04:02 momjian Exp $ * $Id: parse_expr.h,v 1.14 1999/07/19 00:26:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,8 +16,12 @@ ...@@ -16,8 +16,12 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence); extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
extern Oid exprType(Node *expr); extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod); extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int32 attypmod);
#endif /* PARSE_EXPR_H */ #endif /* PARSE_EXPR_H */
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_node.h,v 1.14 1999/07/15 23:04:02 momjian Exp $ * $Id: parse_node.h,v 1.15 1999/07/19 00:26:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,7 +20,6 @@ typedef struct ParseState ...@@ -20,7 +20,6 @@ typedef struct ParseState
{ {
int p_last_resno; int p_last_resno;
List *p_rtable; List *p_rtable;
List *p_insert_columns;
struct ParseState *parentParseState; struct ParseState *parentParseState;
bool p_hasAggs; bool p_hasAggs;
bool p_hasSubLinks; bool p_hasSubLinks;
...@@ -36,12 +35,11 @@ extern ParseState *make_parsestate(ParseState *parentParseState); ...@@ -36,12 +35,11 @@ extern ParseState *make_parsestate(ParseState *parentParseState);
extern Expr *make_op(char *opname, Node *ltree, Node *rtree); extern Expr *make_op(char *opname, Node *ltree, Node *rtree);
extern Var *make_var(ParseState *pstate, Oid relid, char *refname, extern Var *make_var(ParseState *pstate, Oid relid, char *refname,
char *attrname); char *attrname);
extern ArrayRef *make_array_ref(Node *expr, extern ArrayRef *transformArraySubscripts(ParseState *pstate,
List *indirection); Node *arrayBase,
extern ArrayRef *make_array_set(Expr *target_expr, List *indirection,
List *upperIndexpr, bool forceSlice,
List *lowerIndexpr, Node *assignFrom);
Expr *expr);
extern Const *make_const(Value *value); extern Const *make_const(Value *value);
#endif /* PARSE_NODE_H */ #endif /* PARSE_NODE_H */
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* parse_query.h * parse_relation.h
* prototypes for parse_query.c. * prototypes for parse_relation.c.
* *
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_relation.h,v 1.11 1999/07/15 23:04:03 momjian Exp $ * $Id: parse_relation.h,v 1.12 1999/07/19 00:26:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef PARSE_QUERY_H #ifndef PARSE_RELATION_H
#define PARSE_RANGE_H #define PARSE_RELATION_H
#include "parser/parse_node.h" #include "parser/parse_node.h"
...@@ -30,7 +30,5 @@ extern int attnameAttNum(Relation rd, char *a); ...@@ -30,7 +30,5 @@ extern int attnameAttNum(Relation rd, char *a);
extern bool attnameIsSet(Relation rd, char *name); extern bool attnameIsSet(Relation rd, char *name);
extern int attnumAttNelems(Relation rd, int attid); extern int attnumAttNelems(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid); extern Oid attnumTypeId(Relation rd, int attid);
extern void handleTargetColname(ParseState *pstate, char **resname,
char *refname, char *colname);
#endif /* PARSE_RANGE_H */ #endif /* PARSE_RELATION_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_target.h,v 1.14 1999/07/15 23:04:03 momjian Exp $ * $Id: parse_target.h,v 1.15 1999/07/19 00:26:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,23 +15,14 @@ ...@@ -15,23 +15,14 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
extern List *transformTargetList(ParseState *pstate, List *targetlist); extern List *transformTargetList(ParseState *pstate, List *targetlist);
extern List *makeTargetNames(ParseState *pstate, List *cols); extern TargetEntry *transformTargetEntry(ParseState *pstate,
extern TargetEntry *MakeTargetEntryIdent(ParseState *pstate, Node *node, Node *expr,
Node *node, char *colname, bool resjunk);
char **resname, extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
char *refname, char *colname, List *indirection);
char *colname,
bool resjunk);
extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr, extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
Oid type_id, Oid attrtype); Oid type_id, Oid attrtype);
TargetEntry *MakeTargetEntryExpr(ParseState *pstate, extern List *makeTargetNames(ParseState *pstate, List *cols);
char *colname,
Node *expr,
List *arrayRef,
bool resjunk);
#endif /* PARSE_TARGET_H */ #endif /* PARSE_TARGET_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment