1997-11-25 23:07:18 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* parse_target.c
|
|
|
|
* handle target lists
|
|
|
|
*
|
2015-01-06 17:43:47 +01:00
|
|
|
* Portions Copyright (c) 1996-2015, 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_target.c
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2003-06-27 19:07:03 +02:00
|
|
|
#include "commands/dbcommands.h"
|
2005-04-25 23:03:25 +02:00
|
|
|
#include "funcapi.h"
|
2002-03-21 17:02:16 +01:00
|
|
|
#include "miscadmin.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"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/parse_coerce.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "parser/parse_expr.h"
|
1998-01-20 06:05:08 +01:00
|
|
|
#include "parser/parse_func.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "parser/parse_relation.h"
|
|
|
|
#include "parser/parse_target.h"
|
2000-06-15 05:33:12 +02:00
|
|
|
#include "parser/parse_type.h"
|
2001-08-09 20:28:18 +02:00
|
|
|
#include "utils/builtins.h"
|
2004-06-09 21:08:20 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2004-06-19 20:19:56 +02:00
|
|
|
#include "utils/typcache.h"
|
1998-05-10 01:31:34 +02:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
|
2005-10-15 04:49:52 +02:00
|
|
|
Var *var, int levelsup);
|
2004-06-09 21:08:20 +02:00
|
|
|
static Node *transformAssignmentIndirection(ParseState *pstate,
|
|
|
|
Node *basenode,
|
|
|
|
const char *targetName,
|
|
|
|
bool targetIsArray,
|
|
|
|
Oid targetTypeId,
|
|
|
|
int32 targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid targetCollation,
|
2004-06-09 21:08:20 +02:00
|
|
|
ListCell *indirection,
|
2006-03-23 01:19:30 +01:00
|
|
|
Node *rhs,
|
|
|
|
int location);
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
static Node *transformAssignmentSubscripts(ParseState *pstate,
|
|
|
|
Node *basenode,
|
|
|
|
const char *targetName,
|
|
|
|
Oid targetTypeId,
|
|
|
|
int32 targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid targetCollation,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
List *subscripts,
|
|
|
|
bool isSlice,
|
|
|
|
ListCell *next_indirection,
|
|
|
|
Node *rhs,
|
|
|
|
int location);
|
2006-08-02 03:59:48 +02:00
|
|
|
static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry);
|
2008-09-01 22:42:46 +02:00
|
|
|
static List *ExpandAllTables(ParseState *pstate, int location);
|
2006-08-02 03:59:48 +02:00
|
|
|
static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry, ParseExprKind exprKind);
|
2009-10-31 02:41:31 +01:00
|
|
|
static List *ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
int location, bool make_target_entry);
|
2009-10-31 02:41:31 +01:00
|
|
|
static List *ExpandRowReference(ParseState *pstate, Node *expr,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry);
|
2001-10-25 07:50:21 +02:00
|
|
|
static int FigureColnameInternal(Node *node, char **name);
|
1997-11-26 04:43:18 +01:00
|
|
|
|
1998-05-21 05:53:51 +02:00
|
|
|
|
1999-07-19 02:26:20 +02:00
|
|
|
/*
|
|
|
|
* transformTargetEntry()
|
|
|
|
* Transform any ordinary "expression-type" node into a targetlist entry.
|
|
|
|
* This is exported so that parse_clause.c can generate targetlist entries
|
|
|
|
* for ORDER/GROUP BY items that are not already in the targetlist.
|
1998-07-08 16:04:11 +02:00
|
|
|
*
|
1999-07-19 02:26:20 +02:00
|
|
|
* node the (untransformed) parse tree for the value expression.
|
|
|
|
* expr the transformed expression, or NULL if caller didn't do it yet.
|
2013-05-29 22:58:43 +02:00
|
|
|
* exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc)
|
1999-07-19 02:26:20 +02:00
|
|
|
* colname the column name to be assigned, or NULL if none yet set.
|
|
|
|
* resjunk true if the target should be marked resjunk, ie, it is not
|
|
|
|
* wanted in the final projected tuple.
|
1998-05-21 05:53:51 +02:00
|
|
|
*/
|
1998-07-08 16:04:11 +02:00
|
|
|
TargetEntry *
|
1999-07-19 02:26:20 +02:00
|
|
|
transformTargetEntry(ParseState *pstate,
|
1998-07-08 16:04:11 +02:00
|
|
|
Node *node,
|
1999-07-19 02:26:20 +02:00
|
|
|
Node *expr,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
ParseExprKind exprKind,
|
1998-07-08 16:04:11 +02:00
|
|
|
char *colname,
|
2003-02-13 06:53:46 +01:00
|
|
|
bool resjunk)
|
1998-05-21 05:53:51 +02:00
|
|
|
{
|
1999-07-19 02:26:20 +02:00
|
|
|
/* Transform the node if caller didn't do it already */
|
1998-08-23 16:43:46 +02:00
|
|
|
if (expr == NULL)
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
expr = transformExpr(pstate, node, exprKind);
|
1998-08-23 16:43:46 +02:00
|
|
|
|
2003-08-12 01:04:50 +02:00
|
|
|
if (colname == NULL && !resjunk)
|
1998-08-23 16:43:46 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Generate a suitable column name for a column without any explicit
|
|
|
|
* 'AS ColumnName' clause.
|
1998-08-23 16:43:46 +02:00
|
|
|
*/
|
2001-09-17 03:06:36 +02:00
|
|
|
colname = FigureColname(node);
|
1998-08-23 16:43:46 +02:00
|
|
|
}
|
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
return makeTargetEntry((Expr *) expr,
|
|
|
|
(AttrNumber) pstate->p_next_resno++,
|
|
|
|
colname,
|
|
|
|
resjunk);
|
1999-07-19 02:26:20 +02:00
|
|
|
}
|
1998-12-04 16:34:49 +01:00
|
|
|
|
|
|
|
|
1998-08-25 05:17:29 +02:00
|
|
|
/*
|
1999-07-19 02:26:20 +02:00
|
|
|
* transformTargetList()
|
|
|
|
* Turns a list of ResTarget's into a list of TargetEntry's.
|
|
|
|
*
|
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns
(but only one row) to be used to compute the new values of several columns
to be updated. While the same results can be had with an independent
sub-SELECT per column, such a workaround can require a great deal of
duplicated computation.
The standard actually says that the source for a multi-column assignment
could be any row-valued expression. The implementation used here is
tightly tied to our existing sub-SELECT support and can't handle other
cases; the Bison grammar would have some issues with them too. However,
I don't feel too bad about this since other cases can be converted into
sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could
be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
2014-06-18 19:22:25 +02:00
|
|
|
* This code acts mostly the same for SELECT, UPDATE, or RETURNING lists;
|
|
|
|
* the main thing is to transform the given expressions (the "val" fields).
|
|
|
|
* The exprKind parameter distinguishes these cases when necesssary.
|
1998-08-25 05:17:29 +02:00
|
|
|
*/
|
1999-07-19 02:26:20 +02:00
|
|
|
List *
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
transformTargetList(ParseState *pstate, List *targetlist,
|
|
|
|
ParseExprKind exprKind)
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
2004-06-01 05:28:48 +02:00
|
|
|
List *p_target = NIL;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *o_target;
|
1998-08-25 05:17:29 +02:00
|
|
|
|
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns
(but only one row) to be used to compute the new values of several columns
to be updated. While the same results can be had with an independent
sub-SELECT per column, such a workaround can require a great deal of
duplicated computation.
The standard actually says that the source for a multi-column assignment
could be any row-valued expression. The implementation used here is
tightly tied to our existing sub-SELECT support and can't handle other
cases; the Bison grammar would have some issues with them too. However,
I don't feel too bad about this since other cases can be converted into
sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could
be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
2014-06-18 19:22:25 +02:00
|
|
|
/* Shouldn't have any leftover multiassign items at start */
|
|
|
|
Assert(pstate->p_multiassign_exprs == NIL);
|
|
|
|
|
2003-08-11 22:46:47 +02:00
|
|
|
foreach(o_target, targetlist)
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
2003-08-11 22:46:47 +02:00
|
|
|
ResTarget *res = (ResTarget *) lfirst(o_target);
|
1998-08-23 16:43:46 +02:00
|
|
|
|
2004-06-19 20:19:56 +02:00
|
|
|
/*
|
|
|
|
* Check for "something.*". Depending on the complexity of the
|
2008-08-30 03:39:14 +02:00
|
|
|
* "something", the star could appear as the last field in ColumnRef,
|
2005-10-15 04:49:52 +02:00
|
|
|
* or as the last indirection item in A_Indirection.
|
2004-06-19 20:19:56 +02:00
|
|
|
*/
|
2002-03-21 17:02:16 +01:00
|
|
|
if (IsA(res->val, ColumnRef))
|
1999-07-19 02:26:20 +02:00
|
|
|
{
|
2002-03-21 17:02:16 +01:00
|
|
|
ColumnRef *cref = (ColumnRef *) res->val;
|
1998-08-23 16:43:46 +02:00
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(llast(cref->fields), A_Star))
|
1999-07-19 02:26:20 +02:00
|
|
|
{
|
2004-06-19 20:19:56 +02:00
|
|
|
/* It is something.*, expand into multiple items */
|
|
|
|
p_target = list_concat(p_target,
|
2006-06-26 19:24:41 +02:00
|
|
|
ExpandColumnRefStar(pstate, cref,
|
|
|
|
true));
|
2004-06-19 20:19:56 +02:00
|
|
|
continue;
|
1999-07-19 02:26:20 +02:00
|
|
|
}
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
2004-06-19 20:19:56 +02:00
|
|
|
else if (IsA(res->val, A_Indirection))
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
A_Indirection *ind = (A_Indirection *) res->val;
|
2004-06-19 20:19:56 +02:00
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(llast(ind->indirection), A_Star))
|
2004-06-19 20:19:56 +02:00
|
|
|
{
|
|
|
|
/* It is something.*, expand into multiple items */
|
|
|
|
p_target = list_concat(p_target,
|
2006-06-26 19:24:41 +02:00
|
|
|
ExpandIndirectionStar(pstate, ind,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
true, exprKind));
|
2004-06-19 20:19:56 +02:00
|
|
|
continue;
|
|
|
|
}
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
2004-06-19 20:19:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Not "something.*", so transform as a single expression
|
|
|
|
*/
|
|
|
|
p_target = lappend(p_target,
|
|
|
|
transformTargetEntry(pstate,
|
|
|
|
res->val,
|
|
|
|
NULL,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
exprKind,
|
2004-06-19 20:19:56 +02:00
|
|
|
res->name,
|
|
|
|
false));
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
1999-07-19 02:26:20 +02:00
|
|
|
|
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns
(but only one row) to be used to compute the new values of several columns
to be updated. While the same results can be had with an independent
sub-SELECT per column, such a workaround can require a great deal of
duplicated computation.
The standard actually says that the source for a multi-column assignment
could be any row-valued expression. The implementation used here is
tightly tied to our existing sub-SELECT support and can't handle other
cases; the Bison grammar would have some issues with them too. However,
I don't feel too bad about this since other cases can be converted into
sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could
be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
2014-06-18 19:22:25 +02:00
|
|
|
/*
|
|
|
|
* If any multiassign resjunk items were created, attach them to the end
|
|
|
|
* of the targetlist. This should only happen in an UPDATE tlist. We
|
|
|
|
* don't need to worry about numbering of these items; transformUpdateStmt
|
|
|
|
* will set their resnos.
|
|
|
|
*/
|
|
|
|
if (pstate->p_multiassign_exprs)
|
|
|
|
{
|
|
|
|
Assert(exprKind == EXPR_KIND_UPDATE_SOURCE);
|
|
|
|
p_target = list_concat(p_target, pstate->p_multiassign_exprs);
|
|
|
|
pstate->p_multiassign_exprs = NIL;
|
|
|
|
}
|
|
|
|
|
2004-06-01 05:28:48 +02:00
|
|
|
return p_target;
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
|
|
|
|
1999-07-19 02:26:20 +02:00
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
/*
|
|
|
|
* transformExpressionList()
|
|
|
|
*
|
|
|
|
* This is the identical transformation to transformTargetList, except that
|
|
|
|
* the input list elements are bare expressions without ResTarget decoration,
|
|
|
|
* and the output elements are likewise just expressions without TargetEntry
|
2014-05-06 18:12:18 +02:00
|
|
|
* decoration. We use this for ROW() and VALUES() constructs.
|
2006-08-02 03:59:48 +02:00
|
|
|
*/
|
|
|
|
List *
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
transformExpressionList(ParseState *pstate, List *exprlist,
|
|
|
|
ParseExprKind exprKind)
|
2006-08-02 03:59:48 +02:00
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, exprlist)
|
|
|
|
{
|
|
|
|
Node *e = (Node *) lfirst(lc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for "something.*". Depending on the complexity of the
|
2008-08-30 03:39:14 +02:00
|
|
|
* "something", the star could appear as the last field in ColumnRef,
|
2006-08-02 03:59:48 +02:00
|
|
|
* or as the last indirection item in A_Indirection.
|
|
|
|
*/
|
|
|
|
if (IsA(e, ColumnRef))
|
|
|
|
{
|
|
|
|
ColumnRef *cref = (ColumnRef *) e;
|
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(llast(cref->fields), A_Star))
|
2006-08-02 03:59:48 +02:00
|
|
|
{
|
|
|
|
/* It is something.*, expand into multiple items */
|
|
|
|
result = list_concat(result,
|
|
|
|
ExpandColumnRefStar(pstate, cref,
|
|
|
|
false));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (IsA(e, A_Indirection))
|
|
|
|
{
|
|
|
|
A_Indirection *ind = (A_Indirection *) e;
|
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(llast(ind->indirection), A_Star))
|
2006-08-02 03:59:48 +02:00
|
|
|
{
|
|
|
|
/* It is something.*, expand into multiple items */
|
|
|
|
result = list_concat(result,
|
|
|
|
ExpandIndirectionStar(pstate, ind,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
false, exprKind));
|
2006-08-02 03:59:48 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not "something.*", so transform as a single expression
|
|
|
|
*/
|
|
|
|
result = lappend(result,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
transformExpr(pstate, e, exprKind));
|
2006-08-02 03:59:48 +02:00
|
|
|
}
|
|
|
|
|
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns
(but only one row) to be used to compute the new values of several columns
to be updated. While the same results can be had with an independent
sub-SELECT per column, such a workaround can require a great deal of
duplicated computation.
The standard actually says that the source for a multi-column assignment
could be any row-valued expression. The implementation used here is
tightly tied to our existing sub-SELECT support and can't handle other
cases; the Bison grammar would have some issues with them too. However,
I don't feel too bad about this since other cases can be converted into
sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could
be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
2014-06-18 19:22:25 +02:00
|
|
|
/* Shouldn't have any multiassign items here */
|
|
|
|
Assert(pstate->p_multiassign_exprs == NIL);
|
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-05-06 02:20:33 +02:00
|
|
|
/*
|
|
|
|
* markTargetListOrigins()
|
|
|
|
* Mark targetlist columns that are simple Vars with the source
|
|
|
|
* table's OID and column number.
|
|
|
|
*
|
|
|
|
* Currently, this is done only for SELECT targetlists, since we only
|
|
|
|
* need the info if we are going to send it to the frontend.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
markTargetListOrigins(ParseState *pstate, List *targetlist)
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2003-05-06 02:20:33 +02:00
|
|
|
|
|
|
|
foreach(l, targetlist)
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
markTargetListOrigin(pstate, tle, (Var *) tle->expr, 0);
|
2003-05-06 02:20:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* markTargetListOrigin()
|
2005-04-06 18:34:07 +02:00
|
|
|
* If 'var' is a Var of a plain relation, mark 'tle' with its origin
|
2003-05-06 02:20:33 +02:00
|
|
|
*
|
2005-01-13 18:19:10 +01:00
|
|
|
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
|
|
|
|
*
|
2003-05-06 02:20:33 +02:00
|
|
|
* This is split out so it can recurse for join references. Note that we
|
|
|
|
* do not drill down into views, but report the view as the column owner.
|
|
|
|
*/
|
|
|
|
static void
|
2005-04-06 18:34:07 +02:00
|
|
|
markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
|
|
|
|
Var *var, int levelsup)
|
2003-05-06 02:20:33 +02:00
|
|
|
{
|
2005-01-13 18:19:10 +01:00
|
|
|
int netlevelsup;
|
2003-05-06 02:20:33 +02:00
|
|
|
RangeTblEntry *rte;
|
|
|
|
AttrNumber attnum;
|
|
|
|
|
|
|
|
if (var == NULL || !IsA(var, Var))
|
|
|
|
return;
|
2005-01-13 18:19:10 +01:00
|
|
|
netlevelsup = var->varlevelsup + levelsup;
|
|
|
|
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
|
2003-05-06 02:20:33 +02:00
|
|
|
attnum = var->varattno;
|
|
|
|
|
|
|
|
switch (rte->rtekind)
|
|
|
|
{
|
|
|
|
case RTE_RELATION:
|
|
|
|
/* It's a table or view, report it */
|
2005-04-06 18:34:07 +02:00
|
|
|
tle->resorigtbl = rte->relid;
|
|
|
|
tle->resorigcol = attnum;
|
2003-05-06 02:20:33 +02:00
|
|
|
break;
|
|
|
|
case RTE_SUBQUERY:
|
2005-04-26 00:02:30 +02:00
|
|
|
/* Subselect-in-FROM: copy up from the subselect */
|
|
|
|
if (attnum != InvalidAttrNumber)
|
2003-05-06 02:20:33 +02:00
|
|
|
{
|
2005-04-06 18:34:07 +02:00
|
|
|
TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
|
|
|
|
attnum);
|
2003-05-06 02:20:33 +02:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (ste == NULL || ste->resjunk)
|
2003-07-19 22:20:53 +02:00
|
|
|
elog(ERROR, "subquery %s does not have attribute %d",
|
2003-05-06 02:20:33 +02:00
|
|
|
rte->eref->aliasname, attnum);
|
2005-04-06 18:34:07 +02:00
|
|
|
tle->resorigtbl = ste->resorigtbl;
|
|
|
|
tle->resorigcol = ste->resorigcol;
|
2003-05-06 02:20:33 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_JOIN:
|
2005-04-26 00:02:30 +02:00
|
|
|
/* Join RTE --- recursively inspect the alias variable */
|
|
|
|
if (attnum != InvalidAttrNumber)
|
2003-05-06 02:20:33 +02:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
Var *aliasvar;
|
2003-05-06 02:20:33 +02:00
|
|
|
|
2004-05-31 01:40:41 +02:00
|
|
|
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
|
|
|
|
aliasvar = (Var *) 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
|
|
|
/* We intentionally don't strip implicit coercions here */
|
2005-04-06 18:34:07 +02:00
|
|
|
markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);
|
2003-05-06 02:20:33 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_FUNCTION:
|
2006-08-02 03:59:48 +02:00
|
|
|
case RTE_VALUES:
|
2003-05-06 02:20:33 +02:00
|
|
|
/* not a simple relation, leave it unmarked */
|
|
|
|
break;
|
2008-10-04 23:56:55 +02:00
|
|
|
case RTE_CTE:
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-10-06 00:20:17 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* CTE reference: copy up from the subquery, if possible. If the
|
|
|
|
* RTE is a recursive self-reference then we can't do anything
|
|
|
|
* because we haven't finished analyzing it yet. However, it's no
|
|
|
|
* big loss because we must be down inside the recursive term of a
|
|
|
|
* recursive CTE, and so any markings on the current targetlist
|
|
|
|
* are not going to affect the results anyway.
|
2008-10-06 00:20:17 +02:00
|
|
|
*/
|
|
|
|
if (attnum != InvalidAttrNumber && !rte->self_reference)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
2008-10-06 17:15:22 +02:00
|
|
|
CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
|
2008-10-04 23:56:55 +02:00
|
|
|
TargetEntry *ste;
|
|
|
|
|
2011-02-26 00:56:23 +01:00
|
|
|
ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
|
2008-10-04 23:56:55 +02:00
|
|
|
if (ste == NULL || ste->resjunk)
|
|
|
|
elog(ERROR, "subquery %s does not have attribute %d",
|
|
|
|
rte->eref->aliasname, attnum);
|
|
|
|
tle->resorigtbl = ste->resorigtbl;
|
|
|
|
tle->resorigcol = ste->resorigcol;
|
|
|
|
}
|
|
|
|
break;
|
2003-05-06 02:20:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-25 05:17:29 +02:00
|
|
|
/*
|
2006-08-02 03:59:48 +02:00
|
|
|
* transformAssignedExpr()
|
2014-05-06 18:12:18 +02:00
|
|
|
* This is used in INSERT and UPDATE statements only. It prepares an
|
2006-08-02 03:59:48 +02:00
|
|
|
* expression for assignment to a column of the target table.
|
1999-07-19 02:26:20 +02:00
|
|
|
* This includes coercing the given value to the target column's type
|
2004-06-09 21:08:20 +02:00
|
|
|
* (if necessary), and dealing with any subfield names or subscripts
|
2006-08-02 03:59:48 +02:00
|
|
|
* attached to the target column itself. The input expression has
|
|
|
|
* already been through transformExpr().
|
1999-07-19 02:26:20 +02:00
|
|
|
*
|
|
|
|
* pstate parse state
|
2006-08-02 03:59:48 +02:00
|
|
|
* expr expression to be modified
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* exprKind indicates which type of statement we're dealing with
|
1999-07-19 02:26:20 +02:00
|
|
|
* colname target column name (ie, name of attribute to be assigned to)
|
1999-11-01 06:06:21 +01:00
|
|
|
* attrno target attribute number
|
2004-06-09 21:08:20 +02:00
|
|
|
* indirection subscripts/field names for target column, if any
|
2008-08-29 01:09:48 +02:00
|
|
|
* location error cursor position for the target column, or -1
|
2006-08-02 03:59:48 +02:00
|
|
|
*
|
|
|
|
* Returns the modified expression.
|
2008-10-07 03:47:55 +02:00
|
|
|
*
|
|
|
|
* Note: location points at the target column name (SET target or INSERT
|
|
|
|
* column name list entry), and must therefore be -1 in an INSERT that
|
2014-05-06 18:12:18 +02:00
|
|
|
* omits the column name list. So we should usually prefer to use
|
2008-10-07 03:47:55 +02:00
|
|
|
* exprLocation(expr) for errors that can happen in a default INSERT.
|
1998-08-25 05:17:29 +02:00
|
|
|
*/
|
2006-08-02 03:59:48 +02:00
|
|
|
Expr *
|
|
|
|
transformAssignedExpr(ParseState *pstate,
|
|
|
|
Expr *expr,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
ParseExprKind exprKind,
|
1999-07-19 02:26:20 +02:00
|
|
|
char *colname,
|
1999-11-01 06:06:21 +01:00
|
|
|
int attrno,
|
2006-03-23 01:19:30 +01:00
|
|
|
List *indirection,
|
|
|
|
int location)
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
Relation rd = pstate->p_target_relation;
|
2003-08-04 02:43:34 +02:00
|
|
|
Oid type_id; /* type of value provided */
|
1999-07-19 02:26:20 +02:00
|
|
|
Oid attrtype; /* type of target column */
|
|
|
|
int32 attrtypmod;
|
2011-04-22 23:43:18 +02:00
|
|
|
Oid attrcollation; /* collation of target column */
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
ParseExprKind sv_expr_kind;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save and restore identity of expression type we're parsing. We must
|
|
|
|
* set p_expr_kind here because we can parse subscripts without going
|
|
|
|
* through transformExpr().
|
|
|
|
*/
|
|
|
|
Assert(exprKind != EXPR_KIND_NONE);
|
|
|
|
sv_expr_kind = pstate->p_expr_kind;
|
|
|
|
pstate->p_expr_kind = exprKind;
|
1998-08-25 05:17:29 +02:00
|
|
|
|
1999-07-19 02:26:20 +02:00
|
|
|
Assert(rd != NULL);
|
1999-11-01 06:06:21 +01:00
|
|
|
if (attrno <= 0)
|
2003-07-19 22:20:53 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot assign to system column \"%s\"",
|
2006-03-23 01:19:30 +01:00
|
|
|
colname),
|
|
|
|
parser_errposition(pstate, location)));
|
1999-11-01 06:06:21 +01:00
|
|
|
attrtype = attnumTypeId(rd, attrno);
|
|
|
|
attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
2011-02-08 22:04:18 +01:00
|
|
|
attrcollation = rd->rd_att->attrs[attrno - 1]->attcollation;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2003-07-03 18:34:26 +02:00
|
|
|
/*
|
|
|
|
* If the expression is a DEFAULT placeholder, insert the attribute's
|
2011-04-22 23:43:18 +02:00
|
|
|
* type/typmod/collation into it so that exprType etc will report the
|
|
|
|
* right things. (We expect that the eventually substituted default
|
|
|
|
* expression will in fact have this type and typmod. The collation
|
|
|
|
* likely doesn't matter, but let's set it correctly anyway.) Also,
|
|
|
|
* reject trying to update a subfield or array element with DEFAULT, since
|
|
|
|
* there can't be any default for portions of a column.
|
2003-07-03 18:34:26 +02:00
|
|
|
*/
|
2006-08-02 03:59:48 +02:00
|
|
|
if (expr && IsA(expr, SetToDefault))
|
2003-06-25 06:19:24 +02:00
|
|
|
{
|
2006-08-02 03:59:48 +02:00
|
|
|
SetToDefault *def = (SetToDefault *) expr;
|
2003-07-03 18:34:26 +02:00
|
|
|
|
|
|
|
def->typeId = attrtype;
|
|
|
|
def->typeMod = attrtypmod;
|
2011-03-20 01:29:08 +01:00
|
|
|
def->collation = attrcollation;
|
2003-07-03 18:34:26 +02:00
|
|
|
if (indirection)
|
2004-06-09 21:08:20 +02:00
|
|
|
{
|
|
|
|
if (IsA(linitial(indirection), A_Indices))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2006-03-23 01:19:30 +01:00
|
|
|
errmsg("cannot set an array element to DEFAULT"),
|
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2006-03-23 01:19:30 +01:00
|
|
|
errmsg("cannot set a subfield to DEFAULT"),
|
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
2003-06-25 06:19:24 +02:00
|
|
|
}
|
|
|
|
|
2003-07-03 18:34:26 +02:00
|
|
|
/* Now we can use exprType() safely. */
|
2006-08-02 03:59:48 +02:00
|
|
|
type_id = exprType((Node *) expr);
|
2003-06-25 06:19:24 +02:00
|
|
|
|
1998-08-25 05:17:29 +02:00
|
|
|
/*
|
2004-06-09 21:08:20 +02:00
|
|
|
* If there is indirection on the target column, prepare an array or
|
2014-05-06 18:12:18 +02:00
|
|
|
* subfield assignment expression. This will generate a new column value
|
2005-10-15 04:49:52 +02:00
|
|
|
* that the source value has been inserted into, which can then be placed
|
|
|
|
* in the new tuple constructed by INSERT or UPDATE.
|
1998-08-25 05:17:29 +02:00
|
|
|
*/
|
1999-07-19 02:26:20 +02:00
|
|
|
if (indirection)
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
2004-06-09 21:08:20 +02:00
|
|
|
Node *colVar;
|
1999-07-19 02:26:20 +02:00
|
|
|
|
|
|
|
if (pstate->p_is_insert)
|
1998-08-25 05:17:29 +02:00
|
|
|
{
|
1999-07-19 02:26:20 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The command is INSERT INTO table (col.something) ... so there
|
|
|
|
* is not really a source value to work with. Insert a NULL
|
|
|
|
* constant as the source value.
|
2001-02-14 22:35:07 +01:00
|
|
|
*/
|
2011-03-26 01:10:42 +01:00
|
|
|
colVar = (Node *) makeNullConst(attrtype, attrtypmod,
|
|
|
|
attrcollation);
|
2001-02-14 22:35:07 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
2004-06-09 21:08:20 +02:00
|
|
|
* Build a Var for the column to be updated.
|
1999-07-19 02:26:20 +02:00
|
|
|
*/
|
2004-06-09 21:08:20 +02:00
|
|
|
colVar = (Node *) make_var(pstate,
|
|
|
|
pstate->p_target_rangetblentry,
|
2008-08-29 01:09:48 +02:00
|
|
|
attrno,
|
|
|
|
location);
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
2001-02-14 22:35:07 +01:00
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
expr = (Expr *)
|
2004-06-09 21:08:20 +02:00
|
|
|
transformAssignmentIndirection(pstate,
|
|
|
|
colVar,
|
|
|
|
colname,
|
|
|
|
false,
|
|
|
|
attrtype,
|
|
|
|
attrtypmod,
|
2011-03-26 19:25:48 +01:00
|
|
|
attrcollation,
|
2004-06-09 21:08:20 +02:00
|
|
|
list_head(indirection),
|
2006-08-02 03:59:48 +02:00
|
|
|
(Node *) expr,
|
2006-03-23 01:19:30 +01:00
|
|
|
location);
|
1998-08-25 05:17:29 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
2004-06-09 21:08:20 +02:00
|
|
|
* For normal non-qualified target column, do type checking and
|
|
|
|
* coercion.
|
1998-08-25 05:17:29 +02:00
|
|
|
*/
|
2009-06-11 16:49:15 +02:00
|
|
|
Node *orig_expr = (Node *) expr;
|
2008-10-07 03:47:55 +02:00
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
expr = (Expr *)
|
2004-06-09 21:08:20 +02:00
|
|
|
coerce_to_target_type(pstate,
|
2008-10-07 03:47:55 +02:00
|
|
|
orig_expr, type_id,
|
2004-06-09 21:08:20 +02:00
|
|
|
attrtype, attrtypmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
2008-08-29 01:09:48 +02:00
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
2006-08-02 03:59:48 +02:00
|
|
|
if (expr == NULL)
|
2004-06-09 21:08:20 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("column \"%s\" is of type %s"
|
|
|
|
" but expression is of type %s",
|
|
|
|
colname,
|
|
|
|
format_type_be(attrtype),
|
|
|
|
format_type_be(type_id)),
|
2006-10-04 02:30:14 +02:00
|
|
|
errhint("You will need to rewrite or cast the expression."),
|
2008-10-07 03:47:55 +02:00
|
|
|
parser_errposition(pstate, exprLocation(orig_expr))));
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
pstate->p_expr_kind = sv_expr_kind;
|
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* updateTargetListEntry()
|
2006-10-04 02:30:14 +02:00
|
|
|
* This is used in UPDATE statements only. It prepares an UPDATE
|
2006-08-02 03:59:48 +02:00
|
|
|
* TargetEntry for assignment to a column of the target table.
|
|
|
|
* This includes coercing the given value to the target column's type
|
|
|
|
* (if necessary), and dealing with any subfield names or subscripts
|
|
|
|
* attached to the target column itself.
|
|
|
|
*
|
|
|
|
* pstate parse state
|
|
|
|
* tle target list entry to be modified
|
|
|
|
* colname target column name (ie, name of attribute to be assigned to)
|
|
|
|
* attrno target attribute number
|
|
|
|
* indirection subscripts/field names for target column, if any
|
|
|
|
* location error cursor position (should point at column name), or -1
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
updateTargetListEntry(ParseState *pstate,
|
|
|
|
TargetEntry *tle,
|
|
|
|
char *colname,
|
|
|
|
int attrno,
|
|
|
|
List *indirection,
|
|
|
|
int location)
|
|
|
|
{
|
|
|
|
/* Fix up expression as needed */
|
|
|
|
tle->expr = transformAssignedExpr(pstate,
|
|
|
|
tle->expr,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
EXPR_KIND_UPDATE_TARGET,
|
2006-08-02 03:59:48 +02:00
|
|
|
colname,
|
|
|
|
attrno,
|
|
|
|
indirection,
|
|
|
|
location);
|
|
|
|
|
2003-08-12 01:04:50 +02:00
|
|
|
/*
|
|
|
|
* Set the resno to identify the target column --- the rewriter and
|
2014-05-06 18:12:18 +02:00
|
|
|
* planner depend on this. We also set the resname to identify the target
|
2005-10-15 04:49:52 +02:00
|
|
|
* column, but this is only for debugging purposes; it should not be
|
|
|
|
* relied on. (In particular, it might be out of date in a stored rule.)
|
2003-08-12 01:04:50 +02:00
|
|
|
*/
|
2005-04-06 18:34:07 +02:00
|
|
|
tle->resno = (AttrNumber) attrno;
|
|
|
|
tle->resname = colname;
|
1999-07-19 02:26:20 +02:00
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2006-08-02 03:59:48 +02:00
|
|
|
|
2004-06-09 21:08:20 +02:00
|
|
|
/*
|
|
|
|
* Process indirection (field selection or subscripting) of the target
|
|
|
|
* column in INSERT/UPDATE. This routine recurses for multiple levels
|
|
|
|
* of indirection --- but note that several adjacent A_Indices nodes in
|
|
|
|
* the indirection list are treated as a single multidimensional subscript
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
* In the initial call, basenode is a Var for the target column in UPDATE,
|
|
|
|
* or a null Const of the target's type in INSERT. In recursive calls,
|
|
|
|
* basenode is NULL, indicating that a substitute node should be consed up if
|
|
|
|
* needed.
|
|
|
|
*
|
|
|
|
* targetName is the name of the field or subfield we're assigning to, and
|
|
|
|
* targetIsArray is true if we're subscripting it. These are just for
|
|
|
|
* error reporting.
|
|
|
|
*
|
2011-03-26 19:25:48 +01:00
|
|
|
* targetTypeId, targetTypMod, targetCollation indicate the datatype and
|
|
|
|
* collation of the object to be assigned to (initially the target column,
|
|
|
|
* later some subobject).
|
2004-06-09 21:08:20 +02:00
|
|
|
*
|
|
|
|
* indirection is the sublist remaining to process. When it's NULL, we're
|
|
|
|
* done recursing and can just coerce and return the RHS.
|
|
|
|
*
|
|
|
|
* rhs is the already-transformed value to be assigned; note it has not been
|
|
|
|
* coerced to any particular type.
|
2006-03-23 01:19:30 +01:00
|
|
|
*
|
|
|
|
* location is the cursor error position for any errors. (Note: this points
|
|
|
|
* to the head of the target clause, eg "foo" in "foo.bar[baz]". Later we
|
|
|
|
* might want to decorate indirection cells with their own location info,
|
|
|
|
* in which case the location argument could probably be dropped.)
|
2004-06-09 21:08:20 +02:00
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
transformAssignmentIndirection(ParseState *pstate,
|
|
|
|
Node *basenode,
|
|
|
|
const char *targetName,
|
|
|
|
bool targetIsArray,
|
|
|
|
Oid targetTypeId,
|
|
|
|
int32 targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid targetCollation,
|
2004-06-09 21:08:20 +02:00
|
|
|
ListCell *indirection,
|
2006-03-23 01:19:30 +01:00
|
|
|
Node *rhs,
|
|
|
|
int location)
|
2004-06-09 21:08:20 +02:00
|
|
|
{
|
|
|
|
Node *result;
|
|
|
|
List *subscripts = NIL;
|
|
|
|
bool isSlice = false;
|
|
|
|
ListCell *i;
|
|
|
|
|
|
|
|
if (indirection && !basenode)
|
|
|
|
{
|
|
|
|
/* Set up a substitution. We reuse CaseTestExpr for this. */
|
|
|
|
CaseTestExpr *ctest = makeNode(CaseTestExpr);
|
|
|
|
|
|
|
|
ctest->typeId = targetTypeId;
|
|
|
|
ctest->typeMod = targetTypMod;
|
2011-03-26 19:25:48 +01:00
|
|
|
ctest->collation = targetCollation;
|
2004-06-09 21:08:20 +02:00
|
|
|
basenode = (Node *) ctest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to split any field-selection operations apart from
|
2005-10-15 04:49:52 +02:00
|
|
|
* subscripting. Adjacent A_Indices nodes have to be treated as a single
|
|
|
|
* multidimensional subscript operation.
|
2004-06-09 21:08:20 +02:00
|
|
|
*/
|
|
|
|
for_each_cell(i, indirection)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
Node *n = lfirst(i);
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
if (IsA(n, A_Indices))
|
|
|
|
{
|
|
|
|
subscripts = lappend(subscripts, n);
|
|
|
|
if (((A_Indices *) n)->lidx != NULL)
|
|
|
|
isSlice = true;
|
|
|
|
}
|
2008-08-30 03:39:14 +02:00
|
|
|
else if (IsA(n, A_Star))
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("row expansion via \"*\" is not supported here"),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
2004-06-09 21:08:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
FieldStore *fstore;
|
2004-08-29 07:07:03 +02:00
|
|
|
Oid typrelid;
|
|
|
|
AttrNumber attnum;
|
|
|
|
Oid fieldTypeId;
|
|
|
|
int32 fieldTypMod;
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid fieldCollation;
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
Assert(IsA(n, String));
|
|
|
|
|
|
|
|
/* process subscripts before this field selection */
|
|
|
|
if (subscripts)
|
|
|
|
{
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
/* recurse, and then return because we're done */
|
|
|
|
return transformAssignmentSubscripts(pstate,
|
|
|
|
basenode,
|
2004-06-09 21:08:20 +02:00
|
|
|
targetName,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
targetTypeId,
|
2004-06-09 21:08:20 +02:00
|
|
|
targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
targetCollation,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
subscripts,
|
|
|
|
isSlice,
|
2004-06-09 21:08:20 +02:00
|
|
|
i,
|
2006-03-23 01:19:30 +01:00
|
|
|
rhs,
|
|
|
|
location);
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* No subscripts, so can process field selection here */
|
|
|
|
|
|
|
|
typrelid = typeidTypeRelid(targetTypeId);
|
|
|
|
if (!typrelid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
2004-10-25 05:08:29 +02:00
|
|
|
errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
|
|
|
|
strVal(n), targetName,
|
2006-03-23 01:19:30 +01:00
|
|
|
format_type_be(targetTypeId)),
|
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
attnum = get_attnum(typrelid, strVal(n));
|
|
|
|
if (attnum == InvalidAttrNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
2004-10-25 05:08:29 +02:00
|
|
|
errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s",
|
|
|
|
strVal(n), targetName,
|
2006-03-23 01:19:30 +01:00
|
|
|
format_type_be(targetTypeId)),
|
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
if (attnum < 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("cannot assign to system column \"%s\"",
|
2006-03-23 01:19:30 +01:00
|
|
|
strVal(n)),
|
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
|
2011-03-26 19:25:48 +01:00
|
|
|
get_atttypetypmodcoll(typrelid, attnum,
|
2011-04-10 17:42:00 +02:00
|
|
|
&fieldTypeId, &fieldTypMod, &fieldCollation);
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
/* recurse to create appropriate RHS for field assign */
|
|
|
|
rhs = transformAssignmentIndirection(pstate,
|
|
|
|
NULL,
|
|
|
|
strVal(n),
|
|
|
|
false,
|
|
|
|
fieldTypeId,
|
|
|
|
fieldTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
fieldCollation,
|
2004-06-09 21:08:20 +02:00
|
|
|
lnext(i),
|
2006-03-23 01:19:30 +01:00
|
|
|
rhs,
|
|
|
|
location);
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
/* and build a FieldStore node */
|
|
|
|
fstore = makeNode(FieldStore);
|
|
|
|
fstore->arg = (Expr *) basenode;
|
|
|
|
fstore->newvals = list_make1(rhs);
|
|
|
|
fstore->fieldnums = list_make1_int(attnum);
|
|
|
|
fstore->resulttype = targetTypeId;
|
|
|
|
|
|
|
|
return (Node *) fstore;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process trailing subscripts, if any */
|
|
|
|
if (subscripts)
|
|
|
|
{
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
/* recurse, and then return because we're done */
|
|
|
|
return transformAssignmentSubscripts(pstate,
|
|
|
|
basenode,
|
2004-06-09 21:08:20 +02:00
|
|
|
targetName,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
targetTypeId,
|
2004-06-09 21:08:20 +02:00
|
|
|
targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
targetCollation,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
subscripts,
|
|
|
|
isSlice,
|
2004-06-09 21:08:20 +02:00
|
|
|
NULL,
|
2006-03-23 01:19:30 +01:00
|
|
|
rhs,
|
|
|
|
location);
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* base case: just coerce RHS to match target type ID */
|
|
|
|
|
|
|
|
result = coerce_to_target_type(pstate,
|
|
|
|
rhs, exprType(rhs),
|
|
|
|
targetTypeId, targetTypMod,
|
|
|
|
COERCION_ASSIGNMENT,
|
2008-08-29 01:09:48 +02:00
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
2004-06-09 21:08:20 +02:00
|
|
|
if (result == NULL)
|
|
|
|
{
|
|
|
|
if (targetIsArray)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("array assignment to \"%s\" requires type %s"
|
|
|
|
" but expression is of type %s",
|
|
|
|
targetName,
|
|
|
|
format_type_be(targetTypeId),
|
|
|
|
format_type_be(exprType(rhs))),
|
2006-10-04 02:30:14 +02:00
|
|
|
errhint("You will need to rewrite or cast the expression."),
|
2006-03-23 01:19:30 +01:00
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("subfield \"%s\" is of type %s"
|
|
|
|
" but expression is of type %s",
|
|
|
|
targetName,
|
|
|
|
format_type_be(targetTypeId),
|
|
|
|
format_type_be(exprType(rhs))),
|
2006-10-04 02:30:14 +02:00
|
|
|
errhint("You will need to rewrite or cast the expression."),
|
2006-03-23 01:19:30 +01:00
|
|
|
parser_errposition(pstate, location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
/*
|
|
|
|
* helper for transformAssignmentIndirection: process array assignment
|
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
transformAssignmentSubscripts(ParseState *pstate,
|
|
|
|
Node *basenode,
|
|
|
|
const char *targetName,
|
|
|
|
Oid targetTypeId,
|
|
|
|
int32 targetTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid targetCollation,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
List *subscripts,
|
|
|
|
bool isSlice,
|
|
|
|
ListCell *next_indirection,
|
|
|
|
Node *rhs,
|
|
|
|
int location)
|
|
|
|
{
|
|
|
|
Node *result;
|
|
|
|
Oid arrayType;
|
|
|
|
int32 arrayTypMod;
|
|
|
|
Oid elementTypeId;
|
|
|
|
Oid typeNeeded;
|
2011-03-26 19:25:48 +01:00
|
|
|
Oid collationNeeded;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
|
|
|
|
Assert(subscripts != NIL);
|
|
|
|
|
|
|
|
/* Identify the actual array type and element type involved */
|
|
|
|
arrayType = targetTypeId;
|
|
|
|
arrayTypMod = targetTypMod;
|
|
|
|
elementTypeId = transformArrayType(&arrayType, &arrayTypMod);
|
|
|
|
|
|
|
|
/* Identify type that RHS must provide */
|
|
|
|
typeNeeded = isSlice ? arrayType : elementTypeId;
|
|
|
|
|
2011-03-26 19:25:48 +01:00
|
|
|
/*
|
|
|
|
* Array normally has same collation as elements, but there's an
|
2011-04-10 17:42:00 +02:00
|
|
|
* exception: we might be subscripting a domain over an array type. In
|
|
|
|
* that case use collation of the base type.
|
2011-03-26 19:25:48 +01:00
|
|
|
*/
|
|
|
|
if (arrayType == targetTypeId)
|
|
|
|
collationNeeded = targetCollation;
|
|
|
|
else
|
|
|
|
collationNeeded = get_typcollation(arrayType);
|
|
|
|
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
/* recurse to create appropriate RHS for array assign */
|
|
|
|
rhs = transformAssignmentIndirection(pstate,
|
|
|
|
NULL,
|
|
|
|
targetName,
|
|
|
|
true,
|
|
|
|
typeNeeded,
|
|
|
|
arrayTypMod,
|
2011-03-26 19:25:48 +01:00
|
|
|
collationNeeded,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
next_indirection,
|
|
|
|
rhs,
|
|
|
|
location);
|
|
|
|
|
|
|
|
/* process subscripts */
|
|
|
|
result = (Node *) transformArraySubscripts(pstate,
|
|
|
|
basenode,
|
|
|
|
arrayType,
|
|
|
|
elementTypeId,
|
|
|
|
arrayTypMod,
|
|
|
|
subscripts,
|
|
|
|
rhs);
|
|
|
|
|
|
|
|
/* If target was a domain over array, need to coerce up to the domain */
|
|
|
|
if (arrayType != targetTypeId)
|
|
|
|
{
|
Fix array slicing of int2vector and oidvector values.
The previous coding labeled expressions such as pg_index.indkey[1:3] as
being of int2vector type; which is not right because the subscript bounds
of such a result don't, in general, satisfy the restrictions of int2vector.
To fix, implicitly promote the result of slicing int2vector to int2[],
or oidvector to oid[]. This is similar to what we've done with domains
over arrays, which is a good analogy because these types are very much
like restricted domains of the corresponding regular-array types.
A side-effect is that we now also forbid array-element updates on such
columns, eg while "update pg_index set indkey[4] = 42" would have worked
before if you were superuser (and corrupted your catalogs irretrievably,
no doubt) it's now disallowed. This seems like a good thing since, again,
some choices of subscripting would've led to results not satisfying the
restrictions of int2vector. The case of an array-slice update was
rejected before, though with a different error message than you get now.
We could make these cases work in future if we added a cast from int2[]
to int2vector (with a cast function checking the subscript restrictions)
but it seems unlikely that there's any value in that.
Per report from Ronan Dunklau. Back-patch to all supported branches
because of the crash risks involved.
2013-11-24 02:03:56 +01:00
|
|
|
Oid resulttype = exprType(result);
|
|
|
|
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
result = coerce_to_target_type(pstate,
|
Fix array slicing of int2vector and oidvector values.
The previous coding labeled expressions such as pg_index.indkey[1:3] as
being of int2vector type; which is not right because the subscript bounds
of such a result don't, in general, satisfy the restrictions of int2vector.
To fix, implicitly promote the result of slicing int2vector to int2[],
or oidvector to oid[]. This is similar to what we've done with domains
over arrays, which is a good analogy because these types are very much
like restricted domains of the corresponding regular-array types.
A side-effect is that we now also forbid array-element updates on such
columns, eg while "update pg_index set indkey[4] = 42" would have worked
before if you were superuser (and corrupted your catalogs irretrievably,
no doubt) it's now disallowed. This seems like a good thing since, again,
some choices of subscripting would've led to results not satisfying the
restrictions of int2vector. The case of an array-slice update was
rejected before, though with a different error message than you get now.
We could make these cases work in future if we added a cast from int2[]
to int2vector (with a cast function checking the subscript restrictions)
but it seems unlikely that there's any value in that.
Per report from Ronan Dunklau. Back-patch to all supported branches
because of the crash risks involved.
2013-11-24 02:03:56 +01:00
|
|
|
result, resulttype,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
targetTypeId, targetTypMod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
Fix array slicing of int2vector and oidvector values.
The previous coding labeled expressions such as pg_index.indkey[1:3] as
being of int2vector type; which is not right because the subscript bounds
of such a result don't, in general, satisfy the restrictions of int2vector.
To fix, implicitly promote the result of slicing int2vector to int2[],
or oidvector to oid[]. This is similar to what we've done with domains
over arrays, which is a good analogy because these types are very much
like restricted domains of the corresponding regular-array types.
A side-effect is that we now also forbid array-element updates on such
columns, eg while "update pg_index set indkey[4] = 42" would have worked
before if you were superuser (and corrupted your catalogs irretrievably,
no doubt) it's now disallowed. This seems like a good thing since, again,
some choices of subscripting would've led to results not satisfying the
restrictions of int2vector. The case of an array-slice update was
rejected before, though with a different error message than you get now.
We could make these cases work in future if we added a cast from int2[]
to int2vector (with a cast function checking the subscript restrictions)
but it seems unlikely that there's any value in that.
Per report from Ronan Dunklau. Back-patch to all supported branches
because of the crash risks involved.
2013-11-24 02:03:56 +01:00
|
|
|
/* can fail if we had int2vector/oidvector, but not for true domains */
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
if (result == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_CANNOT_COERCE),
|
|
|
|
errmsg("cannot cast type %s to %s",
|
Fix array slicing of int2vector and oidvector values.
The previous coding labeled expressions such as pg_index.indkey[1:3] as
being of int2vector type; which is not right because the subscript bounds
of such a result don't, in general, satisfy the restrictions of int2vector.
To fix, implicitly promote the result of slicing int2vector to int2[],
or oidvector to oid[]. This is similar to what we've done with domains
over arrays, which is a good analogy because these types are very much
like restricted domains of the corresponding regular-array types.
A side-effect is that we now also forbid array-element updates on such
columns, eg while "update pg_index set indkey[4] = 42" would have worked
before if you were superuser (and corrupted your catalogs irretrievably,
no doubt) it's now disallowed. This seems like a good thing since, again,
some choices of subscripting would've led to results not satisfying the
restrictions of int2vector. The case of an array-slice update was
rejected before, though with a different error message than you get now.
We could make these cases work in future if we added a cast from int2[]
to int2vector (with a cast function checking the subscript restrictions)
but it seems unlikely that there's any value in that.
Per report from Ronan Dunklau. Back-patch to all supported branches
because of the crash risks involved.
2013-11-24 02:03:56 +01:00
|
|
|
format_type_be(resulttype),
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
format_type_be(targetTypeId)),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
/*
|
1999-11-01 06:06:21 +01:00
|
|
|
* checkInsertTargets -
|
2002-03-21 17:02:16 +01:00
|
|
|
* generate a list of INSERT column targets if not supplied, or
|
1999-07-19 02:26:20 +02:00
|
|
|
* test supplied column names to make sure they are in target table.
|
1999-11-01 06:06:21 +01:00
|
|
|
* Also return an integer list of the columns' attribute numbers.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
|
|
|
List *
|
1999-11-01 06:06:21 +01:00
|
|
|
checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
1999-11-01 06:06:21 +01:00
|
|
|
*attrnos = NIL;
|
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
if (cols == NIL)
|
|
|
|
{
|
1999-07-19 02:26:20 +02:00
|
|
|
/*
|
|
|
|
* Generate default column list for INSERT.
|
|
|
|
*/
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
|
1999-07-19 02:26:20 +02:00
|
|
|
int numcol = pstate->p_target_relation->rd_rel->relnatts;
|
|
|
|
int i;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
for (i = 0; i < numcol; i++)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ResTarget *col;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
if (attr[i]->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
col = makeNode(ResTarget);
|
2002-03-21 17:02:16 +01:00
|
|
|
col->name = pstrdup(NameStr(attr[i]->attname));
|
|
|
|
col->indirection = NIL;
|
|
|
|
col->val = NULL;
|
2006-03-23 01:19:30 +01:00
|
|
|
col->location = -1;
|
2002-03-21 17:02:16 +01:00
|
|
|
cols = lappend(cols, col);
|
2004-05-31 01:40:41 +02:00
|
|
|
*attrnos = lappend_int(*attrnos, i + 1);
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-07-19 02:26:20 +02:00
|
|
|
/*
|
|
|
|
* Do initial validation of user-supplied INSERT column list.
|
|
|
|
*/
|
2005-03-26 07:28:59 +01:00
|
|
|
Bitmapset *wholecols = NULL;
|
|
|
|
Bitmapset *partialcols = NULL;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *tl;
|
1999-07-19 02:26:20 +02:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
foreach(tl, cols)
|
|
|
|
{
|
2004-06-09 21:08:20 +02:00
|
|
|
ResTarget *col = (ResTarget *) lfirst(tl);
|
|
|
|
char *name = col->name;
|
1999-11-01 06:06:21 +01:00
|
|
|
int attrno;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
2003-07-19 22:20:53 +02:00
|
|
|
/* Lookup column name, ereport on failure */
|
2002-08-02 20:15:10 +02:00
|
|
|
attrno = attnameAttNum(pstate->p_target_relation, name, false);
|
2006-03-23 01:19:30 +01:00
|
|
|
if (attrno == InvalidAttrNumber)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
2006-10-04 02:30:14 +02:00
|
|
|
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
|
|
|
name,
|
|
|
|
RelationGetRelationName(pstate->p_target_relation)),
|
2006-03-23 01:19:30 +01:00
|
|
|
parser_errposition(pstate, col->location)));
|
2004-06-09 21:08:20 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check for duplicates, but only of whole columns --- we allow
|
|
|
|
* INSERT INTO foo (col.subcol1, col.subcol2)
|
2004-06-09 21:08:20 +02:00
|
|
|
*/
|
|
|
|
if (col->indirection == NIL)
|
|
|
|
{
|
|
|
|
/* whole column; must not have any other assignment */
|
2005-03-26 07:28:59 +01:00
|
|
|
if (bms_is_member(attrno, wholecols) ||
|
|
|
|
bms_is_member(attrno, partialcols))
|
2004-06-09 21:08:20 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("column \"%s\" specified more than once",
|
2006-03-23 01:19:30 +01:00
|
|
|
name),
|
|
|
|
parser_errposition(pstate, col->location)));
|
2005-03-26 07:28:59 +01:00
|
|
|
wholecols = bms_add_member(wholecols, attrno);
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* partial column; must not have any whole assignment */
|
2005-03-26 07:28:59 +01:00
|
|
|
if (bms_is_member(attrno, wholecols))
|
2004-06-09 21:08:20 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("column \"%s\" specified more than once",
|
2006-03-23 01:19:30 +01:00
|
|
|
name),
|
|
|
|
parser_errposition(pstate, col->location)));
|
2005-03-26 07:28:59 +01:00
|
|
|
partialcols = bms_add_member(partialcols, attrno);
|
2004-06-09 21:08:20 +02:00
|
|
|
}
|
|
|
|
|
2004-05-31 01:40:41 +02:00
|
|
|
*attrnos = lappend_int(*attrnos, attrno);
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
}
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
return cols;
|
|
|
|
}
|
|
|
|
|
2004-06-19 20:19:56 +02:00
|
|
|
/*
|
|
|
|
* ExpandColumnRefStar()
|
2006-06-26 19:24:41 +02:00
|
|
|
* Transforms foo.* into a list of expressions or targetlist entries.
|
2004-06-19 20:19:56 +02:00
|
|
|
*
|
2008-08-30 03:39:14 +02:00
|
|
|
* This handles the case where '*' appears as the last or only item in a
|
2006-06-26 19:24:41 +02:00
|
|
|
* ColumnRef. The code is shared between the case of foo.* at the top level
|
|
|
|
* in a SELECT target list (where we want TargetEntry nodes in the result)
|
2006-08-02 03:59:48 +02:00
|
|
|
* and foo.* in a ROW() or VALUES() construct (where we want just bare
|
|
|
|
* expressions).
|
2009-01-22 21:16:10 +01:00
|
|
|
*
|
|
|
|
* The referenced columns are marked as requiring SELECT access.
|
2004-06-19 20:19:56 +02:00
|
|
|
*/
|
2006-08-02 03:59:48 +02:00
|
|
|
static List *
|
2006-06-26 19:24:41 +02:00
|
|
|
ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry)
|
2004-06-19 20:19:56 +02:00
|
|
|
{
|
|
|
|
List *fields = cref->fields;
|
|
|
|
int numnames = list_length(fields);
|
|
|
|
|
|
|
|
if (numnames == 1)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Target item is a bare '*', expand all tables
|
|
|
|
*
|
|
|
|
* (e.g., SELECT * FROM emp, dept)
|
2006-06-26 19:24:41 +02:00
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Since the grammar only accepts bare '*' at top level of SELECT, we
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* need not handle the make_target_entry==false case here.
|
2004-06-19 20:19:56 +02:00
|
|
|
*/
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
Assert(make_target_entry);
|
2008-09-01 22:42:46 +02:00
|
|
|
return ExpandAllTables(pstate, cref->location);
|
2004-06-19 20:19:56 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Target item is relation.*, expand that table
|
|
|
|
*
|
|
|
|
* (e.g., SELECT emp.*, dname FROM emp, dept)
|
2009-10-31 02:41:31 +01:00
|
|
|
*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Note: this code is a lot like transformColumnRef; it's tempting to
|
|
|
|
* call that instead and then replace the resulting whole-row Var with
|
2014-05-06 18:12:18 +02:00
|
|
|
* a list of Vars. However, that would leave us with the RTE's
|
2010-02-26 03:01:40 +01:00
|
|
|
* selectedCols bitmap showing the whole row as needing select
|
|
|
|
* permission, as well as the individual columns. That would be
|
|
|
|
* incorrect (since columns added later shouldn't need select
|
2009-10-31 02:41:31 +01:00
|
|
|
* permissions). We could try to remove the whole-row permission bit
|
|
|
|
* after the fact, but duplicating code is less messy.
|
2004-06-19 20:19:56 +02:00
|
|
|
*/
|
2009-10-31 02:41:31 +01:00
|
|
|
char *nspname = NULL;
|
|
|
|
char *relname = NULL;
|
|
|
|
RangeTblEntry *rte = NULL;
|
|
|
|
int levels_up;
|
2010-02-26 03:01:40 +01:00
|
|
|
enum
|
|
|
|
{
|
2009-10-31 02:41:31 +01:00
|
|
|
CRSERR_NO_RTE,
|
|
|
|
CRSERR_WRONG_DB,
|
|
|
|
CRSERR_TOO_MANY
|
|
|
|
} crserr = CRSERR_NO_RTE;
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Give the PreParseColumnRefHook, if any, first shot. If it returns
|
2009-10-31 02:41:31 +01:00
|
|
|
* non-null then we should use that expression.
|
|
|
|
*/
|
|
|
|
if (pstate->p_pre_columnref_hook != NULL)
|
|
|
|
{
|
|
|
|
Node *node;
|
|
|
|
|
|
|
|
node = (*pstate->p_pre_columnref_hook) (pstate, cref);
|
|
|
|
if (node != NULL)
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
return ExpandRowReference(pstate, node, make_target_entry);
|
2009-10-31 02:41:31 +01:00
|
|
|
}
|
2004-06-19 20:19:56 +02:00
|
|
|
|
|
|
|
switch (numnames)
|
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
relname = strVal(linitial(fields));
|
2009-10-31 02:41:31 +01:00
|
|
|
rte = refnameRangeTblEntry(pstate, nspname, relname,
|
|
|
|
cref->location,
|
|
|
|
&levels_up);
|
2004-06-19 20:19:56 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2009-10-31 02:41:31 +01:00
|
|
|
nspname = strVal(linitial(fields));
|
2004-06-19 20:19:56 +02:00
|
|
|
relname = strVal(lsecond(fields));
|
2009-10-31 02:41:31 +01:00
|
|
|
rte = refnameRangeTblEntry(pstate, nspname, relname,
|
|
|
|
cref->location,
|
|
|
|
&levels_up);
|
2004-06-19 20:19:56 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
char *catname = strVal(linitial(fields));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We check the catalog name and then ignore it.
|
|
|
|
*/
|
|
|
|
if (strcmp(catname, get_database_name(MyDatabaseId)) != 0)
|
|
|
|
{
|
|
|
|
crserr = CRSERR_WRONG_DB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nspname = strVal(lsecond(fields));
|
|
|
|
relname = strVal(lthird(fields));
|
|
|
|
rte = refnameRangeTblEntry(pstate, nspname, relname,
|
|
|
|
cref->location,
|
|
|
|
&levels_up);
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-06-19 20:19:56 +02:00
|
|
|
default:
|
2009-10-31 02:41:31 +01:00
|
|
|
crserr = CRSERR_TOO_MANY;
|
2004-06-19 20:19:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Now give the PostParseColumnRefHook, if any, a chance. We cheat a
|
|
|
|
* bit by passing the RangeTblEntry, not a Var, as the planned
|
|
|
|
* translation. (A single Var wouldn't be strictly correct anyway.
|
|
|
|
* This convention allows hooks that really care to know what is
|
|
|
|
* happening.)
|
2009-10-31 02:41:31 +01:00
|
|
|
*/
|
|
|
|
if (pstate->p_post_columnref_hook != NULL)
|
2006-06-26 19:24:41 +02:00
|
|
|
{
|
2009-10-31 02:41:31 +01:00
|
|
|
Node *node;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
node = (*pstate->p_post_columnref_hook) (pstate, cref,
|
|
|
|
(Node *) rte);
|
|
|
|
if (node != NULL)
|
2009-01-22 21:16:10 +01:00
|
|
|
{
|
2009-10-31 02:41:31 +01:00
|
|
|
if (rte != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
|
|
|
|
errmsg("column reference \"%s\" is ambiguous",
|
|
|
|
NameListToString(cref->fields)),
|
|
|
|
parser_errposition(pstate, cref->location)));
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
return ExpandRowReference(pstate, node, make_target_entry);
|
2009-01-22 21:16:10 +01:00
|
|
|
}
|
2009-10-31 02:41:31 +01:00
|
|
|
}
|
2009-01-22 21:16:10 +01:00
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
/*
|
|
|
|
* Throw error if no translation found.
|
|
|
|
*/
|
|
|
|
if (rte == NULL)
|
|
|
|
{
|
|
|
|
switch (crserr)
|
|
|
|
{
|
|
|
|
case CRSERR_NO_RTE:
|
|
|
|
errorMissingRTE(pstate, makeRangeVar(nspname, relname,
|
|
|
|
cref->location));
|
|
|
|
break;
|
|
|
|
case CRSERR_WRONG_DB:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cross-database references are not implemented: %s",
|
|
|
|
NameListToString(cref->fields)),
|
|
|
|
parser_errposition(pstate, cref->location)));
|
|
|
|
break;
|
|
|
|
case CRSERR_TOO_MANY:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("improper qualified name (too many dotted names): %s",
|
|
|
|
NameListToString(cref->fields)),
|
|
|
|
parser_errposition(pstate, cref->location)));
|
|
|
|
break;
|
|
|
|
}
|
2006-06-26 19:24:41 +02:00
|
|
|
}
|
2009-10-31 02:41:31 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* OK, expand the RTE into fields.
|
|
|
|
*/
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
return ExpandSingleTable(pstate, rte, cref->location, make_target_entry);
|
2004-06-19 20:19:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ExpandAllTables()
|
2006-06-26 19:24:41 +02:00
|
|
|
* Transforms '*' (in the target list) into a list of targetlist entries.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2012-08-08 22:41:04 +02:00
|
|
|
* tlist entries are generated for each relation visible for unqualified
|
2014-05-06 18:12:18 +02:00
|
|
|
* column name access. We do not consider qualified-name-only entries because
|
2012-08-08 22:41:04 +02:00
|
|
|
* that would include input tables of aliasless JOINs, NEW/OLD pseudo-entries,
|
|
|
|
* etc.
|
2009-01-22 21:16:10 +01:00
|
|
|
*
|
|
|
|
* The referenced relations/columns are marked as requiring SELECT access.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
1997-11-26 04:43:18 +01:00
|
|
|
static List *
|
2008-09-01 22:42:46 +02:00
|
|
|
ExpandAllTables(ParseState *pstate, int location)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
|
|
|
List *target = NIL;
|
2012-08-08 22:41:04 +02:00
|
|
|
bool found_table = false;
|
2005-06-05 02:38:11 +02:00
|
|
|
ListCell *l;
|
1997-11-25 23:07:18 +01: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;
|
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
|
|
|
/* Should not have any lateral-only items when parsing targetlist */
|
|
|
|
Assert(!nsitem->p_lateral_only);
|
2012-08-08 22:41:04 +02:00
|
|
|
/* Remember we found a p_cols_visible item */
|
|
|
|
found_table = true;
|
2012-08-08 01:02:54 +02:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
target = list_concat(target,
|
2012-08-08 22:41:04 +02:00
|
|
|
expandRelAttrs(pstate,
|
|
|
|
rte,
|
|
|
|
RTERangeTablePosn(pstate, rte,
|
|
|
|
NULL),
|
|
|
|
0,
|
2008-09-01 22:42:46 +02:00
|
|
|
location));
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2012-08-08 22:41:04 +02:00
|
|
|
/*
|
|
|
|
* Check for "SELECT *;". We do it this way, rather than checking for
|
|
|
|
* target == NIL, because we want to allow SELECT * FROM a zero_column
|
|
|
|
* table.
|
|
|
|
*/
|
|
|
|
if (!found_table)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("SELECT * with no tables specified is not valid"),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2004-06-19 20:19:56 +02:00
|
|
|
/*
|
|
|
|
* ExpandIndirectionStar()
|
2006-06-26 19:24:41 +02:00
|
|
|
* Transforms foo.* into a list of expressions or targetlist entries.
|
2004-06-19 20:19:56 +02:00
|
|
|
*
|
|
|
|
* This handles the case where '*' appears as the last item in A_Indirection.
|
2006-06-26 19:24:41 +02:00
|
|
|
* The code is shared between the case of foo.* at the top level in a SELECT
|
|
|
|
* target list (where we want TargetEntry nodes in the result) and foo.* in
|
2006-08-02 03:59:48 +02:00
|
|
|
* a ROW() or VALUES() construct (where we want just bare expressions).
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* For robustness, we use a separate "make_target_entry" flag to control
|
|
|
|
* this rather than relying on exprKind.
|
2004-06-19 20:19:56 +02:00
|
|
|
*/
|
2006-08-02 03:59:48 +02:00
|
|
|
static List *
|
2006-06-26 19:24:41 +02:00
|
|
|
ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry, ParseExprKind exprKind)
|
2004-06-19 20:19:56 +02:00
|
|
|
{
|
|
|
|
Node *expr;
|
|
|
|
|
|
|
|
/* Strip off the '*' to create a reference to the rowtype object */
|
|
|
|
ind = copyObject(ind);
|
|
|
|
ind->indirection = list_truncate(ind->indirection,
|
|
|
|
list_length(ind->indirection) - 1);
|
|
|
|
|
|
|
|
/* And transform that */
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
expr = transformExpr(pstate, (Node *) ind, exprKind);
|
2004-06-19 20:19:56 +02:00
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
/* Expand the rowtype expression into individual fields */
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
return ExpandRowReference(pstate, expr, make_target_entry);
|
2009-10-31 02:41:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ExpandSingleTable()
|
|
|
|
* Transforms foo.* into a list of expressions or targetlist entries.
|
|
|
|
*
|
|
|
|
* This handles the case where foo has been determined to be a simple
|
|
|
|
* reference to an RTE, so we can just generate Vars for the expressions.
|
|
|
|
*
|
|
|
|
* The referenced columns are marked as requiring SELECT access.
|
|
|
|
*/
|
|
|
|
static List *
|
|
|
|
ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
int location, bool make_target_entry)
|
2009-10-31 02:41:31 +01:00
|
|
|
{
|
|
|
|
int sublevels_up;
|
|
|
|
int rtindex;
|
|
|
|
|
|
|
|
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
|
|
|
|
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
if (make_target_entry)
|
2009-10-31 02:41:31 +01:00
|
|
|
{
|
|
|
|
/* expandRelAttrs handles permissions marking */
|
|
|
|
return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
|
|
|
|
location);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
List *vars;
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
expandRTE(rte, rtindex, sublevels_up, location, false,
|
|
|
|
NULL, &vars);
|
|
|
|
|
|
|
|
/*
|
2010-02-26 03:01:40 +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.
|
2009-10-31 02:41:31 +01:00
|
|
|
*/
|
|
|
|
rte->requiredPerms |= ACL_SELECT;
|
|
|
|
|
|
|
|
/* Require read access to each column */
|
|
|
|
foreach(l, vars)
|
|
|
|
{
|
|
|
|
Var *var = (Var *) lfirst(l);
|
|
|
|
|
|
|
|
markVarForSelectPriv(pstate, var, rte);
|
|
|
|
}
|
|
|
|
|
|
|
|
return vars;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ExpandRowReference()
|
|
|
|
* Transforms foo.* into a list of expressions or targetlist entries.
|
|
|
|
*
|
|
|
|
* This handles the case where foo is an arbitrary expression of composite
|
|
|
|
* type.
|
|
|
|
*/
|
|
|
|
static List *
|
|
|
|
ExpandRowReference(ParseState *pstate, Node *expr,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
bool make_target_entry)
|
2009-10-31 02:41:31 +01:00
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
TupleDesc tupleDesc;
|
|
|
|
int numAttrs;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the rowtype expression is a whole-row Var, we can expand the fields
|
2014-05-06 18:12:18 +02:00
|
|
|
* as simple Vars. Note: if the RTE is a relation, this case leaves us
|
2009-10-31 02:41:31 +01:00
|
|
|
* with the RTE's selectedCols bitmap showing the whole row as needing
|
|
|
|
* select permission, as well as the individual columns. However, we can
|
|
|
|
* only get here for weird notations like (table.*).*, so it's not worth
|
|
|
|
* trying to clean up --- arguably, the permissions marking is correct
|
|
|
|
* anyway for such cases.
|
|
|
|
*/
|
|
|
|
if (IsA(expr, Var) &&
|
|
|
|
((Var *) expr)->varattno == InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
Var *var = (Var *) expr;
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
|
|
|
|
rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
return ExpandSingleTable(pstate, rte, var->location, make_target_entry);
|
2009-10-31 02:41:31 +01:00
|
|
|
}
|
|
|
|
|
2005-04-25 23:03:25 +02:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Otherwise we have to do it the hard way. Our current implementation is
|
|
|
|
* to generate multiple copies of the expression and do FieldSelects.
|
2009-10-31 02:41:31 +01:00
|
|
|
* (This can be pretty inefficient if the expression involves nontrivial
|
|
|
|
* computation :-(.)
|
|
|
|
*
|
2005-04-25 23:03:25 +02:00
|
|
|
* Verify it's a composite type, and get the tupdesc. We use
|
2005-10-15 04:49:52 +02:00
|
|
|
* get_expr_result_type() because that can handle references to functions
|
|
|
|
* returning anonymous record types. If that fails, use
|
|
|
|
* lookup_rowtype_tupdesc(), which will almost certainly fail as well, but
|
|
|
|
* it will give an appropriate error message.
|
2005-04-25 23:03:25 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* If it's a Var of type RECORD, we have to work even harder: we have to
|
|
|
|
* find what the Var refers to, and pass that to get_expr_result_type.
|
|
|
|
* That task is handled by expandRecordVariable().
|
2005-04-25 23:03:25 +02:00
|
|
|
*/
|
|
|
|
if (IsA(expr, Var) &&
|
|
|
|
((Var *) expr)->vartype == RECORDOID)
|
|
|
|
tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0);
|
|
|
|
else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
|
2006-06-16 20:42:24 +02:00
|
|
|
tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
|
|
|
|
exprTypmod(expr));
|
2005-04-25 23:03:25 +02:00
|
|
|
Assert(tupleDesc);
|
2004-06-19 20:19:56 +02:00
|
|
|
|
|
|
|
/* Generate a list of references to the individual fields */
|
|
|
|
numAttrs = tupleDesc->natts;
|
|
|
|
for (i = 0; i < numAttrs; i++)
|
|
|
|
{
|
|
|
|
Form_pg_attribute att = tupleDesc->attrs[i];
|
2009-10-31 02:41:31 +01:00
|
|
|
FieldSelect *fselect;
|
2004-06-19 20:19:56 +02:00
|
|
|
|
|
|
|
if (att->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
fselect = makeNode(FieldSelect);
|
|
|
|
fselect->arg = (Expr *) copyObject(expr);
|
|
|
|
fselect->fieldnum = i + 1;
|
|
|
|
fselect->resulttype = att->atttypid;
|
|
|
|
fselect->resulttypmod = att->atttypmod;
|
2011-04-09 20:40:09 +02:00
|
|
|
/* save attribute's collation for parse_collate.c */
|
2011-03-20 01:29:08 +01:00
|
|
|
fselect->resultcollid = att->attcollation;
|
2004-06-19 20:19:56 +02:00
|
|
|
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
if (make_target_entry)
|
2006-06-26 19:24:41 +02:00
|
|
|
{
|
|
|
|
/* add TargetEntry decoration */
|
|
|
|
TargetEntry *te;
|
|
|
|
|
2009-10-31 02:41:31 +01:00
|
|
|
te = makeTargetEntry((Expr *) fselect,
|
2006-06-26 19:24:41 +02:00
|
|
|
(AttrNumber) pstate->p_next_resno++,
|
|
|
|
pstrdup(NameStr(att->attname)),
|
|
|
|
false);
|
|
|
|
result = lappend(result, te);
|
|
|
|
}
|
|
|
|
else
|
2009-10-31 02:41:31 +01:00
|
|
|
result = lappend(result, fselect);
|
2004-06-19 20:19:56 +02:00
|
|
|
}
|
|
|
|
|
2006-06-26 19:24:41 +02:00
|
|
|
return result;
|
2004-06-19 20:19:56 +02:00
|
|
|
}
|
|
|
|
|
2005-04-25 23:03:25 +02:00
|
|
|
/*
|
|
|
|
* expandRecordVariable
|
|
|
|
* Get the tuple descriptor for a Var of type RECORD, if possible.
|
|
|
|
*
|
|
|
|
* Since no actual table or view column is allowed to have type RECORD, such
|
2014-05-06 18:12:18 +02:00
|
|
|
* a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
|
2005-04-25 23:03:25 +02:00
|
|
|
* drill down to find the ultimate defining expression and attempt to infer
|
|
|
|
* the tupdesc from it. We ereport if we can't determine the tupdesc.
|
|
|
|
*
|
|
|
|
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
|
|
|
|
*/
|
2005-05-31 03:03:23 +02:00
|
|
|
TupleDesc
|
2005-04-25 23:03:25 +02:00
|
|
|
expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
|
|
|
|
{
|
|
|
|
TupleDesc tupleDesc;
|
|
|
|
int netlevelsup;
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
AttrNumber attnum;
|
|
|
|
Node *expr;
|
|
|
|
|
|
|
|
/* Check my caller didn't mess up */
|
|
|
|
Assert(IsA(var, Var));
|
|
|
|
Assert(var->vartype == RECORDOID);
|
|
|
|
|
|
|
|
netlevelsup = var->varlevelsup + levelsup;
|
|
|
|
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
|
|
|
|
attnum = var->varattno;
|
|
|
|
|
2005-04-26 00:02:30 +02:00
|
|
|
if (attnum == InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
/* Whole-row reference to an RTE, so expand the known fields */
|
|
|
|
List *names,
|
|
|
|
*vars;
|
|
|
|
ListCell *lname,
|
|
|
|
*lvar;
|
|
|
|
int i;
|
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
expandRTE(rte, var->varno, 0, var->location, false,
|
2005-06-04 21:19:42 +02:00
|
|
|
&names, &vars);
|
2005-04-26 00:02:30 +02:00
|
|
|
|
|
|
|
tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
|
|
|
|
i = 1;
|
|
|
|
forboth(lname, names, lvar, vars)
|
|
|
|
{
|
|
|
|
char *label = strVal(lfirst(lname));
|
|
|
|
Node *varnode = (Node *) lfirst(lvar);
|
|
|
|
|
|
|
|
TupleDescInitEntry(tupleDesc, i,
|
|
|
|
label,
|
|
|
|
exprType(varnode),
|
|
|
|
exprTypmod(varnode),
|
|
|
|
0);
|
2011-02-08 22:04:18 +01:00
|
|
|
TupleDescInitEntryCollation(tupleDesc, i,
|
|
|
|
exprCollation(varnode));
|
2005-04-26 00:02:30 +02:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
Assert(lname == NULL && lvar == NULL); /* lists same length? */
|
|
|
|
|
|
|
|
return tupleDesc;
|
|
|
|
}
|
|
|
|
|
2005-04-25 23:03:25 +02:00
|
|
|
expr = (Node *) var; /* default if we can't drill down */
|
|
|
|
|
|
|
|
switch (rte->rtekind)
|
|
|
|
{
|
|
|
|
case RTE_RELATION:
|
2006-08-02 03:59:48 +02:00
|
|
|
case RTE_VALUES:
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-04-25 23:03:25 +02:00
|
|
|
/*
|
2006-08-02 03:59:48 +02:00
|
|
|
* This case should not occur: a column of a table or values list
|
2006-10-04 02:30:14 +02:00
|
|
|
* shouldn't have type RECORD. Fall through and fail (most
|
|
|
|
* likely) at the bottom.
|
2005-04-25 23:03:25 +02:00
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case RTE_SUBQUERY:
|
|
|
|
{
|
|
|
|
/* Subselect-in-FROM: examine sub-select's output expr */
|
|
|
|
TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
|
|
|
|
attnum);
|
|
|
|
|
|
|
|
if (ste == NULL || ste->resjunk)
|
|
|
|
elog(ERROR, "subquery %s does not have attribute %d",
|
|
|
|
rte->eref->aliasname, attnum);
|
|
|
|
expr = (Node *) ste->expr;
|
|
|
|
if (IsA(expr, Var))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Recurse into the sub-select to see what its Var refers
|
2014-05-06 18:12:18 +02:00
|
|
|
* to. We have to build an additional level of ParseState
|
2005-04-25 23:03:25 +02:00
|
|
|
* to keep in step with varlevelsup in the subselect.
|
|
|
|
*/
|
|
|
|
ParseState mypstate;
|
|
|
|
|
|
|
|
MemSet(&mypstate, 0, sizeof(mypstate));
|
|
|
|
mypstate.parentParseState = pstate;
|
|
|
|
mypstate.p_rtable = rte->subquery->rtable;
|
|
|
|
/* don't bother filling the rest of the fake pstate */
|
|
|
|
|
|
|
|
return expandRecordVariable(&mypstate, (Var *) expr, 0);
|
|
|
|
}
|
|
|
|
/* else fall through to inspect the expression */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTE_JOIN:
|
2005-04-26 00:02:30 +02:00
|
|
|
/* Join RTE --- recursively inspect the alias variable */
|
2005-04-25 23:03:25 +02:00
|
|
|
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
|
|
|
|
expr = (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(expr != NULL);
|
|
|
|
/* We intentionally don't strip implicit coercions here */
|
2005-04-25 23:03:25 +02:00
|
|
|
if (IsA(expr, Var))
|
|
|
|
return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
|
|
|
|
/* else fall through to inspect the expression */
|
|
|
|
break;
|
|
|
|
case RTE_FUNCTION:
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-04-26 00:02:30 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We couldn't get here unless a function is declared with one of
|
|
|
|
* its result columns as RECORD, which is not allowed.
|
2005-04-26 00:02:30 +02:00
|
|
|
*/
|
2005-04-25 23:03:25 +02:00
|
|
|
break;
|
2008-10-04 23:56:55 +02:00
|
|
|
case RTE_CTE:
|
2008-10-06 00:20:17 +02:00
|
|
|
/* CTE reference: examine subquery's output expr */
|
|
|
|
if (!rte->self_reference)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
2008-10-06 17:15:22 +02:00
|
|
|
CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
|
2008-10-04 23:56:55 +02:00
|
|
|
TargetEntry *ste;
|
|
|
|
|
2011-02-26 00:56:23 +01:00
|
|
|
ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
|
2008-10-04 23:56:55 +02:00
|
|
|
if (ste == NULL || ste->resjunk)
|
|
|
|
elog(ERROR, "subquery %s does not have attribute %d",
|
|
|
|
rte->eref->aliasname, attnum);
|
|
|
|
expr = (Node *) ste->expr;
|
|
|
|
if (IsA(expr, Var))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Recurse into the CTE to see what its Var refers to. We
|
|
|
|
* have to build an additional level of ParseState to keep
|
|
|
|
* in step with varlevelsup in the CTE; furthermore it
|
|
|
|
* could be an outer CTE.
|
|
|
|
*/
|
|
|
|
ParseState mypstate;
|
|
|
|
Index levelsup;
|
|
|
|
|
|
|
|
MemSet(&mypstate, 0, sizeof(mypstate));
|
|
|
|
/* this loop must work, since GetCTEForRTE did */
|
2008-10-06 17:15:22 +02:00
|
|
|
for (levelsup = 0;
|
|
|
|
levelsup < rte->ctelevelsup + netlevelsup;
|
|
|
|
levelsup++)
|
2008-10-04 23:56:55 +02:00
|
|
|
pstate = pstate->parentParseState;
|
|
|
|
mypstate.parentParseState = pstate;
|
|
|
|
mypstate.p_rtable = ((Query *) cte->ctequery)->rtable;
|
|
|
|
/* don't bother filling the rest of the fake pstate */
|
|
|
|
|
|
|
|
return expandRecordVariable(&mypstate, (Var *) expr, 0);
|
|
|
|
}
|
|
|
|
/* else fall through to inspect the expression */
|
|
|
|
}
|
|
|
|
break;
|
2005-04-25 23:03:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We now have an expression we can't expand any more, so see if
|
2014-05-06 18:12:18 +02:00
|
|
|
* get_expr_result_type() can do anything with it. If not, pass to
|
2005-10-15 04:49:52 +02:00
|
|
|
* lookup_rowtype_tupdesc() which will probably fail, but will give an
|
|
|
|
* appropriate error message while failing.
|
2005-04-25 23:03:25 +02:00
|
|
|
*/
|
|
|
|
if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
|
2006-06-16 20:42:24 +02:00
|
|
|
tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
|
|
|
|
exprTypmod(expr));
|
2005-04-25 23:03:25 +02:00
|
|
|
|
|
|
|
return tupleDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
/*
|
1998-07-08 16:04:11 +02:00
|
|
|
* FigureColname -
|
1997-11-25 23:07:18 +01:00
|
|
|
* if the name of the resulting column is not specified in the target
|
1999-07-19 02:26:20 +02:00
|
|
|
* list, we have to guess a suitable name. The SQL spec provides some
|
|
|
|
* guidance, but not much...
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
2001-09-17 03:06:36 +02:00
|
|
|
* Note that the argument is the *untransformed* parse tree for the target
|
|
|
|
* item. This is a shade easier to work with than the transformed tree.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2004-09-30 02:24:27 +02:00
|
|
|
char *
|
2001-09-17 03:06:36 +02:00
|
|
|
FigureColname(Node *node)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
char *name = NULL;
|
2001-10-08 23:48:51 +02:00
|
|
|
|
Adjust naming of indexes and their columns per recent discussion.
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N". Digits are
appended to this name if needed to make the column name unique within the
index. (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails. Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)
Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN. Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)
An example of the results:
regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
Column | Type | Definition
--------+---------+------------
f1 | integer | f1
lower | text | lower(f2)
btree, for table "public.foo"
2009-12-23 03:35:25 +01:00
|
|
|
(void) FigureColnameInternal(node, &name);
|
2001-10-08 23:48:51 +02:00
|
|
|
if (name != NULL)
|
|
|
|
return name;
|
|
|
|
/* default result if we can't guess anything */
|
|
|
|
return "?column?";
|
|
|
|
}
|
|
|
|
|
Adjust naming of indexes and their columns per recent discussion.
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N". Digits are
appended to this name if needed to make the column name unique within the
index. (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails. Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)
Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN. Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)
An example of the results:
regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
Column | Type | Definition
--------+---------+------------
f1 | integer | f1
lower | text | lower(f2)
btree, for table "public.foo"
2009-12-23 03:35:25 +01:00
|
|
|
/*
|
|
|
|
* FigureIndexColname -
|
|
|
|
* choose the name for an expression column in an index
|
|
|
|
*
|
|
|
|
* This is actually just like FigureColname, except we return NULL if
|
|
|
|
* we can't pick a good name.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
FigureIndexColname(Node *node)
|
|
|
|
{
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
(void) FigureColnameInternal(node, &name);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FigureColnameInternal -
|
|
|
|
* internal workhorse for FigureColname
|
|
|
|
*
|
|
|
|
* Return value indicates strength of confidence in result:
|
|
|
|
* 0 - no information
|
|
|
|
* 1 - second-best name choice
|
|
|
|
* 2 - good name choice
|
|
|
|
* The return value is actually only used internally.
|
|
|
|
* If the result isn't zero, *name is set to the chosen name.
|
|
|
|
*/
|
2001-10-08 23:48:51 +02:00
|
|
|
static int
|
|
|
|
FigureColnameInternal(Node *node, char **name)
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
int strength = 0;
|
2001-10-08 23:48:51 +02:00
|
|
|
|
2001-09-17 03:06:36 +02:00
|
|
|
if (node == NULL)
|
2001-10-08 23:48:51 +02:00
|
|
|
return strength;
|
2001-09-28 10:09:14 +02:00
|
|
|
|
2001-09-17 03:06:36 +02:00
|
|
|
switch (nodeTag(node))
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2002-03-21 17:02:16 +01:00
|
|
|
case T_ColumnRef:
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2004-06-09 21:08:20 +02:00
|
|
|
char *fname = NULL;
|
|
|
|
ListCell *l;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2004-06-09 21:08:20 +02:00
|
|
|
/* find last field name, if any, ignoring "*" */
|
|
|
|
foreach(l, ((ColumnRef *) node)->fields)
|
1999-07-19 02:26:20 +02:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
Node *i = lfirst(l);
|
2004-06-09 21:08:20 +02:00
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(i, String))
|
2004-06-09 21:08:20 +02:00
|
|
|
fname = strVal(i);
|
|
|
|
}
|
|
|
|
if (fname)
|
|
|
|
{
|
|
|
|
*name = fname;
|
2001-10-08 23:48:51 +02:00
|
|
|
return 2;
|
1999-07-19 02:26:20 +02:00
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
break;
|
2004-06-09 21:08:20 +02:00
|
|
|
case T_A_Indirection:
|
2002-03-21 17:02:16 +01:00
|
|
|
{
|
2004-06-09 21:08:20 +02:00
|
|
|
A_Indirection *ind = (A_Indirection *) node;
|
|
|
|
char *fname = NULL;
|
|
|
|
ListCell *l;
|
2002-03-21 17:02:16 +01:00
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
/* find last field name, if any, ignoring "*" and subscripts */
|
2004-06-09 21:08:20 +02:00
|
|
|
foreach(l, ind->indirection)
|
2002-03-21 17:02:16 +01:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
Node *i = lfirst(l);
|
2003-04-09 01:20:04 +02:00
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
if (IsA(i, String))
|
2004-06-09 21:08:20 +02:00
|
|
|
fname = strVal(i);
|
|
|
|
}
|
|
|
|
if (fname)
|
|
|
|
{
|
|
|
|
*name = fname;
|
|
|
|
return 2;
|
2002-03-21 17:02:16 +01:00
|
|
|
}
|
2004-06-09 21:08:20 +02:00
|
|
|
return FigureColnameInternal(ind->arg, name);
|
2002-03-21 17:02:16 +01:00
|
|
|
}
|
|
|
|
break;
|
2001-09-17 03:06:36 +02:00
|
|
|
case T_FuncCall:
|
2002-04-09 22:35:55 +02:00
|
|
|
*name = strVal(llast(((FuncCall *) node)->funcname));
|
2001-10-08 23:48:51 +02:00
|
|
|
return 2;
|
2003-02-16 03:30:39 +01:00
|
|
|
case T_A_Expr:
|
|
|
|
/* make nullif() act like a regular function */
|
|
|
|
if (((A_Expr *) node)->kind == AEXPR_NULLIF)
|
|
|
|
{
|
|
|
|
*name = "nullif";
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
break;
|
2001-10-25 07:50:21 +02:00
|
|
|
case T_TypeCast:
|
2001-10-08 23:48:51 +02:00
|
|
|
strength = FigureColnameInternal(((TypeCast *) node)->arg,
|
|
|
|
name);
|
|
|
|
if (strength <= 1)
|
2001-09-28 10:09:14 +02:00
|
|
|
{
|
2009-07-16 08:33:46 +02:00
|
|
|
if (((TypeCast *) node)->typeName != NULL)
|
2001-10-08 23:48:51 +02:00
|
|
|
{
|
2009-07-16 08:33:46 +02:00
|
|
|
*name = strVal(llast(((TypeCast *) node)->typeName->names));
|
2002-04-09 22:35:55 +02:00
|
|
|
return 1;
|
2001-10-08 23:48:51 +02:00
|
|
|
}
|
2001-09-28 10:09:14 +02:00
|
|
|
}
|
|
|
|
break;
|
2011-02-08 22:04:18 +01:00
|
|
|
case T_CollateClause:
|
2011-03-11 22:27:51 +01:00
|
|
|
return FigureColnameInternal(((CollateClause *) node)->arg, name);
|
2011-10-01 20:01:46 +02:00
|
|
|
case T_SubLink:
|
|
|
|
switch (((SubLink *) node)->subLinkType)
|
|
|
|
{
|
|
|
|
case EXISTS_SUBLINK:
|
|
|
|
*name = "exists";
|
|
|
|
return 2;
|
|
|
|
case ARRAY_SUBLINK:
|
|
|
|
*name = "array";
|
|
|
|
return 2;
|
|
|
|
case EXPR_SUBLINK:
|
|
|
|
{
|
|
|
|
/* Get column name of the subquery's single target */
|
2012-06-10 21:20:04 +02:00
|
|
|
SubLink *sublink = (SubLink *) node;
|
2011-10-01 20:01:46 +02:00
|
|
|
Query *query = (Query *) sublink->subselect;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The subquery has probably already been transformed,
|
|
|
|
* but let's be careful and check that. (The reason
|
|
|
|
* we can see a transformed subquery here is that
|
|
|
|
* transformSubLink is lazy and modifies the SubLink
|
|
|
|
* node in-place.)
|
|
|
|
*/
|
|
|
|
if (IsA(query, Query))
|
|
|
|
{
|
|
|
|
TargetEntry *te = (TargetEntry *) linitial(query->targetList);
|
|
|
|
|
|
|
|
if (te->resname)
|
|
|
|
{
|
|
|
|
*name = te->resname;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-06-10 21:20:04 +02:00
|
|
|
/* As with other operator-like nodes, these have no names */
|
Implement UPDATE tab SET (col1,col2,...) = (SELECT ...), ...
This SQL-standard feature allows a sub-SELECT yielding multiple columns
(but only one row) to be used to compute the new values of several columns
to be updated. While the same results can be had with an independent
sub-SELECT per column, such a workaround can require a great deal of
duplicated computation.
The standard actually says that the source for a multi-column assignment
could be any row-valued expression. The implementation used here is
tightly tied to our existing sub-SELECT support and can't handle other
cases; the Bison grammar would have some issues with them too. However,
I don't feel too bad about this since other cases can be converted into
sub-SELECTs. For instance, "SET (a,b,c) = row_valued_function(x)" could
be written "SET (a,b,c) = (SELECT * FROM row_valued_function(x))".
2014-06-18 19:22:25 +02:00
|
|
|
case MULTIEXPR_SUBLINK:
|
2011-10-01 20:01:46 +02:00
|
|
|
case ALL_SUBLINK:
|
|
|
|
case ANY_SUBLINK:
|
|
|
|
case ROWCOMPARE_SUBLINK:
|
|
|
|
case CTE_SUBLINK:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
1998-12-14 00:56:44 +01:00
|
|
|
case T_CaseExpr:
|
2002-12-12 16:49:42 +01:00
|
|
|
strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,
|
2001-10-08 23:48:51 +02:00
|
|
|
name);
|
|
|
|
if (strength <= 1)
|
1998-12-14 00:56:44 +01:00
|
|
|
{
|
2001-10-08 23:48:51 +02:00
|
|
|
*name = "case";
|
|
|
|
return 1;
|
1998-12-14 00:56:44 +01:00
|
|
|
}
|
|
|
|
break;
|
2008-03-20 22:42:48 +01:00
|
|
|
case T_A_ArrayExpr:
|
2003-04-09 01:20:04 +02:00
|
|
|
/* make ARRAY[] act like a function */
|
|
|
|
*name = "array";
|
|
|
|
return 2;
|
2004-05-11 00:44:49 +02:00
|
|
|
case T_RowExpr:
|
|
|
|
/* make ROW() act like a function */
|
|
|
|
*name = "row";
|
|
|
|
return 2;
|
2003-02-16 03:30:39 +01:00
|
|
|
case T_CoalesceExpr:
|
|
|
|
/* make coalesce() act like a regular function */
|
|
|
|
*name = "coalesce";
|
|
|
|
return 2;
|
2005-06-27 00:05:42 +02:00
|
|
|
case T_MinMaxExpr:
|
|
|
|
/* make greatest/least act like a regular function */
|
2005-10-15 04:49:52 +02:00
|
|
|
switch (((MinMaxExpr *) node)->op)
|
2005-06-27 00:05:42 +02:00
|
|
|
{
|
|
|
|
case IS_GREATEST:
|
|
|
|
*name = "greatest";
|
|
|
|
return 2;
|
|
|
|
case IS_LEAST:
|
|
|
|
*name = "least";
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
break;
|
2006-12-21 17:05:16 +01:00
|
|
|
case T_XmlExpr:
|
|
|
|
/* make SQL/XML functions act like a regular function */
|
2007-11-15 22:14:46 +01:00
|
|
|
switch (((XmlExpr *) node)->op)
|
|
|
|
{
|
2006-12-21 17:05:16 +01:00
|
|
|
case IS_XMLCONCAT:
|
|
|
|
*name = "xmlconcat";
|
|
|
|
return 2;
|
|
|
|
case IS_XMLELEMENT:
|
|
|
|
*name = "xmlelement";
|
|
|
|
return 2;
|
|
|
|
case IS_XMLFOREST:
|
|
|
|
*name = "xmlforest";
|
|
|
|
return 2;
|
2006-12-24 01:29:20 +01:00
|
|
|
case IS_XMLPARSE:
|
|
|
|
*name = "xmlparse";
|
|
|
|
return 2;
|
|
|
|
case IS_XMLPI:
|
|
|
|
*name = "xmlpi";
|
|
|
|
return 2;
|
|
|
|
case IS_XMLROOT:
|
|
|
|
*name = "xmlroot";
|
|
|
|
return 2;
|
2007-02-03 15:06:56 +01:00
|
|
|
case IS_XMLSERIALIZE:
|
|
|
|
*name = "xmlserialize";
|
|
|
|
return 2;
|
2007-01-14 14:11:54 +01:00
|
|
|
case IS_DOCUMENT:
|
|
|
|
/* nothing */
|
|
|
|
break;
|
2007-11-15 22:14:46 +01:00
|
|
|
}
|
2006-12-21 17:05:16 +01:00
|
|
|
break;
|
2007-02-03 15:06:56 +01:00
|
|
|
case T_XmlSerialize:
|
|
|
|
*name = "xmlserialize";
|
|
|
|
return 2;
|
1997-11-25 23:07:18 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2001-10-08 23:48:51 +02:00
|
|
|
|
|
|
|
return strength;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|