diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-06-09 19:08:20 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-06-09 19:08:20 +0000 |
commit | 7e64dbc6b5e516a2510ae41c8c7999d1d8d25872 (patch) | |
tree | c819b78903b490e720b4c20969ed6cf8816889d1 /src/backend/parser/parse_expr.c | |
parent | 3a0df651da253879bf133a8556853acfb1f664fd (diff) | |
download | postgresql-7e64dbc6b5e516a2510ae41c8c7999d1d8d25872.tar.gz postgresql-7e64dbc6b5e516a2510ae41c8c7999d1d8d25872.zip |
Support assignment to subfields of composite columns in UPDATE and INSERT.
As a side effect, cause subscripts in INSERT targetlists to do something
more or less sensible; previously we evaluated such subscripts and then
effectively ignored them. Another side effect is that UPDATE-ing an
element or slice of an array value that is NULL now produces a non-null
result, namely an array containing just the assigned-to positions.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 105 |
1 files changed, 62 insertions, 43 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 5dbac6338bc..3b4ad7cf8a0 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.172 2004/05/30 23:40:35 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.173 2004/06/09 19:08:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -100,7 +100,6 @@ transformExpr(ParseState *pstate, Node *expr) int paramno = pref->number; ParseState *toppstate; Param *param; - ListCell *fields; /* * Find topmost ParseState, which is where paramtype info @@ -148,18 +147,6 @@ transformExpr(ParseState *pstate, Node *expr) param->paramid = (AttrNumber) paramno; param->paramtype = toppstate->p_paramtypes[paramno - 1]; result = (Node *) param; - - /* handle qualification, if any */ - foreach(fields, pref->fields) - { - result = ParseFuncOrColumn(pstate, - list_make1(lfirst(fields)), - list_make1(result), - false, false, true); - } - /* handle subscripts, if any */ - result = transformIndirection(pstate, result, - pref->indirection); break; } case T_A_Const: @@ -173,23 +160,13 @@ transformExpr(ParseState *pstate, Node *expr) con->typename); break; } - case T_ExprFieldSelect: + case T_A_Indirection: { - ExprFieldSelect *efs = (ExprFieldSelect *) expr; - ListCell *fields; + A_Indirection *ind = (A_Indirection *) expr; - result = transformExpr(pstate, efs->arg); - /* handle qualification, if any */ - foreach(fields, efs->fields) - { - result = ParseFuncOrColumn(pstate, - list_make1(lfirst(fields)), - list_make1(result), - false, false, true); - } - /* handle subscripts, if any */ + result = transformExpr(pstate, ind->arg); result = transformIndirection(pstate, result, - efs->indirection); + ind->indirection); break; } case T_TypeCast: @@ -961,6 +938,7 @@ transformExpr(ParseState *pstate, Node *expr) case T_NullIfExpr: case T_BoolExpr: case T_FieldSelect: + case T_FieldStore: case T_RelabelType: case T_CaseTestExpr: case T_CoerceToDomain: @@ -983,15 +961,55 @@ transformExpr(ParseState *pstate, Node *expr) static Node * transformIndirection(ParseState *pstate, Node *basenode, List *indirection) { - if (indirection == NIL) - return basenode; - return (Node *) transformArraySubscripts(pstate, - basenode, - exprType(basenode), - exprTypmod(basenode), - indirection, - false, - NULL); + Node *result = basenode; + List *subscripts = NIL; + ListCell *i; + + /* + * We have to split any field-selection operations apart from + * subscripting. Adjacent A_Indices nodes have to be treated + * as a single multidimensional subscript operation. + */ + foreach(i, indirection) + { + Node *n = lfirst(i); + + if (IsA(n, A_Indices)) + { + subscripts = lappend(subscripts, n); + } + else + { + Assert(IsA(n, String)); + + /* process subscripts before this field selection */ + if (subscripts) + result = (Node *) transformArraySubscripts(pstate, + result, + exprType(result), + InvalidOid, + -1, + subscripts, + NULL); + subscripts = NIL; + + result = ParseFuncOrColumn(pstate, + list_make1(n), + list_make1(result), + false, false, true); + } + } + /* process trailing subscripts, if any */ + if (subscripts) + result = (Node *) transformArraySubscripts(pstate, + result, + exprType(result), + InvalidOid, + -1, + subscripts, + NULL); + + return result; } static Node * @@ -1051,17 +1069,15 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) } /* - * Try to find the name as a relation ... but not if - * subscripts appear. Note also that only relations - * already entered into the rangetable will be + * Try to find the name as a relation. Note that only + * relations already entered into the rangetable will be * recognized. * * This is a hack for backwards compatibility with * PostQUEL-inspired syntax. The preferred form now * is "rel.*". */ - if (cref->indirection == NIL && - refnameRangeTblEntry(pstate, NULL, name, + if (refnameRangeTblEntry(pstate, NULL, name, &levels_up) != NULL) node = transformWholeRowRef(pstate, NULL, name); else @@ -1172,7 +1188,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) break; } - return transformIndirection(pstate, node, cref->indirection); + return node; } /* @@ -1385,6 +1401,9 @@ exprType(Node *expr) case T_FieldSelect: type = ((FieldSelect *) expr)->resulttype; break; + case T_FieldStore: + type = ((FieldStore *) expr)->resulttype; + break; case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; |