diff options
| author | Tom Lane | 2013-11-22 00:37:02 +0000 |
|---|---|---|
| committer | Tom Lane | 2013-11-22 00:37:20 +0000 |
| commit | 784e762e886e6f72f548da86a27cd2ead87dbd1c (patch) | |
| tree | 9c21fc1545c96a655ec4591e1ba3c8d99cdfccf8 /src/include | |
| parent | 38f432898131270e5b64245786cb67f322538bae (diff) | |
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/access/tupdesc.h | 4 | ||||
| -rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
| -rw-r--r-- | src/include/catalog/pg_operator.h | 1 | ||||
| -rw-r--r-- | src/include/nodes/execnodes.h | 26 | ||||
| -rw-r--r-- | src/include/nodes/nodes.h | 1 | ||||
| -rw-r--r-- | src/include/nodes/parsenodes.h | 83 | ||||
| -rw-r--r-- | src/include/nodes/plannodes.h | 8 | ||||
| -rw-r--r-- | src/include/optimizer/pathnode.h | 2 | ||||
| -rw-r--r-- | src/include/optimizer/paths.h | 3 | ||||
| -rw-r--r-- | src/include/parser/parse_relation.h | 5 |
10 files changed, 85 insertions, 50 deletions
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 49226b70e6..4aee94b0e6 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -87,10 +87,12 @@ extern TupleDesc CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs); extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); -extern TupleDesc CreateTupleDescCopyExtend(TupleDesc tupdesc, int moreatts); extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); +extern void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, + TupleDesc src, AttrNumber srcAttno); + extern void FreeTupleDesc(TupleDesc tupdesc); extern void IncrTupleDescRefCount(TupleDesc tupdesc); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 2d80cc30b7..c783b26281 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201311171 +#define CATALOG_VERSION_NO 201311211 #endif diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 0350ef6687..78efaa5f23 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -175,6 +175,7 @@ DATA(insert OID = 411 ( "<>" PGNSP PGUID b f f 20 20 16 411 410 int8ne neqsel DESCR("not equal"); DATA(insert OID = 412 ( "<" PGNSP PGUID b f f 20 20 16 413 415 int8lt scalarltsel scalarltjoinsel )); DESCR("less than"); +#define Int8LessOperator 412 DATA(insert OID = 413 ( ">" PGNSP PGUID b f f 20 20 16 412 414 int8gt scalargtsel scalargtjoinsel )); DESCR("greater than"); DATA(insert OID = 414 ( "<=" PGNSP PGUID b f f 20 20 16 415 413 int8le scalarltsel scalarltjoinsel )); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index bedcf040a7..5a4034729c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1395,24 +1395,26 @@ typedef struct SubqueryScanState * function appearing in FROM (typically a function returning set). * * eflags node's capability flags - * ordinal column value for WITH ORDINALITY - * scan_tupdesc scan tuple descriptor - * func_tupdesc function tuple descriptor - * func_slot function result slot, or null - * tuplestorestate private state of tuplestore.c - * funcexpr state for function expression being evaluated + * ordinality is this scan WITH ORDINALITY? + * simple true if we have 1 function and no ordinality + * ordinal current ordinal column value + * nfuncs number of functions being executed + * funcstates per-function execution states (private in + * nodeFunctionscan.c) * ---------------- */ +struct FunctionScanPerFuncState; + typedef struct FunctionScanState { ScanState ss; /* its first field is NodeTag */ int eflags; - int64 ordinal; - TupleDesc scan_tupdesc; - TupleDesc func_tupdesc; - TupleTableSlot *func_slot; - Tuplestorestate *tuplestorestate; - ExprState *funcexpr; + bool ordinality; + bool simple; + int64 ordinal; + int nfuncs; + struct FunctionScanPerFuncState *funcstates; /* array of length + * nfuncs */ } FunctionScanState; /* ---------------- diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fc6b1d7dbd..ff9af7691c 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -389,6 +389,7 @@ typedef enum NodeTag T_Constraint, T_DefElem, T_RangeTblEntry, + T_RangeTblFunction, T_WithCheckOption, T_SortGroupClause, T_WindowClause, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 55524b468a..6a5555f918 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -288,10 +288,8 @@ typedef struct CollateClause * aggregate or some other kind of function. However, if FILTER or OVER is * present it had better be an aggregate or window function. * - * Normally, you'd initialize this via makeFuncCall() and then only - * change the parts of the struct its defaults don't match afterwards - * if needed. - * + * Normally, you'd initialize this via makeFuncCall() and then only change the + * parts of the struct its defaults don't match afterwards, as needed. */ typedef struct FuncCall { @@ -466,13 +464,25 @@ typedef struct RangeSubselect /* * RangeFunction - function call appearing in a FROM clause + * + * functions is a List because we use this to represent the construct + * TABLE(func1(...), func2(...), ...). Each element of this list is a + * two-element sublist, the first element being the untransformed function + * call tree, and the second element being a possibly-empty list of ColumnDef + * nodes representing any columndef list attached to that function within the + * TABLE() syntax. + * + * alias and coldeflist represent any alias and/or columndef list attached + * at the top level. (We disallow coldeflist appearing both here and + * per-function, but that's checked in parse analysis, not by the grammar.) */ typedef struct RangeFunction { NodeTag type; bool lateral; /* does it have LATERAL prefix? */ bool ordinality; /* does it have WITH ORDINALITY suffix? */ - Node *funccallnode; /* untransformed function call tree */ + bool is_table; /* is result of TABLE() syntax? */ + List *functions; /* per-function information, see above */ Alias *alias; /* table alias & optional column aliases */ List *coldeflist; /* list of ColumnDef nodes to describe result * of function returning RECORD */ @@ -512,6 +522,7 @@ typedef struct ColumnDef Oid collOid; /* collation OID (InvalidOid if not set) */ List *constraints; /* other constraints on column */ List *fdwoptions; /* per-column FDW options */ + int location; /* parse location, or -1 if none/unknown */ } ColumnDef; /* @@ -652,13 +663,8 @@ typedef struct XmlSerialize * dropped columns. Note however that a stored rule may have nonempty * colnames for columns dropped since the rule was created (and for that * matter the colnames might be out of date due to column renamings). - * - * The same comments apply to FUNCTION RTEs when the function's return type - * is a named composite type. In addition, for all return types, FUNCTION - * RTEs with ORDINALITY must always have the last colname entry being the - * one for the ordinal column; this is enforced when constructing the RTE. - * Thus when ORDINALITY is used, there will be exactly one more colname - * than would have been present otherwise. + * The same comments apply to FUNCTION RTEs when a function's return type + * is a named composite type. * * In JOIN RTEs, the colnames in both alias and eref are one-to-one with * joinaliasvars entries. A JOIN RTE will omit columns of its inputs when @@ -755,23 +761,15 @@ typedef struct RangeTblEntry List *joinaliasvars; /* list of alias-var expansions */ /* - * Fields valid for a function RTE (else NULL): - * - * If the function returns an otherwise-unspecified RECORD, funccoltypes - * lists the column types declared in the RTE's column type specification, - * funccoltypmods lists their declared typmods, funccolcollations their - * collations. Note that in this case, ORDINALITY is not permitted, so - * there is no extra ordinal column to be allowed for. + * Fields valid for a function RTE (else NIL/zero): * - * Otherwise, those fields are NIL, and the result column types must be - * derived from the funcexpr while treating the ordinal column, if - * present, as a special case. (see get_rte_attribute_*) + * When funcordinality is true, the eref->colnames list includes an alias + * for the ordinality column. The ordinality column is otherwise + * implicit, and must be accounted for "by hand" in places such as + * expandRTE(). */ - Node *funcexpr; /* expression tree for func call */ - List *funccoltypes; /* OID list of column type OIDs */ - List *funccoltypmods; /* integer list of column typmods */ - List *funccolcollations; /* OID list of column collation OIDs */ - bool funcordinality; /* is this called WITH ORDINALITY? */ + List *functions; /* list of RangeTblFunction nodes */ + bool funcordinality; /* is this called WITH ORDINALITY? */ /* * Fields valid for a values RTE (else NIL): @@ -804,6 +802,37 @@ typedef struct RangeTblEntry } RangeTblEntry; /* + * RangeTblFunction - + * RangeTblEntry subsidiary data for one function in a FUNCTION RTE. + * + * If the function had a column definition list (required for an + * otherwise-unspecified RECORD result), funccolnames lists the names given + * in the definition list, funccoltypes lists their declared column types, + * funccoltypmods lists their typmods, funccolcollations their collations. + * Otherwise, those fields are NIL. + * + * Notice we don't attempt to store info about the results of functions + * returning named composite types, because those can change from time to + * time. We do however remember how many columns we thought the type had + * (including dropped columns!), so that we can successfully ignore any + * columns added after the query was parsed. + */ +typedef struct RangeTblFunction +{ + NodeTag type; + + Node *funcexpr; /* expression tree for func call */ + int funccolcount; /* number of columns it contributes to RTE */ + /* These fields record the contents of a column definition list, if any: */ + List *funccolnames; /* column names (list of String) */ + List *funccoltypes; /* OID list of column type OIDs */ + List *funccoltypmods; /* integer list of column typmods */ + List *funccolcollations; /* OID list of column collation OIDs */ + /* This is set during planning for use by the executor: */ + Bitmapset *funcparams; /* PARAM_EXEC Param IDs affecting this func */ +} RangeTblFunction; + +/* * WithCheckOption - * representation of WITH CHECK OPTION checks to be applied to new tuples * when inserting/updating an auto-updatable view. diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 44ea0b7752..101e22cee1 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -424,12 +424,8 @@ typedef struct SubqueryScan typedef struct FunctionScan { Scan scan; - Node *funcexpr; /* expression tree for func call */ - bool funcordinality; /* WITH ORDINALITY */ - List *funccolnames; /* output column names (string Value nodes) */ - List *funccoltypes; /* OID list of column type OIDs */ - List *funccoltypmods; /* integer list of column typmods */ - List *funccolcollations; /* OID list of column collation OIDs */ + List *functions; /* list of RangeTblFunction nodes */ + bool funcordinality; /* WITH ORDINALITY */ } FunctionScan; /* ---------------- diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 9686229134..0033a3c529 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -70,7 +70,7 @@ extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer); extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, - Relids required_outer); + List *pathkeys, Relids required_outer); extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer); extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 96ffdb195f..999adaaf8c 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -166,6 +166,9 @@ extern Path *get_cheapest_fractional_path_for_pathkeys(List *paths, double fraction); extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index, ScanDirection scandir); +extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr, + Relids nullable_relids, Oid opno, + Relids rel, bool create_it); extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, List *subquery_pathkeys); extern List *build_join_pathkeys(PlannerInfo *root, diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index 83c9131e78..f20c113a80 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -58,8 +58,9 @@ extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate, bool lateral, bool inFromCl); extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate, - char *funcname, - Node *funcexpr, + List *funcnames, + List *funcexprs, + List *coldeflists, RangeFunction *rangefunc, bool lateral, bool inFromCl); |
