diff options
| author | Tom Lane | 2004-06-09 19:08:20 +0000 |
|---|---|---|
| committer | Tom Lane | 2004-06-09 19:08:20 +0000 |
| commit | 7e64dbc6b5e516a2510ae41c8c7999d1d8d25872 (patch) | |
| tree | c819b78903b490e720b4c20969ed6cf8816889d1 /src/include | |
| parent | 3a0df651da253879bf133a8556853acfb1f664fd (diff) | |
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/include')
| -rw-r--r-- | src/include/nodes/execnodes.h | 14 | ||||
| -rw-r--r-- | src/include/nodes/nodes.h | 6 | ||||
| -rw-r--r-- | src/include/nodes/parsenodes.h | 62 | ||||
| -rw-r--r-- | src/include/nodes/primnodes.h | 35 | ||||
| -rw-r--r-- | src/include/parser/parse_node.h | 7 |
5 files changed, 89 insertions, 35 deletions
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 325bf876800..a32378c7f84 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.116 2004/05/10 22:44:49 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.117 2004/06/09 19:08:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -575,6 +575,18 @@ typedef struct FieldSelectState } FieldSelectState; /* ---------------- + * FieldStoreState node + * ---------------- + */ +typedef struct FieldStoreState +{ + ExprState xprstate; + ExprState *arg; /* input tuple value */ + List *newvals; /* new value(s) for field(s) */ + TupleDesc argdesc; /* tupdesc for most recent input */ +} FieldStoreState; + +/* ---------------- * CaseExprState node * ---------------- */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 6feedf6762c..b719747e762 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.156 2004/05/26 13:57:02 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.157 2004/06/09 19:08:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -110,6 +110,7 @@ typedef enum NodeTag T_SubLink, T_SubPlan, T_FieldSelect, + T_FieldStore, T_RelabelType, T_CaseExpr, T_CaseWhen, @@ -143,6 +144,7 @@ typedef enum NodeTag T_BoolExprState, T_SubPlanState, T_FieldSelectState, + T_FieldStoreState, T_CaseExprState, T_CaseWhenState, T_ArrayExprState, @@ -274,7 +276,7 @@ typedef enum NodeTag T_A_Const, T_FuncCall, T_A_Indices, - T_ExprFieldSelect, + T_A_Indirection, T_ResTarget, T_TypeCast, T_SortBy, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 8f6cc25e0aa..0da9b379077 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.257 2004/06/02 21:01:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.258 2004/06/09 19:08:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -166,26 +166,26 @@ typedef struct TypeName * ColumnRef - specifies a reference to a column, or possibly a whole tuple * * The "fields" list must be nonempty; its last component may be "*" - * instead of a field name. Subscripts are optional. + * instead of a regular field name. + * + * Note: any array subscripting or selection of fields from composite columns + * is represented by an A_Indirection node above the ColumnRef. However, + * for simplicity in the normal case, initial field selection from a table + * name is represented within ColumnRef and not by adding A_Indirection. */ typedef struct ColumnRef { NodeTag type; List *fields; /* field names (list of Value strings) */ - List *indirection; /* subscripts (list of A_Indices) */ } ColumnRef; /* - * ParamRef - specifies a parameter reference - * - * The parameter could be qualified with field names and/or subscripts + * ParamRef - specifies a $n parameter reference */ typedef struct ParamRef { NodeTag type; int number; /* the number of the parameter */ - List *fields; /* field names (list of Value strings) */ - List *indirection; /* subscripts (list of A_Indices) */ } ParamRef; /* @@ -267,40 +267,50 @@ typedef struct A_Indices } A_Indices; /* - * ExprFieldSelect - select a field and/or array element from an expression + * A_Indirection - select a field and/or array element from an expression * - * This is used in the raw parsetree to represent selection from an - * arbitrary expression (not a column or param reference). Either - * fields or indirection may be NIL if not used. + * The indirection list can contain both A_Indices nodes (representing + * subscripting) and string Value nodes (representing field selection + * --- the string value is the name of the field to select). For example, + * a complex selection operation like + * (foo).field1[42][7].field2 + * would be represented with a single A_Indirection node having a 4-element + * indirection list. + * + * Note: as of Postgres 7.5, we don't support arrays of composite values, + * so cases in which a field select follows a subscript aren't actually + * semantically legal. However the parser is prepared to handle such. */ -typedef struct ExprFieldSelect +typedef struct A_Indirection { NodeTag type; Node *arg; /* the thing being selected from */ - List *fields; /* field names (list of Value strings) */ - List *indirection; /* subscripts (list of A_Indices) */ -} ExprFieldSelect; + List *indirection; /* subscripts and/or field names */ +} A_Indirection; /* * ResTarget - - * result target (used in target list of pre-transformed Parse trees) + * result target (used in target list of pre-transformed parse trees) * - * In a SELECT or INSERT target list, 'name' is either NULL or - * the column name assigned to the value. (If there is an 'AS ColumnLabel' - * clause, the grammar sets 'name' from it; otherwise 'name' is initially NULL - * and is filled in during the parse analysis phase.) - * The 'indirection' field is not used at all. + * In a SELECT or INSERT target list, 'name' is the column label from an + * 'AS ColumnLabel' clause, or NULL if there was none, and 'val' is the + * value expression itself. The 'indirection' field is not used. * - * In an UPDATE target list, 'name' is the name of the destination column, + * INSERT has a second ResTarget list which is the target-column-names list. + * Here, 'val' is not used, 'name' is the name of the destination column, * and 'indirection' stores any subscripts attached to the destination. - * That is, our representation is UPDATE table SET name [indirection] = val. + * + * In an UPDATE target list, 'name' is the name of the destination column, + * 'indirection' stores any subscripts attached to the destination, and + * 'val' is the expression to assign. + * + * See A_Indirection for more info about what can appear in 'indirection'. */ typedef struct ResTarget { NodeTag type; char *name; /* column name or NULL */ - List *indirection; /* subscripts for destination column, or - * NIL */ + List *indirection; /* subscripts and field names, or NIL */ Node *val; /* the value expression to compute or * assign */ } ResTarget; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 5db00199cef..3ed4d74ee35 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.99 2004/05/30 23:40:39 neilc Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.100 2004/06/09 19:08:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -36,14 +36,15 @@ * ordinal position (counting from 1). However, in an INSERT or UPDATE * targetlist, resno represents the attribute number of the destination * column for the item; so there may be missing or out-of-order resnos. - * In an UPDATE, it is even legal to have duplicated resnos; consider + * It is even legal to have duplicated resnos; consider * UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ... * The two meanings come together in the executor, because the planner * transforms INSERT/UPDATE tlists into a normalized form with exactly * one entry for each column of the destination table. Before that's * happened, however, it is risky to assume that resno == position. * Generally get_tle_by_resno() should be used rather than list_nth() - * to fetch tlist entries by resno. + * to fetch tlist entries by resno, and only in SELECT should you assume + * that resno is a unique identifier. * * resname is required to represent the correct column name in non-resjunk * entries of top-level SELECT targetlists, since it will be used as the @@ -541,6 +542,31 @@ typedef struct FieldSelect } FieldSelect; /* ---------------- + * FieldStore + * + * FieldStore represents the operation of modifying one field in a tuple + * value, yielding a new tuple value (the input is not touched!). Like + * the assign case of ArrayRef, this is used to implement UPDATE of a + * portion of a column. + * + * A single FieldStore can actually represent updates of several different + * fields. The parser only generates FieldStores with single-element lists, + * but the planner will collapse multiple updates of the same base column + * into one FieldStore. + * ---------------- + */ + +typedef struct FieldStore +{ + Expr xpr; + Expr *arg; /* input tuple value */ + List *newvals; /* new value(s) for field(s) */ + List *fieldnums; /* integer list of field attnums */ + Oid resulttype; /* type of result (same as type of arg) */ + /* Like RowExpr, we deliberately omit a typmod here */ +} FieldStore; + +/* ---------------- * RelabelType * * RelabelType represents a "dummy" type coercion between two binary- @@ -607,6 +633,9 @@ typedef struct CaseWhen * Placeholder node for the test value to be processed by a CASE expression. * This is effectively like a Param, but can be implemented more simply * since we need only one replacement value at a time. + * + * We also use this in nested UPDATE expressions. + * See transformAssignmentIndirection(). */ typedef struct CaseTestExpr { diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 8bb595c7098..de7b4766559 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.38 2003/11/29 22:41:09 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.39 2004/06/09 19:08:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -67,12 +67,13 @@ typedef struct ParseState extern ParseState *make_parsestate(ParseState *parentParseState); extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno); +extern Oid transformArrayType(Oid arrayType); extern ArrayRef *transformArraySubscripts(ParseState *pstate, Node *arrayBase, Oid arrayType, - int32 arrayTypMod, + Oid elementType, + int32 elementTypMod, List *indirection, - bool forceSlice, Node *assignFrom); extern Const *make_const(Value *value); |
