1997-11-25 23:07:18 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* parse_relation.c
|
1997-11-25 23:07:18 +01:00
|
|
|
* parser support routines dealing with relations
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/parser/parse_relation.c
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
2000-06-20 03:41:22 +02:00
|
|
|
|
2001-02-14 22:35:07 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/relation.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "access/sysattr.h"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/table.h"
|
2001-10-23 00:47:57 +02:00
|
|
|
#include "catalog/heap.h"
|
2002-08-08 03:44:31 +02:00
|
|
|
#include "catalog/namespace.h"
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "catalog/pg_type.h"
|
2005-04-01 00:46:33 +02:00
|
|
|
#include "funcapi.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "nodes/makefuncs.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
2017-04-01 06:17:18 +02:00
|
|
|
#include "parser/parse_enr.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/parse_relation.h"
|
|
|
|
#include "parser/parse_type.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "parser/parsetree.h"
|
2018-10-01 18:43:21 +02:00
|
|
|
#include "storage/lmgr.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "utils/builtins.h"
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2001-08-10 20:57:42 +02:00
|
|
|
#include "utils/syscache.h"
|
2017-01-21 02:29:53 +01:00
|
|
|
#include "utils/varlena.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Support for fuzzily matching columns.
|
|
|
|
*
|
2022-11-23 00:46:31 +01:00
|
|
|
* This is for building diagnostic messages, where multiple or non-exact
|
|
|
|
* matching attributes are of interest.
|
|
|
|
*
|
|
|
|
* "distance" is the current best fuzzy-match distance if rfirst isn't NULL,
|
|
|
|
* otherwise it is the maximum acceptable distance plus 1.
|
|
|
|
*
|
|
|
|
* rfirst/first record the closest non-exact match so far, and distance
|
|
|
|
* is its distance from the target name. If we have found a second non-exact
|
|
|
|
* match of exactly the same distance, rsecond/second record that. (If
|
|
|
|
* we find three of the same distance, we conclude that "distance" is not
|
|
|
|
* a tight enough bound for a useful hint and clear rfirst/rsecond again.
|
|
|
|
* Only if we later find something closer will we re-populate rfirst.)
|
|
|
|
*
|
|
|
|
* rexact1/exact1 record the location of the first exactly-matching column,
|
|
|
|
* if any. If we find multiple exact matches then rexact2/exact2 record
|
|
|
|
* another one (we don't especially care which). Currently, these get
|
|
|
|
* populated independently of the fuzzy-match fields.
|
2019-12-26 17:16:42 +01:00
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
int distance; /* Current or limit distance */
|
|
|
|
RangeTblEntry *rfirst; /* RTE of closest non-exact match, or NULL */
|
|
|
|
AttrNumber first; /* Col index in rfirst */
|
|
|
|
RangeTblEntry *rsecond; /* RTE of another non-exact match w/same dist */
|
|
|
|
AttrNumber second; /* Col index in rsecond */
|
|
|
|
RangeTblEntry *rexact1; /* RTE of first exact match, or NULL */
|
|
|
|
AttrNumber exact1; /* Col index in rexact1 */
|
|
|
|
RangeTblEntry *rexact2; /* RTE of second exact match, or NULL */
|
|
|
|
AttrNumber exact2; /* Col index in rexact2 */
|
2019-12-26 17:16:42 +01:00
|
|
|
} FuzzyAttrMatchState;
|
|
|
|
|
2015-03-11 15:44:04 +01:00
|
|
|
#define MAX_FUZZY_DISTANCE 3
|
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
|
|
|
|
static ParseNamespaceItem *scanNameSpaceForRefname(ParseState *pstate,
|
|
|
|
const char *refname,
|
|
|
|
int location);
|
|
|
|
static ParseNamespaceItem *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
|
|
|
|
int location);
|
2014-01-12 01:03:12 +01:00
|
|
|
static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
|
|
|
|
int location);
|
2019-12-26 17:16:42 +01:00
|
|
|
static int scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
|
2021-03-31 10:52:37 +02:00
|
|
|
Alias *eref,
|
2019-12-26 17:16:42 +01:00
|
|
|
const char *colname, int location,
|
|
|
|
int fuzzy_rte_penalty,
|
|
|
|
FuzzyAttrMatchState *fuzzystate);
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
static void markRTEForSelectPriv(ParseState *pstate,
|
2009-01-22 21:16:10 +01:00
|
|
|
int rtindex, AttrNumber col);
|
2004-08-19 22:57:41 +02:00
|
|
|
static void expandRelation(Oid relid, Alias *eref,
|
|
|
|
int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2004-08-19 22:57:41 +02:00
|
|
|
List **colnames, List **colvars);
|
2005-04-01 00:46:33 +02:00
|
|
|
static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
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
2013-11-22 01:37:02 +01:00
|
|
|
int count, int offset,
|
2005-04-01 00:46:33 +02:00
|
|
|
int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2005-04-01 00:46:33 +02:00
|
|
|
List **colnames, List **colvars);
|
2002-08-02 20:15:10 +02:00
|
|
|
static int specialAttNum(const char *attname);
|
2022-11-23 00:46:31 +01:00
|
|
|
static bool rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte);
|
|
|
|
static bool rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte);
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
static bool isQueryUsingTempRelation_walker(Node *node, void *context);
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-12-26 17:16:42 +01:00
|
|
|
* refnameNamespaceItem
|
|
|
|
* Given a possibly-qualified refname, look to see if it matches any visible
|
|
|
|
* namespace item. If so, return a pointer to the nsitem; else return NULL.
|
2002-08-08 03:44:31 +02:00
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Optionally get nsitem's nesting depth (0 = current) into *sublevels_up.
|
2002-08-08 03:44:31 +02:00
|
|
|
* If sublevels_up is NULL, only consider items at the current nesting
|
|
|
|
* level.
|
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* An unqualified refname (schemaname == NULL) can match any item with matching
|
2002-08-08 03:44:31 +02:00
|
|
|
* alias, or matching unqualified relname in the case of alias-less relation
|
2019-12-26 17:16:42 +01:00
|
|
|
* items. It is possible that such a refname matches multiple items in the
|
2003-07-19 22:20:53 +02:00
|
|
|
* nearest nesting level that has a match; if so, we report an error via
|
|
|
|
* ereport().
|
2002-08-08 03:44:31 +02:00
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* A qualified refname (schemaname != NULL) can only match a relation item
|
2002-08-08 03:44:31 +02:00
|
|
|
* that (a) has no alias and (b) is for the same relation identified by
|
|
|
|
* schemaname.refname. In this case we convert schemaname.refname to a
|
|
|
|
* relation OID and search by relid, rather than by alias name. This is
|
2013-04-20 17:04:41 +02:00
|
|
|
* peculiar, but it's what SQL says to do.
|
2000-02-15 04:38:29 +01:00
|
|
|
*/
|
2019-12-26 17:16:42 +01:00
|
|
|
ParseNamespaceItem *
|
|
|
|
refnameNamespaceItem(ParseState *pstate,
|
2002-08-08 03:44:31 +02:00
|
|
|
const char *schemaname,
|
|
|
|
const char *refname,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location,
|
2002-03-12 01:52:10 +01:00
|
|
|
int *sublevels_up)
|
2000-02-15 04:38:29 +01:00
|
|
|
{
|
2002-08-08 03:44:31 +02:00
|
|
|
Oid relId = InvalidOid;
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
if (sublevels_up)
|
|
|
|
*sublevels_up = 0;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2002-08-08 03:44:31 +02:00
|
|
|
if (schemaname != NULL)
|
|
|
|
{
|
|
|
|
Oid namespaceId;
|
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
/*
|
|
|
|
* We can use LookupNamespaceNoError() here because we are only
|
|
|
|
* interested in finding existing RTEs. Checking USAGE permission on
|
|
|
|
* the schema is unnecessary since it would have already been checked
|
|
|
|
* when the RTE was made. Furthermore, we want to report "RTE not
|
|
|
|
* found", not "no permissions for schema", if the name happens to
|
|
|
|
* match a schema name the user hasn't got access to.
|
|
|
|
*/
|
|
|
|
namespaceId = LookupNamespaceNoError(schemaname);
|
2010-04-28 02:46:33 +02:00
|
|
|
if (!OidIsValid(namespaceId))
|
2009-10-31 02:41:31 +01:00
|
|
|
return NULL;
|
2002-08-08 03:44:31 +02:00
|
|
|
relId = get_relname_relid(refname, namespaceId);
|
|
|
|
if (!OidIsValid(relId))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2000-02-15 04:38:29 +01:00
|
|
|
while (pstate != NULL)
|
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
ParseNamespaceItem *result;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2002-08-08 03:44:31 +02:00
|
|
|
if (OidIsValid(relId))
|
2008-09-01 22:42:46 +02:00
|
|
|
result = scanNameSpaceForRelid(pstate, relId, location);
|
2002-08-08 03:44:31 +02:00
|
|
|
else
|
2008-09-01 22:42:46 +02:00
|
|
|
result = scanNameSpaceForRefname(pstate, refname, location);
|
2002-08-08 03:44:31 +02:00
|
|
|
|
2005-06-05 02:38:11 +02:00
|
|
|
if (result)
|
|
|
|
return result;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
if (sublevels_up)
|
|
|
|
(*sublevels_up)++;
|
|
|
|
else
|
|
|
|
break;
|
2005-06-05 02:38:11 +02:00
|
|
|
|
|
|
|
pstate = pstate->parentParseState;
|
2000-02-15 04:38:29 +01:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
return NULL;
|
2000-02-15 04:38:29 +01:00
|
|
|
}
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
/*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Search the query's table namespace for an item matching the
|
|
|
|
* given unqualified refname. Return the nsitem if a unique match, or NULL
|
2002-08-08 03:44:31 +02:00
|
|
|
* if no match. Raise error if multiple matches.
|
2013-11-11 16:42:57 +01:00
|
|
|
*
|
|
|
|
* Note: it might seem that we shouldn't have to worry about the possibility
|
|
|
|
* of multiple matches; after all, the SQL standard disallows duplicate table
|
|
|
|
* aliases within a given SELECT level. Historically, however, Postgres has
|
|
|
|
* been laxer than that. For example, we allow
|
|
|
|
* SELECT ... FROM tab1 x CROSS JOIN (tab2 x CROSS JOIN tab3 y) z
|
|
|
|
* on the grounds that the aliased join (z) hides the aliases within it,
|
|
|
|
* therefore there is no conflict between the two RTEs named "x". However,
|
|
|
|
* if tab3 is a LATERAL subquery, then from within the subquery both "x"es
|
|
|
|
* are visible. Rather than rejecting queries that used to work, we allow
|
|
|
|
* this situation, and complain only if there's actually an ambiguous
|
|
|
|
* reference to "x".
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2019-12-26 17:16:42 +01:00
|
|
|
static ParseNamespaceItem *
|
2008-09-01 22:42:46 +02:00
|
|
|
scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
ParseNamespaceItem *result = NULL;
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
foreach(l, pstate->p_namespace)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
|
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
/* Ignore columns-only items */
|
|
|
|
if (!nsitem->p_rel_visible)
|
|
|
|
continue;
|
2012-08-08 01:02:54 +02:00
|
|
|
/* If not inside LATERAL, ignore lateral-only items */
|
|
|
|
if (nsitem->p_lateral_only && !pstate->p_lateral_active)
|
|
|
|
continue;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2021-03-31 10:52:37 +02:00
|
|
|
if (strcmp(nsitem->p_names->aliasname, refname) == 0)
|
2001-02-14 22:35:07 +01:00
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
if (result)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
|
|
|
|
errmsg("table reference \"%s\" is ambiguous",
|
2008-09-01 22:42:46 +02:00
|
|
|
refname),
|
|
|
|
parser_errposition(pstate, location)));
|
2014-01-12 01:03:12 +01:00
|
|
|
check_lateral_ref_ok(pstate, nsitem, location);
|
2019-12-26 17:16:42 +01:00
|
|
|
result = nsitem;
|
2001-02-14 22:35:07 +01:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2002-08-08 03:44:31 +02:00
|
|
|
/*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Search the query's table namespace for a relation item matching the
|
|
|
|
* given relation OID. Return the nsitem if a unique match, or NULL
|
2013-11-11 16:42:57 +01:00
|
|
|
* if no match. Raise error if multiple matches.
|
2002-08-08 03:44:31 +02:00
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* See the comments for refnameNamespaceItem to understand why this
|
2002-08-08 03:44:31 +02:00
|
|
|
* acts the way it does.
|
|
|
|
*/
|
2019-12-26 17:16:42 +01:00
|
|
|
static ParseNamespaceItem *
|
2008-09-01 22:42:46 +02:00
|
|
|
scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
ParseNamespaceItem *result = NULL;
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l;
|
2002-08-08 03:44:31 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
foreach(l, pstate->p_namespace)
|
2002-08-08 03:44:31 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
|
|
|
|
RangeTblEntry *rte = nsitem->p_rte;
|
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
/* Ignore columns-only items */
|
|
|
|
if (!nsitem->p_rel_visible)
|
|
|
|
continue;
|
2012-08-08 01:02:54 +02:00
|
|
|
/* If not inside LATERAL, ignore lateral-only items */
|
|
|
|
if (nsitem->p_lateral_only && !pstate->p_lateral_active)
|
|
|
|
continue;
|
2002-08-08 03:44:31 +02:00
|
|
|
|
2006-01-10 22:59:59 +01:00
|
|
|
/* yes, the test for alias == NULL should be there... */
|
2002-08-08 03:44:31 +02:00
|
|
|
if (rte->rtekind == RTE_RELATION &&
|
|
|
|
rte->relid == relid &&
|
|
|
|
rte->alias == NULL)
|
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
if (result)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
|
|
|
|
errmsg("table reference %u is ambiguous",
|
2008-09-01 22:42:46 +02:00
|
|
|
relid),
|
|
|
|
parser_errposition(pstate, location)));
|
2014-01-12 01:03:12 +01:00
|
|
|
check_lateral_ref_ok(pstate, nsitem, location);
|
2019-12-26 17:16:42 +01:00
|
|
|
result = nsitem;
|
2002-08-08 03:44:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2008-10-06 04:12:56 +02:00
|
|
|
/*
|
|
|
|
* Search the query's CTE namespace for a CTE matching the given unqualified
|
|
|
|
* refname. Return the CTE (and its levelsup count) if a match, or NULL
|
|
|
|
* if no match. We need not worry about multiple matches, since parse_cte.c
|
|
|
|
* rejects WITH lists containing duplicate CTE names.
|
|
|
|
*/
|
|
|
|
CommonTableExpr *
|
|
|
|
scanNameSpaceForCTE(ParseState *pstate, const char *refname,
|
|
|
|
Index *ctelevelsup)
|
|
|
|
{
|
|
|
|
Index levelsup;
|
|
|
|
|
|
|
|
for (levelsup = 0;
|
|
|
|
pstate != NULL;
|
|
|
|
pstate = pstate->parentParseState, levelsup++)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, pstate->p_ctenamespace)
|
|
|
|
{
|
|
|
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
|
|
|
|
|
|
|
if (strcmp(cte->ctename, refname) == 0)
|
|
|
|
{
|
|
|
|
*ctelevelsup = levelsup;
|
|
|
|
return cte;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-08 03:14:44 +02:00
|
|
|
/*
|
|
|
|
* Search for a possible "future CTE", that is one that is not yet in scope
|
|
|
|
* according to the WITH scoping rules. This has nothing to do with valid
|
|
|
|
* SQL semantics, but it's important for error reporting purposes.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
isFutureCTE(ParseState *pstate, const char *refname)
|
|
|
|
{
|
|
|
|
for (; pstate != NULL; pstate = pstate->parentParseState)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, pstate->p_future_ctes)
|
|
|
|
{
|
|
|
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
|
|
|
|
|
|
|
if (strcmp(cte->ctename, refname) == 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-01 06:17:18 +02:00
|
|
|
/*
|
|
|
|
* Search the query's ephemeral named relation namespace for a relation
|
|
|
|
* matching the given unqualified refname.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
scanNameSpaceForENR(ParseState *pstate, const char *refname)
|
|
|
|
{
|
|
|
|
return name_matches_visible_ENR(pstate, refname);
|
|
|
|
}
|
|
|
|
|
2006-01-10 22:59:59 +01:00
|
|
|
/*
|
2012-08-08 01:02:54 +02:00
|
|
|
* searchRangeTableForRel
|
2006-01-10 22:59:59 +01:00
|
|
|
* See if any RangeTblEntry could possibly match the RangeVar.
|
|
|
|
* If so, return a pointer to the RangeTblEntry; else return NULL.
|
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* This is different from refnameNamespaceItem in that it considers every
|
2006-01-10 22:59:59 +01:00
|
|
|
* entry in the ParseState's rangetable(s), not only those that are currently
|
2012-08-08 22:41:04 +02:00
|
|
|
* visible in the p_namespace list(s). This behavior is invalid per the SQL
|
2006-01-10 22:59:59 +01:00
|
|
|
* spec, and it may give ambiguous results (there might be multiple equally
|
|
|
|
* valid matches, but only one will be returned). This must be used ONLY
|
2009-10-21 22:22:38 +02:00
|
|
|
* as a heuristic in giving suitable error messages. See errorMissingRTE.
|
2006-01-10 22:59:59 +01:00
|
|
|
*
|
2008-10-06 04:12:56 +02:00
|
|
|
* Notice that we consider both matches on actual relation (or CTE) name
|
|
|
|
* and matches on alias.
|
2006-01-10 22:59:59 +01:00
|
|
|
*/
|
|
|
|
static RangeTblEntry *
|
2012-08-08 01:02:54 +02:00
|
|
|
searchRangeTableForRel(ParseState *pstate, RangeVar *relation)
|
2006-01-10 22:59:59 +01:00
|
|
|
{
|
2008-10-06 04:12:56 +02:00
|
|
|
const char *refname = relation->relname;
|
|
|
|
Oid relId = InvalidOid;
|
|
|
|
CommonTableExpr *cte = NULL;
|
2017-04-01 06:17:18 +02:00
|
|
|
bool isenr = false;
|
2008-10-06 04:12:56 +02:00
|
|
|
Index ctelevelsup = 0;
|
|
|
|
Index levelsup;
|
2006-01-10 22:59:59 +01:00
|
|
|
|
2008-10-06 04:12:56 +02:00
|
|
|
/*
|
|
|
|
* If it's an unqualified name, check for possible CTE matches. A CTE
|
|
|
|
* hides any real relation matches. If no CTE, look for a matching
|
|
|
|
* relation.
|
2011-07-09 04:19:30 +02:00
|
|
|
*
|
|
|
|
* NB: It's not critical that RangeVarGetRelid return the correct answer
|
|
|
|
* here in the face of concurrent DDL. If it doesn't, the worst case
|
|
|
|
* scenario is a less-clear error message. Also, the tables involved in
|
|
|
|
* the query are already locked, which reduces the number of cases in
|
|
|
|
* which surprising behavior can occur. So we do the name lookup
|
|
|
|
* unlocked.
|
2008-10-06 04:12:56 +02:00
|
|
|
*/
|
|
|
|
if (!relation->schemaname)
|
2017-04-01 06:17:18 +02:00
|
|
|
{
|
2008-10-06 04:12:56 +02:00
|
|
|
cte = scanNameSpaceForCTE(pstate, refname, &ctelevelsup);
|
2017-04-01 06:17:18 +02:00
|
|
|
if (!cte)
|
|
|
|
isenr = scanNameSpaceForENR(pstate, refname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cte && !isenr)
|
Improve table locking behavior in the face of current DDL.
In the previous coding, callers were faced with an awkward choice:
look up the name, do permissions checks, and then lock the table; or
look up the name, lock the table, and then do permissions checks.
The first choice was wrong because the results of the name lookup
and permissions checks might be out-of-date by the time the table
lock was acquired, while the second allowed a user with no privileges
to interfere with access to a table by users who do have privileges
(e.g. if a malicious backend queues up for an AccessExclusiveLock on
a table on which AccessShareLock is already held, further attempts
to access the table will be blocked until the AccessExclusiveLock
is obtained and the malicious backend's transaction rolls back).
To fix, allow callers of RangeVarGetRelid() to pass a callback which
gets executed after performing the name lookup but before acquiring
the relation lock. If the name lookup is retried (because
invalidation messages are received), the callback will be re-executed
as well, so we get the best of both worlds. RangeVarGetRelid() is
renamed to RangeVarGetRelidExtended(); callers not wishing to supply
a callback can continue to invoke it as RangeVarGetRelid(), which is
now a macro. Since the only one caller that uses nowait = true now
passes a callback anyway, the RangeVarGetRelid() macro defaults nowait
as well. The callback can also be used for supplemental locking - for
example, REINDEX INDEX needs to acquire the table lock before the index
lock to reduce deadlock possibilities.
There's a lot more work to be done here to fix all the cases where this
can be a problem, but this commit provides the general infrastructure
and fixes the following specific cases: REINDEX INDEX, REINDEX TABLE,
LOCK TABLE, and and DROP TABLE/INDEX/SEQUENCE/VIEW/FOREIGN TABLE.
Per discussion with Noah Misch and Alvaro Herrera.
2011-11-30 16:12:27 +01:00
|
|
|
relId = RangeVarGetRelid(relation, NoLock, true);
|
2008-10-06 04:12:56 +02:00
|
|
|
|
2017-04-01 06:17:18 +02:00
|
|
|
/* Now look for RTEs matching either the relation/CTE/ENR or the alias */
|
2008-10-06 04:12:56 +02:00
|
|
|
for (levelsup = 0;
|
|
|
|
pstate != NULL;
|
|
|
|
pstate = pstate->parentParseState, levelsup++)
|
2006-01-10 22:59:59 +01:00
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, pstate->p_rtable)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
|
|
|
2008-10-06 04:12:56 +02:00
|
|
|
if (rte->rtekind == RTE_RELATION &&
|
|
|
|
OidIsValid(relId) &&
|
2006-01-10 22:59:59 +01:00
|
|
|
rte->relid == relId)
|
|
|
|
return rte;
|
2008-10-06 04:12:56 +02:00
|
|
|
if (rte->rtekind == RTE_CTE &&
|
|
|
|
cte != NULL &&
|
|
|
|
rte->ctelevelsup + levelsup == ctelevelsup &&
|
|
|
|
strcmp(rte->ctename, refname) == 0)
|
|
|
|
return rte;
|
2017-04-01 06:17:18 +02:00
|
|
|
if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
|
|
|
|
isenr &&
|
|
|
|
strcmp(rte->enrname, refname) == 0)
|
|
|
|
return rte;
|
2006-01-10 22:59:59 +01:00
|
|
|
if (strcmp(rte->eref->aliasname, refname) == 0)
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2012-08-08 22:41:04 +02:00
|
|
|
* Check for relation-name conflicts between two namespace lists.
|
2005-06-05 02:38:11 +02:00
|
|
|
* Raise an error if any is found.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2001-02-14 22:35:07 +01:00
|
|
|
* Note: we assume that each given argument does not contain conflicts
|
|
|
|
* itself; we just want to know if the two can be merged together.
|
2002-08-08 03:44:31 +02:00
|
|
|
*
|
2013-04-20 17:04:41 +02:00
|
|
|
* Per SQL, two alias-less plain relation RTEs do not conflict even if
|
2002-08-08 03:44:31 +02:00
|
|
|
* they have the same eref->aliasname (ie, same relation name), if they
|
|
|
|
* are for different relation OIDs (implying they are in different schemas).
|
2012-08-08 01:02:54 +02:00
|
|
|
*
|
|
|
|
* We ignore the lateral-only flags in the namespace items: the lists must
|
2012-08-08 22:41:04 +02:00
|
|
|
* not conflict, even when all items are considered visible. However,
|
|
|
|
* columns-only items should be ignored.
|
2000-03-23 08:38:30 +01:00
|
|
|
*/
|
2001-02-14 22:35:07 +01:00
|
|
|
void
|
2005-06-05 02:38:11 +02:00
|
|
|
checkNameSpaceConflicts(ParseState *pstate, List *namespace1,
|
|
|
|
List *namespace2)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l1;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2005-06-05 02:38:11 +02:00
|
|
|
foreach(l1, namespace1)
|
2002-08-08 03:44:31 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
ParseNamespaceItem *nsitem1 = (ParseNamespaceItem *) lfirst(l1);
|
|
|
|
RangeTblEntry *rte1 = nsitem1->p_rte;
|
2021-03-31 10:52:37 +02:00
|
|
|
const char *aliasname1 = nsitem1->p_names->aliasname;
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l2;
|
2002-08-08 03:44:31 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
if (!nsitem1->p_rel_visible)
|
|
|
|
continue;
|
|
|
|
|
2005-06-05 02:38:11 +02:00
|
|
|
foreach(l2, namespace2)
|
2002-08-08 03:44:31 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
ParseNamespaceItem *nsitem2 = (ParseNamespaceItem *) lfirst(l2);
|
|
|
|
RangeTblEntry *rte2 = nsitem2->p_rte;
|
2021-03-31 10:52:37 +02:00
|
|
|
const char *aliasname2 = nsitem2->p_names->aliasname;
|
2005-06-05 02:38:11 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
if (!nsitem2->p_rel_visible)
|
|
|
|
continue;
|
2021-03-31 10:52:37 +02:00
|
|
|
if (strcmp(aliasname2, aliasname1) != 0)
|
2005-06-05 02:38:11 +02:00
|
|
|
continue; /* definitely no conflict */
|
|
|
|
if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL &&
|
|
|
|
rte2->rtekind == RTE_RELATION && rte2->alias == NULL &&
|
|
|
|
rte1->relid != rte2->relid)
|
2013-04-20 17:04:41 +02:00
|
|
|
continue; /* no conflict per SQL rule */
|
2005-06-05 02:38:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_ALIAS),
|
2003-07-19 22:20:53 +02:00
|
|
|
errmsg("table name \"%s\" specified more than once",
|
|
|
|
aliasname1)));
|
2002-08-08 03:44:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-12 01:03:12 +01:00
|
|
|
/*
|
|
|
|
* Complain if a namespace item is currently disallowed as a LATERAL reference.
|
|
|
|
* This enforces both SQL:2008's rather odd idea of what to do with a LATERAL
|
|
|
|
* reference to the wrong side of an outer join, and our own prohibition on
|
|
|
|
* referencing the target table of an UPDATE or DELETE as a lateral reference
|
|
|
|
* in a FROM/USING clause.
|
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Note: the pstate should be the same query level the nsitem was found in.
|
|
|
|
*
|
2014-01-12 01:03:12 +01:00
|
|
|
* Convenience subroutine to avoid multiple copies of a rather ugly ereport.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
|
|
|
|
int location)
|
|
|
|
{
|
|
|
|
if (nsitem->p_lateral_only && !nsitem->p_lateral_ok)
|
|
|
|
{
|
|
|
|
/* SQL:2008 demands this be an error, not an invisible item */
|
|
|
|
RangeTblEntry *rte = nsitem->p_rte;
|
2021-03-31 10:52:37 +02:00
|
|
|
char *refname = nsitem->p_names->aliasname;
|
2014-01-12 01:03:12 +01:00
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
|
|
|
refname),
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
(pstate->p_target_nsitem != NULL &&
|
|
|
|
rte == pstate->p_target_nsitem->p_rte) ?
|
2014-01-12 01:03:12 +01:00
|
|
|
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
|
|
|
refname) :
|
|
|
|
errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
/*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Given an RT index and nesting depth, find the corresponding
|
|
|
|
* ParseNamespaceItem (there must be one).
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2019-12-26 17:16:42 +01:00
|
|
|
ParseNamespaceItem *
|
|
|
|
GetNSItemByRangeTablePosn(ParseState *pstate,
|
|
|
|
int varno,
|
|
|
|
int sublevels_up)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
ListCell *lc;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
while (sublevels_up-- > 0)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2000-09-12 23:07:18 +02:00
|
|
|
pstate = pstate->parentParseState;
|
2019-12-26 17:16:42 +01:00
|
|
|
Assert(pstate != NULL);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2019-12-26 17:16:42 +01:00
|
|
|
foreach(lc, pstate->p_namespace)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);
|
2001-02-14 22:35:07 +01:00
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
if (nsitem->p_rtindex == varno)
|
|
|
|
return nsitem;
|
|
|
|
}
|
|
|
|
elog(ERROR, "nsitem not found (internal error)");
|
|
|
|
return NULL; /* keep compiler quiet */
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
2004-04-02 21:07:02 +02:00
|
|
|
/*
|
|
|
|
* Given an RT index and nesting depth, find the corresponding RTE.
|
2019-12-26 17:16:42 +01:00
|
|
|
* (Note that the RTE need not be in the query's namespace.)
|
2004-04-02 21:07:02 +02:00
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
GetRTEByRangeTablePosn(ParseState *pstate,
|
|
|
|
int varno,
|
|
|
|
int sublevels_up)
|
|
|
|
{
|
|
|
|
while (sublevels_up-- > 0)
|
|
|
|
{
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
Assert(pstate != NULL);
|
|
|
|
}
|
2004-05-31 01:40:41 +02:00
|
|
|
Assert(varno > 0 && varno <= list_length(pstate->p_rtable));
|
2004-04-02 21:07:02 +02:00
|
|
|
return rt_fetch(varno, pstate->p_rtable);
|
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
/*
|
|
|
|
* Fetch the CTE for a CTE-reference RTE.
|
2008-10-06 17:15:22 +02:00
|
|
|
*
|
|
|
|
* rtelevelsup is the number of query levels above the given pstate that the
|
2019-12-26 17:16:42 +01:00
|
|
|
* RTE came from.
|
2008-10-04 23:56:55 +02:00
|
|
|
*/
|
|
|
|
CommonTableExpr *
|
2008-10-06 17:15:22 +02:00
|
|
|
GetCTEForRTE(ParseState *pstate, RangeTblEntry *rte, int rtelevelsup)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
|
|
|
Index levelsup;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
Assert(rte->rtekind == RTE_CTE);
|
2008-10-06 17:15:22 +02:00
|
|
|
levelsup = rte->ctelevelsup + rtelevelsup;
|
2008-10-04 23:56:55 +02:00
|
|
|
while (levelsup-- > 0)
|
|
|
|
{
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
if (!pstate) /* shouldn't happen */
|
|
|
|
elog(ERROR, "bad levelsup for CTE \"%s\"", rte->ctename);
|
|
|
|
}
|
|
|
|
foreach(lc, pstate->p_ctenamespace)
|
|
|
|
{
|
|
|
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
|
|
|
|
|
|
|
if (strcmp(cte->ctename, rte->ctename) == 0)
|
|
|
|
return cte;
|
|
|
|
}
|
|
|
|
/* shouldn't happen */
|
|
|
|
elog(ERROR, "could not find CTE \"%s\"", rte->ctename);
|
|
|
|
return NULL; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
2015-03-11 15:44:04 +01:00
|
|
|
/*
|
|
|
|
* updateFuzzyAttrMatchState
|
|
|
|
* Using Levenshtein distance, consider if column is best fuzzy match.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
updateFuzzyAttrMatchState(int fuzzy_rte_penalty,
|
|
|
|
FuzzyAttrMatchState *fuzzystate, RangeTblEntry *rte,
|
|
|
|
const char *actual, const char *match, int attnum)
|
|
|
|
{
|
|
|
|
int columndistance;
|
|
|
|
int matchlen;
|
|
|
|
|
|
|
|
/* Bail before computing the Levenshtein distance if there's no hope. */
|
|
|
|
if (fuzzy_rte_penalty > fuzzystate->distance)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Outright reject dropped columns, which can appear here with apparent
|
|
|
|
* empty actual names, per remarks within scanRTEForColumn().
|
|
|
|
*/
|
|
|
|
if (actual[0] == '\0')
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Use Levenshtein to compute match distance. */
|
|
|
|
matchlen = strlen(match);
|
|
|
|
columndistance =
|
|
|
|
varstr_levenshtein_less_equal(actual, strlen(actual), match, matchlen,
|
|
|
|
1, 1, 1,
|
|
|
|
fuzzystate->distance + 1
|
2016-01-22 17:53:06 +01:00
|
|
|
- fuzzy_rte_penalty,
|
|
|
|
true);
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If more than half the characters are different, don't treat it as a
|
|
|
|
* match, to avoid making ridiculous suggestions.
|
|
|
|
*/
|
|
|
|
if (columndistance > matchlen / 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* From this point on, we can ignore the distinction between the RTE-name
|
|
|
|
* distance and the column-name distance.
|
|
|
|
*/
|
|
|
|
columndistance += fuzzy_rte_penalty;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the new distance is less than or equal to that of the best match
|
|
|
|
* found so far, update fuzzystate.
|
|
|
|
*/
|
|
|
|
if (columndistance < fuzzystate->distance)
|
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
/* Store new lowest observed distance as first/only match */
|
2015-03-11 15:44:04 +01:00
|
|
|
fuzzystate->distance = columndistance;
|
|
|
|
fuzzystate->rfirst = rte;
|
|
|
|
fuzzystate->first = attnum;
|
|
|
|
fuzzystate->rsecond = NULL;
|
|
|
|
}
|
|
|
|
else if (columndistance == fuzzystate->distance)
|
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
/* If we already have a match of this distance, update state */
|
|
|
|
if (fuzzystate->rsecond != NULL)
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
/*
|
|
|
|
* Too many matches at same distance. Clearly, this value of
|
|
|
|
* distance is too low a bar, so drop these entries while keeping
|
|
|
|
* the current distance value, so that only smaller distances will
|
|
|
|
* be considered interesting. Only if we find something of lower
|
|
|
|
* distance will we re-populate rfirst (via the stanza above).
|
|
|
|
*/
|
2015-03-11 15:44:04 +01:00
|
|
|
fuzzystate->rfirst = NULL;
|
|
|
|
fuzzystate->rsecond = NULL;
|
|
|
|
}
|
2022-11-23 00:46:31 +01:00
|
|
|
else if (fuzzystate->rfirst != NULL)
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
/* Record as provisional second match */
|
2015-03-11 15:44:04 +01:00
|
|
|
fuzzystate->rsecond = rte;
|
|
|
|
fuzzystate->second = attnum;
|
|
|
|
}
|
2022-11-23 00:46:31 +01:00
|
|
|
else
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
|
|
|
/*
|
2022-11-23 00:46:31 +01:00
|
|
|
* Do nothing. When rfirst is NULL, distance is more than what we
|
|
|
|
* want to consider acceptable, so we should ignore this match.
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
/*
|
|
|
|
* scanNSItemForColumn
|
|
|
|
* Search the column names of a single namespace item for the given name.
|
|
|
|
* If found, return an appropriate Var node, else return NULL.
|
|
|
|
* If the name proves ambiguous within this nsitem, raise error.
|
|
|
|
*
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
* Side effect: if we find a match, mark the corresponding RTE as requiring
|
|
|
|
* read access for the column.
|
2019-12-26 17:16:42 +01:00
|
|
|
*/
|
|
|
|
Node *
|
|
|
|
scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem,
|
|
|
|
int sublevels_up, const char *colname, int location)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = nsitem->p_rte;
|
|
|
|
int attnum;
|
|
|
|
Var *var;
|
|
|
|
|
|
|
|
/*
|
2021-03-31 10:52:37 +02:00
|
|
|
* Scan the nsitem's column names (or aliases) for a match. Complain if
|
2019-12-26 17:16:42 +01:00
|
|
|
* multiple matches.
|
|
|
|
*/
|
2021-03-31 10:52:37 +02:00
|
|
|
attnum = scanRTEForColumn(pstate, rte, nsitem->p_names,
|
2019-12-26 17:16:42 +01:00
|
|
|
colname, location,
|
|
|
|
0, NULL);
|
|
|
|
|
|
|
|
if (attnum == InvalidAttrNumber)
|
|
|
|
return NULL; /* Return NULL if no match */
|
|
|
|
|
|
|
|
/* In constraint check, no system column is allowed except tableOid */
|
|
|
|
if (pstate->p_expr_kind == EXPR_KIND_CHECK_CONSTRAINT &&
|
|
|
|
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("system column \"%s\" reference in check constraint is invalid",
|
|
|
|
colname),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
|
|
|
/* In generated column, no system column is allowed except tableOid */
|
|
|
|
if (pstate->p_expr_kind == EXPR_KIND_GENERATED_COLUMN &&
|
|
|
|
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("cannot use system column \"%s\" in column generation expression",
|
|
|
|
colname),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
2022-03-28 16:45:58 +02:00
|
|
|
/*
|
|
|
|
* In a MERGE WHEN condition, no system column is allowed except tableOid
|
|
|
|
*/
|
|
|
|
if (pstate->p_expr_kind == EXPR_KIND_MERGE_WHEN &&
|
|
|
|
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("cannot use system column \"%s\" in MERGE WHEN condition",
|
|
|
|
colname),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
/* Found a valid match, so build a Var */
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
if (attnum > InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
/* Get attribute data from the ParseNamespaceColumn array */
|
|
|
|
ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
|
|
|
|
|
|
|
|
/* Complain if dropped column. See notes in scanRTEForColumn. */
|
|
|
|
if (nscol->p_varno == 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
|
|
colname,
|
2021-03-31 10:52:37 +02:00
|
|
|
nsitem->p_names->aliasname)));
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
var = makeVar(nscol->p_varno,
|
|
|
|
nscol->p_varattno,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nscol->p_vartype,
|
|
|
|
nscol->p_vartypmod,
|
|
|
|
nscol->p_varcollid,
|
|
|
|
sublevels_up);
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
/* makeVar doesn't offer parameters for these, so set them by hand: */
|
|
|
|
var->varnosyn = nscol->p_varnosyn;
|
|
|
|
var->varattnosyn = nscol->p_varattnosyn;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* System column, so use predetermined type data */
|
|
|
|
const FormData_pg_attribute *sysatt;
|
|
|
|
|
|
|
|
sysatt = SystemAttributeDefinition(attnum);
|
|
|
|
var = makeVar(nsitem->p_rtindex,
|
|
|
|
attnum,
|
|
|
|
sysatt->atttypid,
|
|
|
|
sysatt->atttypmod,
|
|
|
|
sysatt->attcollation,
|
|
|
|
sublevels_up);
|
|
|
|
}
|
2019-12-26 17:16:42 +01:00
|
|
|
var->location = location;
|
|
|
|
|
Make Vars be outer-join-aware.
Traditionally we used the same Var struct to represent the value
of a table column everywhere in parse and plan trees. This choice
predates our support for SQL outer joins, and it's really a pretty
bad idea with outer joins, because the Var's value can depend on
where it is in the tree: it might go to NULL above an outer join.
So expression nodes that are equal() per equalfuncs.c might not
represent the same value, which is a huge correctness hazard for
the planner.
To improve this, decorate Var nodes with a bitmapset showing
which outer joins (identified by RTE indexes) may have nulled
them at the point in the parse tree where the Var appears.
This allows us to trust that equal() Vars represent the same value.
A certain amount of klugery is still needed to cope with cases
where we re-order two outer joins, but it's possible to make it
work without sacrificing that core principle. PlaceHolderVars
receive similar decoration for the same reason.
In the planner, we include these outer join bitmapsets into the relids
that an expression is considered to depend on, and in consequence also
add outer-join relids to the relids of join RelOptInfos. This allows
us to correctly perceive whether an expression can be calculated above
or below a particular outer join.
This change affects FDWs that want to plan foreign joins. They *must*
follow suit when labeling foreign joins in order to match with the
core planner, but for many purposes (if postgres_fdw is any guide)
they'd prefer to consider only base relations within the join.
To support both requirements, redefine ForeignScan.fs_relids as
base+OJ relids, and add a new field fs_base_relids that's set up by
the core planner.
Large though it is, this commit just does the minimum necessary to
install the new mechanisms and get check-world passing again.
Follow-up patches will perform some cleanup. (The README additions
and comments mention some stuff that will appear in the follow-up.)
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
2023-01-30 19:16:20 +01:00
|
|
|
/* Mark Var if it's nulled by any outer joins */
|
|
|
|
markNullableIfNeeded(pstate, var);
|
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
/* Require read access to the column */
|
2021-02-11 17:23:25 +01:00
|
|
|
markVarForSelectPriv(pstate, var);
|
2019-12-26 17:16:42 +01:00
|
|
|
|
|
|
|
return (Node *) var;
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
|
|
|
* scanRTEForColumn
|
|
|
|
* Search the column names of a single RTE for the given name.
|
2019-12-26 17:16:42 +01:00
|
|
|
* If found, return the attnum (possibly negative, for a system column);
|
|
|
|
* else return InvalidAttrNumber.
|
2000-09-12 23:07:18 +02:00
|
|
|
* If the name proves ambiguous within this RTE, raise error.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
2021-03-31 17:09:24 +02:00
|
|
|
* Actually, we only search the names listed in "eref". This can be either
|
|
|
|
* rte->eref, in which case we are indeed searching all the column names,
|
|
|
|
* or for a join it can be rte->join_using_alias, in which case we are only
|
|
|
|
* considering the common column names (which are the first N columns of the
|
|
|
|
* join, so everything works).
|
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* pstate and location are passed only for error-reporting purposes.
|
2015-03-11 15:44:04 +01:00
|
|
|
*
|
2019-12-26 17:16:42 +01:00
|
|
|
* Side effect: if fuzzystate is non-NULL, check non-system columns
|
2015-03-11 15:44:04 +01:00
|
|
|
* for an approximate match and update fuzzystate accordingly.
|
2019-12-26 17:16:42 +01:00
|
|
|
*
|
|
|
|
* Note: this is factored out of scanNSItemForColumn because error message
|
|
|
|
* creation may want to check RTEs that are not in the namespace. To support
|
|
|
|
* that usage, minimize the number of validity checks performed here. It's
|
|
|
|
* okay to complain about ambiguous-name cases, though, since if we are
|
|
|
|
* working to complain about an invalid name, we've already eliminated that.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2019-12-26 17:16:42 +01:00
|
|
|
static int
|
|
|
|
scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
|
2021-03-31 10:52:37 +02:00
|
|
|
Alias *eref,
|
2019-12-26 17:16:42 +01:00
|
|
|
const char *colname, int location,
|
|
|
|
int fuzzy_rte_penalty,
|
2015-03-11 15:44:04 +01:00
|
|
|
FuzzyAttrMatchState *fuzzystate)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
int result = InvalidAttrNumber;
|
2000-09-12 23:07:18 +02:00
|
|
|
int attnum = 0;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *c;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
|
|
|
* Scan the user column names (or aliases) for a match. Complain if
|
|
|
|
* multiple matches.
|
2002-08-02 20:15:10 +02:00
|
|
|
*
|
2004-08-19 22:57:41 +02:00
|
|
|
* Note: eref->colnames may include entries for dropped columns, but those
|
|
|
|
* will be empty strings that cannot match any legal SQL identifier, so we
|
|
|
|
* don't bother to test for that case here.
|
2002-08-02 20:15:10 +02:00
|
|
|
*
|
2004-08-19 22:57:41 +02:00
|
|
|
* Should this somehow go wrong and we try to access a dropped column,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* we'll still catch it by virtue of the check in scanNSItemForColumn().
|
|
|
|
* Callers interested in finding match with shortest distance need to
|
|
|
|
* defend against this directly, though.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2021-03-31 10:52:37 +02:00
|
|
|
foreach(c, eref->colnames)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2015-03-11 15:44:04 +01:00
|
|
|
const char *attcolname = strVal(lfirst(c));
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
attnum++;
|
2015-03-11 15:44:04 +01:00
|
|
|
if (strcmp(attcolname, colname) == 0)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2000-09-12 23:07:18 +02:00
|
|
|
if (result)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
|
|
|
|
errmsg("column reference \"%s\" is ambiguous",
|
2006-03-14 23:48:25 +01:00
|
|
|
colname),
|
|
|
|
parser_errposition(pstate, location)));
|
2019-12-26 17:16:42 +01:00
|
|
|
result = attnum;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2015-03-11 15:44:04 +01:00
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
/* Update fuzzy match state, if provided. */
|
2015-03-11 15:44:04 +01:00
|
|
|
if (fuzzystate != NULL)
|
|
|
|
updateFuzzyAttrMatchState(fuzzy_rte_penalty, fuzzystate,
|
|
|
|
rte, attcolname, colname, attnum);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
|
|
|
* If we have a unique match, return it. Note that this allows a user
|
|
|
|
* alias to override a system column name (such as OID) without error.
|
|
|
|
*/
|
|
|
|
if (result)
|
|
|
|
return result;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
Fix several bugs related to ON CONFLICT's EXCLUDED pseudo relation.
Four related issues:
1) attnos/varnos/resnos for EXCLUDED were out of sync when a column
after one dropped in the underlying relation was referenced.
2) References to whole-row variables (i.e. EXCLUDED.*) lead to errors.
3) It was possible to reference system columns in the EXCLUDED pseudo
relations, even though they would not have valid contents.
4) References to EXCLUDED were rewritten by the RLS machinery, as
EXCLUDED was treated as if it were the underlying relation.
To fix the first two issues, generate the excluded targetlist with
dropped columns in mind and add an entry for whole row
variables. Instead of unconditionally adding a wholerow entry we could
pull up the expression if needed, but doing it unconditionally seems
simpler. The wholerow entry is only really needed for ruleutils/EXPLAIN
support anyway.
The remaining two issues are addressed by changing the EXCLUDED RTE to
have relkind = composite. That fits with EXCLUDED not actually being a
real relation, and allows to treat it differently in the relevant
places. scanRTEForColumn now skips looking up system columns when the
RTE has a composite relkind; fireRIRrules() already had a corresponding
check, thereby preventing RLS expansion on EXCLUDED.
Also add tests for these issues, and improve a few comments around
excluded handling in setrefs.c.
Reported-By: Peter Geoghegan, Geoff Winkless
Author: Andres Freund, Amit Langote, Peter Geoghegan
Discussion: CAEzk6fdzJ3xYQZGbcuYM2rBd2BuDkUksmK=mY9UYYDugg_GgZg@mail.gmail.com,
CAM3SWZS+CauzbiCEcg-GdE6K6ycHE_Bz6Ksszy8AoixcMHOmsA@mail.gmail.com
Backpatch: 9.5, where ON CONFLICT was introduced
2015-10-03 15:12:10 +02:00
|
|
|
* If the RTE represents a real relation, consider system column names.
|
|
|
|
* Composites are only used for pseudo-relations like ON CONFLICT's
|
|
|
|
* excluded.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
Fix several bugs related to ON CONFLICT's EXCLUDED pseudo relation.
Four related issues:
1) attnos/varnos/resnos for EXCLUDED were out of sync when a column
after one dropped in the underlying relation was referenced.
2) References to whole-row variables (i.e. EXCLUDED.*) lead to errors.
3) It was possible to reference system columns in the EXCLUDED pseudo
relations, even though they would not have valid contents.
4) References to EXCLUDED were rewritten by the RLS machinery, as
EXCLUDED was treated as if it were the underlying relation.
To fix the first two issues, generate the excluded targetlist with
dropped columns in mind and add an entry for whole row
variables. Instead of unconditionally adding a wholerow entry we could
pull up the expression if needed, but doing it unconditionally seems
simpler. The wholerow entry is only really needed for ruleutils/EXPLAIN
support anyway.
The remaining two issues are addressed by changing the EXCLUDED RTE to
have relkind = composite. That fits with EXCLUDED not actually being a
real relation, and allows to treat it differently in the relevant
places. scanRTEForColumn now skips looking up system columns when the
RTE has a composite relkind; fireRIRrules() already had a corresponding
check, thereby preventing RLS expansion on EXCLUDED.
Also add tests for these issues, and improve a few comments around
excluded handling in setrefs.c.
Reported-By: Peter Geoghegan, Geoff Winkless
Author: Andres Freund, Amit Langote, Peter Geoghegan
Discussion: CAEzk6fdzJ3xYQZGbcuYM2rBd2BuDkUksmK=mY9UYYDugg_GgZg@mail.gmail.com,
CAM3SWZS+CauzbiCEcg-GdE6K6ycHE_Bz6Ksszy8AoixcMHOmsA@mail.gmail.com
Backpatch: 9.5, where ON CONFLICT was introduced
2015-10-03 15:12:10 +02:00
|
|
|
if (rte->rtekind == RTE_RELATION &&
|
|
|
|
rte->relkind != RELKIND_COMPOSITE_TYPE)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2001-08-10 20:57:42 +02:00
|
|
|
/* quick check to see if name could be a system column */
|
2000-09-12 23:07:18 +02:00
|
|
|
attnum = specialAttNum(colname);
|
|
|
|
if (attnum != InvalidAttrNumber)
|
2000-09-29 20:21:41 +02:00
|
|
|
{
|
2001-08-10 20:57:42 +02:00
|
|
|
/* now check to see if column actually is defined */
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists2(ATTNUM,
|
|
|
|
ObjectIdGetDatum(rte->relid),
|
|
|
|
Int16GetDatum(attnum)))
|
2019-12-26 17:16:42 +01:00
|
|
|
result = attnum;
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2004-04-18 20:12:58 +02:00
|
|
|
* colNameToVar
|
2000-09-12 23:07:18 +02:00
|
|
|
* Search for an unqualified column name.
|
|
|
|
* If found, return the appropriate Var node (or expression).
|
|
|
|
* If not found, return NULL. If the name proves ambiguous, raise error.
|
2004-04-18 20:12:58 +02:00
|
|
|
* If localonly is true, only names in the innermost query are considered.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
|
|
|
Node *
|
2017-10-31 15:34:31 +01:00
|
|
|
colNameToVar(ParseState *pstate, const char *colname, bool localonly,
|
2006-03-14 23:48:25 +01:00
|
|
|
int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
|
|
|
Node *result = NULL;
|
2019-12-26 17:16:42 +01:00
|
|
|
int sublevels_up = 0;
|
2000-09-12 23:07:18 +02:00
|
|
|
ParseState *orig_pstate = pstate;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
while (pstate != NULL)
|
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
foreach(l, pstate->p_namespace)
|
2005-06-05 02:38:11 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
|
2005-06-05 02:38:11 +02:00
|
|
|
Node *newresult;
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
/* Ignore table-only items */
|
|
|
|
if (!nsitem->p_cols_visible)
|
|
|
|
continue;
|
2012-08-08 01:02:54 +02:00
|
|
|
/* If not inside LATERAL, ignore lateral-only items */
|
|
|
|
if (nsitem->p_lateral_only && !pstate->p_lateral_active)
|
|
|
|
continue;
|
|
|
|
|
2019-12-26 17:16:42 +01:00
|
|
|
/* use orig_pstate here for consistency with other callers */
|
|
|
|
newresult = scanNSItemForColumn(orig_pstate, nsitem, sublevels_up,
|
|
|
|
colname, location);
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
if (newresult)
|
|
|
|
{
|
|
|
|
if (result)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
|
|
|
|
errmsg("column reference \"%s\" is ambiguous",
|
2006-03-14 23:48:25 +01:00
|
|
|
colname),
|
2014-01-12 01:03:12 +01:00
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
check_lateral_ref_ok(pstate, nsitem, location);
|
2000-09-12 23:07:18 +02:00
|
|
|
result = newresult;
|
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2004-04-18 20:12:58 +02:00
|
|
|
if (result != NULL || localonly)
|
|
|
|
break; /* found, or don't want to look at parent */
|
2000-03-23 08:38:30 +01:00
|
|
|
|
|
|
|
pstate = pstate->parentParseState;
|
2019-12-26 17:16:42 +01:00
|
|
|
sublevels_up++;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
return result;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* searchRangeTableForCol
|
2015-03-11 15:44:04 +01:00
|
|
|
* See if any RangeTblEntry could possibly provide the given column name (or
|
|
|
|
* find the best match available). Returns state with relevant details.
|
2012-08-08 01:02:54 +02:00
|
|
|
*
|
|
|
|
* This is different from colNameToVar in that it considers every entry in
|
|
|
|
* the ParseState's rangetable(s), not only those that are currently visible
|
2012-08-08 22:41:04 +02:00
|
|
|
* in the p_namespace list(s). This behavior is invalid per the SQL spec,
|
2022-11-23 00:46:31 +01:00
|
|
|
* and it may give ambiguous results (since there might be multiple equally
|
|
|
|
* valid matches). This must be used ONLY as a heuristic in giving suitable
|
|
|
|
* error messages. See errorMissingColumn.
|
2015-03-11 15:44:04 +01:00
|
|
|
*
|
|
|
|
* This function is also different in that it will consider approximate
|
|
|
|
* matches -- if the user entered an alias/column pair that is only slightly
|
|
|
|
* different from a valid pair, we may be able to infer what they meant to
|
2022-11-23 00:46:31 +01:00
|
|
|
* type and provide a reasonable hint. We return a FuzzyAttrMatchState
|
|
|
|
* struct providing information about both exact and approximate matches.
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2015-03-11 15:44:04 +01:00
|
|
|
static FuzzyAttrMatchState *
|
2017-10-31 15:34:31 +01:00
|
|
|
searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colname,
|
2015-03-11 15:44:04 +01:00
|
|
|
int location)
|
2012-08-08 01:02:54 +02:00
|
|
|
{
|
|
|
|
ParseState *orig_pstate = pstate;
|
2015-03-11 15:44:04 +01:00
|
|
|
FuzzyAttrMatchState *fuzzystate = palloc(sizeof(FuzzyAttrMatchState));
|
|
|
|
|
|
|
|
fuzzystate->distance = MAX_FUZZY_DISTANCE + 1;
|
|
|
|
fuzzystate->rfirst = NULL;
|
|
|
|
fuzzystate->rsecond = NULL;
|
2022-11-23 00:46:31 +01:00
|
|
|
fuzzystate->rexact1 = NULL;
|
|
|
|
fuzzystate->rexact2 = NULL;
|
2012-08-08 01:02:54 +02:00
|
|
|
|
|
|
|
while (pstate != NULL)
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, pstate->p_rtable)
|
|
|
|
{
|
2015-03-11 15:44:04 +01:00
|
|
|
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
|
|
int fuzzy_rte_penalty = 0;
|
2022-11-23 00:46:31 +01:00
|
|
|
int attnum;
|
2012-08-08 01:02:54 +02:00
|
|
|
|
2015-03-11 15:44:04 +01:00
|
|
|
/*
|
|
|
|
* Typically, it is not useful to look for matches within join
|
|
|
|
* RTEs; they effectively duplicate other RTEs for our purposes,
|
|
|
|
* and if a match is chosen from a join RTE, an unhelpful alias is
|
|
|
|
* displayed in the final diagnostic message.
|
|
|
|
*/
|
|
|
|
if (rte->rtekind == RTE_JOIN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the user didn't specify an alias, then matches against one
|
|
|
|
* RTE are as good as another. But if the user did specify an
|
|
|
|
* alias, then we want at least a fuzzy - and preferably an exact
|
|
|
|
* - match for the range table entry.
|
|
|
|
*/
|
|
|
|
if (alias != NULL)
|
|
|
|
fuzzy_rte_penalty =
|
2016-01-22 17:53:06 +01:00
|
|
|
varstr_levenshtein_less_equal(alias, strlen(alias),
|
|
|
|
rte->eref->aliasname,
|
|
|
|
strlen(rte->eref->aliasname),
|
|
|
|
1, 1, 1,
|
|
|
|
MAX_FUZZY_DISTANCE + 1,
|
|
|
|
true);
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
/*
|
2022-11-23 00:46:31 +01:00
|
|
|
* Scan for a matching column, and update fuzzystate. Non-exact
|
|
|
|
* matches are dealt with inside scanRTEForColumn, but exact
|
|
|
|
* matches are handled here. (There won't be more than one exact
|
|
|
|
* match in the same RTE, else we'd have thrown error earlier.)
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
2022-11-23 00:46:31 +01:00
|
|
|
attnum = scanRTEForColumn(orig_pstate, rte, rte->eref,
|
|
|
|
colname, location,
|
|
|
|
fuzzy_rte_penalty, fuzzystate);
|
|
|
|
if (attnum != InvalidAttrNumber && fuzzy_rte_penalty == 0)
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
2022-11-23 00:46:31 +01:00
|
|
|
if (fuzzystate->rexact1 == NULL)
|
|
|
|
{
|
|
|
|
fuzzystate->rexact1 = rte;
|
|
|
|
fuzzystate->exact1 = attnum;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Needn't worry about overwriting previous rexact2 */
|
|
|
|
fuzzystate->rexact2 = rte;
|
|
|
|
fuzzystate->exact2 = attnum;
|
|
|
|
}
|
2015-03-11 15:44:04 +01:00
|
|
|
}
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
}
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
return fuzzystate;
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
|
|
|
|
Make Vars be outer-join-aware.
Traditionally we used the same Var struct to represent the value
of a table column everywhere in parse and plan trees. This choice
predates our support for SQL outer joins, and it's really a pretty
bad idea with outer joins, because the Var's value can depend on
where it is in the tree: it might go to NULL above an outer join.
So expression nodes that are equal() per equalfuncs.c might not
represent the same value, which is a huge correctness hazard for
the planner.
To improve this, decorate Var nodes with a bitmapset showing
which outer joins (identified by RTE indexes) may have nulled
them at the point in the parse tree where the Var appears.
This allows us to trust that equal() Vars represent the same value.
A certain amount of klugery is still needed to cope with cases
where we re-order two outer joins, but it's possible to make it
work without sacrificing that core principle. PlaceHolderVars
receive similar decoration for the same reason.
In the planner, we include these outer join bitmapsets into the relids
that an expression is considered to depend on, and in consequence also
add outer-join relids to the relids of join RelOptInfos. This allows
us to correctly perceive whether an expression can be calculated above
or below a particular outer join.
This change affects FDWs that want to plan foreign joins. They *must*
follow suit when labeling foreign joins in order to match with the
core planner, but for many purposes (if postgres_fdw is any guide)
they'd prefer to consider only base relations within the join.
To support both requirements, redefine ForeignScan.fs_relids as
base+OJ relids, and add a new field fs_base_relids that's set up by
the core planner.
Large though it is, this commit just does the minimum necessary to
install the new mechanisms and get check-world passing again.
Follow-up patches will perform some cleanup. (The README additions
and comments mention some stuff that will appear in the follow-up.)
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
2023-01-30 19:16:20 +01:00
|
|
|
/*
|
|
|
|
* markNullableIfNeeded
|
|
|
|
* If the RTE referenced by the Var is nullable by outer join(s)
|
|
|
|
* at this point in the query, set var->varnullingrels to show that.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
markNullableIfNeeded(ParseState *pstate, Var *var)
|
|
|
|
{
|
|
|
|
int rtindex = var->varno;
|
|
|
|
Bitmapset *relids;
|
|
|
|
|
|
|
|
/* Find the appropriate pstate */
|
|
|
|
for (int lv = 0; lv < var->varlevelsup; lv++)
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
|
|
|
|
/* Find currently-relevant join relids for the Var's rel */
|
|
|
|
if (rtindex > 0 && rtindex <= list_length(pstate->p_nullingrels))
|
|
|
|
relids = (Bitmapset *) list_nth(pstate->p_nullingrels, rtindex - 1);
|
|
|
|
else
|
|
|
|
relids = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Merge with any already-declared nulling rels. (Typically there won't
|
|
|
|
* be any, but let's get it right if there are.)
|
|
|
|
*/
|
|
|
|
if (relids != NULL)
|
|
|
|
var->varnullingrels = bms_union(var->varnullingrels, relids);
|
|
|
|
}
|
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
/*
|
|
|
|
* markRTEForSelectPriv
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
* Mark the specified column of the RTE with index rtindex
|
|
|
|
* as requiring SELECT privilege
|
2009-01-22 21:16:10 +01:00
|
|
|
*
|
|
|
|
* col == InvalidAttrNumber means a "whole row" reference
|
|
|
|
*/
|
|
|
|
static void
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col)
|
2009-01-22 21:16:10 +01:00
|
|
|
{
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
RangeTblEntry *rte = rt_fetch(rtindex, pstate->p_rtable);
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
if (rte->rtekind == RTE_RELATION)
|
|
|
|
{
|
2022-12-06 16:09:24 +01:00
|
|
|
RTEPermissionInfo *perminfo;
|
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
/* Make sure the rel as a whole is marked for SELECT access */
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo = getRTEPermissionInfo(pstate->p_rteperminfos, rte);
|
|
|
|
perminfo->requiredPerms |= ACL_SELECT;
|
2009-01-22 21:16:10 +01:00
|
|
|
/* Must offset the attnum to fit in a bitmapset */
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo->selectedCols =
|
|
|
|
bms_add_member(perminfo->selectedCols,
|
|
|
|
col - FirstLowInvalidHeapAttributeNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else if (rte->rtekind == RTE_JOIN)
|
|
|
|
{
|
|
|
|
if (col == InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* A whole-row reference to a join has to be treated as whole-row
|
|
|
|
* references to the two inputs.
|
|
|
|
*/
|
|
|
|
JoinExpr *j;
|
|
|
|
|
|
|
|
if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs))
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
j = list_nth_node(JoinExpr, pstate->p_joinexprs, rtindex - 1);
|
2009-01-22 21:16:10 +01:00
|
|
|
else
|
|
|
|
j = NULL;
|
|
|
|
if (j == NULL)
|
|
|
|
elog(ERROR, "could not find JoinExpr for whole-row reference");
|
|
|
|
|
|
|
|
/* Note: we can't see FromExpr here */
|
|
|
|
if (IsA(j->larg, RangeTblRef))
|
|
|
|
{
|
|
|
|
int varno = ((RangeTblRef *) j->larg)->rtindex;
|
|
|
|
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else if (IsA(j->larg, JoinExpr))
|
|
|
|
{
|
|
|
|
int varno = ((JoinExpr *) j->larg)->rtindex;
|
|
|
|
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(j->larg));
|
|
|
|
if (IsA(j->rarg, RangeTblRef))
|
|
|
|
{
|
|
|
|
int varno = ((RangeTblRef *) j->rarg)->rtindex;
|
|
|
|
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else if (IsA(j->rarg, JoinExpr))
|
|
|
|
{
|
|
|
|
int varno = ((JoinExpr *) j->rarg)->rtindex;
|
|
|
|
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(j->rarg));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
* Join alias Vars for ordinary columns must refer to merged JOIN
|
|
|
|
* USING columns. We don't need to do anything here, because the
|
|
|
|
* join input columns will also be referenced in the join's qual
|
|
|
|
* clause, and will get marked for select privilege there.
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* other RTE types don't require privilege marking */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* markVarForSelectPriv
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
* Mark the RTE referenced by the Var as requiring SELECT privilege
|
|
|
|
* for the Var's column (the Var could be a whole-row Var, too)
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
|
|
|
void
|
2021-02-11 17:23:25 +01:00
|
|
|
markVarForSelectPriv(ParseState *pstate, Var *var)
|
2009-01-22 21:16:10 +01:00
|
|
|
{
|
|
|
|
Index lv;
|
|
|
|
|
|
|
|
Assert(IsA(var, Var));
|
|
|
|
/* Find the appropriate pstate if it's an uplevel Var */
|
|
|
|
for (lv = 0; lv < var->varlevelsup; lv++)
|
|
|
|
pstate = pstate->parentParseState;
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
markRTEForSelectPriv(pstate, var->varno, var->varattno);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* buildRelationAliases
|
|
|
|
* Construct the eref column name list for a relation RTE.
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* This code is also used for function RTEs.
|
2004-08-19 22:57:41 +02:00
|
|
|
*
|
|
|
|
* tupdesc: the physical column information
|
|
|
|
* alias: the user-supplied alias, or NULL if none
|
|
|
|
* eref: the eref Alias to store column names in
|
|
|
|
*
|
|
|
|
* eref->colnames is filled in. Also, alias->colnames is rebuilt to insert
|
|
|
|
* empty strings for any dropped columns, so that it will be one-to-one with
|
|
|
|
* physical column numbers.
|
2013-07-29 17:38:01 +02:00
|
|
|
*
|
|
|
|
* It is an error for there to be more aliases present than required.
|
2004-08-19 22:57:41 +02:00
|
|
|
*/
|
|
|
|
static void
|
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
2013-11-22 01:37:02 +01:00
|
|
|
buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
|
2004-08-19 22:57:41 +02:00
|
|
|
{
|
|
|
|
int maxattrs = tupdesc->natts;
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
List *aliaslist;
|
2004-08-19 22:57:41 +02:00
|
|
|
ListCell *aliaslc;
|
|
|
|
int numaliases;
|
|
|
|
int varattno;
|
|
|
|
int numdropped = 0;
|
|
|
|
|
|
|
|
Assert(eref->colnames == NIL);
|
|
|
|
|
|
|
|
if (alias)
|
|
|
|
{
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliaslist = alias->colnames;
|
|
|
|
aliaslc = list_head(aliaslist);
|
|
|
|
numaliases = list_length(aliaslist);
|
2004-08-19 22:57:41 +02:00
|
|
|
/* We'll rebuild the alias colname list */
|
|
|
|
alias->colnames = NIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliaslist = NIL;
|
2004-08-19 22:57:41 +02:00
|
|
|
aliaslc = NULL;
|
|
|
|
numaliases = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (varattno = 0; varattno < maxattrs; varattno++)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
|
Remove Value node struct
The Value node struct is a weird construct. It is its own node type,
but most of the time, it actually has a node type of Integer, Float,
String, or BitString. As a consequence, the struct name and the node
type don't match most of the time, and so it has to be treated
specially a lot. There doesn't seem to be any value in the special
construct. There is very little code that wants to accept all Value
variants but nothing else (and even if it did, this doesn't provide
any convenient way to check it), and most code wants either just one
particular node type (usually String), or it accepts a broader set of
node types besides just Value.
This change removes the Value struct and node type and replaces them
by separate Integer, Float, String, and BitString node types that are
proper node types and structs of their own and behave mostly like
normal node types.
Also, this removes the T_Null node tag, which was previously also a
possible variant of Value but wasn't actually used outside of the
Value contained in A_Const. Replace that by an isnull field in
A_Const.
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/5ba6bc5b-3f95-04f2-2419-f8ddb4c046fb@enterprisedb.com
2021-09-09 07:58:12 +02:00
|
|
|
String *attrname;
|
2004-08-19 22:57:41 +02:00
|
|
|
|
|
|
|
if (attr->attisdropped)
|
|
|
|
{
|
|
|
|
/* Always insert an empty string for a dropped column */
|
|
|
|
attrname = makeString(pstrdup(""));
|
|
|
|
if (aliaslc)
|
|
|
|
alias->colnames = lappend(alias->colnames, attrname);
|
|
|
|
numdropped++;
|
|
|
|
}
|
|
|
|
else if (aliaslc)
|
|
|
|
{
|
|
|
|
/* Use the next user-supplied alias */
|
Remove Value node struct
The Value node struct is a weird construct. It is its own node type,
but most of the time, it actually has a node type of Integer, Float,
String, or BitString. As a consequence, the struct name and the node
type don't match most of the time, and so it has to be treated
specially a lot. There doesn't seem to be any value in the special
construct. There is very little code that wants to accept all Value
variants but nothing else (and even if it did, this doesn't provide
any convenient way to check it), and most code wants either just one
particular node type (usually String), or it accepts a broader set of
node types besides just Value.
This change removes the Value struct and node type and replaces them
by separate Integer, Float, String, and BitString node types that are
proper node types and structs of their own and behave mostly like
normal node types.
Also, this removes the T_Null node tag, which was previously also a
possible variant of Value but wasn't actually used outside of the
Value contained in A_Const. Replace that by an isnull field in
A_Const.
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/5ba6bc5b-3f95-04f2-2419-f8ddb4c046fb@enterprisedb.com
2021-09-09 07:58:12 +02:00
|
|
|
attrname = lfirst_node(String, aliaslc);
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliaslc = lnext(aliaslist, aliaslc);
|
2004-08-19 22:57:41 +02:00
|
|
|
alias->colnames = lappend(alias->colnames, attrname);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
attrname = makeString(pstrdup(NameStr(attr->attname)));
|
|
|
|
/* we're done with the alias if any */
|
|
|
|
}
|
|
|
|
|
|
|
|
eref->colnames = lappend(eref->colnames, attrname);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Too many user-supplied aliases? */
|
|
|
|
if (aliaslc)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("table \"%s\" has %d columns available but %d columns specified",
|
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
2013-11-22 01:37:02 +01:00
|
|
|
eref->aliasname, maxattrs - numdropped, numaliases)));
|
2004-08-19 22:57:41 +02:00
|
|
|
}
|
|
|
|
|
2005-10-06 21:51:16 +02:00
|
|
|
/*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* chooseScalarFunctionAlias
|
|
|
|
* Select the column alias for a function in a function RTE,
|
2005-10-06 21:51:16 +02:00
|
|
|
* when the function returns a scalar type (not composite or RECORD).
|
|
|
|
*
|
|
|
|
* funcexpr: transformed expression tree for the function call
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* funcname: function name (as determined by FigureColname)
|
|
|
|
* alias: the user-supplied alias for the RTE, or NULL if none
|
|
|
|
* nfuncs: the number of functions appearing in the function RTE
|
2013-07-29 17:38:01 +02:00
|
|
|
*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* Note that the name we choose might be overridden later, if the user-given
|
|
|
|
* alias includes column alias names. That's of no concern here.
|
2005-10-06 21:51:16 +02:00
|
|
|
*/
|
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
2013-11-22 01:37:02 +01:00
|
|
|
static char *
|
|
|
|
chooseScalarFunctionAlias(Node *funcexpr, char *funcname,
|
|
|
|
Alias *alias, int nfuncs)
|
2005-10-06 21:51:16 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
char *pname;
|
2005-10-06 21:51:16 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* If the expression is a simple function call, and the function has a
|
|
|
|
* single OUT parameter that is named, use the parameter's name.
|
|
|
|
*/
|
|
|
|
if (funcexpr && IsA(funcexpr, FuncExpr))
|
2005-10-06 21:51:16 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
pname = get_func_result_name(((FuncExpr *) funcexpr)->funcid);
|
|
|
|
if (pname)
|
|
|
|
return pname;
|
2005-10-06 21:51:16 +02:00
|
|
|
}
|
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* If there's just one function in the RTE, and the user gave an RTE alias
|
|
|
|
* name, use that name. (This makes FROM func() AS foo use "foo" as the
|
|
|
|
* column name as well as the table alias.)
|
|
|
|
*/
|
|
|
|
if (nfuncs == 1 && alias)
|
|
|
|
return alias->aliasname;
|
2013-07-29 17:38:01 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* Otherwise use the function name.
|
|
|
|
*/
|
|
|
|
return funcname;
|
2005-10-06 21:51:16 +02:00
|
|
|
}
|
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* buildNSItemFromTupleDesc
|
|
|
|
* Build a ParseNamespaceItem, given a tupdesc describing the columns.
|
|
|
|
*
|
|
|
|
* rte: the new RangeTblEntry for the rel
|
|
|
|
* rtindex: its index in the rangetable list
|
2022-12-06 16:09:24 +01:00
|
|
|
* perminfo: permission list entry for the rel
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* tupdesc: the physical column information
|
|
|
|
*/
|
|
|
|
static ParseNamespaceItem *
|
2022-12-06 16:09:24 +01:00
|
|
|
buildNSItemFromTupleDesc(RangeTblEntry *rte, Index rtindex,
|
|
|
|
RTEPermissionInfo *perminfo,
|
|
|
|
TupleDesc tupdesc)
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem;
|
|
|
|
ParseNamespaceColumn *nscolumns;
|
|
|
|
int maxattrs = tupdesc->natts;
|
|
|
|
int varattno;
|
|
|
|
|
|
|
|
/* colnames must have the same number of entries as the nsitem */
|
|
|
|
Assert(maxattrs == list_length(rte->eref->colnames));
|
|
|
|
|
|
|
|
/* extract per-column data from the tupdesc */
|
|
|
|
nscolumns = (ParseNamespaceColumn *)
|
|
|
|
palloc0(maxattrs * sizeof(ParseNamespaceColumn));
|
|
|
|
|
|
|
|
for (varattno = 0; varattno < maxattrs; varattno++)
|
|
|
|
{
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
|
|
|
|
|
|
|
|
/* For a dropped column, just leave the entry as zeroes */
|
|
|
|
if (attr->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nscolumns[varattno].p_varno = rtindex;
|
|
|
|
nscolumns[varattno].p_varattno = varattno + 1;
|
|
|
|
nscolumns[varattno].p_vartype = attr->atttypid;
|
|
|
|
nscolumns[varattno].p_vartypmod = attr->atttypmod;
|
|
|
|
nscolumns[varattno].p_varcollid = attr->attcollation;
|
|
|
|
nscolumns[varattno].p_varnosyn = rtindex;
|
|
|
|
nscolumns[varattno].p_varattnosyn = varattno + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ... and build the nsitem */
|
|
|
|
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
|
2021-03-31 10:52:37 +02:00
|
|
|
nsitem->p_names = rte->eref;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nsitem->p_rte = rte;
|
|
|
|
nsitem->p_rtindex = rtindex;
|
2022-12-06 16:09:24 +01:00
|
|
|
nsitem->p_perminfo = perminfo;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nsitem->p_nscolumns = nscolumns;
|
|
|
|
/* set default visibility flags; might get changed later */
|
|
|
|
nsitem->p_rel_visible = true;
|
|
|
|
nsitem->p_cols_visible = true;
|
|
|
|
nsitem->p_lateral_only = false;
|
|
|
|
nsitem->p_lateral_ok = true;
|
|
|
|
|
|
|
|
return nsitem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* buildNSItemFromLists
|
|
|
|
* Build a ParseNamespaceItem, given column type information in lists.
|
|
|
|
*
|
|
|
|
* rte: the new RangeTblEntry for the rel
|
|
|
|
* rtindex: its index in the rangetable list
|
|
|
|
* coltypes: per-column datatype OIDs
|
|
|
|
* coltypmods: per-column type modifiers
|
|
|
|
* colcollation: per-column collation OIDs
|
|
|
|
*/
|
|
|
|
static ParseNamespaceItem *
|
|
|
|
buildNSItemFromLists(RangeTblEntry *rte, Index rtindex,
|
|
|
|
List *coltypes, List *coltypmods, List *colcollations)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem;
|
|
|
|
ParseNamespaceColumn *nscolumns;
|
|
|
|
int maxattrs = list_length(coltypes);
|
|
|
|
int varattno;
|
|
|
|
ListCell *lct;
|
|
|
|
ListCell *lcm;
|
|
|
|
ListCell *lcc;
|
|
|
|
|
|
|
|
/* colnames must have the same number of entries as the nsitem */
|
|
|
|
Assert(maxattrs == list_length(rte->eref->colnames));
|
|
|
|
|
|
|
|
Assert(maxattrs == list_length(coltypmods));
|
|
|
|
Assert(maxattrs == list_length(colcollations));
|
|
|
|
|
|
|
|
/* extract per-column data from the lists */
|
|
|
|
nscolumns = (ParseNamespaceColumn *)
|
|
|
|
palloc0(maxattrs * sizeof(ParseNamespaceColumn));
|
|
|
|
|
|
|
|
varattno = 0;
|
|
|
|
forthree(lct, coltypes,
|
|
|
|
lcm, coltypmods,
|
|
|
|
lcc, colcollations)
|
|
|
|
{
|
|
|
|
nscolumns[varattno].p_varno = rtindex;
|
|
|
|
nscolumns[varattno].p_varattno = varattno + 1;
|
|
|
|
nscolumns[varattno].p_vartype = lfirst_oid(lct);
|
|
|
|
nscolumns[varattno].p_vartypmod = lfirst_int(lcm);
|
|
|
|
nscolumns[varattno].p_varcollid = lfirst_oid(lcc);
|
|
|
|
nscolumns[varattno].p_varnosyn = rtindex;
|
|
|
|
nscolumns[varattno].p_varattnosyn = varattno + 1;
|
|
|
|
varattno++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ... and build the nsitem */
|
|
|
|
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
|
2021-03-31 10:52:37 +02:00
|
|
|
nsitem->p_names = rte->eref;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nsitem->p_rte = rte;
|
|
|
|
nsitem->p_rtindex = rtindex;
|
|
|
|
nsitem->p_nscolumns = nscolumns;
|
|
|
|
/* set default visibility flags; might get changed later */
|
|
|
|
nsitem->p_rel_visible = true;
|
|
|
|
nsitem->p_cols_visible = true;
|
|
|
|
nsitem->p_lateral_only = false;
|
|
|
|
nsitem->p_lateral_ok = true;
|
|
|
|
|
|
|
|
return nsitem;
|
|
|
|
}
|
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
/*
|
|
|
|
* Open a table during parse analysis
|
|
|
|
*
|
2019-01-21 19:32:19 +01:00
|
|
|
* This is essentially just the same as table_openrv(), except that it caters
|
2008-10-08 03:14:44 +02:00
|
|
|
* to some parser-specific error reporting needs, notably that it arranges
|
|
|
|
* to include the RangeVar's parse location in any resulting error.
|
2008-09-01 22:42:46 +02:00
|
|
|
*
|
|
|
|
* Note: properly, lockmode should be declared LOCKMODE not int, but that
|
|
|
|
* would require importing storage/lock.h into parse_relation.h. Since
|
|
|
|
* LOCKMODE is typedef'd as int anyway, that seems like overkill.
|
|
|
|
*/
|
|
|
|
Relation
|
|
|
|
parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
ParseCallbackState pcbstate;
|
|
|
|
|
|
|
|
setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_openrv_extended(relation, lockmode, true);
|
2008-10-08 03:14:44 +02:00
|
|
|
if (rel == NULL)
|
|
|
|
{
|
|
|
|
if (relation->schemaname)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
|
|
|
errmsg("relation \"%s.%s\" does not exist",
|
|
|
|
relation->schemaname, relation->relname)));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* An unqualified name might have been meant as a reference to
|
|
|
|
* some not-yet-in-scope CTE. The bare "does not exist" message
|
|
|
|
* has proven remarkably unhelpful for figuring out such problems,
|
|
|
|
* so we take pains to offer a specific hint.
|
|
|
|
*/
|
Fix incorrect handling of CTEs and ENRs as DML target relations.
setTargetTable threw an error if the proposed target RangeVar's relname
matched any visible CTE or ENR. This breaks backwards compatibility in
the CTE case, since pre-v10 we never looked for a CTE here at all, so that
CTE names did not mask regular tables. It does seem like a good idea to
throw an error for the ENR case, though, thus causing ENRs to mask tables
for this purpose; ENRs are new in v10 so we're not breaking existing code,
and we may someday want to allow them to be the targets of DML.
To fix that, replace use of getRTEForSpecialRelationTypes, which was
overkill anyway, with use of scanNameSpaceForENR.
A second problem was that the check neglected to verify null schemaname,
so that a CTE or ENR could incorrectly be thought to match a qualified
RangeVar. That happened because getRTEForSpecialRelationTypes relied
on its caller to have checked for null schemaname. Even though the one
remaining caller got it right, this is obviously bug-prone, so move
the check inside getRTEForSpecialRelationTypes.
Also, revert commit 18ce3a4ab's extremely poorly thought out decision to
add a NULL return case to parserOpenTable --- without either documenting
that or adjusting any of the callers to check for it. The current bug
seems to have arisen in part due to working around that bad idea.
In passing, remove the one-line shim functions transformCTEReference and
transformENRReference --- they don't seem to be adding any clarity or
functionality.
Per report from Hugo Mercier (via Julien Rouhaud). Back-patch to v10
where the bug was introduced.
Thomas Munro, with minor editing by me
Discussion: https://postgr.es/m/CAOBaU_YdPVH+PTtiKSSLOiiW3mVDYsnNUekK+XPbHXiP=wrFLA@mail.gmail.com
2017-10-16 23:56:42 +02:00
|
|
|
if (isFutureCTE(pstate, relation->relname))
|
2008-10-08 03:14:44 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
|
|
|
errmsg("relation \"%s\" does not exist",
|
|
|
|
relation->relname),
|
|
|
|
errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.",
|
|
|
|
relation->relname),
|
|
|
|
errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references.")));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
|
|
|
errmsg("relation \"%s\" does not exist",
|
|
|
|
relation->relname)));
|
|
|
|
}
|
|
|
|
}
|
2008-09-01 22:42:46 +02:00
|
|
|
cancel_parser_errposition_callback(&pcbstate);
|
|
|
|
return rel;
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2000-09-29 20:21:41 +02:00
|
|
|
* Add an entry for a relation to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
|
|
|
*
|
|
|
|
* We do not link the ParseNamespaceItem into the pstate here; it's the
|
|
|
|
* caller's job to do that in the appropriate way.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
2001-02-14 22:35:07 +01:00
|
|
|
* Note: formerly this checked for refname conflicts, but that's wrong.
|
|
|
|
* Caller is responsible for checking for conflicts in the appropriate scope.
|
1999-07-19 02:26:20 +02:00
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
1997-11-25 23:07:18 +01:00
|
|
|
addRangeTableEntry(ParseState *pstate,
|
2002-03-22 03:56:37 +01:00
|
|
|
RangeVar *relation,
|
2002-03-21 17:02:16 +01:00
|
|
|
Alias *alias,
|
1997-11-25 23:07:18 +01:00
|
|
|
bool inh,
|
2000-09-12 23:07:18 +02:00
|
|
|
bool inFromCl)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2001-02-14 22:35:07 +01:00
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2022-12-06 16:09:24 +01:00
|
|
|
RTEPermissionInfo *perminfo;
|
2002-03-22 03:56:37 +01:00
|
|
|
char *refname = alias ? alias->aliasname : relation->relname;
|
2000-11-08 23:10:03 +01:00
|
|
|
LOCKMODE lockmode;
|
2000-02-15 04:38:29 +01:00
|
|
|
Relation rel;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *nsitem;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2015-03-03 22:31:26 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->rtekind = RTE_RELATION;
|
2000-09-12 23:07:18 +02:00
|
|
|
rte->alias = alias;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
/*
|
|
|
|
* Identify the type of lock we'll need on this relation. It's not the
|
|
|
|
* query's target table (that case is handled elsewhere), so we need
|
|
|
|
* either RowShareLock if it's locked by FOR UPDATE/SHARE, or plain
|
|
|
|
* AccessShareLock otherwise.
|
|
|
|
*/
|
|
|
|
lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
|
|
|
|
|
1999-10-07 06:23:24 +02:00
|
|
|
/*
|
|
|
|
* Get the rel's OID. This access also ensures that we have an up-to-date
|
2000-11-08 23:10:03 +01:00
|
|
|
* relcache entry for the rel. Since this is typically the first access
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
* to a rel in a statement, we must open the rel with the proper lockmode.
|
1999-10-07 06:23:24 +02:00
|
|
|
*/
|
2008-09-01 22:42:46 +02:00
|
|
|
rel = parserOpenTable(pstate, relation, lockmode);
|
2000-02-15 04:38:29 +01:00
|
|
|
rte->relid = RelationGetRelid(rel);
|
2011-02-23 01:23:23 +01:00
|
|
|
rte->relkind = rel->rd_rel->relkind;
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
rte->rellockmode = lockmode;
|
2000-03-15 00:06:59 +01:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
2004-08-19 22:57:41 +02:00
|
|
|
* Build the list of effective column names using user-supplied aliases
|
|
|
|
* and/or actual column names.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
2004-08-19 22:57:41 +02:00
|
|
|
rte->eref = makeAlias(refname, NIL);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
buildRelationAliases(rel->rd_att, alias, rte->eref);
|
2002-03-22 03:56:37 +01:00
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Set flags and initialize access permissions.
|
2002-03-22 03:56:37 +01:00
|
|
|
*
|
|
|
|
* The initial default on access checks is always check-for-READ-access,
|
|
|
|
* which is the right thing for all except target tables.
|
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = false;
|
2002-03-22 03:56:37 +01:00
|
|
|
rte->inh = inh;
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo = addRTEPermissionInfo(&pstate->p_rteperminfos, rte);
|
|
|
|
perminfo->requiredPerms = ACL_SELECT;
|
2002-03-22 03:56:37 +01:00
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2002-03-22 03:56:37 +01:00
|
|
|
*/
|
2015-03-03 22:31:26 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2002-03-22 03:56:37 +01:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
nsitem = buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo, rel->rd_att);
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Drop the rel refcount, but keep the access lock till end of transaction
|
|
|
|
* so that the table can't be deleted or have its schema modified
|
|
|
|
* underneath us.
|
|
|
|
*/
|
|
|
|
table_close(rel, NoLock);
|
|
|
|
|
|
|
|
return nsitem;
|
2002-03-22 03:56:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an entry for a relation to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2002-03-22 03:56:37 +01:00
|
|
|
*
|
|
|
|
* This is just like addRangeTableEntry() except that it makes an RTE
|
2005-04-13 18:50:55 +02:00
|
|
|
* given an already-open relation instead of a RangeVar reference.
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
*
|
|
|
|
* lockmode is the lock type required for query execution; it must be one
|
|
|
|
* of AccessShareLock, RowShareLock, or RowExclusiveLock depending on the
|
2018-10-01 18:43:21 +02:00
|
|
|
* RTE's role within the query. The caller must hold that lock mode
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
* or a stronger one.
|
|
|
|
*
|
|
|
|
* Note: properly, lockmode should be declared LOCKMODE not int, but that
|
|
|
|
* would require importing storage/lock.h into parse_relation.h. Since
|
|
|
|
* LOCKMODE is typedef'd as int anyway, that seems like overkill.
|
2002-03-22 03:56:37 +01:00
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2002-03-22 03:56:37 +01:00
|
|
|
addRangeTableEntryForRelation(ParseState *pstate,
|
2005-04-13 18:50:55 +02:00
|
|
|
Relation rel,
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
int lockmode,
|
2002-03-22 03:56:37 +01:00
|
|
|
Alias *alias,
|
|
|
|
bool inh,
|
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2022-12-06 16:09:24 +01:00
|
|
|
RTEPermissionInfo *perminfo;
|
2005-04-13 18:50:55 +02:00
|
|
|
char *refname = alias ? alias->aliasname : RelationGetRelationName(rel);
|
2002-03-22 03:56:37 +01:00
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
Assert(lockmode == AccessShareLock ||
|
|
|
|
lockmode == RowShareLock ||
|
|
|
|
lockmode == RowExclusiveLock);
|
2018-10-01 18:43:21 +02:00
|
|
|
Assert(CheckRelationLockedByMe(rel, lockmode, true));
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
|
2002-03-22 03:56:37 +01:00
|
|
|
rte->rtekind = RTE_RELATION;
|
|
|
|
rte->alias = alias;
|
2005-04-13 18:50:55 +02:00
|
|
|
rte->relid = RelationGetRelid(rel);
|
2011-02-23 01:23:23 +01:00
|
|
|
rte->relkind = rel->rd_rel->relkind;
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
rte->rellockmode = lockmode;
|
2002-03-22 03:56:37 +01:00
|
|
|
|
|
|
|
/*
|
2004-08-19 22:57:41 +02:00
|
|
|
* Build the list of effective column names using user-supplied aliases
|
|
|
|
* and/or actual column names.
|
2002-03-22 03:56:37 +01:00
|
|
|
*/
|
2004-08-19 22:57:41 +02:00
|
|
|
rte->eref = makeAlias(refname, NIL);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
buildRelationAliases(rel->rd_att, alias, rte->eref);
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Set flags and initialize access permissions.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
|
|
|
* The initial default on access checks is always check-for-READ-access,
|
|
|
|
* which is the right thing for all except target tables.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = false;
|
1997-11-25 23:07:18 +01:00
|
|
|
rte->inh = inh;
|
|
|
|
rte->inFromCl = inFromCl;
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo = addRTEPermissionInfo(&pstate->p_rteperminfos, rte);
|
|
|
|
perminfo->requiredPerms = ACL_SELECT;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
1997-11-25 23:07:18 +01:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable),
|
2022-12-06 16:09:24 +01:00
|
|
|
perminfo, rel->rd_att);
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2000-09-29 20:21:41 +02:00
|
|
|
* Add an entry for a subquery to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* This is much like addRangeTableEntry() except that it makes a subquery RTE.
|
2022-07-20 10:29:42 +02:00
|
|
|
*
|
|
|
|
* If the subquery does not have an alias, the auto-generated relation name in
|
|
|
|
* the returned ParseNamespaceItem will be marked as not visible, and so only
|
|
|
|
* unqualified references to the subquery columns will be allowed, and the
|
|
|
|
* relation name will not conflict with others in the pstate's namespace list.
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2000-09-29 20:21:41 +02:00
|
|
|
addRangeTableEntryForSubquery(ParseState *pstate,
|
|
|
|
Query *subquery,
|
2002-03-21 17:02:16 +01:00
|
|
|
Alias *alias,
|
2012-08-08 01:02:54 +02:00
|
|
|
bool lateral,
|
2000-09-29 20:21:41 +02:00
|
|
|
bool inFromCl)
|
|
|
|
{
|
2001-02-14 22:35:07 +01:00
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2002-03-21 17:02:16 +01:00
|
|
|
Alias *eref;
|
2000-09-29 20:21:41 +02:00
|
|
|
int numaliases;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
List *coltypes,
|
|
|
|
*coltypmods,
|
|
|
|
*colcollations;
|
2000-09-29 20:21:41 +02:00
|
|
|
int varattno;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *tlistitem;
|
2022-07-20 10:29:42 +02:00
|
|
|
ParseNamespaceItem *nsitem;
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->rtekind = RTE_SUBQUERY;
|
2000-09-29 20:21:41 +02:00
|
|
|
rte->subquery = subquery;
|
|
|
|
rte->alias = alias;
|
|
|
|
|
2022-07-20 10:29:42 +02:00
|
|
|
eref = alias ? copyObject(alias) : makeAlias("unnamed_subquery", NIL);
|
2004-05-31 01:40:41 +02:00
|
|
|
numaliases = list_length(eref->colnames);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/* fill in any unspecified alias columns, and extract column type info */
|
|
|
|
coltypes = coltypmods = colcollations = NIL;
|
2000-09-29 20:21:41 +02:00
|
|
|
varattno = 0;
|
|
|
|
foreach(tlistitem, subquery->targetList)
|
|
|
|
{
|
|
|
|
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
|
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (te->resjunk)
|
2000-09-29 20:21:41 +02:00
|
|
|
continue;
|
|
|
|
varattno++;
|
2005-04-06 18:34:07 +02:00
|
|
|
Assert(varattno == te->resno);
|
2000-09-29 20:21:41 +02:00
|
|
|
if (varattno > numaliases)
|
|
|
|
{
|
|
|
|
char *attrname;
|
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
attrname = pstrdup(te->resname);
|
2002-03-21 17:02:16 +01:00
|
|
|
eref->colnames = lappend(eref->colnames, makeString(attrname));
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
coltypes = lappend_oid(coltypes,
|
|
|
|
exprType((Node *) te->expr));
|
|
|
|
coltypmods = lappend_int(coltypmods,
|
|
|
|
exprTypmod((Node *) te->expr));
|
|
|
|
colcollations = lappend_oid(colcollations,
|
|
|
|
exprCollation((Node *) te->expr));
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
|
|
|
if (varattno < numaliases)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("table \"%s\" has %d columns available but %d columns specified",
|
2022-07-20 10:29:42 +02:00
|
|
|
eref->aliasname, varattno, numaliases)));
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
rte->eref = eref;
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Set flags.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Subqueries are never checked for access rights, so no need to perform
|
|
|
|
* addRTEPermissionInfo().
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = lateral;
|
2000-09-29 20:21:41 +02:00
|
|
|
rte->inh = false; /* never true for subqueries */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
2022-07-20 10:29:42 +02:00
|
|
|
nsitem = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
|
|
|
|
coltypes, coltypmods, colcollations);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark it visible as a relation name only if it had a user-written alias.
|
|
|
|
*/
|
|
|
|
nsitem->p_rel_visible = (alias != NULL);
|
|
|
|
|
|
|
|
return nsitem;
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
/*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* Add an entry for a function (or functions) to the pstate's range table
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* (p_rtable). Then, construct and return a ParseNamespaceItem for the new RTE.
|
2002-05-12 22:10:05 +02:00
|
|
|
*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* This is much like addRangeTableEntry() except that it makes a function RTE.
|
2002-05-12 22:10:05 +02:00
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2002-05-12 22:10:05 +02:00
|
|
|
addRangeTableEntryForFunction(ParseState *pstate,
|
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
2013-11-22 01:37:02 +01:00
|
|
|
List *funcnames,
|
|
|
|
List *funcexprs,
|
|
|
|
List *coldeflists,
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
RangeFunction *rangefunc,
|
2012-08-08 01:02:54 +02:00
|
|
|
bool lateral,
|
2002-05-12 22:10:05 +02:00
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
Alias *alias = rangefunc->alias;
|
2002-05-12 22:10:05 +02:00
|
|
|
Alias *eref;
|
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
2013-11-22 01:37:02 +01:00
|
|
|
char *aliasname;
|
|
|
|
int nfuncs = list_length(funcexprs);
|
|
|
|
TupleDesc *functupdescs;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
ListCell *lc1,
|
|
|
|
*lc2,
|
|
|
|
*lc3;
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int funcno;
|
|
|
|
int natts,
|
|
|
|
totalatts;
|
2002-05-12 22:10:05 +02:00
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
rte->rtekind = RTE_FUNCTION;
|
|
|
|
rte->relid = InvalidOid;
|
|
|
|
rte->subquery = NULL;
|
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
2013-11-22 01:37:02 +01:00
|
|
|
rte->functions = NIL; /* we'll fill this list below */
|
|
|
|
rte->funcordinality = rangefunc->ordinality;
|
2002-05-12 22:10:05 +02:00
|
|
|
rte->alias = alias;
|
|
|
|
|
|
|
|
/*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* Choose the RTE alias name. We default to using the first function's
|
|
|
|
* name even when there's more than one; which is maybe arguable but beats
|
|
|
|
* using something constant like "table".
|
2005-04-01 00:46:33 +02:00
|
|
|
*/
|
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
2013-11-22 01:37:02 +01:00
|
|
|
if (alias)
|
|
|
|
aliasname = alias->aliasname;
|
2002-08-06 07:33:29 +02:00
|
|
|
else
|
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
2013-11-22 01:37:02 +01:00
|
|
|
aliasname = linitial(funcnames);
|
|
|
|
|
|
|
|
eref = makeAlias(aliasname, NIL);
|
|
|
|
rte->eref = eref;
|
|
|
|
|
|
|
|
/* Process each function ... */
|
|
|
|
functupdescs = (TupleDesc *) palloc(nfuncs * sizeof(TupleDesc));
|
|
|
|
|
|
|
|
totalatts = 0;
|
|
|
|
funcno = 0;
|
|
|
|
forthree(lc1, funcexprs, lc2, funcnames, lc3, coldeflists)
|
2002-08-06 07:33:29 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
Node *funcexpr = (Node *) lfirst(lc1);
|
|
|
|
char *funcname = (char *) lfirst(lc2);
|
|
|
|
List *coldeflist = (List *) lfirst(lc3);
|
|
|
|
RangeTblFunction *rtfunc = makeNode(RangeTblFunction);
|
|
|
|
TypeFuncClass functypclass;
|
|
|
|
Oid funcrettype;
|
|
|
|
|
|
|
|
/* Initialize RangeTblFunction node */
|
|
|
|
rtfunc->funcexpr = funcexpr;
|
|
|
|
rtfunc->funccolnames = NIL;
|
|
|
|
rtfunc->funccoltypes = NIL;
|
|
|
|
rtfunc->funccoltypmods = NIL;
|
|
|
|
rtfunc->funccolcollations = NIL;
|
|
|
|
rtfunc->funcparams = NULL; /* not set until planning */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now determine if the function returns a simple or composite type.
|
|
|
|
*/
|
|
|
|
functypclass = get_expr_result_type(funcexpr,
|
|
|
|
&funcrettype,
|
|
|
|
&tupdesc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A coldeflist is required if the function returns RECORD and hasn't
|
2020-09-22 16:49:11 +02:00
|
|
|
* got a predetermined record type, and is prohibited otherwise. This
|
|
|
|
* can be a bit confusing, so we expend some effort on delivering a
|
|
|
|
* relevant error message.
|
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
2013-11-22 01:37:02 +01:00
|
|
|
*/
|
|
|
|
if (coldeflist != NIL)
|
|
|
|
{
|
2020-09-22 16:49:11 +02:00
|
|
|
switch (functypclass)
|
|
|
|
{
|
|
|
|
case TYPEFUNC_RECORD:
|
|
|
|
/* ok */
|
|
|
|
break;
|
|
|
|
case TYPEFUNC_COMPOSITE:
|
|
|
|
case TYPEFUNC_COMPOSITE_DOMAIN:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the function's raw result type is RECORD, we must
|
|
|
|
* have resolved it using its OUT parameters. Otherwise,
|
|
|
|
* it must have a named composite type.
|
|
|
|
*/
|
|
|
|
if (exprType(funcexpr) == RECORDOID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("a column definition list is redundant for a function with OUT parameters"),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) coldeflist))));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("a column definition list is redundant for a function returning a named composite type"),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) coldeflist))));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("a column definition list is only allowed for functions returning \"record\""),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) coldeflist))));
|
|
|
|
break;
|
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (functypclass == TYPEFUNC_RECORD)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("a column definition list is required for functions returning \"record\""),
|
|
|
|
parser_errposition(pstate, exprLocation(funcexpr))));
|
|
|
|
}
|
|
|
|
|
2017-10-26 19:47:45 +02:00
|
|
|
if (functypclass == TYPEFUNC_COMPOSITE ||
|
|
|
|
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
|
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
2013-11-22 01:37:02 +01:00
|
|
|
{
|
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Assert(tupdesc);
|
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_SCALAR)
|
|
|
|
{
|
|
|
|
/* Base data type, i.e. scalar */
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
tupdesc = CreateTemplateTupleDesc(1);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
TupleDescInitEntry(tupdesc,
|
|
|
|
(AttrNumber) 1,
|
|
|
|
chooseScalarFunctionAlias(funcexpr, funcname,
|
|
|
|
alias, nfuncs),
|
|
|
|
funcrettype,
|
2020-01-02 19:48:54 +01:00
|
|
|
exprTypmod(funcexpr),
|
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
2013-11-22 01:37:02 +01:00
|
|
|
0);
|
2020-01-02 19:48:54 +01:00
|
|
|
TupleDescInitEntryCollation(tupdesc,
|
|
|
|
(AttrNumber) 1,
|
|
|
|
exprCollation(funcexpr));
|
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
2013-11-22 01:37:02 +01:00
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_RECORD)
|
|
|
|
{
|
|
|
|
ListCell *col;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the column definition list to construct a tupdesc and fill
|
2022-08-01 18:22:35 +02:00
|
|
|
* in the RangeTblFunction's lists. Limit number of columns to
|
|
|
|
* MaxHeapAttributeNumber, because CheckAttributeNamesTypes will.
|
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
2013-11-22 01:37:02 +01:00
|
|
|
*/
|
2022-08-01 18:22:35 +02:00
|
|
|
if (list_length(coldeflist) > MaxHeapAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_COLUMNS),
|
|
|
|
errmsg("column definition lists can have at most %d entries",
|
|
|
|
MaxHeapAttributeNumber),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) coldeflist))));
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
tupdesc = CreateTemplateTupleDesc(list_length(coldeflist));
|
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
2013-11-22 01:37:02 +01:00
|
|
|
i = 1;
|
|
|
|
foreach(col, coldeflist)
|
|
|
|
{
|
|
|
|
ColumnDef *n = (ColumnDef *) lfirst(col);
|
|
|
|
char *attrname;
|
|
|
|
Oid attrtype;
|
|
|
|
int32 attrtypmod;
|
|
|
|
Oid attrcollation;
|
|
|
|
|
|
|
|
attrname = n->colname;
|
|
|
|
if (n->typeName->setof)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("column \"%s\" cannot be declared SETOF",
|
|
|
|
attrname),
|
|
|
|
parser_errposition(pstate, n->location)));
|
|
|
|
typenameTypeIdAndMod(pstate, n->typeName,
|
|
|
|
&attrtype, &attrtypmod);
|
|
|
|
attrcollation = GetColumnDefCollation(pstate, n, attrtype);
|
|
|
|
TupleDescInitEntry(tupdesc,
|
|
|
|
(AttrNumber) i,
|
|
|
|
attrname,
|
|
|
|
attrtype,
|
|
|
|
attrtypmod,
|
|
|
|
0);
|
|
|
|
TupleDescInitEntryCollation(tupdesc,
|
|
|
|
(AttrNumber) i,
|
|
|
|
attrcollation);
|
|
|
|
rtfunc->funccolnames = lappend(rtfunc->funccolnames,
|
|
|
|
makeString(pstrdup(attrname)));
|
|
|
|
rtfunc->funccoltypes = lappend_oid(rtfunc->funccoltypes,
|
|
|
|
attrtype);
|
|
|
|
rtfunc->funccoltypmods = lappend_int(rtfunc->funccoltypmods,
|
|
|
|
attrtypmod);
|
|
|
|
rtfunc->funccolcollations = lappend_oid(rtfunc->funccolcollations,
|
|
|
|
attrcollation);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that the coldeflist defines a legal set of names (no
|
2019-01-31 01:25:33 +01:00
|
|
|
* duplicates, but we needn't worry about system column names) and
|
|
|
|
* datatypes. Although we mostly can't allow pseudo-types, it
|
|
|
|
* seems safe to allow RECORD and RECORD[], since values within
|
|
|
|
* those type classes are self-identifying at runtime, and the
|
|
|
|
* coldeflist doesn't represent anything that will be visible to
|
|
|
|
* other sessions.
|
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
2013-11-22 01:37:02 +01:00
|
|
|
*/
|
2019-01-31 01:25:33 +01:00
|
|
|
CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE,
|
|
|
|
CHKATYPE_ANYRECORD);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
}
|
|
|
|
else
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
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
2013-11-22 01:37:02 +01:00
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("function \"%s\" in FROM has unsupported return type %s",
|
|
|
|
funcname, format_type_be(funcrettype)),
|
2008-09-01 22:42:46 +02:00
|
|
|
parser_errposition(pstate, exprLocation(funcexpr))));
|
2002-08-06 07:33:29 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/* Finish off the RangeTblFunction and add it to the RTE's list */
|
|
|
|
rtfunc->funccolcount = tupdesc->natts;
|
|
|
|
rte->functions = lappend(rte->functions, rtfunc);
|
|
|
|
|
|
|
|
/* Save the tupdesc for use below */
|
|
|
|
functupdescs[funcno] = tupdesc;
|
|
|
|
totalatts += tupdesc->natts;
|
|
|
|
funcno++;
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* If there's more than one function, or we want an ordinality column, we
|
|
|
|
* have to produce a merged tupdesc.
|
|
|
|
*/
|
|
|
|
if (nfuncs > 1 || rangefunc->ordinality)
|
|
|
|
{
|
2013-07-29 17:38:01 +02:00
|
|
|
if (rangefunc->ordinality)
|
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
2013-11-22 01:37:02 +01:00
|
|
|
totalatts++;
|
2013-07-29 17:38:01 +02:00
|
|
|
|
2022-08-01 18:22:35 +02:00
|
|
|
/* Disallow more columns than will fit in a tuple */
|
|
|
|
if (totalatts > MaxTupleAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_COLUMNS),
|
|
|
|
errmsg("functions in FROM can return at most %d columns",
|
|
|
|
MaxTupleAttributeNumber),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) funcexprs))));
|
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/* Merge the tuple descs of each function into a composite one */
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
tupdesc = CreateTemplateTupleDesc(totalatts);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
natts = 0;
|
|
|
|
for (i = 0; i < nfuncs; i++)
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
for (j = 1; j <= functupdescs[i]->natts; j++)
|
|
|
|
TupleDescCopyEntry(tupdesc, ++natts, functupdescs[i], j);
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
/* Add the ordinality column if needed */
|
|
|
|
if (rangefunc->ordinality)
|
2020-01-02 19:48:54 +01:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
TupleDescInitEntry(tupdesc,
|
|
|
|
(AttrNumber) ++natts,
|
|
|
|
"ordinality",
|
|
|
|
INT8OID,
|
|
|
|
-1,
|
|
|
|
0);
|
2020-01-02 19:48:54 +01:00
|
|
|
/* no need to set collation */
|
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
Assert(natts == totalatts);
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
}
|
|
|
|
else
|
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
2013-11-22 01:37:02 +01:00
|
|
|
{
|
|
|
|
/* We can just use the single function's tupdesc as-is */
|
|
|
|
tupdesc = functupdescs[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use the tupdesc while assigning column aliases for the RTE */
|
|
|
|
buildRelationAliases(tupdesc, alias, eref);
|
2002-05-12 22:10:05 +02:00
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2004-01-15 00:01:55 +01:00
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Functions are never checked for access rights (at least, not by
|
|
|
|
* ExecCheckPermissions()), so no need to perform addRTEPermissionInfo().
|
2002-05-12 22:10:05 +02:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = lateral;
|
2002-05-12 22:10:05 +02:00
|
|
|
rte->inh = false; /* never true for functions */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2002-05-12 22:10:05 +02:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2002-05-12 22:10:05 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
2022-12-06 16:09:24 +01:00
|
|
|
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), NULL,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
tupdesc);
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
/*
|
|
|
|
* Add an entry for a table function to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2017-03-08 16:39:37 +01:00
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
|
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2017-03-08 16:39:37 +01:00
|
|
|
addRangeTableEntryForTableFunc(ParseState *pstate,
|
|
|
|
TableFunc *tf,
|
|
|
|
Alias *alias,
|
|
|
|
bool lateral,
|
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2022-09-14 15:36:21 +02:00
|
|
|
char *refname;
|
2017-03-08 16:39:37 +01:00
|
|
|
Alias *eref;
|
|
|
|
int numaliases;
|
|
|
|
|
2022-08-01 18:22:35 +02:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
|
|
|
/* Disallow more columns than will fit in a tuple */
|
|
|
|
if (list_length(tf->colnames) > MaxTupleAttributeNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_COLUMNS),
|
|
|
|
errmsg("functions in FROM can return at most %d columns",
|
|
|
|
MaxTupleAttributeNumber),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) tf))));
|
|
|
|
Assert(list_length(tf->coltypes) == list_length(tf->colnames));
|
|
|
|
Assert(list_length(tf->coltypmods) == list_length(tf->colnames));
|
|
|
|
Assert(list_length(tf->colcollations) == list_length(tf->colnames));
|
|
|
|
|
2022-09-14 15:36:21 +02:00
|
|
|
refname = alias ? alias->aliasname : pstrdup("xmltable");
|
2022-05-18 20:28:31 +02:00
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
rte->rtekind = RTE_TABLEFUNC;
|
|
|
|
rte->relid = InvalidOid;
|
|
|
|
rte->subquery = NULL;
|
|
|
|
rte->tablefunc = tf;
|
|
|
|
rte->coltypes = tf->coltypes;
|
|
|
|
rte->coltypmods = tf->coltypmods;
|
|
|
|
rte->colcollations = tf->colcollations;
|
|
|
|
rte->alias = alias;
|
|
|
|
|
|
|
|
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
|
|
|
|
numaliases = list_length(eref->colnames);
|
|
|
|
|
|
|
|
/* fill in any unspecified alias columns */
|
|
|
|
if (numaliases < list_length(tf->colnames))
|
|
|
|
eref->colnames = list_concat(eref->colnames,
|
|
|
|
list_copy_tail(tf->colnames, numaliases));
|
|
|
|
|
2022-05-18 20:28:31 +02:00
|
|
|
if (numaliases > list_length(tf->colnames))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("%s function has %d columns available but %d columns specified",
|
2022-09-01 23:07:14 +02:00
|
|
|
"XMLTABLE",
|
2022-05-18 20:28:31 +02:00
|
|
|
list_length(tf->colnames), numaliases)));
|
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
rte->eref = eref;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Tablefuncs are never checked for access rights (at least, not by
|
|
|
|
* ExecCheckPermissions()), so no need to perform addRTEPermissionInfo().
|
2017-03-08 16:39:37 +01:00
|
|
|
*/
|
|
|
|
rte->lateral = lateral;
|
|
|
|
rte->inh = false; /* never true for tablefunc RTEs */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2017-03-08 16:39:37 +01:00
|
|
|
*/
|
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
|
|
|
|
rte->coltypes, rte->coltypmods,
|
|
|
|
rte->colcollations);
|
2017-03-08 16:39:37 +01:00
|
|
|
}
|
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
/*
|
|
|
|
* Add an entry for a VALUES list to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2006-08-02 03:59:48 +02:00
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a values RTE.
|
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2006-08-02 03:59:48 +02:00
|
|
|
addRangeTableEntryForValues(ParseState *pstate,
|
|
|
|
List *exprs,
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
List *coltypes,
|
|
|
|
List *coltypmods,
|
|
|
|
List *colcollations,
|
2006-08-02 03:59:48 +02:00
|
|
|
Alias *alias,
|
2012-08-19 20:12:16 +02:00
|
|
|
bool lateral,
|
2006-08-02 03:59:48 +02:00
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
|
|
|
char *refname = alias ? alias->aliasname : pstrdup("*VALUES*");
|
|
|
|
Alias *eref;
|
|
|
|
int numaliases;
|
|
|
|
int numcolumns;
|
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
rte->rtekind = RTE_VALUES;
|
|
|
|
rte->relid = InvalidOid;
|
|
|
|
rte->subquery = NULL;
|
|
|
|
rte->values_lists = exprs;
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
rte->coltypes = coltypes;
|
|
|
|
rte->coltypmods = coltypmods;
|
|
|
|
rte->colcollations = colcollations;
|
2006-08-02 03:59:48 +02:00
|
|
|
rte->alias = alias;
|
|
|
|
|
|
|
|
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
|
|
|
|
|
|
|
|
/* fill in any unspecified alias columns */
|
|
|
|
numcolumns = list_length((List *) linitial(exprs));
|
|
|
|
numaliases = list_length(eref->colnames);
|
|
|
|
while (numaliases < numcolumns)
|
|
|
|
{
|
|
|
|
char attrname[64];
|
|
|
|
|
|
|
|
numaliases++;
|
|
|
|
snprintf(attrname, sizeof(attrname), "column%d", numaliases);
|
|
|
|
eref->colnames = lappend(eref->colnames,
|
|
|
|
makeString(pstrdup(attrname)));
|
|
|
|
}
|
|
|
|
if (numcolumns < numaliases)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("VALUES lists \"%s\" have %d columns available but %d columns specified",
|
|
|
|
refname, numcolumns, numaliases)));
|
|
|
|
|
|
|
|
rte->eref = eref;
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2006-08-02 03:59:48 +02:00
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Subqueries are never checked for access rights, so no need to perform
|
|
|
|
* addRTEPermissionInfo().
|
2006-08-02 03:59:48 +02:00
|
|
|
*/
|
2012-08-19 20:12:16 +02:00
|
|
|
rte->lateral = lateral;
|
2006-08-02 03:59:48 +02:00
|
|
|
rte->inh = false; /* never true for values RTEs */
|
|
|
|
rte->inFromCl = inFromCl;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2006-08-02 03:59:48 +02:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2006-08-02 03:59:48 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
return buildNSItemFromLists(rte, list_length(pstate->p_rtable),
|
|
|
|
rte->coltypes, rte->coltypmods,
|
|
|
|
rte->colcollations);
|
2006-08-02 03:59:48 +02:00
|
|
|
}
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
/*
|
|
|
|
* Add an entry for a join to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2002-03-12 01:52:10 +01:00
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a join RTE.
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Also, it's more convenient for the caller to construct the
|
|
|
|
* ParseNamespaceColumn array, so we pass that in.
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2002-03-12 01:52:10 +01:00
|
|
|
addRangeTableEntryForJoin(ParseState *pstate,
|
|
|
|
List *colnames,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceColumn *nscolumns,
|
2002-03-12 01:52:10 +01:00
|
|
|
JoinType jointype,
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
int nummergedcols,
|
2002-04-28 21:54:29 +02:00
|
|
|
List *aliasvars,
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
List *leftcols,
|
|
|
|
List *rightcols,
|
2021-03-31 17:09:24 +02:00
|
|
|
Alias *join_using_alias,
|
2002-03-21 17:02:16 +01:00
|
|
|
Alias *alias,
|
2002-03-12 01:52:10 +01:00
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2002-03-21 17:02:16 +01:00
|
|
|
Alias *eref;
|
2002-03-12 01:52:10 +01:00
|
|
|
int numaliases;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *nsitem;
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2008-04-05 03:58:20 +02:00
|
|
|
/*
|
|
|
|
* Fail if join has too many columns --- we must be able to reference any
|
|
|
|
* of the columns with an AttrNumber.
|
|
|
|
*/
|
|
|
|
if (list_length(aliasvars) > MaxAttrNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
|
|
|
errmsg("joins can have at most %d columns",
|
|
|
|
MaxAttrNumber)));
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->rtekind = RTE_JOIN;
|
|
|
|
rte->relid = InvalidOid;
|
|
|
|
rte->subquery = NULL;
|
|
|
|
rte->jointype = jointype;
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
rte->joinmergedcols = nummergedcols;
|
2002-04-28 21:54:29 +02:00
|
|
|
rte->joinaliasvars = aliasvars;
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
rte->joinleftcols = leftcols;
|
|
|
|
rte->joinrightcols = rightcols;
|
2021-03-31 17:09:24 +02:00
|
|
|
rte->join_using_alias = join_using_alias;
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->alias = alias;
|
|
|
|
|
2017-03-09 21:18:59 +01:00
|
|
|
eref = alias ? copyObject(alias) : makeAlias("unnamed_join", NIL);
|
2004-05-31 01:40:41 +02:00
|
|
|
numaliases = list_length(eref->colnames);
|
2002-03-12 01:52:10 +01:00
|
|
|
|
|
|
|
/* fill in any unspecified alias columns */
|
2004-05-31 01:40:41 +02:00
|
|
|
if (numaliases < list_length(colnames))
|
|
|
|
eref->colnames = list_concat(eref->colnames,
|
|
|
|
list_copy_tail(colnames, numaliases));
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2022-05-18 20:28:31 +02:00
|
|
|
if (numaliases > list_length(colnames))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("join expression \"%s\" has %d columns available but %d columns specified",
|
|
|
|
eref->aliasname, list_length(colnames), numaliases)));
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->eref = eref;
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2002-03-12 01:52:10 +01:00
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Joins are never checked for access rights, so no need to perform
|
|
|
|
* addRTEPermissionInfo().
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = false;
|
2002-03-12 01:52:10 +01:00
|
|
|
rte->inh = false; /* never true for joins */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2002-03-12 01:52:10 +01:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
|
2021-03-31 10:52:37 +02:00
|
|
|
nsitem->p_names = rte->eref;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nsitem->p_rte = rte;
|
2022-12-06 16:09:24 +01:00
|
|
|
nsitem->p_perminfo = NULL;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nsitem->p_rtindex = list_length(pstate->p_rtable);
|
|
|
|
nsitem->p_nscolumns = nscolumns;
|
|
|
|
/* set default visibility flags; might get changed later */
|
|
|
|
nsitem->p_rel_visible = true;
|
|
|
|
nsitem->p_cols_visible = true;
|
|
|
|
nsitem->p_lateral_only = false;
|
|
|
|
nsitem->p_lateral_ok = true;
|
|
|
|
|
|
|
|
return nsitem;
|
2002-03-12 01:52:10 +01:00
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
/*
|
|
|
|
* Add an entry for a CTE reference to the pstate's range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2008-10-04 23:56:55 +02:00
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a CTE RTE.
|
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2008-10-04 23:56:55 +02:00
|
|
|
addRangeTableEntryForCTE(ParseState *pstate,
|
|
|
|
CommonTableExpr *cte,
|
|
|
|
Index levelsup,
|
2011-02-26 00:56:23 +01:00
|
|
|
RangeVar *rv,
|
2008-10-04 23:56:55 +02:00
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
2011-02-26 00:56:23 +01:00
|
|
|
Alias *alias = rv->alias;
|
2008-10-04 23:56:55 +02:00
|
|
|
char *refname = alias ? alias->aliasname : cte->ctename;
|
|
|
|
Alias *eref;
|
|
|
|
int numaliases;
|
|
|
|
int varattno;
|
|
|
|
ListCell *lc;
|
2021-02-01 13:54:59 +01:00
|
|
|
int n_dontexpand_columns = 0;
|
|
|
|
ParseNamespaceItem *psi;
|
2008-10-04 23:56:55 +02:00
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
rte->rtekind = RTE_CTE;
|
|
|
|
rte->ctename = cte->ctename;
|
|
|
|
rte->ctelevelsup = levelsup;
|
|
|
|
|
|
|
|
/* Self-reference if and only if CTE's parse analysis isn't completed */
|
|
|
|
rte->self_reference = !IsA(cte->ctequery, Query);
|
|
|
|
Assert(cte->cterecursive || !rte->self_reference);
|
|
|
|
/* Bump the CTE's refcount if this isn't a self-reference */
|
|
|
|
if (!rte->self_reference)
|
|
|
|
cte->cterefcount++;
|
|
|
|
|
2011-02-26 00:56:23 +01:00
|
|
|
/*
|
|
|
|
* We throw error if the CTE is INSERT/UPDATE/DELETE without RETURNING.
|
|
|
|
* This won't get checked in case of a self-reference, but that's OK
|
|
|
|
* because data-modifying CTEs aren't allowed to be recursive anyhow.
|
|
|
|
*/
|
|
|
|
if (IsA(cte->ctequery, Query))
|
|
|
|
{
|
|
|
|
Query *ctequery = (Query *) cte->ctequery;
|
|
|
|
|
|
|
|
if (ctequery->commandType != CMD_SELECT &&
|
|
|
|
ctequery->returningList == NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("WITH query \"%s\" does not have a RETURNING clause",
|
|
|
|
cte->ctename),
|
|
|
|
parser_errposition(pstate, rv->location)));
|
|
|
|
}
|
|
|
|
|
2021-02-01 13:54:59 +01:00
|
|
|
rte->coltypes = list_copy(cte->ctecoltypes);
|
|
|
|
rte->coltypmods = list_copy(cte->ctecoltypmods);
|
|
|
|
rte->colcollations = list_copy(cte->ctecolcollations);
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
rte->alias = alias;
|
|
|
|
if (alias)
|
|
|
|
eref = copyObject(alias);
|
|
|
|
else
|
|
|
|
eref = makeAlias(refname, NIL);
|
|
|
|
numaliases = list_length(eref->colnames);
|
|
|
|
|
|
|
|
/* fill in any unspecified alias columns */
|
|
|
|
varattno = 0;
|
|
|
|
foreach(lc, cte->ctecolnames)
|
|
|
|
{
|
|
|
|
varattno++;
|
|
|
|
if (varattno > numaliases)
|
|
|
|
eref->colnames = lappend(eref->colnames, lfirst(lc));
|
|
|
|
}
|
|
|
|
if (varattno < numaliases)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("table \"%s\" has %d columns available but %d columns specified",
|
|
|
|
refname, varattno, numaliases)));
|
|
|
|
|
|
|
|
rte->eref = eref;
|
|
|
|
|
2021-02-01 13:54:59 +01:00
|
|
|
if (cte->search_clause)
|
|
|
|
{
|
|
|
|
rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->search_clause->search_seq_column));
|
|
|
|
if (cte->search_clause->search_breadth_first)
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, RECORDOID);
|
|
|
|
else
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID);
|
|
|
|
rte->coltypmods = lappend_int(rte->coltypmods, -1);
|
|
|
|
rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
|
|
|
|
|
|
|
|
n_dontexpand_columns += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cte->cycle_clause)
|
|
|
|
{
|
|
|
|
rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_mark_column));
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, cte->cycle_clause->cycle_mark_type);
|
|
|
|
rte->coltypmods = lappend_int(rte->coltypmods, cte->cycle_clause->cycle_mark_typmod);
|
|
|
|
rte->colcollations = lappend_oid(rte->colcollations, cte->cycle_clause->cycle_mark_collation);
|
|
|
|
|
|
|
|
rte->eref->colnames = lappend(rte->eref->colnames, makeString(cte->cycle_clause->cycle_path_column));
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, RECORDARRAYOID);
|
|
|
|
rte->coltypmods = lappend_int(rte->coltypmods, -1);
|
|
|
|
rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
|
|
|
|
|
|
|
|
n_dontexpand_columns += 2;
|
|
|
|
}
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2008-10-04 23:56:55 +02:00
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* Subqueries are never checked for access rights, so no need to perform
|
|
|
|
* addRTEPermissionInfo().
|
2008-10-04 23:56:55 +02:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte->lateral = false;
|
2008-10-04 23:56:55 +02:00
|
|
|
rte->inh = false; /* never true for subqueries */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2008-10-04 23:56:55 +02:00
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2008-10-04 23:56:55 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
2021-02-01 13:54:59 +01:00
|
|
|
psi = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
rte->coltypes, rte->coltypmods,
|
|
|
|
rte->colcollations);
|
2021-02-01 13:54:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The columns added by search and cycle clauses are not included in star
|
|
|
|
* expansion in queries contained in the CTE.
|
|
|
|
*/
|
|
|
|
if (rte->ctelevelsup > 0)
|
|
|
|
for (int i = 0; i < n_dontexpand_columns; i++)
|
2021-03-31 10:52:37 +02:00
|
|
|
psi->p_nscolumns[list_length(psi->p_names->colnames) - 1 - i].p_dontexpand = true;
|
2021-02-01 13:54:59 +01:00
|
|
|
|
|
|
|
return psi;
|
2008-10-04 23:56:55 +02:00
|
|
|
}
|
|
|
|
|
2017-04-01 06:17:18 +02:00
|
|
|
/*
|
|
|
|
* Add an entry for an ephemeral named relation reference to the pstate's
|
|
|
|
* range table (p_rtable).
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
2017-04-01 06:17:18 +02:00
|
|
|
*
|
|
|
|
* It is expected that the RangeVar, which up until now is only known to be an
|
|
|
|
* ephemeral named relation, will (in conjunction with the QueryEnvironment in
|
|
|
|
* the ParseState), create a RangeTblEntry for a specific *kind* of ephemeral
|
|
|
|
* named relation, based on enrtype.
|
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes an RTE for an
|
|
|
|
* ephemeral named relation.
|
|
|
|
*/
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
ParseNamespaceItem *
|
2017-04-01 06:17:18 +02:00
|
|
|
addRangeTableEntryForENR(ParseState *pstate,
|
|
|
|
RangeVar *rv,
|
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
|
|
|
Alias *alias = rv->alias;
|
|
|
|
char *refname = alias ? alias->aliasname : rv->relname;
|
2017-04-16 20:02:47 +02:00
|
|
|
EphemeralNamedRelationMetadata enrmd;
|
2017-04-01 06:17:18 +02:00
|
|
|
TupleDesc tupdesc;
|
|
|
|
int attno;
|
|
|
|
|
2017-04-16 20:02:47 +02:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
enrmd = get_visible_ENR(pstate, rv->relname);
|
2017-04-01 06:17:18 +02:00
|
|
|
Assert(enrmd != NULL);
|
|
|
|
|
|
|
|
switch (enrmd->enrtype)
|
|
|
|
{
|
|
|
|
case ENR_NAMED_TUPLESTORE:
|
|
|
|
rte->rtekind = RTE_NAMEDTUPLESTORE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-04-16 20:02:47 +02:00
|
|
|
elog(ERROR, "unexpected enrtype: %d", enrmd->enrtype);
|
2017-04-01 06:17:18 +02:00
|
|
|
return NULL; /* for fussy compilers */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Record dependency on a relation. This allows plans to be invalidated
|
|
|
|
* if they access transition tables linked to a table that is altered.
|
|
|
|
*/
|
|
|
|
rte->relid = enrmd->reliddesc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the list of effective column names using user-supplied aliases
|
2017-09-06 16:41:05 +02:00
|
|
|
* and/or actual column names.
|
2017-04-01 06:17:18 +02:00
|
|
|
*/
|
|
|
|
tupdesc = ENRMetadataGetTupDesc(enrmd);
|
|
|
|
rte->eref = makeAlias(refname, NIL);
|
|
|
|
buildRelationAliases(tupdesc, alias, rte->eref);
|
2017-09-06 16:41:05 +02:00
|
|
|
|
|
|
|
/* Record additional data for ENR, including column type info */
|
2017-04-01 06:17:18 +02:00
|
|
|
rte->enrname = enrmd->name;
|
|
|
|
rte->enrtuples = enrmd->enrtuples;
|
|
|
|
rte->coltypes = NIL;
|
|
|
|
rte->coltypmods = NIL;
|
|
|
|
rte->colcollations = NIL;
|
|
|
|
for (attno = 1; attno <= tupdesc->natts; ++attno)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
|
|
|
|
|
2017-09-06 16:41:05 +02:00
|
|
|
if (att->attisdropped)
|
|
|
|
{
|
|
|
|
/* Record zeroes for a dropped column */
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, InvalidOid);
|
|
|
|
rte->coltypmods = lappend_int(rte->coltypmods, 0);
|
|
|
|
rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Let's just make sure we can tell this isn't dropped */
|
|
|
|
if (att->atttypid == InvalidOid)
|
|
|
|
elog(ERROR, "atttypid is invalid for non-dropped column in \"%s\"",
|
|
|
|
rv->relname);
|
|
|
|
rte->coltypes = lappend_oid(rte->coltypes, att->atttypid);
|
|
|
|
rte->coltypmods = lappend_int(rte->coltypmods, att->atttypmod);
|
|
|
|
rte->colcollations = lappend_oid(rte->colcollations,
|
|
|
|
att->attcollation);
|
|
|
|
}
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
|
|
|
*
|
2022-12-06 16:09:24 +01:00
|
|
|
* ENRs are never checked for access rights, so no need to perform
|
|
|
|
* addRTEPermissionInfo().
|
2017-04-01 06:17:18 +02:00
|
|
|
*/
|
|
|
|
rte->lateral = false;
|
|
|
|
rte->inh = false; /* never true for ENRs */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add completed RTE to pstate's range table list, so that we know its
|
|
|
|
* index. But we don't add it to the join list --- caller must do that if
|
|
|
|
* appropriate.
|
2017-04-01 06:17:18 +02:00
|
|
|
*/
|
2017-04-16 20:02:47 +02:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2017-04-01 06:17:18 +02:00
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
|
|
|
* list --- caller must do that if appropriate.
|
|
|
|
*/
|
2022-12-06 16:09:24 +01:00
|
|
|
return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), NULL,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
tupdesc);
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
2005-04-28 23:47:18 +02:00
|
|
|
* Has the specified refname been selected FOR UPDATE/FOR SHARE?
|
2006-04-30 20:30:40 +02:00
|
|
|
*
|
2009-10-27 18:11:18 +01:00
|
|
|
* This is used when we have not yet done transformLockingClause, but need
|
|
|
|
* to know the correct lock to take during initial opening of relations.
|
|
|
|
*
|
2022-07-20 10:29:42 +02:00
|
|
|
* Note that refname may be NULL (for a subquery without an alias), in which
|
|
|
|
* case the relation can't be locked by name, but it might still be locked if
|
|
|
|
* a locking clause requests that all tables be locked.
|
|
|
|
*
|
2009-10-27 18:11:18 +01:00
|
|
|
* Note: we pay no attention to whether it's FOR UPDATE vs FOR SHARE,
|
|
|
|
* since the table-level lock is the same either way.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
2009-10-27 18:11:18 +01:00
|
|
|
bool
|
|
|
|
isLockedRefname(ParseState *pstate, const char *refname)
|
2000-11-08 23:10:03 +01:00
|
|
|
{
|
2009-10-27 18:11:18 +01:00
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are in a subquery specified as locked FOR UPDATE/SHARE from
|
|
|
|
* parent level, then act as though there's a generic FOR UPDATE here.
|
|
|
|
*/
|
|
|
|
if (pstate->p_locked_from_parent)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
foreach(l, pstate->p_locking_clause)
|
2000-11-08 23:10:03 +01:00
|
|
|
{
|
2009-10-27 18:11:18 +01:00
|
|
|
LockingClause *lc = (LockingClause *) lfirst(l);
|
2006-04-30 20:30:40 +02:00
|
|
|
|
2009-10-27 18:11:18 +01:00
|
|
|
if (lc->lockedRels == NIL)
|
2000-11-08 23:10:03 +01:00
|
|
|
{
|
2009-10-27 18:11:18 +01:00
|
|
|
/* all tables used in query */
|
|
|
|
return true;
|
|
|
|
}
|
2022-07-20 10:29:42 +02:00
|
|
|
else if (refname != NULL)
|
2009-10-27 18:11:18 +01:00
|
|
|
{
|
|
|
|
/* just the named tables */
|
|
|
|
ListCell *l2;
|
2006-04-30 20:30:40 +02:00
|
|
|
|
2009-10-27 18:11:18 +01:00
|
|
|
foreach(l2, lc->lockedRels)
|
2000-11-08 23:10:03 +01:00
|
|
|
{
|
2009-10-27 18:11:18 +01:00
|
|
|
RangeVar *thisrel = (RangeVar *) lfirst(l2);
|
2000-11-08 23:10:03 +01:00
|
|
|
|
2009-10-27 18:11:18 +01:00
|
|
|
if (strcmp(refname, thisrel->relname) == 0)
|
|
|
|
return true;
|
2000-11-08 23:10:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
/*
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* Add the given nsitem/RTE as a top-level entry in the pstate's join list
|
2012-08-08 22:41:04 +02:00
|
|
|
* and/or namespace list. (We assume caller has checked for any
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
* namespace conflicts.) The nsitem is always marked as unconditionally
|
2012-08-08 01:02:54 +02:00
|
|
|
* visible, that is, not LATERAL-only.
|
2000-02-15 04:38:29 +01:00
|
|
|
*/
|
2000-09-12 23:07:18 +02:00
|
|
|
void
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem,
|
|
|
|
bool addToJoinList,
|
|
|
|
bool addToRelNameSpace, bool addToVarNameSpace)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2001-02-14 22:35:07 +01:00
|
|
|
if (addToJoinList)
|
2005-06-05 02:38:11 +02:00
|
|
|
{
|
|
|
|
RangeTblRef *rtr = makeNode(RangeTblRef);
|
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
rtr->rtindex = nsitem->p_rtindex;
|
2001-02-14 22:35:07 +01:00
|
|
|
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
|
2005-06-05 02:38:11 +02:00
|
|
|
}
|
2012-08-08 01:02:54 +02:00
|
|
|
if (addToRelNameSpace || addToVarNameSpace)
|
|
|
|
{
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/* Set the new nsitem's visibility flags correctly */
|
2012-08-08 22:41:04 +02:00
|
|
|
nsitem->p_rel_visible = addToRelNameSpace;
|
|
|
|
nsitem->p_cols_visible = addToVarNameSpace;
|
2012-08-08 01:02:54 +02:00
|
|
|
nsitem->p_lateral_only = false;
|
|
|
|
nsitem->p_lateral_ok = true;
|
2012-08-08 22:41:04 +02:00
|
|
|
pstate->p_namespace = lappend(pstate->p_namespace, nsitem);
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* expandRTE -- expand the columns of a rangetable entry
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2004-08-19 22:57:41 +02:00
|
|
|
* This creates lists of an RTE's column names (aliases if provided, else
|
|
|
|
* real names) and Vars for each column. Only user columns are considered.
|
2017-08-16 06:22:32 +02:00
|
|
|
* If include_dropped is false then dropped columns are omitted from the
|
|
|
|
* results. If include_dropped is true then empty strings and NULL constants
|
2004-08-19 22:57:41 +02:00
|
|
|
* (not Vars!) are returned for dropped columns.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2008-09-01 22:42:46 +02:00
|
|
|
* rtindex, sublevels_up, and location are the varno, varlevelsup, and location
|
|
|
|
* values to use in the created Vars. Ordinarily rtindex should match the
|
|
|
|
* actual position of the RTE in its rangetable.
|
2004-08-19 22:57:41 +02:00
|
|
|
*
|
|
|
|
* The output lists go into *colnames and *colvars.
|
2000-09-12 23:07:18 +02:00
|
|
|
* If only one of the two kinds of output list is needed, pass NULL for the
|
|
|
|
* output pointer for the unwanted one.
|
|
|
|
*/
|
|
|
|
void
|
2005-06-04 21:19:42 +02:00
|
|
|
expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2000-09-12 23:07:18 +02:00
|
|
|
List **colnames, List **colvars)
|
|
|
|
{
|
2004-08-19 22:57:41 +02:00
|
|
|
int varattno;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
if (colnames)
|
|
|
|
*colnames = NIL;
|
|
|
|
if (colvars)
|
|
|
|
*colvars = NIL;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
switch (rte->rtekind)
|
2000-09-29 20:21:41 +02:00
|
|
|
{
|
2002-05-12 22:10:05 +02:00
|
|
|
case RTE_RELATION:
|
2004-08-19 22:57:41 +02:00
|
|
|
/* Ordinary relation RTE */
|
2008-09-01 22:42:46 +02:00
|
|
|
expandRelation(rte->relid, rte->eref,
|
|
|
|
rtindex, sublevels_up, location,
|
2004-08-19 22:57:41 +02:00
|
|
|
include_dropped, colnames, colvars);
|
2002-05-12 22:10:05 +02:00
|
|
|
break;
|
|
|
|
case RTE_SUBQUERY:
|
|
|
|
{
|
|
|
|
/* Subquery RTE */
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *aliasp_item = list_head(rte->eref->colnames);
|
|
|
|
ListCell *tlistitem;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
varattno = 0;
|
|
|
|
foreach(tlistitem, rte->subquery->targetList)
|
|
|
|
{
|
|
|
|
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (te->resjunk)
|
2002-05-12 22:10:05 +02:00
|
|
|
continue;
|
|
|
|
varattno++;
|
2005-04-06 18:34:07 +02:00
|
|
|
Assert(varattno == te->resno);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2017-10-27 23:10:21 +02:00
|
|
|
/*
|
|
|
|
* In scenarios where columns have been added to a view
|
|
|
|
* since the outer query was originally parsed, there can
|
|
|
|
* be more items in the subquery tlist than the outer
|
|
|
|
* query expects. We should ignore such extra column(s)
|
|
|
|
* --- compare the behavior for composite-returning
|
|
|
|
* functions, in the RTE_FUNCTION case below.
|
|
|
|
*/
|
|
|
|
if (!aliasp_item)
|
|
|
|
break;
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
if (colnames)
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
char *label = strVal(lfirst(aliasp_item));
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
*colnames = lappend(*colnames, makeString(pstrdup(label)));
|
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
Var *varnode;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
varnode = makeVar(rtindex, varattno,
|
2005-04-06 18:34:07 +02:00
|
|
|
exprType((Node *) te->expr),
|
|
|
|
exprTypmod((Node *) te->expr),
|
2011-02-08 22:04:18 +01:00
|
|
|
exprCollation((Node *) te->expr),
|
2002-05-12 22:10:05 +02:00
|
|
|
sublevels_up);
|
2008-09-01 22:42:46 +02:00
|
|
|
varnode->location = location;
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
2017-10-28 00:16:24 +02:00
|
|
|
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliasp_item = lnext(rte->eref->colnames, aliasp_item);
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_FUNCTION:
|
|
|
|
{
|
|
|
|
/* Function RTE */
|
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
2013-11-22 01:37:02 +01:00
|
|
|
int atts_done = 0;
|
|
|
|
ListCell *lc;
|
2013-07-29 17:38:01 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
foreach(lc, rte->functions)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
|
|
|
|
TypeFuncClass functypclass;
|
|
|
|
Oid funcrettype;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
|
|
|
functypclass = get_expr_result_type(rtfunc->funcexpr,
|
|
|
|
&funcrettype,
|
|
|
|
&tupdesc);
|
2017-10-26 19:47:45 +02:00
|
|
|
if (functypclass == TYPEFUNC_COMPOSITE ||
|
|
|
|
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Assert(tupdesc);
|
|
|
|
expandTupleDesc(tupdesc, rte->eref,
|
|
|
|
rtfunc->funccolcount, atts_done,
|
|
|
|
rtindex, sublevels_up, location,
|
|
|
|
include_dropped, colnames, colvars);
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
else if (functypclass == TYPEFUNC_SCALAR)
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/* Base data type, i.e. scalar */
|
|
|
|
if (colnames)
|
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
list_nth(rte->eref->colnames,
|
|
|
|
atts_done));
|
|
|
|
|
|
|
|
if (colvars)
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
{
|
|
|
|
Var *varnode;
|
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
varnode = makeVar(rtindex, atts_done + 1,
|
2020-01-02 20:02:46 +01:00
|
|
|
funcrettype,
|
|
|
|
exprTypmod(rtfunc->funcexpr),
|
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
2013-11-22 01:37:02 +01:00
|
|
|
exprCollation(rtfunc->funcexpr),
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
sublevels_up);
|
2008-09-01 22:42:46 +02:00
|
|
|
varnode->location = location;
|
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
2013-11-22 01:37:02 +01:00
|
|
|
|
Attached are two patches to implement and document anonymous composite
types for Table Functions, as previously proposed on HACKERS. Here is a
brief explanation:
1. Creates a new pg_type typtype: 'p' for pseudo type (currently either
'b' for base or 'c' for catalog, i.e. a class).
2. Creates new builtin type of typtype='p' named RECORD. This is the
first of potentially several pseudo types.
3. Modify FROM clause grammer to accept:
SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...)
where m is the table alias, colname1, etc are the column names, and
type1, etc are the column types.
4. When typtype == 'p' and the function return type is RECORD, a list
of column defs is required, and when typtype != 'p', it is
disallowed.
5. A check was added to ensure that the tupdesc provide via the parser
and the actual return tupdesc match in number and type of
attributes.
When creating a function you can do:
CREATE FUNCTION foo(text) RETURNS setof RECORD ...
When using it you can do:
SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp)
or
SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp)
Included in the patches are adjustments to the regression test sql and
expected files, and documentation.
p.s.
This potentially solves (or at least improves) the issue of builtin
Table Functions. They can be bootstrapped as returning RECORD, and
we can wrap system views around them with properly specified column
defs. For example:
CREATE VIEW pg_settings AS
SELECT s.name, s.setting
FROM show_all_settings()AS s(name text, setting text);
Then we can also add the UPDATE RULE that I previously posted to
pg_settings, and have pg_settings act like a virtual table, allowing
settings to be queried and set.
Joe Conway
2002-08-04 21:48:11 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
else if (functypclass == TYPEFUNC_RECORD)
|
|
|
|
{
|
|
|
|
if (colnames)
|
|
|
|
{
|
|
|
|
List *namelist;
|
|
|
|
|
|
|
|
/* extract appropriate subset of column list */
|
|
|
|
namelist = list_copy_tail(rte->eref->colnames,
|
|
|
|
atts_done);
|
|
|
|
namelist = list_truncate(namelist,
|
|
|
|
rtfunc->funccolcount);
|
|
|
|
*colnames = list_concat(*colnames, namelist);
|
|
|
|
}
|
2013-07-29 17:38:01 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
ListCell *l1;
|
|
|
|
ListCell *l2;
|
|
|
|
ListCell *l3;
|
|
|
|
int attnum = atts_done;
|
|
|
|
|
|
|
|
forthree(l1, rtfunc->funccoltypes,
|
|
|
|
l2, rtfunc->funccoltypmods,
|
|
|
|
l3, rtfunc->funccolcollations)
|
|
|
|
{
|
|
|
|
Oid attrtype = lfirst_oid(l1);
|
|
|
|
int32 attrtypmod = lfirst_int(l2);
|
|
|
|
Oid attrcollation = lfirst_oid(l3);
|
|
|
|
Var *varnode;
|
|
|
|
|
|
|
|
attnum++;
|
|
|
|
varnode = makeVar(rtindex,
|
|
|
|
attnum,
|
|
|
|
attrtype,
|
|
|
|
attrtypmod,
|
|
|
|
attrcollation,
|
|
|
|
sublevels_up);
|
|
|
|
varnode->location = location;
|
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* addRangeTableEntryForFunction should've caught this */
|
|
|
|
elog(ERROR, "function in FROM has unsupported return type");
|
|
|
|
}
|
|
|
|
atts_done += rtfunc->funccolcount;
|
2004-10-20 18:04:50 +02:00
|
|
|
}
|
2013-07-29 17:38:01 +02:00
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
/* Append the ordinality column if any */
|
2013-07-29 17:38:01 +02:00
|
|
|
if (rte->funcordinality)
|
|
|
|
{
|
|
|
|
if (colnames)
|
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
2013-11-22 01:37:02 +01:00
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
llast(rte->eref->colnames));
|
2013-07-29 17:38:01 +02:00
|
|
|
|
|
|
|
if (colvars)
|
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
Var *varnode = makeVar(rtindex,
|
|
|
|
atts_done + 1,
|
|
|
|
INT8OID,
|
|
|
|
-1,
|
|
|
|
InvalidOid,
|
|
|
|
sublevels_up);
|
|
|
|
|
2013-07-29 17:38:01 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
2002-05-12 22:10:05 +02:00
|
|
|
break;
|
|
|
|
case RTE_JOIN:
|
|
|
|
{
|
|
|
|
/* Join RTE */
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *colname;
|
|
|
|
ListCell *aliasvar;
|
|
|
|
|
2004-05-31 01:40:41 +02:00
|
|
|
Assert(list_length(rte->eref->colnames) == list_length(rte->joinaliasvars));
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
varattno = 0;
|
2004-05-26 06:41:50 +02:00
|
|
|
forboth(colname, rte->eref->colnames, aliasvar, rte->joinaliasvars)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
2005-06-04 01:05:30 +02:00
|
|
|
Node *avar = (Node *) lfirst(aliasvar);
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
varattno++;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* During ordinary parsing, there will never be any
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
* deleted columns in the join. While this function is
|
|
|
|
* also used by the rewriter and planner, they do not
|
|
|
|
* currently call it on any JOIN RTEs. Therefore, this
|
|
|
|
* next bit is dead code, but it seems prudent to handle
|
|
|
|
* the case correctly anyway.
|
2004-08-19 22:57:41 +02:00
|
|
|
*/
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 22:23:01 +02:00
|
|
|
if (avar == NULL)
|
2004-08-19 22:57:41 +02:00
|
|
|
{
|
|
|
|
if (include_dropped)
|
|
|
|
{
|
|
|
|
if (colnames)
|
|
|
|
*colnames = lappend(*colnames,
|
2005-06-04 01:05:30 +02:00
|
|
|
makeString(pstrdup("")));
|
2004-08-19 22:57:41 +02:00
|
|
|
if (colvars)
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 22:23:01 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Can't use join's column type here (it might
|
|
|
|
* be dropped!); but it doesn't really matter
|
|
|
|
* what type the Const claims to be.
|
|
|
|
*/
|
2004-08-19 22:57:41 +02:00
|
|
|
*colvars = lappend(*colvars,
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 22:23:01 +02:00
|
|
|
makeNullConst(INT4OID, -1,
|
|
|
|
InvalidOid));
|
|
|
|
}
|
2004-08-19 22:57:41 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
if (colnames)
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
char *label = strVal(lfirst(colname));
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
makeString(pstrdup(label)));
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
1998-01-20 06:05:08 +01:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
Var *varnode;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
/*
|
|
|
|
* If the joinaliasvars entry is a simple Var, just
|
|
|
|
* copy it (with adjustment of varlevelsup and
|
|
|
|
* location); otherwise it is a JOIN USING column and
|
|
|
|
* we must generate a join alias Var. This matches
|
|
|
|
* the results that expansion of "join.*" by
|
|
|
|
* expandNSItemVars would have produced, if we had
|
|
|
|
* access to the ParseNamespaceItem for the join.
|
|
|
|
*/
|
|
|
|
if (IsA(avar, Var))
|
|
|
|
{
|
|
|
|
varnode = copyObject((Var *) avar);
|
|
|
|
varnode->varlevelsup = sublevels_up;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
varnode = makeVar(rtindex, varattno,
|
|
|
|
exprType(avar),
|
|
|
|
exprTypmod(avar),
|
|
|
|
exprCollation(avar),
|
|
|
|
sublevels_up);
|
2008-09-01 22:42:46 +02:00
|
|
|
varnode->location = location;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2017-03-08 16:39:37 +01:00
|
|
|
case RTE_TABLEFUNC:
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
case RTE_VALUES:
|
2008-10-04 23:56:55 +02:00
|
|
|
case RTE_CTE:
|
2017-04-01 06:17:18 +02:00
|
|
|
case RTE_NAMEDTUPLESTORE:
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
2017-09-06 16:41:05 +02:00
|
|
|
/* Tablefunc, Values, CTE, or ENR RTE */
|
2008-10-04 23:56:55 +02:00
|
|
|
ListCell *aliasp_item = list_head(rte->eref->colnames);
|
|
|
|
ListCell *lct;
|
|
|
|
ListCell *lcm;
|
2011-02-08 22:04:18 +01:00
|
|
|
ListCell *lcc;
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
varattno = 0;
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
forthree(lct, rte->coltypes,
|
|
|
|
lcm, rte->coltypmods,
|
|
|
|
lcc, rte->colcollations)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
|
|
|
Oid coltype = lfirst_oid(lct);
|
|
|
|
int32 coltypmod = lfirst_int(lcm);
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid colcoll = lfirst_oid(lcc);
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
varattno++;
|
|
|
|
|
|
|
|
if (colnames)
|
|
|
|
{
|
|
|
|
/* Assume there is one alias per output column */
|
2017-09-06 16:41:05 +02:00
|
|
|
if (OidIsValid(coltype))
|
|
|
|
{
|
|
|
|
char *label = strVal(lfirst(aliasp_item));
|
|
|
|
|
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
makeString(pstrdup(label)));
|
|
|
|
}
|
|
|
|
else if (include_dropped)
|
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
makeString(pstrdup("")));
|
2008-10-04 23:56:55 +02:00
|
|
|
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliasp_item = lnext(rte->eref->colnames, aliasp_item);
|
2008-10-04 23:56:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (colvars)
|
|
|
|
{
|
2017-09-06 16:41:05 +02:00
|
|
|
if (OidIsValid(coltype))
|
|
|
|
{
|
|
|
|
Var *varnode;
|
2008-10-04 23:56:55 +02:00
|
|
|
|
2017-09-06 16:41:05 +02:00
|
|
|
varnode = makeVar(rtindex, varattno,
|
|
|
|
coltype, coltypmod, colcoll,
|
|
|
|
sublevels_up);
|
|
|
|
varnode->location = location;
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
|
2017-09-06 16:41:05 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
else if (include_dropped)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* It doesn't really matter what type the Const
|
|
|
|
* claims to be.
|
|
|
|
*/
|
|
|
|
*colvars = lappend(*colvars,
|
|
|
|
makeNullConst(INT4OID, -1,
|
|
|
|
InvalidOid));
|
|
|
|
}
|
2008-10-04 23:56:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
In the planner, replace an empty FROM clause with a dummy RTE.
The fact that "SELECT expression" has no base relations has long been a
thorn in the side of the planner. It makes it hard to flatten a sub-query
that looks like that, or is a trivial VALUES() item, because the planner
generally uses relid sets to identify sub-relations, and such a sub-query
would have an empty relid set if we flattened it. prepjointree.c contains
some baroque logic that works around this in certain special cases --- but
there is a much better answer. We can replace an empty FROM clause with a
dummy RTE that acts like a table of one row and no columns, and then there
are no such corner cases to worry about. Instead we need some logic to
get rid of useless dummy RTEs, but that's simpler and covers more cases
than what was there before.
For really trivial cases, where the query is just "SELECT expression" and
nothing else, there's a hazard that adding the extra RTE makes for a
noticeable slowdown; even though it's not much processing, there's not
that much for the planner to do overall. However testing says that the
penalty is very small, close to the noise level. In more complex queries,
this is able to find optimizations that we could not find before.
The new RTE type is called RTE_RESULT, since the "scan" plan type it
gives rise to is a Result node (the same plan we produced for a "SELECT
expression" query before). To avoid confusion, rename the old ResultPath
path type to GroupResultPath, reflecting that it's only used in degenerate
grouping cases where we know the query produces just one grouped row.
(It wouldn't work to unify the two cases, because there are different
rules about where the associated quals live during query_planner.)
Note: although this touches readfuncs.c, I don't think a catversion
bump is required, because the added case can't occur in stored rules,
only plans.
Patch by me, reviewed by David Rowley and Mark Dilger
Discussion: https://postgr.es/m/15944.1521127664@sss.pgh.pa.us
2019-01-28 23:54:10 +01:00
|
|
|
case RTE_RESULT:
|
|
|
|
/* These expose no columns, so nothing to do */
|
|
|
|
break;
|
2002-05-12 22:10:05 +02:00
|
|
|
default:
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
|
2002-03-12 01:52:10 +01:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* expandRelation -- expandRTE subroutine
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2004-08-19 22:57:41 +02:00
|
|
|
List **colnames, List **colvars)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
|
2005-04-01 00:46:33 +02:00
|
|
|
/* Get the tupledesc and turn it over to expandTupleDesc */
|
2004-08-19 22:57:41 +02:00
|
|
|
rel = relation_open(relid, AccessShareLock);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
expandTupleDesc(rel->rd_att, eref, rel->rd_att->natts, 0,
|
|
|
|
rtindex, sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
location, include_dropped,
|
2005-04-01 00:46:33 +02:00
|
|
|
colnames, colvars);
|
|
|
|
relation_close(rel, AccessShareLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* expandTupleDesc -- expandRTE subroutine
|
2013-07-29 17:38:01 +02:00
|
|
|
*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* Generate names and/or Vars for the first "count" attributes of the tupdesc,
|
|
|
|
* and append them to colnames/colvars. "offset" is added to the varattno
|
|
|
|
* that each Var would otherwise have, and we also skip the first "offset"
|
|
|
|
* entries in eref->colnames. (These provisions allow use of this code for
|
|
|
|
* an individual composite-returning function in an RTE_FUNCTION RTE.)
|
2005-04-01 00:46:33 +02:00
|
|
|
*/
|
|
|
|
static void
|
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
2013-11-22 01:37:02 +01:00
|
|
|
expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
|
2005-04-01 00:46:33 +02:00
|
|
|
int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2005-04-01 00:46:33 +02:00
|
|
|
List **colnames, List **colvars)
|
|
|
|
{
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
ListCell *aliascell;
|
2005-04-01 00:46:33 +02:00
|
|
|
int varattno;
|
2004-08-19 22:57:41 +02:00
|
|
|
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliascell = (offset < list_length(eref->colnames)) ?
|
|
|
|
list_nth_cell(eref->colnames, offset) : NULL;
|
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
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
Assert(count <= tupdesc->natts);
|
|
|
|
for (varattno = 0; varattno < count; varattno++)
|
2004-08-19 22:57:41 +02:00
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
|
2004-08-19 22:57:41 +02:00
|
|
|
|
|
|
|
if (attr->attisdropped)
|
|
|
|
{
|
|
|
|
if (include_dropped)
|
|
|
|
{
|
|
|
|
if (colnames)
|
|
|
|
*colnames = lappend(*colnames, makeString(pstrdup("")));
|
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* can't use atttypid here, but it doesn't really matter
|
|
|
|
* what type the Const claims to be.
|
|
|
|
*/
|
2011-03-26 01:10:42 +01:00
|
|
|
*colvars = lappend(*colvars,
|
|
|
|
makeNullConst(INT4OID, -1, InvalidOid));
|
2004-08-19 22:57:41 +02:00
|
|
|
}
|
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
if (aliascell)
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliascell = lnext(eref->colnames, aliascell);
|
2004-08-19 22:57:41 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colnames)
|
|
|
|
{
|
|
|
|
char *label;
|
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
if (aliascell)
|
|
|
|
{
|
|
|
|
label = strVal(lfirst(aliascell));
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
aliascell = lnext(eref->colnames, aliascell);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
}
|
2004-08-19 22:57:41 +02:00
|
|
|
else
|
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
2013-11-22 01:37:02 +01:00
|
|
|
{
|
|
|
|
/* If we run out of aliases, use the underlying name */
|
2004-08-19 22:57:41 +02:00
|
|
|
label = NameStr(attr->attname);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
}
|
2004-08-19 22:57:41 +02:00
|
|
|
*colnames = lappend(*colnames, makeString(pstrdup(label)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
Var *varnode;
|
|
|
|
|
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
2013-11-22 01:37:02 +01:00
|
|
|
varnode = makeVar(rtindex, varattno + offset + 1,
|
2011-04-22 23:43:18 +02:00
|
|
|
attr->atttypid, attr->atttypmod,
|
|
|
|
attr->attcollation,
|
2004-08-19 22:57:41 +02:00
|
|
|
sublevels_up);
|
2008-09-01 22:42:46 +02:00
|
|
|
varnode->location = location;
|
2004-08-19 22:57:41 +02:00
|
|
|
|
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
/*
|
|
|
|
* expandNSItemVars
|
|
|
|
* Produce a list of Vars, and optionally a list of column names,
|
|
|
|
* for the non-dropped columns of the nsitem.
|
|
|
|
*
|
|
|
|
* The emitted Vars are marked with the given sublevels_up and location.
|
|
|
|
*
|
|
|
|
* If colnames isn't NULL, a list of String items for the columns is stored
|
|
|
|
* there; note that it's just a subset of the RTE's eref list, and hence
|
|
|
|
* the list elements mustn't be modified.
|
|
|
|
*/
|
|
|
|
List *
|
Make Vars be outer-join-aware.
Traditionally we used the same Var struct to represent the value
of a table column everywhere in parse and plan trees. This choice
predates our support for SQL outer joins, and it's really a pretty
bad idea with outer joins, because the Var's value can depend on
where it is in the tree: it might go to NULL above an outer join.
So expression nodes that are equal() per equalfuncs.c might not
represent the same value, which is a huge correctness hazard for
the planner.
To improve this, decorate Var nodes with a bitmapset showing
which outer joins (identified by RTE indexes) may have nulled
them at the point in the parse tree where the Var appears.
This allows us to trust that equal() Vars represent the same value.
A certain amount of klugery is still needed to cope with cases
where we re-order two outer joins, but it's possible to make it
work without sacrificing that core principle. PlaceHolderVars
receive similar decoration for the same reason.
In the planner, we include these outer join bitmapsets into the relids
that an expression is considered to depend on, and in consequence also
add outer-join relids to the relids of join RelOptInfos. This allows
us to correctly perceive whether an expression can be calculated above
or below a particular outer join.
This change affects FDWs that want to plan foreign joins. They *must*
follow suit when labeling foreign joins in order to match with the
core planner, but for many purposes (if postgres_fdw is any guide)
they'd prefer to consider only base relations within the join.
To support both requirements, redefine ForeignScan.fs_relids as
base+OJ relids, and add a new field fs_base_relids that's set up by
the core planner.
Large though it is, this commit just does the minimum necessary to
install the new mechanisms and get check-world passing again.
Follow-up patches will perform some cleanup. (The README additions
and comments mention some stuff that will appear in the follow-up.)
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
2023-01-30 19:16:20 +01:00
|
|
|
expandNSItemVars(ParseState *pstate, ParseNamespaceItem *nsitem,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
int sublevels_up, int location,
|
|
|
|
List **colnames)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
int colindex;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
if (colnames)
|
|
|
|
*colnames = NIL;
|
|
|
|
colindex = 0;
|
2021-03-31 10:52:37 +02:00
|
|
|
foreach(lc, nsitem->p_names->colnames)
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
{
|
Remove Value node struct
The Value node struct is a weird construct. It is its own node type,
but most of the time, it actually has a node type of Integer, Float,
String, or BitString. As a consequence, the struct name and the node
type don't match most of the time, and so it has to be treated
specially a lot. There doesn't seem to be any value in the special
construct. There is very little code that wants to accept all Value
variants but nothing else (and even if it did, this doesn't provide
any convenient way to check it), and most code wants either just one
particular node type (usually String), or it accepts a broader set of
node types besides just Value.
This change removes the Value struct and node type and replaces them
by separate Integer, Float, String, and BitString node types that are
proper node types and structs of their own and behave mostly like
normal node types.
Also, this removes the T_Null node tag, which was previously also a
possible variant of Value but wasn't actually used outside of the
Value contained in A_Const. Replace that by an isnull field in
A_Const.
Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/5ba6bc5b-3f95-04f2-2419-f8ddb4c046fb@enterprisedb.com
2021-09-09 07:58:12 +02:00
|
|
|
String *colnameval = lfirst(lc);
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
const char *colname = strVal(colnameval);
|
|
|
|
ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex;
|
|
|
|
|
2021-02-01 13:54:59 +01:00
|
|
|
if (nscol->p_dontexpand)
|
|
|
|
{
|
|
|
|
/* skip */
|
|
|
|
}
|
|
|
|
else if (colname[0])
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
{
|
|
|
|
Var *var;
|
|
|
|
|
|
|
|
Assert(nscol->p_varno > 0);
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
var = makeVar(nscol->p_varno,
|
|
|
|
nscol->p_varattno,
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
nscol->p_vartype,
|
|
|
|
nscol->p_vartypmod,
|
|
|
|
nscol->p_varcollid,
|
|
|
|
sublevels_up);
|
Reconsider the representation of join alias Vars.
The core idea of this patch is to make the parser generate join alias
Vars (that is, ones with varno pointing to a JOIN RTE) only when the
alias Var is actually different from any raw join input, that is a type
coercion and/or COALESCE is necessary to generate the join output value.
Otherwise just generate varno/varattno pointing to the relevant join
input column.
In effect, this means that the planner's flatten_join_alias_vars()
transformation is already done in the parser, for all cases except
(a) columns that are merged by JOIN USING and are transformed in the
process, and (b) whole-row join Vars. In principle that would allow
us to skip doing flatten_join_alias_vars() in many more queries than
we do now, but we don't have quite enough infrastructure to know that
we can do so --- in particular there's no cheap way to know whether
there are any whole-row join Vars. I'm not sure if it's worth the
trouble to add a Query-level flag for that, and in any case it seems
like fit material for a separate patch. But even without skipping the
work entirely, this should make flatten_join_alias_vars() faster,
particularly where there are nested joins that it previously had to
flatten recursively.
An essential part of this change is to replace Var nodes'
varnoold/varoattno fields with varnosyn/varattnosyn, which have
considerably more tightly-defined meanings than the old fields: when
they differ from varno/varattno, they identify the Var's position in
an aliased JOIN RTE, and the join alias is what ruleutils.c should
print for the Var. This is necessary because the varno change
destroyed ruleutils.c's ability to find the JOIN RTE from the Var's
varno.
Another way in which this change broke ruleutils.c is that it's no
longer feasible to determine, from a JOIN RTE's joinaliasvars list,
which join columns correspond to which columns of the join's immediate
input relations. (If those are sub-joins, the joinaliasvars entries
may point to columns of their base relations, not the sub-joins.)
But that was a horrid mess requiring a lot of fragile assumptions
already, so let's just bite the bullet and add some more JOIN RTE
fields to make it more straightforward to figure that out. I added
two integer-List fields containing the relevant column numbers from
the left and right input rels, plus a count of how many merged columns
there are.
This patch depends on the ParseNamespaceColumn infrastructure that
I added in commit 5815696bc. The biggest bit of code change is
restructuring transformFromClauseItem's handling of JOINs so that
the ParseNamespaceColumn data is propagated upward correctly.
Other than that and the ruleutils fixes, everything pretty much
just works, though some processing is now inessential. I grabbed
two pieces of low-hanging fruit in that line:
1. In find_expr_references, we don't need to recurse into join alias
Vars anymore. There aren't any except for references to merged USING
columns, which are more properly handled when we scan the join's RTE.
This change actually fixes an edge-case issue: we will now record a
dependency on any type-coercion function present in a USING column's
joinaliasvar, even if that join column has no references in the query
text. The odds of the missing dependency causing a problem seem quite
small: you'd have to posit somebody dropping an implicit cast between
two data types, without removing the types themselves, and then having
a stored rule containing a whole-row Var for a join whose USING merge
depends on that cast. So I don't feel a great need to change this in
the back branches. But in theory this way is more correct.
2. markRTEForSelectPriv and markTargetListOrigin don't need to recurse
into join alias Vars either, because the cases they care about don't
apply to alias Vars for USING columns that are semantically distinct
from the underlying columns. This removes the only case in which
markVarForSelectPriv could be called with NULL for the RTE, so adjust
the comments to describe that hack as being strictly internal to
markRTEForSelectPriv.
catversion bump required due to changes in stored rules.
Discussion: https://postgr.es/m/7115.1577986646@sss.pgh.pa.us
2020-01-09 17:56:59 +01:00
|
|
|
/* makeVar doesn't offer parameters for these, so set by hand: */
|
|
|
|
var->varnosyn = nscol->p_varnosyn;
|
|
|
|
var->varattnosyn = nscol->p_varattnosyn;
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
var->location = location;
|
Make Vars be outer-join-aware.
Traditionally we used the same Var struct to represent the value
of a table column everywhere in parse and plan trees. This choice
predates our support for SQL outer joins, and it's really a pretty
bad idea with outer joins, because the Var's value can depend on
where it is in the tree: it might go to NULL above an outer join.
So expression nodes that are equal() per equalfuncs.c might not
represent the same value, which is a huge correctness hazard for
the planner.
To improve this, decorate Var nodes with a bitmapset showing
which outer joins (identified by RTE indexes) may have nulled
them at the point in the parse tree where the Var appears.
This allows us to trust that equal() Vars represent the same value.
A certain amount of klugery is still needed to cope with cases
where we re-order two outer joins, but it's possible to make it
work without sacrificing that core principle. PlaceHolderVars
receive similar decoration for the same reason.
In the planner, we include these outer join bitmapsets into the relids
that an expression is considered to depend on, and in consequence also
add outer-join relids to the relids of join RelOptInfos. This allows
us to correctly perceive whether an expression can be calculated above
or below a particular outer join.
This change affects FDWs that want to plan foreign joins. They *must*
follow suit when labeling foreign joins in order to match with the
core planner, but for many purposes (if postgres_fdw is any guide)
they'd prefer to consider only base relations within the join.
To support both requirements, redefine ForeignScan.fs_relids as
base+OJ relids, and add a new field fs_base_relids that's set up by
the core planner.
Large though it is, this commit just does the minimum necessary to
install the new mechanisms and get check-world passing again.
Follow-up patches will perform some cleanup. (The README additions
and comments mention some stuff that will appear in the follow-up.)
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
2023-01-30 19:16:20 +01:00
|
|
|
|
|
|
|
/* ... and update varnullingrels */
|
|
|
|
markNullableIfNeeded(pstate, var);
|
|
|
|
|
Make parser rely more heavily on the ParseNamespaceItem data structure.
When I added the ParseNamespaceItem data structure (in commit 5ebaaa494),
it wasn't very tightly integrated into the parser's APIs. In the wake of
adding p_rtindex to that struct (commit b541e9acc), there is a good reason
to make more use of it: by passing around ParseNamespaceItem pointers
instead of bare RTE pointers, we can get rid of various messy methods for
passing back or deducing the rangetable index of an RTE during parsing.
Hence, refactor the addRangeTableEntryXXX functions to build and return
a ParseNamespaceItem struct, not just the RTE proper; and replace
addRTEtoQuery with addNSItemToQuery, which is passed a ParseNamespaceItem
rather than building one internally.
Also, add per-column data (a ParseNamespaceColumn array) to each
ParseNamespaceItem. These arrays are built during addRangeTableEntryXXX,
where we have column type data at hand so that it's nearly free to fill
the data structure. Later, when we need to build Vars referencing RTEs,
we can use the ParseNamespaceColumn info to avoid the rather expensive
operations done in get_rte_attribute_type() or expandRTE().
get_rte_attribute_type() is indeed dead code now, so I've removed it.
This makes for a useful improvement in parse analysis speed, around 20%
in one moderately-complex test query.
The ParseNamespaceColumn structs also include Var identity information
(varno/varattno). That info isn't actually being used in this patch,
except that p_varno == 0 is a handy test for a dropped column.
A follow-on patch will make more use of it.
Discussion: https://postgr.es/m/2461.1577764221@sss.pgh.pa.us
2020-01-02 17:29:01 +01:00
|
|
|
result = lappend(result, var);
|
|
|
|
if (colnames)
|
|
|
|
*colnames = lappend(*colnames, colnameval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* dropped column, ignore */
|
|
|
|
Assert(nscol->p_varno == 0);
|
|
|
|
}
|
|
|
|
colindex++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2019-12-26 17:16:42 +01:00
|
|
|
* expandNSItemAttrs -
|
2002-03-12 01:52:10 +01:00
|
|
|
* Workhorse for "*" expansion: produce a list of targetentries
|
2019-12-26 17:16:42 +01:00
|
|
|
* for the attributes of the nsitem
|
2005-06-04 21:19:42 +02:00
|
|
|
*
|
2008-09-01 22:42:46 +02:00
|
|
|
* pstate->p_next_resno determines the resnos assigned to the TLEs.
|
2022-03-28 16:45:58 +02:00
|
|
|
* The referenced columns are marked as requiring SELECT access, if
|
|
|
|
* caller requests that.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2002-03-12 01:52:10 +01:00
|
|
|
List *
|
2019-12-26 17:16:42 +01:00
|
|
|
expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem,
|
2022-03-28 16:45:58 +02:00
|
|
|
int sublevels_up, bool require_col_privs, int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2019-12-26 17:16:42 +01:00
|
|
|
RangeTblEntry *rte = nsitem->p_rte;
|
2022-12-06 16:09:24 +01:00
|
|
|
RTEPermissionInfo *perminfo = nsitem->p_perminfo;
|
2002-03-12 01:52:10 +01:00
|
|
|
List *names,
|
|
|
|
*vars;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *name,
|
|
|
|
*var;
|
2000-09-12 23:07:18 +02:00
|
|
|
List *te_list = NIL;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
Make Vars be outer-join-aware.
Traditionally we used the same Var struct to represent the value
of a table column everywhere in parse and plan trees. This choice
predates our support for SQL outer joins, and it's really a pretty
bad idea with outer joins, because the Var's value can depend on
where it is in the tree: it might go to NULL above an outer join.
So expression nodes that are equal() per equalfuncs.c might not
represent the same value, which is a huge correctness hazard for
the planner.
To improve this, decorate Var nodes with a bitmapset showing
which outer joins (identified by RTE indexes) may have nulled
them at the point in the parse tree where the Var appears.
This allows us to trust that equal() Vars represent the same value.
A certain amount of klugery is still needed to cope with cases
where we re-order two outer joins, but it's possible to make it
work without sacrificing that core principle. PlaceHolderVars
receive similar decoration for the same reason.
In the planner, we include these outer join bitmapsets into the relids
that an expression is considered to depend on, and in consequence also
add outer-join relids to the relids of join RelOptInfos. This allows
us to correctly perceive whether an expression can be calculated above
or below a particular outer join.
This change affects FDWs that want to plan foreign joins. They *must*
follow suit when labeling foreign joins in order to match with the
core planner, but for many purposes (if postgres_fdw is any guide)
they'd prefer to consider only base relations within the join.
To support both requirements, redefine ForeignScan.fs_relids as
base+OJ relids, and add a new field fs_base_relids that's set up by
the core planner.
Large though it is, this commit just does the minimum necessary to
install the new mechanisms and get check-world passing again.
Follow-up patches will perform some cleanup. (The README additions
and comments mention some stuff that will appear in the follow-up.)
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
2023-01-30 19:16:20 +01:00
|
|
|
vars = expandNSItemVars(pstate, nsitem, sublevels_up, location, &names);
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
/*
|
|
|
|
* Require read access to the table. This is normally redundant with the
|
|
|
|
* markVarForSelectPriv calls below, but not if the table has zero
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
* columns. We need not do anything if the nsitem is for a join: its
|
|
|
|
* component tables will have been marked ACL_SELECT when they were added
|
|
|
|
* to the rangetable. (This step changes things only for the target
|
|
|
|
* relation of UPDATE/DELETE, which cannot be under a join.)
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
Fix mishandling of column-level SELECT privileges for join aliases.
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
pass the wrong RTE to markVarForSelectPriv when dealing with a join
ParseNamespaceItem: they'd pass the join RTE, when what we need to
mark is the base table that the join column came from. The end
result was to not fill the base table's selectedCols bitmap correctly,
resulting in an understatement of the set of columns that are read
by the query. The executor would still insist on there being at
least one selectable column; but with a correctly crafted query,
a user having SELECT privilege on just one column of a table would
nonetheless be allowed to read all its columns.
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
ignoring the possibly-mismatched RTE passed by the caller. Later,
we'll get rid of some now-unused RTE arguments, but that risks
API breaks so we won't do it in released branches.
This problem was introduced by commit 9ce77d75c, so back-patch
to v13 where that came in. Thanks to Sven Klemm for reporting
the problem.
Security: CVE-2021-20229
2021-02-08 16:14:09 +01:00
|
|
|
if (rte->rtekind == RTE_RELATION)
|
2022-12-06 16:09:24 +01:00
|
|
|
{
|
|
|
|
Assert(perminfo != NULL);
|
|
|
|
perminfo->requiredPerms |= ACL_SELECT;
|
|
|
|
}
|
2009-01-22 21:16:10 +01:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
forboth(name, names, var, vars)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
char *label = strVal(lfirst(name));
|
2009-01-22 21:16:10 +01:00
|
|
|
Var *varnode = (Var *) lfirst(var);
|
2005-04-06 18:34:07 +02:00
|
|
|
TargetEntry *te;
|
|
|
|
|
|
|
|
te = makeTargetEntry((Expr *) varnode,
|
|
|
|
(AttrNumber) pstate->p_next_resno++,
|
|
|
|
label,
|
|
|
|
false);
|
1999-07-19 02:26:20 +02:00
|
|
|
te_list = lappend(te_list, te);
|
2009-01-22 21:16:10 +01:00
|
|
|
|
2022-03-28 16:45:58 +02:00
|
|
|
if (require_col_privs)
|
|
|
|
{
|
|
|
|
/* Require read access to each column */
|
|
|
|
markVarForSelectPriv(pstate, varnode);
|
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
Assert(name == NULL && var == NULL); /* lists not the same length? */
|
1998-01-20 06:05:08 +01:00
|
|
|
|
1999-07-19 02:26:20 +02:00
|
|
|
return te_list;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
/*
|
2000-09-25 20:14:55 +02:00
|
|
|
* get_rte_attribute_name
|
|
|
|
* Get an attribute name from a RangeTblEntry
|
|
|
|
*
|
|
|
|
* This is unlike get_attname() because we use aliases if available.
|
2002-03-12 01:52:10 +01:00
|
|
|
* In particular, it will work on an RTE for a subselect or join, whereas
|
2000-09-25 20:14:55 +02:00
|
|
|
* get_attname() only works on real relations.
|
2001-02-14 22:35:07 +01:00
|
|
|
*
|
2001-04-18 19:04:24 +02:00
|
|
|
* "*" is returned if the given attnum is InvalidAttrNumber --- this case
|
|
|
|
* occurs when a Var represents a whole tuple of a relation.
|
Fix ruleutils issues with dropped cols in functions-returning-composite.
Due to lack of concern for the case in the dependency code, it's
possible to drop a column of a composite type even though stored
queries have references to the dropped column via functions-in-FROM
that return the composite type. There are "soft" references,
namely FROM-clause aliases for such columns, and "hard" references,
that is actual Vars referring to them. The right fix for hard
references is to add dependencies preventing the drop; something
we've known for many years and not done (and this commit still doesn't
address it). A "soft" reference shouldn't prevent a drop though.
We've been around on this before (cf. 9b35ddce9, 2c4debbd0), but
nobody had noticed that the current behavior can result in dump/reload
failures, because ruleutils.c can print more column aliases than the
underlying composite type now has. So we need to rejigger the
column-alias-handling code to treat such columns as dropped and not
print aliases for them.
Rather than writing new code for this, I used expandRTE() which already
knows how to figure out which function result columns are dropped.
I'd initially thought maybe we could use expandRTE() in all cases, but
that fails for EXPLAIN's purposes, because the planner strips a lot of
RTE infrastructure that expandRTE() needs. So this patch just uses it
for unplanned function RTEs and otherwise does things the old way.
If there is a hard reference (Var), then removing the column alias
causes us to fail to print the Var, since there's no longer a name
to print. Failing seems less desirable than printing a made-up
name, so I made it print "?dropped?column?" instead.
Per report from Timo Stolz. Back-patch to all supported branches.
Discussion: https://postgr.es/m/5c91267e-3b6d-5795-189c-d15a55d61dbb@nullachtvierzehn.de
2022-07-21 19:56:02 +02:00
|
|
|
*
|
|
|
|
* It is caller's responsibility to not call this on a dropped attribute.
|
|
|
|
* (You will get some answer for such cases, but it might not be sensible.)
|
2000-09-25 20:14:55 +02:00
|
|
|
*/
|
|
|
|
char *
|
|
|
|
get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
|
|
|
|
{
|
2001-04-18 19:04:24 +02:00
|
|
|
if (attnum == InvalidAttrNumber)
|
|
|
|
return "*";
|
|
|
|
|
2000-09-25 20:14:55 +02:00
|
|
|
/*
|
2002-08-08 19:00:19 +02:00
|
|
|
* If there is a user-written column alias, use it.
|
2000-09-25 20:14:55 +02:00
|
|
|
*/
|
2002-08-08 19:00:19 +02:00
|
|
|
if (rte->alias &&
|
2004-05-31 01:40:41 +02:00
|
|
|
attnum > 0 && attnum <= list_length(rte->alias->colnames))
|
|
|
|
return strVal(list_nth(rte->alias->colnames, attnum - 1));
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-09-25 20:14:55 +02:00
|
|
|
/*
|
2002-08-08 19:00:19 +02:00
|
|
|
* If the RTE is a relation, go to the system catalogs not the
|
|
|
|
* eref->colnames list. This is a little slower but it will give the
|
|
|
|
* right answer if the column has been renamed since the eref list was
|
|
|
|
* built (which can easily happen for rules).
|
2000-09-25 20:14:55 +02:00
|
|
|
*/
|
2002-08-08 19:00:19 +02:00
|
|
|
if (rte->rtekind == RTE_RELATION)
|
2018-02-12 23:30:30 +01:00
|
|
|
return get_attname(rte->relid, attnum, false);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-09-25 20:14:55 +02:00
|
|
|
/*
|
2002-08-08 19:00:19 +02:00
|
|
|
* Otherwise use the column name from eref. There should always be one.
|
2000-09-25 20:14:55 +02:00
|
|
|
*/
|
2004-05-31 01:40:41 +02:00
|
|
|
if (attnum > 0 && attnum <= list_length(rte->eref->colnames))
|
|
|
|
return strVal(list_nth(rte->eref->colnames, attnum - 1));
|
2002-08-08 19:00:19 +02:00
|
|
|
|
2003-07-19 22:20:53 +02:00
|
|
|
/* else caller gave us a bogus attnum */
|
|
|
|
elog(ERROR, "invalid attnum %d for rangetable entry %s",
|
2002-08-08 19:00:19 +02:00
|
|
|
attnum, rte->eref->aliasname);
|
|
|
|
return NULL; /* keep compiler quiet */
|
2000-09-25 20:14:55 +02:00
|
|
|
}
|
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
/*
|
|
|
|
* get_rte_attribute_is_dropped
|
|
|
|
* Check whether attempted attribute ref is to a dropped column
|
|
|
|
*/
|
2004-08-17 20:47:09 +02:00
|
|
|
bool
|
2005-06-04 01:05:30 +02:00
|
|
|
get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
|
2002-08-02 20:15:10 +02:00
|
|
|
{
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
switch (rte->rtekind)
|
|
|
|
{
|
|
|
|
case RTE_RELATION:
|
|
|
|
{
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* Plain relation RTE --- get the attribute's catalog entry
|
|
|
|
*/
|
2002-08-02 20:15:10 +02:00
|
|
|
HeapTuple tp;
|
|
|
|
Form_pg_attribute att_tup;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tp = SearchSysCache2(ATTNUM,
|
|
|
|
ObjectIdGetDatum(rte->relid),
|
|
|
|
Int16GetDatum(attnum));
|
2003-07-19 22:20:53 +02:00
|
|
|
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
|
|
attnum, rte->relid);
|
2002-08-02 20:15:10 +02:00
|
|
|
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
|
|
|
|
result = att_tup->attisdropped;
|
|
|
|
ReleaseSysCache(tp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_SUBQUERY:
|
2017-03-08 16:39:37 +01:00
|
|
|
case RTE_TABLEFUNC:
|
2006-08-02 03:59:48 +02:00
|
|
|
case RTE_VALUES:
|
2008-10-04 23:56:55 +02:00
|
|
|
case RTE_CTE:
|
2017-03-08 16:39:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Subselect, Table Functions, Values, CTE RTEs never have dropped
|
|
|
|
* columns
|
|
|
|
*/
|
2002-08-02 20:15:10 +02:00
|
|
|
result = false;
|
|
|
|
break;
|
2017-04-01 06:17:18 +02:00
|
|
|
case RTE_NAMEDTUPLESTORE:
|
|
|
|
{
|
2017-09-06 16:41:05 +02:00
|
|
|
/* Check dropped-ness by testing for valid coltype */
|
|
|
|
if (attnum <= 0 ||
|
|
|
|
attnum > list_length(rte->coltypes))
|
|
|
|
elog(ERROR, "invalid varattno %d", attnum);
|
|
|
|
result = !OidIsValid((list_nth_oid(rte->coltypes, attnum - 1)));
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-08-19 22:57:41 +02:00
|
|
|
case RTE_JOIN:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* A join RTE would not have dropped columns when constructed,
|
|
|
|
* but one in a stored rule might contain columns that were
|
|
|
|
* dropped from the underlying tables, if said columns are
|
|
|
|
* nowhere explicitly referenced in the rule. This will be
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 22:23:01 +02:00
|
|
|
* signaled to us by a null pointer in the joinaliasvars list.
|
2004-08-19 22:57:41 +02:00
|
|
|
*/
|
|
|
|
Var *aliasvar;
|
|
|
|
|
|
|
|
if (attnum <= 0 ||
|
|
|
|
attnum > list_length(rte->joinaliasvars))
|
|
|
|
elog(ERROR, "invalid varattno %d", attnum);
|
|
|
|
aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
|
2004-08-29 07:07:03 +02:00
|
|
|
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 22:23:01 +02:00
|
|
|
result = (aliasvar == NULL);
|
2004-08-19 22:57:41 +02:00
|
|
|
}
|
|
|
|
break;
|
2002-08-02 20:15:10 +02:00
|
|
|
case RTE_FUNCTION:
|
|
|
|
{
|
|
|
|
/* Function RTE */
|
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
2013-11-22 01:37:02 +01:00
|
|
|
ListCell *lc;
|
|
|
|
int atts_done = 0;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
2013-07-29 17:38:01 +02:00
|
|
|
/*
|
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
2013-11-22 01:37:02 +01:00
|
|
|
* Dropped attributes are only possible with functions that
|
|
|
|
* return named composite types. In such a case we have to
|
|
|
|
* look up the result type to see if it currently has this
|
|
|
|
* column dropped. So first, loop over the funcs until we
|
|
|
|
* find the one that covers the requested column.
|
2013-07-29 17:38:01 +02:00
|
|
|
*/
|
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
2013-11-22 01:37:02 +01:00
|
|
|
foreach(lc, rte->functions)
|
2013-07-29 17:38:01 +02:00
|
|
|
{
|
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
2013-11-22 01:37:02 +01:00
|
|
|
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
|
|
|
|
|
|
|
|
if (attnum > atts_done &&
|
|
|
|
attnum <= atts_done + rtfunc->funccolcount)
|
|
|
|
{
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
2017-10-26 19:47:45 +02:00
|
|
|
tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr,
|
|
|
|
true);
|
|
|
|
if (tupdesc)
|
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
2013-11-22 01:37:02 +01:00
|
|
|
{
|
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Form_pg_attribute att_tup;
|
|
|
|
|
|
|
|
Assert(tupdesc);
|
|
|
|
Assert(attnum - atts_done <= tupdesc->natts);
|
2017-08-20 20:19:07 +02:00
|
|
|
att_tup = TupleDescAttr(tupdesc,
|
|
|
|
attnum - atts_done - 1);
|
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
2013-11-22 01:37:02 +01:00
|
|
|
return att_tup->attisdropped;
|
|
|
|
}
|
|
|
|
/* Otherwise, it can't have any dropped columns */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
atts_done += rtfunc->funccolcount;
|
2002-08-02 20:15:10 +02:00
|
|
|
}
|
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
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
/* If we get here, must be looking for the ordinality column */
|
|
|
|
if (rte->funcordinality && attnum == atts_done + 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* this probably can't happen ... */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column %d of relation \"%s\" does not exist",
|
|
|
|
attnum,
|
|
|
|
rte->eref->aliasname)));
|
|
|
|
result = false; /* keep compiler quiet */
|
2002-08-02 20:15:10 +02:00
|
|
|
}
|
|
|
|
break;
|
In the planner, replace an empty FROM clause with a dummy RTE.
The fact that "SELECT expression" has no base relations has long been a
thorn in the side of the planner. It makes it hard to flatten a sub-query
that looks like that, or is a trivial VALUES() item, because the planner
generally uses relid sets to identify sub-relations, and such a sub-query
would have an empty relid set if we flattened it. prepjointree.c contains
some baroque logic that works around this in certain special cases --- but
there is a much better answer. We can replace an empty FROM clause with a
dummy RTE that acts like a table of one row and no columns, and then there
are no such corner cases to worry about. Instead we need some logic to
get rid of useless dummy RTEs, but that's simpler and covers more cases
than what was there before.
For really trivial cases, where the query is just "SELECT expression" and
nothing else, there's a hazard that adding the extra RTE makes for a
noticeable slowdown; even though it's not much processing, there's not
that much for the planner to do overall. However testing says that the
penalty is very small, close to the noise level. In more complex queries,
this is able to find optimizations that we could not find before.
The new RTE type is called RTE_RESULT, since the "scan" plan type it
gives rise to is a Result node (the same plan we produced for a "SELECT
expression" query before). To avoid confusion, rename the old ResultPath
path type to GroupResultPath, reflecting that it's only used in degenerate
grouping cases where we know the query produces just one grouped row.
(It wouldn't work to unify the two cases, because there are different
rules about where the associated quals live during query_planner.)
Note: although this touches readfuncs.c, I don't think a catversion
bump is required, because the added case can't occur in stored rules,
only plans.
Patch by me, reviewed by David Rowley and Mark Dilger
Discussion: https://postgr.es/m/15944.1521127664@sss.pgh.pa.us
2019-01-28 23:54:10 +01:00
|
|
|
case RTE_RESULT:
|
|
|
|
/* this probably can't happen ... */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column %d of relation \"%s\" does not exist",
|
|
|
|
attnum,
|
|
|
|
rte->eref->aliasname)));
|
|
|
|
result = false; /* keep compiler quiet */
|
|
|
|
break;
|
2002-08-02 20:15:10 +02:00
|
|
|
default:
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
|
2002-08-02 20:15:10 +02:00
|
|
|
result = false; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-08-11 22:46:47 +02:00
|
|
|
/*
|
|
|
|
* Given a targetlist and a resno, return the matching TargetEntry
|
|
|
|
*
|
|
|
|
* Returns NULL if resno is not present in list.
|
|
|
|
*
|
2004-05-31 01:40:41 +02:00
|
|
|
* Note: we need to search, rather than just indexing with list_nth(),
|
|
|
|
* because not all tlists are sorted by resno.
|
2003-08-11 22:46:47 +02:00
|
|
|
*/
|
|
|
|
TargetEntry *
|
|
|
|
get_tle_by_resno(List *tlist, AttrNumber resno)
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2003-08-11 22:46:47 +02:00
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, tlist)
|
2003-08-11 22:46:47 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
2003-08-11 22:46:47 +02:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (tle->resno == resno)
|
2003-08-11 22:46:47 +02:00
|
|
|
return tle;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-04-30 20:30:40 +02:00
|
|
|
/*
|
|
|
|
* Given a Query and rangetable index, return relation's RowMarkClause if any
|
|
|
|
*
|
|
|
|
* Returns NULL if relation is not selected FOR UPDATE/SHARE
|
|
|
|
*/
|
|
|
|
RowMarkClause *
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
get_parse_rowmark(Query *qry, Index rtindex)
|
2006-04-30 20:30:40 +02:00
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, qry->rowMarks)
|
|
|
|
{
|
|
|
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
|
|
|
|
|
|
|
if (rc->rti == rtindex)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1998-01-20 06:05:08 +01:00
|
|
|
/*
|
2006-03-23 01:19:30 +01:00
|
|
|
* given relation and att name, return attnum of variable
|
|
|
|
*
|
|
|
|
* Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
|
1998-01-20 06:05:08 +01:00
|
|
|
*
|
|
|
|
* This should only be used if the relation is already
|
2019-01-21 19:32:19 +01:00
|
|
|
* table_open()'ed. Use the cache version get_attnum()
|
1998-01-20 06:05:08 +01:00
|
|
|
* for access to non-opened relations.
|
|
|
|
*/
|
1997-11-25 23:07:18 +01:00
|
|
|
int
|
2002-08-02 20:15:10 +02:00
|
|
|
attnameAttNum(Relation rd, const char *attname, bool sysColOK)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
for (i = 0; i < RelationGetNumberOfAttributes(rd); i++)
|
2002-08-02 20:15:10 +02:00
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute att = TupleDescAttr(rd->rd_att, i);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped)
|
1997-11-25 23:07:18 +01:00
|
|
|
return i + 1;
|
2002-08-02 20:15:10 +02:00
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
if (sysColOK)
|
2001-08-10 20:57:42 +02:00
|
|
|
{
|
2002-08-02 20:15:10 +02:00
|
|
|
if ((i = specialAttNum(attname)) != InvalidAttrNumber)
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
return i;
|
2001-08-10 20:57:42 +02:00
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
/* on failure */
|
2006-03-23 01:19:30 +01:00
|
|
|
return InvalidAttrNumber;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2000-02-15 04:38:29 +01:00
|
|
|
/* specialAttNum()
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
* Check attribute name to see if it is "special", e.g. "xmin".
|
2000-02-15 04:38:29 +01:00
|
|
|
* - thomas 2000-02-07
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
|
|
|
* Note: this only discovers whether the name could be a system attribute.
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
* Caller needs to ensure that it really is an attribute of the rel.
|
2000-02-15 04:38:29 +01:00
|
|
|
*/
|
2001-08-10 20:57:42 +02:00
|
|
|
static int
|
2002-08-02 20:15:10 +02:00
|
|
|
specialAttNum(const char *attname)
|
2000-02-15 04:38:29 +01:00
|
|
|
{
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *sysatt;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
sysatt = SystemAttributeByName(attname);
|
2001-10-23 00:47:57 +02:00
|
|
|
if (sysatt != NULL)
|
|
|
|
return sysatt->attnum;
|
2000-02-15 04:38:29 +01:00
|
|
|
return InvalidAttrNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-23 19:39:03 +02:00
|
|
|
/*
|
|
|
|
* given attribute id, return name of that attribute
|
|
|
|
*
|
|
|
|
* This should only be used if the relation is already
|
2019-01-21 19:32:19 +01:00
|
|
|
* table_open()'ed. Use the cache version get_atttype()
|
2001-10-23 19:39:03 +02:00
|
|
|
* for access to non-opened relations.
|
|
|
|
*/
|
2018-10-16 18:44:43 +02:00
|
|
|
const NameData *
|
2001-10-23 19:39:03 +02:00
|
|
|
attnumAttName(Relation rd, int attid)
|
|
|
|
{
|
|
|
|
if (attid <= 0)
|
|
|
|
{
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *sysatt;
|
2001-10-23 19:39:03 +02:00
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
sysatt = SystemAttributeDefinition(attid);
|
2001-10-23 19:39:03 +02:00
|
|
|
return &sysatt->attname;
|
|
|
|
}
|
|
|
|
if (attid > rd->rd_att->natts)
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "invalid attribute number %d", attid);
|
2017-08-20 20:19:07 +02:00
|
|
|
return &TupleDescAttr(rd->rd_att, attid - 1)->attname;
|
2001-10-23 19:39:03 +02:00
|
|
|
}
|
|
|
|
|
1998-01-20 06:05:08 +01:00
|
|
|
/*
|
2001-10-23 00:47:57 +02:00
|
|
|
* given attribute id, return type of that attribute
|
|
|
|
*
|
1998-01-20 06:05:08 +01:00
|
|
|
* This should only be used if the relation is already
|
2019-01-21 19:32:19 +01:00
|
|
|
* table_open()'ed. Use the cache version get_atttype()
|
1998-01-20 06:05:08 +01:00
|
|
|
* for access to non-opened relations.
|
|
|
|
*/
|
1997-11-25 23:07:18 +01:00
|
|
|
Oid
|
|
|
|
attnumTypeId(Relation rd, int attid)
|
|
|
|
{
|
2001-10-23 00:47:57 +02:00
|
|
|
if (attid <= 0)
|
2000-06-20 03:41:22 +02:00
|
|
|
{
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *sysatt;
|
2000-06-20 03:41:22 +02:00
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
sysatt = SystemAttributeDefinition(attid);
|
2001-10-23 00:47:57 +02:00
|
|
|
return sysatt->atttypid;
|
2000-06-20 03:41:22 +02:00
|
|
|
}
|
2001-10-23 19:39:03 +02:00
|
|
|
if (attid > rd->rd_att->natts)
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "invalid attribute number %d", attid);
|
2017-08-20 20:19:07 +02:00
|
|
|
return TupleDescAttr(rd->rd_att, attid - 1)->atttypid;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
2000-06-03 06:41:34 +02:00
|
|
|
|
2011-04-12 03:32:53 +02:00
|
|
|
/*
|
|
|
|
* given attribute id, return collation of that attribute
|
|
|
|
*
|
2019-01-21 19:32:19 +01:00
|
|
|
* This should only be used if the relation is already table_open()'ed.
|
2011-04-12 03:32:53 +02:00
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
attnumCollationId(Relation rd, int attid)
|
|
|
|
{
|
|
|
|
if (attid <= 0)
|
|
|
|
{
|
|
|
|
/* All system attributes are of noncollatable types. */
|
|
|
|
return InvalidOid;
|
|
|
|
}
|
|
|
|
if (attid > rd->rd_att->natts)
|
|
|
|
elog(ERROR, "invalid attribute number %d", attid);
|
2017-08-20 20:19:07 +02:00
|
|
|
return TupleDescAttr(rd->rd_att, attid - 1)->attcollation;
|
2011-04-12 03:32:53 +02:00
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2009-10-21 22:22:38 +02:00
|
|
|
* Generate a suitable error about a missing RTE.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2009-10-21 22:22:38 +02:00
|
|
|
* Since this is a very common type of error, we work rather hard to
|
|
|
|
* produce a helpful message.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2009-10-21 22:22:38 +02:00
|
|
|
void
|
|
|
|
errorMissingRTE(ParseState *pstate, RangeVar *relation)
|
2000-06-03 06:41:34 +02:00
|
|
|
{
|
2006-01-10 22:59:59 +01:00
|
|
|
RangeTblEntry *rte;
|
|
|
|
const char *badAlias = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if there are any potential matches in the query's
|
2009-10-31 02:41:31 +01:00
|
|
|
* rangetable. (Note: cases involving a bad schema name in the RangeVar
|
|
|
|
* will throw error immediately here. That seems OK.)
|
2006-01-10 22:59:59 +01:00
|
|
|
*/
|
2012-08-08 01:02:54 +02:00
|
|
|
rte = searchRangeTableForRel(pstate, relation);
|
2006-01-10 22:59:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we found a match that has an alias and the alias is visible in the
|
|
|
|
* namespace, then the problem is probably use of the relation's real name
|
|
|
|
* instead of its alias, ie "SELECT foo.* FROM foo f". This mistake is
|
|
|
|
* common enough to justify a specific hint.
|
|
|
|
*
|
|
|
|
* If we found a match that doesn't meet those criteria, assume the
|
|
|
|
* problem is illegal use of a relation outside its scope, as in the
|
|
|
|
* MySQL-ism "SELECT ... FROM a, b LEFT JOIN c ON (a.x = c.y)".
|
|
|
|
*/
|
|
|
|
if (rte && rte->alias &&
|
2019-12-26 17:16:42 +01:00
|
|
|
strcmp(rte->eref->aliasname, relation->relname) != 0)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem;
|
|
|
|
int sublevels_up;
|
|
|
|
|
|
|
|
nsitem = refnameNamespaceItem(pstate, NULL, rte->eref->aliasname,
|
|
|
|
relation->location,
|
|
|
|
&sublevels_up);
|
|
|
|
if (nsitem && nsitem->p_rte == rte)
|
|
|
|
badAlias = rte->eref->aliasname;
|
|
|
|
}
|
2006-01-10 22:59:59 +01:00
|
|
|
|
2022-11-23 00:46:31 +01:00
|
|
|
/* If it looks like the user forgot to use an alias, hint about that */
|
|
|
|
if (badAlias)
|
2009-10-21 22:22:38 +02:00
|
|
|
ereport(ERROR,
|
2006-01-10 22:59:59 +01:00
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
2009-10-21 22:22:38 +02:00
|
|
|
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
2008-10-06 04:12:56 +02:00
|
|
|
relation->relname),
|
2022-11-23 00:46:31 +01:00
|
|
|
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
|
|
|
badAlias),
|
2009-10-21 22:22:38 +02:00
|
|
|
parser_errposition(pstate, relation->location)));
|
2022-11-23 00:46:31 +01:00
|
|
|
/* Hint about case where we found an (inaccessible) exact match */
|
|
|
|
else if (rte)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
|
|
|
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
|
|
|
relation->relname),
|
|
|
|
errdetail("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
|
|
|
rte->eref->aliasname),
|
|
|
|
rte_visible_if_lateral(pstate, rte) ?
|
|
|
|
errhint("To reference that table, you must mark this subquery with LATERAL.") : 0,
|
|
|
|
parser_errposition(pstate, relation->location)));
|
|
|
|
/* Else, we have nothing to offer but the bald statement of error */
|
2009-10-21 22:22:38 +02:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
|
|
|
errmsg("missing FROM-clause entry for table \"%s\"",
|
|
|
|
relation->relname),
|
2008-09-01 22:42:46 +02:00
|
|
|
parser_errposition(pstate, relation->location)));
|
2000-06-03 06:41:34 +02:00
|
|
|
}
|
2012-08-08 01:02:54 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate a suitable error about a missing column.
|
|
|
|
*
|
|
|
|
* Since this is a very common type of error, we work rather hard to
|
|
|
|
* produce a helpful message.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
errorMissingColumn(ParseState *pstate,
|
2017-10-31 15:34:31 +01:00
|
|
|
const char *relname, const char *colname, int location)
|
2012-08-08 01:02:54 +02:00
|
|
|
{
|
2015-03-11 15:44:04 +01:00
|
|
|
FuzzyAttrMatchState *state;
|
2012-08-08 01:02:54 +02:00
|
|
|
|
|
|
|
/*
|
2015-03-11 15:44:04 +01:00
|
|
|
* Search the entire rtable looking for possible matches. If we find one,
|
|
|
|
* emit a hint about it.
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2015-03-11 15:44:04 +01:00
|
|
|
state = searchRangeTableForCol(pstate, relname, colname, location);
|
2012-08-08 01:02:54 +02:00
|
|
|
|
|
|
|
/*
|
2022-11-23 00:46:31 +01:00
|
|
|
* If there are exact match(es), they must be inaccessible for some
|
|
|
|
* reason.
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2022-11-23 00:46:31 +01:00
|
|
|
if (state->rexact1)
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
|
|
|
/*
|
2022-11-23 00:46:31 +01:00
|
|
|
* We don't try too hard when there's multiple inaccessible exact
|
|
|
|
* matches, but at least be sure that we don't misleadingly suggest
|
|
|
|
* that there's only one.
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
2022-11-23 00:46:31 +01:00
|
|
|
if (state->rexact2)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
|
|
|
errdetail("There are columns named \"%s\", but they are in tables that cannot be referenced from this part of the query.",
|
|
|
|
colname),
|
|
|
|
!relname ? errhint("Try using a table-qualified name.") : 0,
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
/* Single exact match, so try to determine why it's inaccessible. */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
|
|
|
errdetail("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
|
|
|
|
colname, state->rexact1->eref->aliasname),
|
|
|
|
rte_visible_if_lateral(pstate, state->rexact1) ?
|
|
|
|
errhint("To reference that column, you must mark this subquery with LATERAL.") :
|
|
|
|
(!relname && rte_visible_if_qualified(pstate, state->rexact1)) ?
|
|
|
|
errhint("To reference that column, you must use a table-qualified name.") : 0,
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state->rsecond)
|
|
|
|
{
|
|
|
|
/* If we found no match at all, we have little to report */
|
|
|
|
if (!state->rfirst)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
/* Handle case where we have a single alternative spelling to offer */
|
2015-03-11 15:44:04 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
2015-11-17 03:16:42 +01:00
|
|
|
errhint("Perhaps you meant to reference the column \"%s.%s\".",
|
2022-11-23 00:46:31 +01:00
|
|
|
state->rfirst->eref->aliasname,
|
|
|
|
strVal(list_nth(state->rfirst->eref->colnames,
|
|
|
|
state->first - 1))),
|
2015-03-11 15:44:04 +01:00
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle case where there are two equally useful column hints */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
2015-11-17 03:16:42 +01:00
|
|
|
errhint("Perhaps you meant to reference the column \"%s.%s\" or the column \"%s.%s\".",
|
2022-11-23 00:46:31 +01:00
|
|
|
state->rfirst->eref->aliasname,
|
|
|
|
strVal(list_nth(state->rfirst->eref->colnames,
|
|
|
|
state->first - 1)),
|
|
|
|
state->rsecond->eref->aliasname,
|
|
|
|
strVal(list_nth(state->rsecond->eref->colnames,
|
|
|
|
state->second - 1))),
|
2015-03-11 15:44:04 +01:00
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
|
2022-11-23 00:46:31 +01:00
|
|
|
/*
|
|
|
|
* Find ParseNamespaceItem for RTE, if it's visible at all.
|
|
|
|
* We assume an RTE couldn't appear more than once in the namespace lists.
|
|
|
|
*/
|
|
|
|
static ParseNamespaceItem *
|
|
|
|
findNSItemForRTE(ParseState *pstate, RangeTblEntry *rte)
|
|
|
|
{
|
|
|
|
while (pstate != NULL)
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, pstate->p_namespace)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
|
|
|
|
|
|
|
|
if (nsitem->p_rte == rte)
|
|
|
|
return nsitem;
|
|
|
|
}
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Would this RTE be visible, if only the user had written LATERAL?
|
|
|
|
*
|
|
|
|
* This is a helper for deciding whether to issue a HINT about LATERAL.
|
|
|
|
* As such, it doesn't need to be 100% accurate; the HINT could be useful
|
|
|
|
* even if it's not quite right. Hence, we don't delve into fine points
|
|
|
|
* about whether a found nsitem has the appropriate one of p_rel_visible or
|
|
|
|
* p_cols_visible set.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem;
|
|
|
|
|
|
|
|
/* If LATERAL *is* active, we're clearly barking up the wrong tree */
|
|
|
|
if (pstate->p_lateral_active)
|
|
|
|
return false;
|
|
|
|
nsitem = findNSItemForRTE(pstate, rte);
|
|
|
|
if (nsitem)
|
|
|
|
{
|
|
|
|
/* Found it, report whether it's LATERAL-only */
|
|
|
|
return nsitem->p_lateral_only && nsitem->p_lateral_ok;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Would columns in this RTE be visible if qualified?
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem = findNSItemForRTE(pstate, rte);
|
|
|
|
|
|
|
|
if (nsitem)
|
|
|
|
{
|
|
|
|
/* Found it, report whether it's relation-only */
|
|
|
|
return nsitem->p_rel_visible && !nsitem->p_cols_visible;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
|
|
|
|
/*
|
2017-08-16 06:22:32 +02:00
|
|
|
* Examine a fully-parsed query, and return true iff any relation underlying
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
* the query is a temporary relation (table, view, or materialized view).
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
isQueryUsingTempRelation(Query *query)
|
|
|
|
{
|
|
|
|
return isQueryUsingTempRelation_walker((Node *) query, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
isQueryUsingTempRelation_walker(Node *node, void *context)
|
|
|
|
{
|
|
|
|
if (node == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (IsA(node, Query))
|
|
|
|
{
|
|
|
|
Query *query = (Query *) node;
|
|
|
|
ListCell *rtable;
|
|
|
|
|
|
|
|
foreach(rtable, query->rtable)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = lfirst(rtable);
|
|
|
|
|
|
|
|
if (rte->rtekind == RTE_RELATION)
|
|
|
|
{
|
2019-01-21 19:32:19 +01:00
|
|
|
Relation rel = table_open(rte->relid, AccessShareLock);
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
char relpersistence = rel->rd_rel->relpersistence;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, AccessShareLock);
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
if (relpersistence == RELPERSISTENCE_TEMP)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return query_tree_walker(query,
|
|
|
|
isQueryUsingTempRelation_walker,
|
|
|
|
context,
|
|
|
|
QTW_IGNORE_JOINALIASES);
|
|
|
|
}
|
|
|
|
|
|
|
|
return expression_tree_walker(node,
|
|
|
|
isQueryUsingTempRelation_walker,
|
|
|
|
context);
|
|
|
|
}
|
2022-12-06 16:09:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* addRTEPermissionInfo
|
|
|
|
* Creates RTEPermissionInfo for a given RTE and adds it into the
|
|
|
|
* provided list.
|
|
|
|
*
|
|
|
|
* Returns the RTEPermissionInfo and sets rte->perminfoindex.
|
|
|
|
*/
|
|
|
|
RTEPermissionInfo *
|
|
|
|
addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
|
|
|
|
{
|
|
|
|
RTEPermissionInfo *perminfo;
|
|
|
|
|
2023-01-18 19:23:57 +01:00
|
|
|
Assert(OidIsValid(rte->relid));
|
2022-12-06 16:09:24 +01:00
|
|
|
Assert(rte->perminfoindex == 0);
|
|
|
|
|
|
|
|
/* Nope, so make one and add to the list. */
|
|
|
|
perminfo = makeNode(RTEPermissionInfo);
|
|
|
|
perminfo->relid = rte->relid;
|
|
|
|
perminfo->inh = rte->inh;
|
|
|
|
/* Other information is set by fetching the node as and where needed. */
|
|
|
|
|
|
|
|
*rteperminfos = lappend(*rteperminfos, perminfo);
|
|
|
|
|
|
|
|
/* Note its index (1-based!) */
|
|
|
|
rte->perminfoindex = list_length(*rteperminfos);
|
|
|
|
|
|
|
|
return perminfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* getRTEPermissionInfo
|
|
|
|
* Find RTEPermissionInfo for a given relation in the provided list.
|
|
|
|
*
|
|
|
|
* This is a simple list_nth() operation, though it's good to have the
|
|
|
|
* function for the various sanity checks.
|
|
|
|
*/
|
|
|
|
RTEPermissionInfo *
|
|
|
|
getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
|
|
|
|
{
|
|
|
|
RTEPermissionInfo *perminfo;
|
|
|
|
|
|
|
|
if (rte->perminfoindex == 0 ||
|
|
|
|
rte->perminfoindex > list_length(rteperminfos))
|
2023-02-10 12:00:51 +01:00
|
|
|
elog(ERROR, "invalid perminfoindex %u in RTE with relid %u",
|
2022-12-06 16:09:24 +01:00
|
|
|
rte->perminfoindex, rte->relid);
|
|
|
|
perminfo = list_nth_node(RTEPermissionInfo, rteperminfos,
|
|
|
|
rte->perminfoindex - 1);
|
|
|
|
if (perminfo->relid != rte->relid)
|
|
|
|
elog(ERROR, "permission info at index %u (with relid=%u) does not match provided RTE (with relid=%u)",
|
|
|
|
rte->perminfoindex, perminfo->relid, rte->relid);
|
|
|
|
|
|
|
|
return perminfo;
|
|
|
|
}
|