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
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, 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"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "access/sysattr.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"
|
2000-09-12 23:07:18 +02:00
|
|
|
#include "parser/parsetree.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"
|
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
|
|
|
|
2005-04-01 00:46:33 +02:00
|
|
|
|
2015-03-11 15:44:04 +01:00
|
|
|
#define MAX_FUZZY_DISTANCE 3
|
|
|
|
|
2005-06-05 02:38:11 +02:00
|
|
|
static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
|
2008-09-01 22:42:46 +02:00
|
|
|
const char *refname, int location);
|
|
|
|
static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
|
2009-06-11 16:49:15 +02:00
|
|
|
int location);
|
2014-01-12 01:03:12 +01:00
|
|
|
static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
|
|
|
|
int location);
|
2009-01-22 21:16:10 +01:00
|
|
|
static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
2009-06-11 16:49:15 +02:00
|
|
|
int rtindex, AttrNumber col);
|
2004-08-19 22:57:41 +02:00
|
|
|
static void expandRelation(Oid relid, Alias *eref,
|
2004-08-29 07:07:03 +02:00
|
|
|
int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2004-08-29 07:07:03 +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-10-15 04:49:52 +02:00
|
|
|
int rtindex, int sublevels_up,
|
2008-09-01 22:42:46 +02:00
|
|
|
int location, bool include_dropped,
|
2005-10-15 04:49:52 +02:00
|
|
|
List **colnames, List **colvars);
|
2002-08-02 20:15:10 +02:00
|
|
|
static int specialAttNum(const char *attname);
|
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
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-03-12 01:52:10 +01:00
|
|
|
* refnameRangeTblEntry
|
2002-08-08 03:44:31 +02:00
|
|
|
* Given a possibly-qualified refname, look to see if it matches any RTE.
|
|
|
|
* If so, return a pointer to the RangeTblEntry; else return NULL.
|
|
|
|
*
|
|
|
|
* Optionally get RTE's nesting depth (0 = current) into *sublevels_up.
|
|
|
|
* If sublevels_up is NULL, only consider items at the current nesting
|
|
|
|
* level.
|
|
|
|
*
|
|
|
|
* An unqualified refname (schemaname == NULL) can match any RTE with matching
|
|
|
|
* alias, or matching unqualified relname in the case of alias-less relation
|
|
|
|
* RTEs. It is possible that such a refname matches multiple RTEs 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
|
|
|
*
|
|
|
|
* A qualified refname (schemaname != NULL) can only match a relation RTE
|
|
|
|
* that (a) has no alias and (b) is for the same relation identified by
|
2014-05-06 18:12:18 +02:00
|
|
|
* schemaname.refname. In this case we convert schemaname.refname to a
|
2002-08-08 03:44:31 +02:00
|
|
|
* 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
|
|
|
*/
|
2002-03-12 01:52:10 +01:00
|
|
|
RangeTblEntry *
|
|
|
|
refnameRangeTblEntry(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
|
2010-02-26 03:01:40 +01:00
|
|
|
* 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.
|
2009-10-31 02:41:31 +01:00
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
RangeTblEntry *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
|
|
|
/*
|
2005-06-05 02:38:11 +02:00
|
|
|
* Search the query's table namespace for an RTE matching the
|
|
|
|
* given unqualified refname. Return the RTE 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
|
|
|
*/
|
2005-06-05 02:38:11 +02:00
|
|
|
static RangeTblEntry *
|
2008-09-01 22:42:46 +02:00
|
|
|
scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
RangeTblEntry *result = NULL;
|
|
|
|
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);
|
|
|
|
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;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2002-03-21 17:02:16 +01:00
|
|
|
if (strcmp(rte->eref->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);
|
2005-06-05 02:38:11 +02:00
|
|
|
result = rte;
|
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
|
|
|
/*
|
2005-06-05 02:38:11 +02:00
|
|
|
* Search the query's table namespace for a relation RTE matching the
|
2014-05-06 18:12:18 +02:00
|
|
|
* given relation OID. Return the RTE 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
|
|
|
*
|
|
|
|
* See the comments for refnameRangeTblEntry to understand why this
|
|
|
|
* acts the way it does.
|
|
|
|
*/
|
2005-06-05 02:38:11 +02:00
|
|
|
static RangeTblEntry *
|
2008-09-01 22:42:46 +02:00
|
|
|
scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2005-06-05 02:38:11 +02:00
|
|
|
RangeTblEntry *result = NULL;
|
|
|
|
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);
|
2005-06-05 02:38:11 +02:00
|
|
|
result = rte;
|
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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Index levelsup;
|
2008-10-06 04:12:56 +02:00
|
|
|
|
|
|
|
for (levelsup = 0;
|
|
|
|
pstate != NULL;
|
|
|
|
pstate = pstate->parentParseState, levelsup++)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
ListCell *lc;
|
2008-10-06 04:12:56 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
ListCell *lc;
|
2008-10-08 03:14:44 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
* This is different from refnameRangeTblEntry in that it considers every
|
|
|
|
* entry in the ParseState's rangetable(s), not only those that are currently
|
2014-05-06 18:12:18 +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
|
|
|
/*
|
2009-06-11 16:49:15 +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
|
2014-05-06 18:12:18 +02:00
|
|
|
* 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
|
2011-07-09 04:19:30 +02:00
|
|
|
* the query are already locked, which reduces the number of cases in
|
2012-06-10 21:20:04 +02:00
|
|
|
* 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;
|
2005-06-05 02:38:11 +02:00
|
|
|
const char *aliasname1 = rte1->eref->aliasname;
|
|
|
|
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;
|
2005-06-05 02:38:11 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
if (!nsitem2->p_rel_visible)
|
|
|
|
continue;
|
2005-06-05 02:38:11 +02:00
|
|
|
if (strcmp(rte2->eref->aliasname, aliasname1) != 0)
|
|
|
|
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-08-04 02:43:34 +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.
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
char *refname = rte->eref->aliasname;
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
|
|
|
refname),
|
|
|
|
(rte == pstate->p_target_rangetblentry) ?
|
|
|
|
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
|
|
|
/*
|
2000-09-12 23:07:18 +02:00
|
|
|
* given an RTE, return RT index (starting with 1) of the entry,
|
2014-05-06 18:12:18 +02:00
|
|
|
* and optionally get its nesting depth (0 = current). If sublevels_up
|
2000-09-12 23:07:18 +02:00
|
|
|
* is NULL, only consider rels at the current nesting level.
|
|
|
|
* Raises error if RTE not found.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2000-09-12 23:07:18 +02:00
|
|
|
int
|
|
|
|
RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2000-09-12 23:07:18 +02:00
|
|
|
int index;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
if (sublevels_up)
|
|
|
|
*sublevels_up = 0;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
1998-01-20 23:12:17 +01:00
|
|
|
while (pstate != NULL)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2000-09-12 23:07:18 +02:00
|
|
|
index = 1;
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, pstate->p_rtable)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
if (rte == (RangeTblEntry *) lfirst(l))
|
2000-09-12 23:07:18 +02:00
|
|
|
return index;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
if (sublevels_up)
|
|
|
|
(*sublevels_up)++;
|
1998-01-20 23:12:17 +01:00
|
|
|
else
|
2000-09-12 23:07:18 +02:00
|
|
|
break;
|
|
|
|
}
|
2001-02-14 22:35:07 +01:00
|
|
|
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "RTE not found (internal error)");
|
2000-09-12 23:07:18 +02:00
|
|
|
return 0; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
2004-04-02 21:07:02 +02:00
|
|
|
/*
|
|
|
|
* Given an RT index and nesting depth, find the corresponding RTE.
|
|
|
|
* This is the inverse of RTERangeTablePosn.
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
* RTE came from. Callers that don't have this information readily available
|
|
|
|
* may pass -1 instead.
|
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;
|
|
|
|
|
2008-10-06 17:15:22 +02:00
|
|
|
/* Determine RTE's levelsup if caller didn't know it */
|
|
|
|
if (rtelevelsup < 0)
|
|
|
|
(void) RTERangeTablePosn(pstate, rte, &rtelevelsup);
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
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)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
int columndistance;
|
|
|
|
int matchlen;
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* From this point on, we can ignore the distinction between the RTE-name
|
|
|
|
* distance and the column-name distance.
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
/* Store new lowest observed distance for RTE */
|
|
|
|
fuzzystate->distance = columndistance;
|
|
|
|
fuzzystate->rfirst = rte;
|
|
|
|
fuzzystate->first = attnum;
|
|
|
|
fuzzystate->rsecond = NULL;
|
|
|
|
fuzzystate->second = InvalidAttrNumber;
|
|
|
|
}
|
|
|
|
else if (columndistance == fuzzystate->distance)
|
|
|
|
{
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* This match distance may equal a prior match within this same range
|
|
|
|
* table. When that happens, the prior match may also be given, but
|
|
|
|
* only if there is no more than two equally distant matches from the
|
|
|
|
* RTE (in turn, our caller will only accept two equally distant
|
|
|
|
* matches overall).
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
|
|
|
if (AttributeNumberIsValid(fuzzystate->second))
|
|
|
|
{
|
|
|
|
/* Too many RTE-level matches */
|
|
|
|
fuzzystate->rfirst = NULL;
|
|
|
|
fuzzystate->first = InvalidAttrNumber;
|
|
|
|
fuzzystate->rsecond = NULL;
|
|
|
|
fuzzystate->second = InvalidAttrNumber;
|
|
|
|
/* Clearly, distance is too low a bar (for *any* RTE) */
|
|
|
|
fuzzystate->distance = columndistance - 1;
|
|
|
|
}
|
|
|
|
else if (AttributeNumberIsValid(fuzzystate->first))
|
|
|
|
{
|
|
|
|
/* Record as provisional second match for RTE */
|
|
|
|
fuzzystate->rsecond = rte;
|
|
|
|
fuzzystate->second = attnum;
|
|
|
|
}
|
|
|
|
else if (fuzzystate->distance <= MAX_FUZZY_DISTANCE)
|
|
|
|
{
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Record as provisional first match (this can occasionally occur
|
|
|
|
* because previous lowest distance was "too low a bar", rather
|
|
|
|
* than being associated with a real match)
|
2015-03-11 15:44:04 +01:00
|
|
|
*/
|
|
|
|
fuzzystate->rfirst = rte;
|
|
|
|
fuzzystate->first = attnum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
|
|
|
* scanRTEForColumn
|
|
|
|
* Search the column names of a single RTE for the given name.
|
|
|
|
* If found, return an appropriate Var node, else return NULL.
|
|
|
|
* If the name proves ambiguous within this RTE, raise error.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
2009-01-22 21:16:10 +01:00
|
|
|
* Side effect: if we find a match, mark the RTE as requiring read access
|
|
|
|
* for the column.
|
2015-03-11 15:44:04 +01:00
|
|
|
*
|
|
|
|
* Additional side effect: if fuzzystate is non-NULL, check non-system columns
|
|
|
|
* for an approximate match and update fuzzystate accordingly.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2004-04-02 21:07:02 +02:00
|
|
|
Node *
|
2006-03-14 23:48:25 +01:00
|
|
|
scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
|
2015-03-11 15:44:04 +01:00
|
|
|
int location, int fuzzy_rte_penalty,
|
|
|
|
FuzzyAttrMatchState *fuzzystate)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
|
|
|
Node *result = NULL;
|
|
|
|
int attnum = 0;
|
2009-01-22 21:16:10 +01:00
|
|
|
Var *var;
|
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
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Scan the user column names (or aliases) for a match. Complain if
|
|
|
|
* multiple matches.
|
2002-08-02 20:15:10 +02:00
|
|
|
*
|
2005-10-15 04:49:52 +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
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* Should this somehow go wrong and we try to access a dropped column,
|
|
|
|
* we'll still catch it by virtue of the checks in
|
|
|
|
* get_rte_attribute_type(), which is called by make_var(). That routine
|
2015-03-11 15:44:04 +01:00
|
|
|
* has to do a cache lookup anyway, so the check there is cheap. Callers
|
|
|
|
* interested in finding match with shortest distance need to defend
|
|
|
|
* against this directly, though.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2002-03-21 17:02:16 +01:00
|
|
|
foreach(c, rte->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)));
|
2009-01-22 21:16:10 +01:00
|
|
|
var = make_var(pstate, rte, attnum, location);
|
|
|
|
/* Require read access to the column */
|
|
|
|
markVarForSelectPriv(pstate, var, rte);
|
|
|
|
result = (Node *) var;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
/* Updating fuzzy match state, if provided. */
|
|
|
|
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);
|
Don't allow system columns in CHECK constraints, except tableoid.
Previously, arbitray system columns could be mentioned in table
constraints, but they were not correctly checked at runtime, because
the values weren't actually set correctly in the tuple. Since it
seems easy enough to initialize the table OID properly, do that,
and continue allowing that column, but disallow the rest unless and
until someone figures out a way to make them work properly.
No back-patch, because this doesn't seem important enough to take the
risk of destabilizing the back branches. In fact, this will pose a
dump-and-reload hazard for those upgrading from previous versions:
constraints that were accepted before but were not correctly enforced
will now either be enforced correctly or not accepted at all. Either
could result in restore failures, but in practice I think very few
users will notice the difference, since the use case is pretty
marginal anyway and few users will be relying on features that have
not historically worked.
Amit Kapila, reviewed by Rushabh Lathia, with doc changes by me.
2013-09-23 19:31:22 +02:00
|
|
|
|
|
|
|
/* In constraint check, no system column is allowed except tableOid */
|
|
|
|
if (pstate->p_expr_kind == EXPR_KIND_CHECK_CONSTRAINT &&
|
2014-05-06 18:12:18 +02:00
|
|
|
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
|
Don't allow system columns in CHECK constraints, except tableoid.
Previously, arbitray system columns could be mentioned in table
constraints, but they were not correctly checked at runtime, because
the values weren't actually set correctly in the tuple. Since it
seems easy enough to initialize the table OID properly, do that,
and continue allowing that column, but disallow the rest unless and
until someone figures out a way to make them work properly.
No back-patch, because this doesn't seem important enough to take the
risk of destabilizing the back branches. In fact, this will pose a
dump-and-reload hazard for those upgrading from previous versions:
constraints that were accepted before but were not correctly enforced
will now either be enforced correctly or not accepted at all. Either
could result in restore failures, but in practice I think very few
users will notice the difference, since the use case is pretty
marginal anyway and few users will be relying on features that have
not historically worked.
Amit Kapila, reviewed by Rushabh Lathia, with doc changes by me.
2013-09-23 19:31:22 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("system column \"%s\" reference in check constraint is invalid",
|
2014-05-06 18:12:18 +02:00
|
|
|
colname),
|
Don't allow system columns in CHECK constraints, except tableoid.
Previously, arbitray system columns could be mentioned in table
constraints, but they were not correctly checked at runtime, because
the values weren't actually set correctly in the tuple. Since it
seems easy enough to initialize the table OID properly, do that,
and continue allowing that column, but disallow the rest unless and
until someone figures out a way to make them work properly.
No back-patch, because this doesn't seem important enough to take the
risk of destabilizing the back branches. In fact, this will pose a
dump-and-reload hazard for those upgrading from previous versions:
constraints that were accepted before but were not correctly enforced
will now either be enforced correctly or not accepted at all. Either
could result in restore failures, but in practice I think very few
users will notice the difference, since the use case is pretty
marginal anyway and few users will be relying on features that have
not historically worked.
Amit Kapila, reviewed by Rushabh Lathia, with doc changes by me.
2013-09-23 19:31:22 +02:00
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
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)))
|
2001-08-10 20:57:42 +02:00
|
|
|
{
|
2009-01-22 21:16:10 +01:00
|
|
|
var = make_var(pstate, rte, attnum, location);
|
|
|
|
/* Require read access to the column */
|
|
|
|
markVarForSelectPriv(pstate, var, rte);
|
|
|
|
result = (Node *) var;
|
2001-08-10 20:57:42 +02:00
|
|
|
}
|
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 *
|
2006-03-14 23:48:25 +01:00
|
|
|
colNameToVar(ParseState *pstate, char *colname, bool localonly,
|
|
|
|
int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
|
|
|
Node *result = NULL;
|
|
|
|
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);
|
|
|
|
RangeTblEntry *rte = nsitem->p_rte;
|
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;
|
|
|
|
|
2005-06-05 02:38:11 +02:00
|
|
|
/* use orig_pstate here to get the right sublevels_up */
|
2015-03-11 15:44:04 +01:00
|
|
|
newresult = scanRTEForColumn(orig_pstate, rte, colname, location,
|
|
|
|
0, NULL);
|
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),
|
2005-10-15 04:49:52 +02:00
|
|
|
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;
|
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
|
2014-05-06 18:12:18 +02:00
|
|
|
* in the p_namespace list(s). This behavior is invalid per the SQL spec,
|
2012-08-08 01:02:54 +02:00
|
|
|
* and it may give ambiguous results (there might be multiple equally valid
|
|
|
|
* matches, but only one will be returned). 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
|
|
|
|
* type and provide a reasonable hint.
|
|
|
|
*
|
|
|
|
* The FuzzyAttrMatchState will have 'rfirst' pointing to the best RTE
|
|
|
|
* containing the most promising match for the alias and column name. If
|
|
|
|
* the alias and column names match exactly, 'first' will be InvalidAttrNumber;
|
|
|
|
* otherwise, it will be the attribute number for the match. In the latter
|
|
|
|
* case, 'rsecond' may point to a second, equally close approximate match,
|
|
|
|
* and 'second' will contain the attribute number for the second match.
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2015-03-11 15:44:04 +01:00
|
|
|
static FuzzyAttrMatchState *
|
|
|
|
searchRangeTableForCol(ParseState *pstate, const char *alias, char *colname,
|
|
|
|
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;
|
|
|
|
fuzzystate->first = InvalidAttrNumber;
|
|
|
|
fuzzystate->second = InvalidAttrNumber;
|
2012-08-08 01:02:54 +02:00
|
|
|
|
|
|
|
while (pstate != NULL)
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, pstate->p_rtable)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
|
|
int fuzzy_rte_penalty = 0;
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan for a matching column; if we find an exact match, we're
|
|
|
|
* done. Otherwise, update fuzzystate.
|
|
|
|
*/
|
|
|
|
if (scanRTEForColumn(orig_pstate, rte, colname, location,
|
|
|
|
fuzzy_rte_penalty, fuzzystate)
|
2015-05-24 03:35:49 +02:00
|
|
|
&& fuzzy_rte_penalty == 0)
|
2015-03-11 15:44:04 +01:00
|
|
|
{
|
|
|
|
fuzzystate->rfirst = rte;
|
|
|
|
fuzzystate->first = InvalidAttrNumber;
|
|
|
|
fuzzystate->rsecond = NULL;
|
|
|
|
fuzzystate->second = InvalidAttrNumber;
|
|
|
|
return fuzzystate;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
/*
|
|
|
|
* markRTEForSelectPriv
|
|
|
|
* Mark the specified column of an RTE as requiring SELECT privilege
|
|
|
|
*
|
|
|
|
* col == InvalidAttrNumber means a "whole row" reference
|
|
|
|
*
|
|
|
|
* The caller should pass the actual RTE if it has it handy; otherwise pass
|
|
|
|
* NULL, and we'll look it up here. (This uglification of the API is
|
|
|
|
* worthwhile because nearly all external callers have the RTE at hand.)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
|
|
|
int rtindex, AttrNumber col)
|
|
|
|
{
|
|
|
|
if (rte == NULL)
|
|
|
|
rte = rt_fetch(rtindex, pstate->p_rtable);
|
|
|
|
|
|
|
|
if (rte->rtekind == RTE_RELATION)
|
|
|
|
{
|
|
|
|
/* Make sure the rel as a whole is marked for SELECT access */
|
|
|
|
rte->requiredPerms |= ACL_SELECT;
|
|
|
|
/* Must offset the attnum to fit in a bitmapset */
|
|
|
|
rte->selectedCols = bms_add_member(rte->selectedCols,
|
2009-06-11 16:49:15 +02:00
|
|
|
col - FirstLowInvalidHeapAttributeNumber);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
|
|
|
else if (rte->rtekind == RTE_JOIN)
|
|
|
|
{
|
|
|
|
if (col == InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* A whole-row reference to a join has to be treated as whole-row
|
|
|
|
* references to the two inputs.
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
|
|
|
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))
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int varno = ((RangeTblRef *) j->larg)->rtindex;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
|
|
}
|
|
|
|
else if (IsA(j->larg, JoinExpr))
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int varno = ((JoinExpr *) j->larg)->rtindex;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(j->larg));
|
|
|
|
if (IsA(j->rarg, RangeTblRef))
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int varno = ((RangeTblRef *) j->rarg)->rtindex;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
|
|
}
|
|
|
|
else if (IsA(j->rarg, JoinExpr))
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int varno = ((JoinExpr *) j->rarg)->rtindex;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(j->rarg));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Regular join attribute, look at the alias-variable list.
|
|
|
|
*
|
|
|
|
* The aliasvar could be either a Var or a COALESCE expression,
|
|
|
|
* but in the latter case we should already have marked the two
|
|
|
|
* referent variables as being selected, due to their use in the
|
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
|
|
|
* JOIN clause. So we need only be concerned with the Var case.
|
|
|
|
* But we do need to drill down through implicit coercions.
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
2009-06-11 16:49:15 +02:00
|
|
|
Var *aliasvar;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
Assert(col > 0 && col <= list_length(rte->joinaliasvars));
|
|
|
|
aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1);
|
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
|
|
|
aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
|
|
|
|
if (aliasvar && IsA(aliasvar, Var))
|
2009-01-22 21:16:10 +01:00
|
|
|
markVarForSelectPriv(pstate, aliasvar, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* other RTE types don't require privilege marking */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* markVarForSelectPriv
|
|
|
|
* Mark the RTE referenced by a Var as requiring SELECT privilege
|
|
|
|
*
|
|
|
|
* The caller should pass the Var's referenced RTE if it has it handy
|
|
|
|
* (nearly all do); otherwise pass NULL.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Index lv;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
|
|
Assert(IsA(var, Var));
|
|
|
|
/* Find the appropriate pstate if it's an uplevel Var */
|
|
|
|
for (lv = 0; lv < var->varlevelsup; lv++)
|
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
markRTEForSelectPriv(pstate, rte, var->varno, var->varattno);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
ListCell *aliaslc;
|
|
|
|
int numaliases;
|
|
|
|
int varattno;
|
|
|
|
int numdropped = 0;
|
|
|
|
|
|
|
|
Assert(eref->colnames == NIL);
|
|
|
|
|
|
|
|
if (alias)
|
|
|
|
{
|
|
|
|
aliaslc = list_head(alias->colnames);
|
|
|
|
numaliases = list_length(alias->colnames);
|
|
|
|
/* We'll rebuild the alias colname list */
|
|
|
|
alias->colnames = NIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aliaslc = NULL;
|
|
|
|
numaliases = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (varattno = 0; varattno < maxattrs; varattno++)
|
|
|
|
{
|
|
|
|
Form_pg_attribute attr = tupdesc->attrs[varattno];
|
|
|
|
Value *attrname;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
attrname = (Value *) lfirst(aliaslc);
|
|
|
|
aliaslc = lnext(aliaslc);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
/*
|
|
|
|
* Open a table during parse analysis
|
|
|
|
*
|
2008-10-08 03:14:44 +02:00
|
|
|
* This is essentially just the same as heap_openrv(), except that it caters
|
|
|
|
* 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);
|
2011-06-27 21:06:32 +02:00
|
|
|
rel = heap_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
|
|
|
|
{
|
2017-04-01 06:17:18 +02:00
|
|
|
/*
|
|
|
|
* An unqualified name might be a named ephemeral relation.
|
|
|
|
*/
|
|
|
|
if (get_visible_ENR_metadata(pstate->p_queryEnv, relation->relname))
|
|
|
|
rel = NULL;
|
2017-05-17 22:31:56 +02:00
|
|
|
|
2008-10-08 03:14:44 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-04-01 06:17:18 +02:00
|
|
|
else 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).
|
|
|
|
*
|
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
|
|
|
*/
|
1997-11-25 23:07:18 +01:00
|
|
|
RangeTblEntry *
|
|
|
|
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);
|
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-04-12 19:17:23 +02:00
|
|
|
Relation rel;
|
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
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Get the rel's OID. This access also ensures that we have an up-to-date
|
2014-05-06 18:12:18 +02:00
|
|
|
* relcache entry for the rel. Since this is typically the first access
|
2005-10-15 04:49:52 +02:00
|
|
|
* to a rel in a statement, be careful to get the right access level
|
|
|
|
* depending on whether we're doing SELECT FOR UPDATE/SHARE.
|
1999-10-07 06:23:24 +02:00
|
|
|
*/
|
2009-10-27 18:11:18 +01:00
|
|
|
lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
|
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;
|
2000-03-15 00:06:59 +01:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +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
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02: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.
|
2002-03-22 03:56:37 +01:00
|
|
|
*/
|
|
|
|
heap_close(rel, NoLock);
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and 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;
|
|
|
|
|
2004-01-15 00:01:55 +01:00
|
|
|
rte->requiredPerms = ACL_SELECT;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2002-03-22 03:56:37 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- 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
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an entry for a relation to the pstate's range table (p_rtable).
|
|
|
|
*
|
|
|
|
* 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.
|
2002-03-22 03:56:37 +01:00
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
addRangeTableEntryForRelation(ParseState *pstate,
|
2005-04-13 18:50:55 +02:00
|
|
|
Relation rel,
|
2002-03-22 03:56:37 +01:00
|
|
|
Alias *alias,
|
|
|
|
bool inh,
|
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
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);
|
|
|
|
|
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;
|
2002-03-22 03:56:37 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +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
|
|
|
/*
|
|
|
|
* Set flags and 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
|
|
|
|
2004-01-15 00:01:55 +01:00
|
|
|
rte->requiredPerms = ACL_SELECT;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- 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
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
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).
|
|
|
|
*
|
|
|
|
* This is just like addRangeTableEntry() except that it makes a subquery RTE.
|
|
|
|
* Note that an alias clause *must* be supplied.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
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
|
|
|
char *refname = alias->aliasname;
|
|
|
|
Alias *eref;
|
2000-09-29 20:21:41 +02:00
|
|
|
int numaliases;
|
|
|
|
int varattno;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *tlistitem;
|
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->relid = InvalidOid;
|
|
|
|
rte->subquery = subquery;
|
|
|
|
rte->alias = alias;
|
|
|
|
|
|
|
|
eref = copyObject(alias);
|
2004-05-31 01:40:41 +02:00
|
|
|
numaliases = list_length(eref->colnames);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
/* fill in any unspecified alias columns */
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
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",
|
|
|
|
refname, varattno, numaliases)));
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
rte->eref = eref;
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
|
|
|
* Subqueries are never checked for access rights.
|
|
|
|
*/
|
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;
|
|
|
|
|
2004-01-15 00:01:55 +01:00
|
|
|
rte->requiredPerms = 0;
|
2005-06-28 07:09:14 +02:00
|
|
|
rte->checkAsUser = InvalidOid;
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- 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
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
* (p_rtable).
|
2002-05-12 22:10:05 +02:00
|
|
|
*
|
|
|
|
* This is just like addRangeTableEntry() except that it makes a function RTE.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
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;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
rtfunc->funcparams = NULL; /* not set until planning */
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* got a predetermined record type, and is prohibited otherwise.
|
|
|
|
*/
|
|
|
|
if (coldeflist != NIL)
|
|
|
|
{
|
|
|
|
if (functypclass != TYPEFUNC_RECORD)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("a column definition list is only allowed for functions returning \"record\""),
|
|
|
|
parser_errposition(pstate,
|
|
|
|
exprLocation((Node *) coldeflist))));
|
|
|
|
}
|
|
|
|
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))));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (functypclass == TYPEFUNC_COMPOSITE)
|
|
|
|
{
|
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Assert(tupdesc);
|
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_SCALAR)
|
|
|
|
{
|
|
|
|
/* Base data type, i.e. scalar */
|
|
|
|
tupdesc = CreateTemplateTupleDesc(1, false);
|
|
|
|
TupleDescInitEntry(tupdesc,
|
|
|
|
(AttrNumber) 1,
|
|
|
|
chooseScalarFunctionAlias(funcexpr, funcname,
|
|
|
|
alias, nfuncs),
|
|
|
|
funcrettype,
|
|
|
|
-1,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_RECORD)
|
|
|
|
{
|
|
|
|
ListCell *col;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the column definition list to construct a tupdesc and fill
|
|
|
|
* in the RangeTblFunction's lists.
|
|
|
|
*/
|
|
|
|
tupdesc = CreateTemplateTupleDesc(list_length(coldeflist), false);
|
|
|
|
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
|
|
|
|
* duplicates) and datatypes (no pseudo-types, for instance).
|
|
|
|
*/
|
|
|
|
CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE, false);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
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 */
|
|
|
|
tupdesc = CreateTemplateTupleDesc(totalatts, false);
|
|
|
|
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)
|
|
|
|
TupleDescInitEntry(tupdesc,
|
|
|
|
(AttrNumber) ++natts,
|
|
|
|
"ordinality",
|
|
|
|
INT8OID,
|
|
|
|
-1,
|
|
|
|
0);
|
|
|
|
|
|
|
|
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
|
|
|
*
|
2012-08-08 01:02:54 +02:00
|
|
|
* Functions are never checked for access rights (at least, not by the RTE
|
|
|
|
* permissions mechanism).
|
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;
|
|
|
|
|
2004-01-15 00:01:55 +01:00
|
|
|
rte->requiredPerms = 0;
|
2005-06-28 07:09:14 +02:00
|
|
|
rte->checkAsUser = InvalidOid;
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2002-05-12 22:10:05 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- 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
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
/*
|
|
|
|
* Add an entry for a table function to the pstate's range table (p_rtable).
|
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
addRangeTableEntryForTableFunc(ParseState *pstate,
|
|
|
|
TableFunc *tf,
|
|
|
|
Alias *alias,
|
|
|
|
bool lateral,
|
|
|
|
bool inFromCl)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
|
|
|
char *refname = alias ? alias->aliasname : pstrdup("xmltable");
|
|
|
|
Alias *eref;
|
|
|
|
int numaliases;
|
|
|
|
|
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
rte->eref = eref;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
|
|
|
*
|
|
|
|
* Tablefuncs are never checked for access rights (at least, not by the
|
|
|
|
* RTE permissions mechanism).
|
|
|
|
*/
|
|
|
|
rte->lateral = lateral;
|
|
|
|
rte->inh = false; /* never true for tablefunc RTEs */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
rte->requiredPerms = 0;
|
|
|
|
rte->checkAsUser = InvalidOid;
|
|
|
|
rte->selectedCols = NULL;
|
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- caller must do that if appropriate.
|
|
|
|
*/
|
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
/*
|
|
|
|
* Add an entry for a VALUES list to the pstate's range table (p_rtable).
|
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a values RTE.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
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)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
char attrname[64];
|
2006-08-02 03:59:48 +02:00
|
|
|
|
|
|
|
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
|
|
|
*
|
|
|
|
* Subqueries are never checked for access rights.
|
|
|
|
*/
|
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
|
|
|
rte->requiredPerms = 0;
|
|
|
|
rte->checkAsUser = InvalidOid;
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2006-08-02 03:59:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- caller must do that if appropriate.
|
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2006-08-02 03:59:48 +02:00
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
/*
|
|
|
|
* Add an entry for a join to the pstate's range table (p_rtable).
|
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a join RTE.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
addRangeTableEntryForJoin(ParseState *pstate,
|
|
|
|
List *colnames,
|
|
|
|
JoinType jointype,
|
2002-04-28 21:54:29 +02:00
|
|
|
List *aliasvars,
|
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;
|
|
|
|
|
2015-03-11 20:26:43 +01:00
|
|
|
Assert(pstate != NULL);
|
|
|
|
|
2008-04-05 03:58:20 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Fail if join has too many columns --- we must be able to reference any
|
|
|
|
* of the columns with an AttrNumber.
|
2008-04-05 03:58:20 +02:00
|
|
|
*/
|
|
|
|
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;
|
2002-04-28 21:54:29 +02:00
|
|
|
rte->joinaliasvars = aliasvars;
|
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,
|
2005-10-15 04:49:52 +02:00
|
|
|
list_copy_tail(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
|
|
|
*
|
|
|
|
* Joins are never checked for access rights.
|
|
|
|
*/
|
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;
|
|
|
|
|
2004-01-15 00:01:55 +01:00
|
|
|
rte->requiredPerms = 0;
|
2005-06-28 07:09:14 +02:00
|
|
|
rte->checkAsUser = InvalidOid;
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2002-03-12 01:52:10 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- 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
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
/*
|
|
|
|
* Add an entry for a CTE reference to the pstate's range table (p_rtable).
|
|
|
|
*
|
|
|
|
* This is much like addRangeTableEntry() except that it makes a CTE RTE.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
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;
|
|
|
|
|
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))
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
Query *ctequery = (Query *) cte->ctequery;
|
2011-02-26 00:56:23 +01:00
|
|
|
|
|
|
|
if (ctequery->commandType != CMD_SELECT &&
|
|
|
|
ctequery->returningList == NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2011-04-10 17:42:00 +02:00
|
|
|
errmsg("WITH query \"%s\" does not have a RETURNING clause",
|
|
|
|
cte->ctename),
|
2011-02-26 00:56:23 +01:00
|
|
|
parser_errposition(pstate, rv->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
|
|
|
rte->coltypes = cte->ctecoltypes;
|
|
|
|
rte->coltypmods = cte->ctecoltypmods;
|
|
|
|
rte->colcollations = 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;
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
2008-10-04 23:56:55 +02:00
|
|
|
*
|
|
|
|
* Subqueries are never checked for access rights.
|
|
|
|
*/
|
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;
|
|
|
|
|
|
|
|
rte->requiredPerms = 0;
|
|
|
|
rte->checkAsUser = InvalidOid;
|
2009-01-22 21:16:10 +01:00
|
|
|
rte->selectedCols = NULL;
|
2015-05-08 00:20:46 +02:00
|
|
|
rte->insertedCols = NULL;
|
|
|
|
rte->updatedCols = NULL;
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- caller must do that if appropriate.
|
|
|
|
*/
|
2015-03-11 20:26:43 +01:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
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).
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
RangeTblEntry *
|
|
|
|
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-05-17 22:31:56 +02:00
|
|
|
return NULL; /* for fussy compilers */
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* and/or actual column names. Also build the cannibalized fields.
|
|
|
|
*/
|
|
|
|
tupdesc = ENRMetadataGetTupDesc(enrmd);
|
|
|
|
rte->eref = makeAlias(refname, NIL);
|
|
|
|
buildRelationAliases(tupdesc, alias, rte->eref);
|
|
|
|
rte->enrname = enrmd->name;
|
|
|
|
rte->enrtuples = enrmd->enrtuples;
|
|
|
|
rte->coltypes = NIL;
|
|
|
|
rte->coltypmods = NIL;
|
|
|
|
rte->colcollations = NIL;
|
|
|
|
for (attno = 1; attno <= tupdesc->natts; ++attno)
|
|
|
|
{
|
|
|
|
if (tupdesc->attrs[attno - 1]->atttypid == InvalidOid &&
|
|
|
|
!(tupdesc->attrs[attno - 1]->attisdropped))
|
|
|
|
elog(ERROR, "atttypid was invalid for column which has not been dropped from \"%s\"",
|
|
|
|
rv->relname);
|
|
|
|
rte->coltypes =
|
|
|
|
lappend_oid(rte->coltypes,
|
|
|
|
tupdesc->attrs[attno - 1]->atttypid);
|
|
|
|
rte->coltypmods =
|
|
|
|
lappend_int(rte->coltypmods,
|
|
|
|
tupdesc->attrs[attno - 1]->atttypmod);
|
|
|
|
rte->colcollations =
|
|
|
|
lappend_oid(rte->colcollations,
|
|
|
|
tupdesc->attrs[attno - 1]->attcollation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set flags and access permissions.
|
|
|
|
*
|
|
|
|
* ENRs are never checked for access rights.
|
|
|
|
*/
|
|
|
|
rte->lateral = false;
|
|
|
|
rte->inh = false; /* never true for ENRs */
|
|
|
|
rte->inFromCl = inFromCl;
|
|
|
|
|
|
|
|
rte->requiredPerms = 0;
|
|
|
|
rte->checkAsUser = InvalidOid;
|
|
|
|
rte->selectedCols = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add completed RTE to pstate's range table list, but not to join list
|
|
|
|
* nor namespace --- caller must do that if appropriate.
|
|
|
|
*/
|
2017-04-16 20:02:47 +02:00
|
|
|
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
2017-04-01 06:17:18 +02:00
|
|
|
|
|
|
|
return rte;
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* 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
|
|
|
/*
|
2001-02-14 22:35:07 +01:00
|
|
|
* Add the given 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
|
2012-08-08 01:02:54 +02:00
|
|
|
* namespace conflicts.) The RTE is always marked as unconditionally
|
|
|
|
* visible, that is, not LATERAL-only.
|
2014-01-07 21:25:16 +01:00
|
|
|
*
|
|
|
|
* Note: some callers know that they can find the new ParseNamespaceItem
|
|
|
|
* at the end of the pstate->p_namespace list. This is a bit ugly but not
|
|
|
|
* worth complicating this function's signature for.
|
2000-02-15 04:38:29 +01:00
|
|
|
*/
|
2000-09-12 23:07:18 +02:00
|
|
|
void
|
2001-02-14 22:35:07 +01:00
|
|
|
addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
|
2005-06-05 02:38:11 +02:00
|
|
|
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
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
int rtindex = RTERangeTablePosn(pstate, rte, NULL);
|
2005-06-05 02:38:11 +02:00
|
|
|
RangeTblRef *rtr = makeNode(RangeTblRef);
|
|
|
|
|
|
|
|
rtr->rtindex = 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)
|
|
|
|
{
|
|
|
|
ParseNamespaceItem *nsitem;
|
|
|
|
|
|
|
|
nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
|
|
|
|
nsitem->p_rte = rte;
|
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.
|
|
|
|
* If include_dropped is FALSE then dropped columns are omitted from the
|
|
|
|
* results. If include_dropped is TRUE then empty strings and NULL constants
|
|
|
|
* (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-08-29 07:07:03 +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
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
if (colnames)
|
|
|
|
{
|
|
|
|
/* Assume there is one alias per target item */
|
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)));
|
2004-05-26 06:41:50 +02:00
|
|
|
aliasp_item = lnext(aliasp_item);
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
if (functypclass == TYPEFUNC_COMPOSITE)
|
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,
|
|
|
|
funcrettype, -1,
|
|
|
|
exprCollation(rtfunc->funcexpr),
|
2002-09-04 22:31:48 +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-08-29 07:07:03 +02:00
|
|
|
ListCell *colname;
|
|
|
|
ListCell *aliasvar;
|
2004-05-26 06:41:50 +02:00
|
|
|
|
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-08-29 07:07:03 +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
|
2005-10-15 04:49:52 +02:00
|
|
|
* deleted columns in the join; but we have to check since
|
|
|
|
* this routine is also used by the rewriter, and joins
|
|
|
|
* found in stored rules might have join columns for
|
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
|
|
|
* since-deleted columns. This will be signaled by a null
|
|
|
|
* pointer in the alias-vars list.
|
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
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
varnode = makeVar(rtindex, varattno,
|
2004-05-26 06:41:50 +02:00
|
|
|
exprType(avar),
|
|
|
|
exprTypmod(avar),
|
2011-02-08 22:04:18 +01:00
|
|
|
exprCollation(avar),
|
2002-05-12 22:10:05 +02:00
|
|
|
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-03-08 16:39:37 +01:00
|
|
|
/* Tablefunc, Values or CTE 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
|
|
|
{
|
2009-06-11 16:49:15 +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 */
|
|
|
|
char *label = strVal(lfirst(aliasp_item));
|
|
|
|
|
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
|
|
|
*colnames = lappend(*colnames,
|
|
|
|
makeString(pstrdup(label)));
|
2008-10-04 23:56:55 +02:00
|
|
|
aliasp_item = lnext(aliasp_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
Var *varnode;
|
|
|
|
|
|
|
|
varnode = makeVar(rtindex, varattno,
|
2011-02-08 22:04:18 +01:00
|
|
|
coltype, coltypmod, colcoll,
|
2008-10-04 23:56:55 +02:00
|
|
|
sublevels_up);
|
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
|
|
|
varnode->location = location;
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
*colvars = lappend(*colvars, varnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
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 *aliascell = list_head(eref->colnames);
|
2005-04-01 00:46:33 +02:00
|
|
|
int varattno;
|
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 (colnames)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < offset; i++)
|
|
|
|
{
|
|
|
|
if (aliascell)
|
|
|
|
aliascell = lnext(aliascell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Assert(count <= tupdesc->natts);
|
|
|
|
for (varattno = 0; varattno < count; varattno++)
|
2004-08-19 22:57:41 +02:00
|
|
|
{
|
2005-04-01 00:46:33 +02:00
|
|
|
Form_pg_attribute attr = tupdesc->attrs[varattno];
|
2004-08-19 22:57:41 +02:00
|
|
|
|
|
|
|
if (attr->attisdropped)
|
|
|
|
{
|
|
|
|
if (include_dropped)
|
|
|
|
{
|
|
|
|
if (colnames)
|
|
|
|
*colnames = lappend(*colnames, makeString(pstrdup("")));
|
|
|
|
if (colvars)
|
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* can't use atttypid here, but it doesn't really matter
|
|
|
|
* what type the Const claims to be.
|
2004-08-19 22:57:41 +02:00
|
|
|
*/
|
2011-03-26 01:10:42 +01:00
|
|
|
*colvars = lappend(*colvars,
|
2011-04-10 17:42:00 +02:00
|
|
|
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)
|
|
|
|
aliascell = lnext(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));
|
|
|
|
aliascell = lnext(aliascell);
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2002-03-12 01:52:10 +01:00
|
|
|
* expandRelAttrs -
|
|
|
|
* Workhorse for "*" expansion: produce a list of targetentries
|
2008-09-01 22:42:46 +02:00
|
|
|
* for the attributes of the RTE
|
2005-06-04 21:19:42 +02:00
|
|
|
*
|
|
|
|
* As with expandRTE, rtindex/sublevels_up determine the varno/varlevelsup
|
2008-09-01 22:42:46 +02:00
|
|
|
* fields of the Vars produced, and location sets their location.
|
|
|
|
* pstate->p_next_resno determines the resnos assigned to the TLEs.
|
2009-01-22 21:16:10 +01:00
|
|
|
* The referenced columns are marked as requiring SELECT access.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2002-03-12 01:52:10 +01:00
|
|
|
List *
|
2005-06-04 21:19:42 +02:00
|
|
|
expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
2008-09-01 22:42:46 +02:00
|
|
|
int rtindex, int sublevels_up, int location)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
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
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
expandRTE(rte, rtindex, sublevels_up, location, false,
|
2005-06-04 21:19:42 +02:00
|
|
|
&names, &vars);
|
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
|
|
|
|
* columns.
|
|
|
|
*/
|
|
|
|
rte->requiredPerms |= ACL_SELECT;
|
|
|
|
|
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
|
|
|
|
|
|
|
/* Require read access to each column */
|
|
|
|
markVarForSelectPriv(pstate, varnode, rte);
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +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.
|
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
|
2002-09-04 22:31:48 +02:00
|
|
|
* 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)
|
2003-08-12 01:04:50 +02:00
|
|
|
return get_relid_attribute_name(rte->relid, attnum);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-09-25 20:14:55 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +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-03-12 01:52:10 +01:00
|
|
|
/*
|
|
|
|
* get_rte_attribute_type
|
2011-04-22 23:43:18 +02:00
|
|
|
* Get attribute type/typmod/collation information from a RangeTblEntry
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid *vartype, int32 *vartypmod, Oid *varcollid)
|
2002-03-12 01:52:10 +01:00
|
|
|
{
|
2002-05-12 22:10:05 +02:00
|
|
|
switch (rte->rtekind)
|
2002-03-12 01:52:10 +01:00
|
|
|
{
|
2002-05-12 22:10:05 +02:00
|
|
|
case RTE_RELATION:
|
|
|
|
{
|
|
|
|
/* Plain relation RTE --- get the attribute's type info */
|
|
|
|
HeapTuple tp;
|
|
|
|
Form_pg_attribute att_tup;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tp = SearchSysCache2(ATTNUM,
|
|
|
|
ObjectIdGetDatum(rte->relid),
|
|
|
|
Int16GetDatum(attnum));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
|
|
attnum, rte->relid);
|
2002-05-12 22:10:05 +02:00
|
|
|
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If dropped column, pretend it ain't there. See notes in
|
|
|
|
* scanRTEForColumn.
|
2002-08-02 20:15:10 +02:00
|
|
|
*/
|
|
|
|
if (att_tup->attisdropped)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
|
|
NameStr(att_tup->attname),
|
|
|
|
get_rel_name(rte->relid))));
|
2002-05-12 22:10:05 +02:00
|
|
|
*vartype = att_tup->atttypid;
|
|
|
|
*vartypmod = att_tup->atttypmod;
|
2011-02-08 22:04:18 +01:00
|
|
|
*varcollid = att_tup->attcollation;
|
2002-05-12 22:10:05 +02:00
|
|
|
ReleaseSysCache(tp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_SUBQUERY:
|
|
|
|
{
|
|
|
|
/* Subselect RTE --- get type info from subselect's tlist */
|
2003-08-11 22:46:47 +02:00
|
|
|
TargetEntry *te = get_tle_by_resno(rte->subquery->targetList,
|
|
|
|
attnum);
|
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (te == NULL || te->resjunk)
|
2003-08-11 22:46:47 +02:00
|
|
|
elog(ERROR, "subquery %s does not have attribute %d",
|
|
|
|
rte->eref->aliasname, attnum);
|
2005-04-06 18:34:07 +02:00
|
|
|
*vartype = exprType((Node *) te->expr);
|
|
|
|
*vartypmod = exprTypmod((Node *) te->expr);
|
2011-02-08 22:04:18 +01:00
|
|
|
*varcollid = exprCollation((Node *) te->expr);
|
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
|
|
|
ListCell *lc;
|
|
|
|
int atts_done = 0;
|
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
|
|
|
/* Identify which function covers the requested column */
|
|
|
|
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);
|
2002-08-29 02:17:06 +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 (attnum > atts_done &&
|
|
|
|
attnum <= atts_done + rtfunc->funccolcount)
|
|
|
|
{
|
|
|
|
TypeFuncClass functypclass;
|
|
|
|
Oid funcrettype;
|
|
|
|
TupleDesc tupdesc;
|
2002-08-29 02:17:06 +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
|
|
|
attnum -= atts_done; /* now relative to this func */
|
|
|
|
functypclass = get_expr_result_type(rtfunc->funcexpr,
|
|
|
|
&funcrettype,
|
|
|
|
&tupdesc);
|
2002-09-04 22:31:48 +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 (functypclass == TYPEFUNC_COMPOSITE)
|
|
|
|
{
|
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Form_pg_attribute att_tup;
|
|
|
|
|
|
|
|
Assert(tupdesc);
|
|
|
|
Assert(attnum <= tupdesc->natts);
|
|
|
|
att_tup = tupdesc->attrs[attnum - 1];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If dropped column, pretend it ain't there. See
|
|
|
|
* notes in scanRTEForColumn.
|
|
|
|
*/
|
|
|
|
if (att_tup->attisdropped)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
|
|
NameStr(att_tup->attname),
|
|
|
|
rte->eref->aliasname)));
|
|
|
|
*vartype = att_tup->atttypid;
|
|
|
|
*vartypmod = att_tup->atttypmod;
|
|
|
|
*varcollid = att_tup->attcollation;
|
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_SCALAR)
|
|
|
|
{
|
|
|
|
/* Base data type, i.e. scalar */
|
|
|
|
*vartype = funcrettype;
|
|
|
|
*vartypmod = -1;
|
|
|
|
*varcollid = exprCollation(rtfunc->funcexpr);
|
|
|
|
}
|
|
|
|
else if (functypclass == TYPEFUNC_RECORD)
|
|
|
|
{
|
|
|
|
*vartype = list_nth_oid(rtfunc->funccoltypes,
|
|
|
|
attnum - 1);
|
|
|
|
*vartypmod = list_nth_int(rtfunc->funccoltypmods,
|
|
|
|
attnum - 1);
|
|
|
|
*varcollid = list_nth_oid(rtfunc->funccolcollations,
|
|
|
|
attnum - 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* addRangeTableEntryForFunction should've caught
|
|
|
|
* this
|
|
|
|
*/
|
|
|
|
elog(ERROR, "function in FROM has unsupported return type");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
atts_done += rtfunc->funccolcount;
|
2002-05-12 22:10:05 +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
|
|
|
/* If we get here, must be looking for the ordinality column */
|
|
|
|
if (rte->funcordinality && attnum == atts_done + 1)
|
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
|
|
|
*vartype = INT8OID;
|
|
|
|
*vartypmod = -1;
|
|
|
|
*varcollid = InvalidOid;
|
|
|
|
return;
|
2004-10-20 18:04:50 +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
|
|
|
|
|
|
|
/* this probably can't happen ... */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column %d of relation \"%s\" does not exist",
|
|
|
|
attnum,
|
|
|
|
rte->eref->aliasname)));
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_JOIN:
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Join RTE --- get type info from join RTE's alias variable
|
2002-09-04 22:31:48 +02:00
|
|
|
*/
|
|
|
|
Node *aliasvar;
|
2002-04-28 21:54:29 +02:00
|
|
|
|
2004-05-31 01:40:41 +02:00
|
|
|
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
|
|
|
|
aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
|
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
|
|
|
Assert(aliasvar != NULL);
|
2002-05-12 22:10:05 +02:00
|
|
|
*vartype = exprType(aliasvar);
|
|
|
|
*vartypmod = exprTypmod(aliasvar);
|
2011-02-08 22:04:18 +01:00
|
|
|
*varcollid = exprCollation(aliasvar);
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
|
|
|
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-03-08 16:39:37 +01:00
|
|
|
/*
|
|
|
|
* tablefunc, VALUES or CTE RTE --- get type info from lists
|
|
|
|
* in the RTE
|
|
|
|
*/
|
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
|
|
|
Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
|
|
|
|
*vartype = list_nth_oid(rte->coltypes, attnum - 1);
|
|
|
|
*vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
|
|
|
|
*varcollid = list_nth_oid(rte->colcollations, attnum - 1);
|
2008-10-04 23:56:55 +02:00
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
bool result;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
switch (rte->rtekind)
|
|
|
|
{
|
|
|
|
case RTE_RELATION:
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Plain relation RTE --- get the attribute's catalog entry
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
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));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
|
2003-07-19 22:20:53 +02:00
|
|
|
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:
|
|
|
|
{
|
|
|
|
Assert(rte->enrname);
|
|
|
|
|
|
|
|
/*
|
2017-04-07 00:32:53 +02:00
|
|
|
* We checked when we loaded coltypes for the tuplestore that
|
|
|
|
* InvalidOid was only used for dropped columns, so it is safe
|
|
|
|
* to count on that here.
|
2017-04-01 06:17:18 +02:00
|
|
|
*/
|
|
|
|
result =
|
2017-04-07 00:32:53 +02:00
|
|
|
((list_nth_oid(rte->coltypes, attnum - 1) == InvalidOid));
|
2017-04-01 06:17:18 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-08-19 22:57:41 +02:00
|
|
|
case RTE_JOIN:
|
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* 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
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
Var *aliasvar;
|
2004-08-19 22:57:41 +02:00
|
|
|
|
|
|
|
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
|
2014-05-06 18:12:18 +02:00
|
|
|
* column dropped. So first, loop over the funcs until we
|
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
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
TypeFuncClass functypclass;
|
|
|
|
Oid funcrettype;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
|
|
|
functypclass = get_expr_result_type(rtfunc->funcexpr,
|
|
|
|
&funcrettype,
|
|
|
|
&tupdesc);
|
|
|
|
if (functypclass == TYPEFUNC_COMPOSITE)
|
|
|
|
{
|
|
|
|
/* Composite data type, e.g. a table's row type */
|
|
|
|
Form_pg_attribute att_tup;
|
|
|
|
|
|
|
|
Assert(tupdesc);
|
|
|
|
Assert(attnum - atts_done <= tupdesc->natts);
|
|
|
|
att_tup = tupdesc->attrs[attnum - atts_done - 1];
|
|
|
|
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;
|
|
|
|
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-08-29 07:07:03 +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
|
|
|
|
* heap_open()'ed. Use the cache version get_attnum()
|
|
|
|
* 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;
|
|
|
|
|
2016-04-08 20:52:13 +02:00
|
|
|
for (i = 0; i < rd->rd_rel->relnatts; i++)
|
2002-08-02 20:15:10 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Form_pg_attribute att = rd->rd_att->attrs[i];
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped)
|
1998-09-01 05:29:17 +02: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)
|
|
|
|
{
|
|
|
|
if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids)
|
|
|
|
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
|
|
|
*
|
2000-02-15 04:38:29 +01:00
|
|
|
* Check attribute name to see if it is "special", e.g. "oid".
|
|
|
|
* - thomas 2000-02-07
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
|
|
|
* Note: this only discovers whether the name could be a system attribute.
|
|
|
|
* Caller needs to verify that it really is an attribute of the rel,
|
|
|
|
* at least in the case of "oid", which is now optional.
|
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
|
|
|
{
|
2001-10-23 00:47:57 +02:00
|
|
|
Form_pg_attribute sysatt;
|
2000-02-15 04:38:29 +01:00
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
sysatt = SystemAttributeByName(attname,
|
|
|
|
true /* "oid" will be accepted */ );
|
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
|
|
|
|
* heap_open()'ed. Use the cache version get_atttype()
|
|
|
|
* for access to non-opened relations.
|
|
|
|
*/
|
|
|
|
Name
|
|
|
|
attnumAttName(Relation rd, int attid)
|
|
|
|
{
|
|
|
|
if (attid <= 0)
|
|
|
|
{
|
|
|
|
Form_pg_attribute sysatt;
|
|
|
|
|
|
|
|
sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids);
|
|
|
|
return &sysatt->attname;
|
|
|
|
}
|
|
|
|
if (attid > rd->rd_att->natts)
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "invalid attribute number %d", attid);
|
2001-10-23 19:39:03 +02:00
|
|
|
return &rd->rd_att->attrs[attid - 1]->attname;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
* heap_open()'ed. Use the cache version get_atttype()
|
|
|
|
* 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
|
|
|
{
|
2001-10-23 00:47:57 +02:00
|
|
|
Form_pg_attribute sysatt;
|
2000-06-20 03:41:22 +02:00
|
|
|
|
2001-10-23 00:47:57 +02:00
|
|
|
sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids);
|
|
|
|
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);
|
1998-09-01 05:29:17 +02:00
|
|
|
return rd->rd_att->attrs[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
|
|
|
|
*
|
|
|
|
* This should only be used if the relation is already heap_open()'ed.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
return rd->rd_att->attrs[attid - 1]->attcollation;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
int sublevels_up;
|
|
|
|
const char *badAlias = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if there are any potential matches in the query's
|
2014-05-06 18:12:18 +02:00
|
|
|
* rangetable. (Note: cases involving a bad schema name in the RangeVar
|
2010-02-26 03:01:40 +01:00
|
|
|
* 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
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02: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.
|
2006-01-10 22:59:59 +01:00
|
|
|
*
|
|
|
|
* 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 &&
|
|
|
|
strcmp(rte->eref->aliasname, relation->relname) != 0 &&
|
|
|
|
refnameRangeTblEntry(pstate, NULL, rte->eref->aliasname,
|
2008-09-01 22:42:46 +02:00
|
|
|
relation->location,
|
2006-01-10 22:59:59 +01:00
|
|
|
&sublevels_up) == rte)
|
|
|
|
badAlias = rte->eref->aliasname;
|
|
|
|
|
2009-10-21 22:22:38 +02:00
|
|
|
if (rte)
|
|
|
|
ereport(ERROR,
|
2006-01-10 22:59:59 +01:00
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
2010-02-26 03:01:40 +01:00
|
|
|
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
|
|
|
relation->relname),
|
2006-01-10 22:59:59 +01:00
|
|
|
(badAlias ?
|
2010-02-26 03:01:40 +01:00
|
|
|
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
|
|
|
badAlias) :
|
2009-10-21 22:22:38 +02:00
|
|
|
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
|
|
|
rte->eref->aliasname)),
|
|
|
|
parser_errposition(pstate, relation->location)));
|
|
|
|
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,
|
|
|
|
char *relname, char *colname, int location)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
FuzzyAttrMatchState *state;
|
|
|
|
char *closestfirst = NULL;
|
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.
|
|
|
|
*
|
|
|
|
* TODO: improve this code (and also errorMissingRTE) to mention using
|
|
|
|
* LATERAL if appropriate.
|
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
|
|
|
|
|
|
|
/*
|
2015-03-11 15:44:04 +01:00
|
|
|
* Extract closest col string for best match, if any.
|
2012-08-08 01:02:54 +02:00
|
|
|
*
|
2015-03-11 15:44:04 +01:00
|
|
|
* Infer an exact match referenced despite not being visible from the fact
|
2015-05-24 03:35:49 +02:00
|
|
|
* that an attribute number was not present in state passed back -- this
|
|
|
|
* is what is reported when !closestfirst. There might also be an exact
|
|
|
|
* match that was qualified with an incorrect alias, in which case
|
|
|
|
* closestfirst will be set (so hint is the same as generic fuzzy case).
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2015-03-11 15:44:04 +01:00
|
|
|
if (state->rfirst && AttributeNumberIsValid(state->first))
|
|
|
|
closestfirst = strVal(list_nth(state->rfirst->eref->colnames,
|
|
|
|
state->first - 1));
|
|
|
|
|
|
|
|
if (!state->rsecond)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Handle case where there is zero or one column suggestions to hint,
|
|
|
|
* including exact matches referenced but not visible.
|
|
|
|
*/
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
2015-03-11 15:44:04 +01:00
|
|
|
errmsg("column \"%s\" does not exist", colname),
|
|
|
|
state->rfirst ? closestfirst ?
|
2016-06-10 00:02:36 +02:00
|
|
|
errhint("Perhaps you meant to reference the column \"%s.%s\".",
|
|
|
|
state->rfirst->eref->aliasname, closestfirst) :
|
2015-03-11 15:44:04 +01:00
|
|
|
errhint("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
|
2015-05-24 03:35:49 +02:00
|
|
|
colname, state->rfirst->eref->aliasname) : 0,
|
2015-03-11 15:44:04 +01:00
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle case where there are two equally useful column hints */
|
2015-05-24 03:35:49 +02:00
|
|
|
char *closestsecond;
|
2015-03-11 15:44:04 +01:00
|
|
|
|
|
|
|
closestsecond = strVal(list_nth(state->rsecond->eref->colnames,
|
|
|
|
state->second - 1));
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
relname ?
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("column %s.%s does not exist", relname, colname) :
|
2015-03-11 15:44:04 +01:00
|
|
|
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\".",
|
2015-03-11 15:44:04 +01:00
|
|
|
state->rfirst->eref->aliasname, closestfirst,
|
|
|
|
state->rsecond->eref->aliasname, closestsecond),
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Examine a fully-parsed query, and return TRUE iff any relation underlying
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
Relation rel = heap_open(rte->relid, AccessShareLock);
|
|
|
|
char relpersistence = rel->rd_rel->relpersistence;
|
|
|
|
|
|
|
|
heap_close(rel, AccessShareLock);
|
|
|
|
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);
|
|
|
|
}
|