1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* equalfuncs.c
|
2000-06-29 09:35:57 +02:00
|
|
|
* Equality functions to compare node trees.
|
|
|
|
*
|
2002-12-05 16:50:39 +01:00
|
|
|
* NOTE: we currently support comparing all node types found in parse
|
|
|
|
* trees. We do not support comparing executor state trees; there
|
|
|
|
* is no need for that, and no point in maintaining all the code that
|
|
|
|
* would be needed. We also do not support comparing Path trees, mainly
|
|
|
|
* because the circular linkages between RelOptInfo and Path nodes can't
|
|
|
|
* be handled easily in a simple depth-first traversal.
|
2000-06-29 09:35:57 +02:00
|
|
|
*
|
2002-12-05 16:50:39 +01:00
|
|
|
* Currently, in fact, equal() doesn't know how to compare Plan trees
|
2014-05-06 18:12:18 +02:00
|
|
|
* either. This might need to be fixed someday.
|
2000-06-29 09:35:57 +02:00
|
|
|
*
|
2008-08-29 01:09:48 +02:00
|
|
|
* NOTE: it is intentional that parse location fields (in nodes that have
|
|
|
|
* one) are not compared. This is because we want, for example, a variable
|
|
|
|
* "x" to be considered equal() to another reference to "x" in the query.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
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
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/nodes/equalfuncs.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-01-10 21:19:49 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "nodes/relation.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "utils/datum.h"
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Macros to simplify comparison of different kinds of fields. Use these
|
|
|
|
* wherever possible to reduce the chance for silly typos. Note that these
|
2002-11-25 04:33:27 +01:00
|
|
|
* hard-wire the convention that the local variables in an Equal routine are
|
|
|
|
* named 'a' and 'b'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Compare a simple scalar field (int, float, bool, enum, etc) */
|
|
|
|
#define COMPARE_SCALAR_FIELD(fldname) \
|
|
|
|
do { \
|
|
|
|
if (a->fldname != b->fldname) \
|
|
|
|
return false; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Compare a field that is a pointer to some kind of Node or Node tree */
|
|
|
|
#define COMPARE_NODE_FIELD(fldname) \
|
|
|
|
do { \
|
|
|
|
if (!equal(a->fldname, b->fldname)) \
|
|
|
|
return false; \
|
|
|
|
} while (0)
|
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
/* Compare a field that is a pointer to a Bitmapset */
|
|
|
|
#define COMPARE_BITMAPSET_FIELD(fldname) \
|
|
|
|
do { \
|
|
|
|
if (!bms_equal(a->fldname, b->fldname)) \
|
|
|
|
return false; \
|
|
|
|
} while (0)
|
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
/* Compare a field that is a pointer to a C string, or perhaps NULL */
|
|
|
|
#define COMPARE_STRING_FIELD(fldname) \
|
|
|
|
do { \
|
|
|
|
if (!equalstr(a->fldname, b->fldname)) \
|
|
|
|
return false; \
|
|
|
|
} while (0)
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
/* Macro for comparing string fields that might be NULL */
|
2001-03-22 05:01:46 +01:00
|
|
|
#define equalstr(a, b) \
|
2000-08-12 01:45:35 +02:00
|
|
|
(((a) != NULL && (b) != NULL) ? (strcmp(a, b) == 0) : (a) == (b))
|
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
/* Compare a field that is a pointer to a simple palloc'd object of size sz */
|
|
|
|
#define COMPARE_POINTER_FIELD(fldname, sz) \
|
|
|
|
do { \
|
|
|
|
if (memcmp(a->fldname, b->fldname, (sz)) != 0) \
|
|
|
|
return false; \
|
|
|
|
} while (0)
|
|
|
|
|
2008-08-29 01:09:48 +02:00
|
|
|
/* Compare a parse location field (this is a no-op, per note above) */
|
|
|
|
#define COMPARE_LOCATION_FIELD(fldname) \
|
|
|
|
((void) 0)
|
|
|
|
|
2012-10-12 18:10:49 +02:00
|
|
|
/* Compare a CoercionForm field (also a no-op, per comment in primnodes.h) */
|
|
|
|
#define COMPARE_COERCIONFORM_FIELD(fldname) \
|
|
|
|
((void) 0)
|
|
|
|
|
1999-07-29 04:45:36 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Stuff from primnodes.h
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlias(const Alias *a, const Alias *b)
|
2002-11-25 04:33:27 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(aliasname);
|
|
|
|
COMPARE_NODE_FIELD(colnames);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRangeVar(const RangeVar *a, const RangeVar *b)
|
2002-11-25 04:33:27 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(catalogname);
|
|
|
|
COMPARE_STRING_FIELD(schemaname);
|
|
|
|
COMPARE_STRING_FIELD(relname);
|
|
|
|
COMPARE_SCALAR_FIELD(inhOpt);
|
2010-12-13 18:34:26 +01:00
|
|
|
COMPARE_SCALAR_FIELD(relpersistence);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(alias);
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2007-02-20 18:32:18 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalIntoClause(const IntoClause *a, const IntoClause *b)
|
2007-02-20 18:32:18 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(rel);
|
|
|
|
COMPARE_NODE_FIELD(colNames);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_SCALAR_FIELD(onCommit);
|
|
|
|
COMPARE_STRING_FIELD(tableSpaceName);
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
COMPARE_NODE_FIELD(viewQuery);
|
2011-11-25 05:21:06 +01:00
|
|
|
COMPARE_SCALAR_FIELD(skipData);
|
2007-02-20 18:32:18 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
/*
|
|
|
|
* We don't need an _equalExpr because Expr is an abstract supertype which
|
2014-05-06 18:12:18 +02:00
|
|
|
* should never actually get instantiated. Also, since it has no common
|
2002-12-12 16:49:42 +01:00
|
|
|
* fields except NodeTag, there's no need for a helper routine to factor
|
|
|
|
* out comparing the common fields...
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalVar(const Var *a, const Var *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(varno);
|
|
|
|
COMPARE_SCALAR_FIELD(varattno);
|
|
|
|
COMPARE_SCALAR_FIELD(vartype);
|
|
|
|
COMPARE_SCALAR_FIELD(vartypmod);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(varcollid);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(varlevelsup);
|
|
|
|
COMPARE_SCALAR_FIELD(varnoold);
|
|
|
|
COMPARE_SCALAR_FIELD(varoattno);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalConst(const Const *a, const Const *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(consttype);
|
2007-03-17 01:11:05 +01:00
|
|
|
COMPARE_SCALAR_FIELD(consttypmod);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(constcollid);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(constlen);
|
|
|
|
COMPARE_SCALAR_FIELD(constisnull);
|
|
|
|
COMPARE_SCALAR_FIELD(constbyval);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
1999-12-24 07:43:34 +01:00
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
* We treat all NULL constants of the same type as equal. Someday this
|
2005-10-15 04:49:52 +02:00
|
|
|
* might need to change? But datumIsEqual doesn't work on nulls, so...
|
1999-12-24 07:43:34 +01:00
|
|
|
*/
|
|
|
|
if (a->constisnull)
|
|
|
|
return true;
|
2000-07-12 04:37:39 +02:00
|
|
|
return datumIsEqual(a->constvalue, b->constvalue,
|
|
|
|
a->constbyval, a->constlen);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalParam(const Param *a, const Param *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(paramkind);
|
2006-04-22 03:26:01 +02:00
|
|
|
COMPARE_SCALAR_FIELD(paramid);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(paramtype);
|
2006-12-10 23:13:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(paramtypmod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(paramcollid);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1999-07-29 04:45:36 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAggref(const Aggref *a, const Aggref *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(aggfnoid);
|
|
|
|
COMPARE_SCALAR_FIELD(aggtype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(aggcollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
Support ordered-set (WITHIN GROUP) aggregates.
This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.
Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.
In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.
Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane
2013-12-23 22:11:35 +01:00
|
|
|
COMPARE_NODE_FIELD(aggdirectargs);
|
2006-07-27 21:52:07 +02:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2009-12-15 18:57:48 +01:00
|
|
|
COMPARE_NODE_FIELD(aggorder);
|
|
|
|
COMPARE_NODE_FIELD(aggdistinct);
|
2013-07-17 02:15:36 +02:00
|
|
|
COMPARE_NODE_FIELD(aggfilter);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_SCALAR_FIELD(aggstar);
|
Allow aggregate functions to be VARIADIC.
There's no inherent reason why an aggregate function can't be variadic
(even VARIADIC ANY) if its transition function can handle the case.
Indeed, this patch to add the feature touches none of the planner or
executor, and little of the parser; the main missing stuff was DDL and
pg_dump support.
It is true that variadic aggregates can create the same sort of ambiguity
about parameters versus ORDER BY keys that was complained of when we
(briefly) had both one- and two-argument forms of string_agg(). However,
the policy formed in response to that discussion only said that we'd not
create any built-in aggregates with varying numbers of arguments, not that
we shouldn't allow users to do it. So the logical extension of that is
we can allow users to make variadic aggregates as long as we're wary about
shipping any such in core.
In passing, this patch allows aggregate function arguments to be named, to
the extent of remembering the names in pg_proc and dumping them in pg_dump.
You can't yet call an aggregate using named-parameter notation. That seems
like a likely future extension, but it'll take some work, and it's not what
this patch is really about. Likewise, there's still some work needed to
make window functions handle VARIADIC fully, but I left that for another
day.
initdb forced because of new aggvariadic field in Aggref parse nodes.
2013-09-03 23:08:38 +02:00
|
|
|
COMPARE_SCALAR_FIELD(aggvariadic);
|
Support ordered-set (WITHIN GROUP) aggregates.
This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.
Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.
In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.
Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane
2013-12-23 22:11:35 +01:00
|
|
|
COMPARE_SCALAR_FIELD(aggkind);
|
2009-12-15 18:57:48 +01:00
|
|
|
COMPARE_SCALAR_FIELD(agglevelsup);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Support GROUPING SETS, CUBE and ROLLUP.
This SQL standard functionality allows to aggregate data by different
GROUP BY clauses at once. Each grouping set returns rows with columns
grouped by in other sets set to NULL.
This could previously be achieved by doing each grouping as a separate
query, conjoined by UNION ALLs. Besides being considerably more concise,
grouping sets will in many cases be faster, requiring only one scan over
the underlying data.
The current implementation of grouping sets only supports using sorting
for input. Individual sets that share a sort order are computed in one
pass. If there are sets that don't share a sort order, additional sort &
aggregation steps are performed. These additional passes are sourced by
the previous sort step; thus avoiding repeated scans of the source data.
The code is structured in a way that adding support for purely using
hash aggregation or a mix of hashing and sorting is possible. Sorting
was chosen to be supported first, as it is the most generic method of
implementation.
Instead of, as in an earlier versions of the patch, representing the
chain of sort and aggregation steps as full blown planner and executor
nodes, all but the first sort are performed inside the aggregation node
itself. This avoids the need to do some unusual gymnastics to handle
having to return aggregated and non-aggregated tuples from underlying
nodes, as well as having to shut down underlying nodes early to limit
memory usage. The optimizer still builds Sort/Agg node to describe each
phase, but they're not part of the plan tree, but instead additional
data for the aggregation node. They're a convenient and preexisting way
to describe aggregation and sorting. The first (and possibly only) sort
step is still performed as a separate execution step. That retains
similarity with existing group by plans, makes rescans fairly simple,
avoids very deep plans (leading to slow explains) and easily allows to
avoid the sorting step if the underlying data is sorted by other means.
A somewhat ugly side of this patch is having to deal with a grammar
ambiguity between the new CUBE keyword and the cube extension/functions
named cube (and rollup). To avoid breaking existing deployments of the
cube extension it has not been renamed, neither has cube been made a
reserved keyword. Instead precedence hacking is used to make GROUP BY
cube(..) refer to the CUBE grouping sets feature, and not the function
cube(). To actually group by a function cube(), unlikely as that might
be, the function name has to be quoted.
Needs a catversion bump because stored rules may change.
Author: Andrew Gierth and Atri Sharma, with contributions from Andres Freund
Reviewed-By: Andres Freund, Noah Misch, Tom Lane, Svenne Krap, Tomas
Vondra, Erik Rijkers, Marti Raudsepp, Pavel Stehule
Discussion: CAOeZVidmVRe2jU6aMk_5qkxnB7dfmPROzM7Ur8JPW5j8Y5X-Lw@mail.gmail.com
2015-05-16 03:40:59 +02:00
|
|
|
static bool
|
|
|
|
_equalGroupingFunc(const GroupingFunc *a, const GroupingFunc *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We must not compare the refs or cols field
|
|
|
|
*/
|
|
|
|
|
|
|
|
COMPARE_SCALAR_FIELD(agglevelsup);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-12-28 19:54:01 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalWindowFunc(const WindowFunc *a, const WindowFunc *b)
|
2008-12-28 19:54:01 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(winfnoid);
|
|
|
|
COMPARE_SCALAR_FIELD(wintype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(wincollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2013-07-17 02:15:36 +02:00
|
|
|
COMPARE_NODE_FIELD(aggfilter);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_SCALAR_FIELD(winref);
|
|
|
|
COMPARE_SCALAR_FIELD(winstar);
|
|
|
|
COMPARE_SCALAR_FIELD(winagg);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalArrayRef(const ArrayRef *a, const ArrayRef *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
2003-04-09 01:20:04 +02:00
|
|
|
COMPARE_SCALAR_FIELD(refarraytype);
|
|
|
|
COMPARE_SCALAR_FIELD(refelemtype);
|
2007-03-17 01:11:05 +01:00
|
|
|
COMPARE_SCALAR_FIELD(reftypmod);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(refcollid);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(refupperindexpr);
|
|
|
|
COMPARE_NODE_FIELD(reflowerindexpr);
|
|
|
|
COMPARE_NODE_FIELD(refexpr);
|
|
|
|
COMPARE_NODE_FIELD(refassgnexpr);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
|
1999-07-29 04:45:36 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(funcid);
|
|
|
|
COMPARE_SCALAR_FIELD(funcresulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(funcretset);
|
2013-01-22 02:25:26 +01:00
|
|
|
COMPARE_SCALAR_FIELD(funcvariadic);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(funcformat);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(funccollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
1999-07-29 04:45:36 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-08 04:39:25 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalNamedArgExpr(const NamedArgExpr *a, const NamedArgExpr *b)
|
2009-10-08 04:39:25 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_SCALAR_FIELD(argnumber);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1999-06-06 19:46:40 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalOpExpr(const OpExpr *a, const OpExpr *b)
|
1999-06-06 19:46:40 +02:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_SCALAR_FIELD(opno);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Special-case opfuncid: it is allowable for it to differ if one node
|
2005-10-15 04:49:52 +02:00
|
|
|
* contains zero and the other doesn't. This just means that the one node
|
|
|
|
* isn't as far along in the parse/plan pipeline and hasn't had the
|
|
|
|
* opfuncid cache filled yet.
|
2002-12-12 16:49:42 +01:00
|
|
|
*/
|
|
|
|
if (a->opfuncid != b->opfuncid &&
|
|
|
|
a->opfuncid != 0 &&
|
|
|
|
b->opfuncid != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
COMPARE_SCALAR_FIELD(opresulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(opretset);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(opcollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDistinctExpr(const DistinctExpr *a, const DistinctExpr *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(opno);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Special-case opfuncid: it is allowable for it to differ if one node
|
2005-10-15 04:49:52 +02:00
|
|
|
* contains zero and the other doesn't. This just means that the one node
|
|
|
|
* isn't as far along in the parse/plan pipeline and hasn't had the
|
|
|
|
* opfuncid cache filled yet.
|
2002-12-12 16:49:42 +01:00
|
|
|
*/
|
|
|
|
if (a->opfuncid != b->opfuncid &&
|
|
|
|
a->opfuncid != 0 &&
|
|
|
|
b->opfuncid != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
COMPARE_SCALAR_FIELD(opresulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(opretset);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(opcollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalNullIfExpr(const NullIfExpr *a, const NullIfExpr *b)
|
2011-03-20 01:29:08 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(opno);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Special-case opfuncid: it is allowable for it to differ if one node
|
|
|
|
* contains zero and the other doesn't. This just means that the one node
|
|
|
|
* isn't as far along in the parse/plan pipeline and hasn't had the
|
|
|
|
* opfuncid cache filled yet.
|
|
|
|
*/
|
|
|
|
if (a->opfuncid != b->opfuncid &&
|
|
|
|
a->opfuncid != 0 &&
|
|
|
|
b->opfuncid != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
COMPARE_SCALAR_FIELD(opresulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(opretset);
|
|
|
|
COMPARE_SCALAR_FIELD(opcollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-06-29 02:33:44 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalScalarArrayOpExpr(const ScalarArrayOpExpr *a, const ScalarArrayOpExpr *b)
|
2003-06-29 02:33:44 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(opno);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-06-29 02:33:44 +02:00
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Special-case opfuncid: it is allowable for it to differ if one node
|
2005-10-15 04:49:52 +02:00
|
|
|
* contains zero and the other doesn't. This just means that the one node
|
|
|
|
* isn't as far along in the parse/plan pipeline and hasn't had the
|
|
|
|
* opfuncid cache filled yet.
|
2003-06-29 02:33:44 +02:00
|
|
|
*/
|
|
|
|
if (a->opfuncid != b->opfuncid &&
|
|
|
|
a->opfuncid != 0 &&
|
|
|
|
b->opfuncid != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
COMPARE_SCALAR_FIELD(useOr);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2003-06-29 02:33:44 +02:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2003-06-29 02:33:44 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalBoolExpr(const BoolExpr *a, const BoolExpr *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(boolop);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
1999-06-06 19:46:40 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1999-09-26 04:28:44 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSubLink(const SubLink *a, const SubLink *b)
|
1999-09-26 04:28:44 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(subLinkType);
|
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
|
|
|
COMPARE_SCALAR_FIELD(subLinkId);
|
2005-12-28 02:30:02 +01:00
|
|
|
COMPARE_NODE_FIELD(testexpr);
|
2003-01-10 22:08:15 +01:00
|
|
|
COMPARE_NODE_FIELD(operName);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(subselect);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
1999-09-26 04:28:44 +02:00
|
|
|
|
2002-08-26 19:54:02 +02:00
|
|
|
return true;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSubPlan(const SubPlan *a, const SubPlan *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
2002-12-14 01:17:59 +01:00
|
|
|
COMPARE_SCALAR_FIELD(subLinkType);
|
2005-12-28 02:30:02 +01:00
|
|
|
COMPARE_NODE_FIELD(testexpr);
|
2004-05-26 06:41:50 +02:00
|
|
|
COMPARE_NODE_FIELD(paramIds);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_SCALAR_FIELD(plan_id);
|
2009-04-05 21:59:40 +02:00
|
|
|
COMPARE_STRING_FIELD(plan_name);
|
2007-02-22 23:00:26 +01:00
|
|
|
COMPARE_SCALAR_FIELD(firstColType);
|
2009-03-10 23:09:26 +01:00
|
|
|
COMPARE_SCALAR_FIELD(firstColTypmod);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(firstColCollation);
|
2003-01-10 22:08:15 +01:00
|
|
|
COMPARE_SCALAR_FIELD(useHashTable);
|
|
|
|
COMPARE_SCALAR_FIELD(unknownEqFalse);
|
2004-05-26 06:41:50 +02:00
|
|
|
COMPARE_NODE_FIELD(setParam);
|
|
|
|
COMPARE_NODE_FIELD(parParam);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-22 02:16:04 +02:00
|
|
|
COMPARE_SCALAR_FIELD(startup_cost);
|
|
|
|
COMPARE_SCALAR_FIELD(per_call_cost);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlternativeSubPlan(const AlternativeSubPlan *a, const AlternativeSubPlan *b)
|
2008-08-22 02:16:04 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(subplans);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-08 17:43:12 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFieldSelect(const FieldSelect *a, const FieldSelect *b)
|
2000-08-08 17:43:12 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(fieldnum);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttypmod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resultcollid);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
2000-08-08 17:43:12 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-06-09 21:08:20 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFieldStore(const FieldStore *a, const FieldStore *b)
|
2004-06-09 21:08:20 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_NODE_FIELD(newvals);
|
|
|
|
COMPARE_NODE_FIELD(fieldnums);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-02-20 22:32:16 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRelabelType(const RelabelType *a, const RelabelType *b)
|
2000-02-20 22:32:16 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttypmod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resultcollid);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(relabelformat);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2000-02-20 22:32:16 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-06-05 23:31:09 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCoerceViaIO(const CoerceViaIO *a, const CoerceViaIO *b)
|
2007-06-05 23:31:09 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resultcollid);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(coerceformat);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2007-06-05 23:31:09 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-03-28 01:21:12 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalArrayCoerceExpr(const ArrayCoerceExpr *a, const ArrayCoerceExpr *b)
|
2007-03-28 01:21:12 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(elemfuncid);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttypmod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resultcollid);
|
2007-03-28 01:21:12 +02:00
|
|
|
COMPARE_SCALAR_FIELD(isExplicit);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(coerceformat);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2007-03-28 01:21:12 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-12-12 00:26:51 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalConvertRowtypeExpr(const ConvertRowtypeExpr *a, const ConvertRowtypeExpr *b)
|
2004-12-12 00:26:51 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(convertformat);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2004-12-12 00:26:51 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-03-11 22:27:51 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCollateExpr(const CollateExpr *a, const CollateExpr *b)
|
2011-03-11 22:27:51 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(collOid);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCaseExpr(const CaseExpr *a, const CaseExpr *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_SCALAR_FIELD(casetype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(casecollid);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_NODE_FIELD(defresult);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCaseWhen(const CaseWhen *a, const CaseWhen *b)
|
2002-11-25 04:33:27 +01:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(expr);
|
|
|
|
COMPARE_NODE_FIELD(result);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-03-17 21:48:43 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCaseTestExpr(const CaseTestExpr *a, const CaseTestExpr *b)
|
2004-03-17 21:48:43 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(typeId);
|
|
|
|
COMPARE_SCALAR_FIELD(typeMod);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(collation);
|
2004-03-17 21:48:43 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-04-09 01:20:04 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalArrayExpr(const ArrayExpr *a, const ArrayExpr *b)
|
2003-04-09 01:20:04 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(array_typeid);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(array_collid);
|
2003-04-09 01:20:04 +02:00
|
|
|
COMPARE_SCALAR_FIELD(element_typeid);
|
|
|
|
COMPARE_NODE_FIELD(elements);
|
2003-08-18 01:43:27 +02:00
|
|
|
COMPARE_SCALAR_FIELD(multidims);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2003-04-09 01:20:04 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-05-11 00:44:49 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRowExpr(const RowExpr *a, const RowExpr *b)
|
2004-05-11 00:44:49 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_SCALAR_FIELD(row_typeid);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(row_format);
|
2008-10-06 19:39:26 +02:00
|
|
|
COMPARE_NODE_FIELD(colnames);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2004-05-11 00:44:49 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-12-28 02:30:02 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRowCompareExpr(const RowCompareExpr *a, const RowCompareExpr *b)
|
2005-12-28 02:30:02 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(rctype);
|
|
|
|
COMPARE_NODE_FIELD(opnos);
|
2006-12-23 01:43:13 +01:00
|
|
|
COMPARE_NODE_FIELD(opfamilies);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_NODE_FIELD(inputcollids);
|
2005-12-28 02:30:02 +01:00
|
|
|
COMPARE_NODE_FIELD(largs);
|
|
|
|
COMPARE_NODE_FIELD(rargs);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-02-16 03:30:39 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCoalesceExpr(const CoalesceExpr *a, const CoalesceExpr *b)
|
2003-02-16 03:30:39 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(coalescetype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(coalescecollid);
|
2003-02-16 03:30:39 +01:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2003-02-16 03:30:39 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-06-27 00:05:42 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
|
2005-06-27 00:05:42 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(minmaxtype);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(minmaxcollid);
|
|
|
|
COMPARE_SCALAR_FIELD(inputcollid);
|
2005-06-27 00:05:42 +02:00
|
|
|
COMPARE_SCALAR_FIELD(op);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2005-06-27 00:05:42 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-12-24 01:29:20 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalXmlExpr(const XmlExpr *a, const XmlExpr *b)
|
2006-12-24 01:29:20 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(op);
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(named_args);
|
|
|
|
COMPARE_NODE_FIELD(arg_names);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
2007-02-03 15:06:56 +01:00
|
|
|
COMPARE_SCALAR_FIELD(xmloption);
|
|
|
|
COMPARE_SCALAR_FIELD(type);
|
|
|
|
COMPARE_SCALAR_FIELD(typmod);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2006-12-24 01:29:20 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalNullTest(const NullTest *a, const NullTest *b)
|
2000-09-29 20:21:41 +02:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(nulltesttype);
|
2010-01-02 00:03:10 +01:00
|
|
|
COMPARE_SCALAR_FIELD(argisrow);
|
2015-02-22 20:40:27 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalBooleanTest(const BooleanTest *a, const BooleanTest *b)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_SCALAR_FIELD(booltesttype);
|
2015-02-22 20:40:27 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
return true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCoerceToDomain(const CoerceToDomain *a, const CoerceToDomain *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
2003-02-03 22:15:45 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resulttype);
|
|
|
|
COMPARE_SCALAR_FIELD(resulttypmod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(resultcollid);
|
2012-10-12 18:10:49 +02:00
|
|
|
COMPARE_COERCIONFORM_FIELD(coercionformat);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
return true;
|
|
|
|
}
|
2002-11-25 04:33:27 +01:00
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCoerceToDomainValue(const CoerceToDomainValue *a, const CoerceToDomainValue *b)
|
2002-11-25 04:33:27 +01:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_SCALAR_FIELD(typeId);
|
|
|
|
COMPARE_SCALAR_FIELD(typeMod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(collation);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-07-03 18:34:26 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSetToDefault(const SetToDefault *a, const SetToDefault *b)
|
2003-07-03 18:34:26 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(typeId);
|
|
|
|
COMPARE_SCALAR_FIELD(typeMod);
|
2011-03-20 01:29:08 +01:00
|
|
|
COMPARE_SCALAR_FIELD(collation);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2003-07-03 18:34:26 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-06-11 03:16:30 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCurrentOfExpr(const CurrentOfExpr *a, const CurrentOfExpr *b)
|
2007-06-11 03:16:30 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(cvarno);
|
|
|
|
COMPARE_STRING_FIELD(cursor_name);
|
2007-06-12 00:22:42 +02:00
|
|
|
COMPARE_SCALAR_FIELD(cursor_param);
|
2007-06-11 03:16:30 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
static bool
|
|
|
|
_equalInferenceElem(const InferenceElem *a, const InferenceElem *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(expr);
|
|
|
|
COMPARE_SCALAR_FIELD(infercollid);
|
2015-05-19 21:17:52 +02:00
|
|
|
COMPARE_SCALAR_FIELD(inferopclass);
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalTargetEntry(const TargetEntry *a, const TargetEntry *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(expr);
|
2005-04-06 18:34:07 +02:00
|
|
|
COMPARE_SCALAR_FIELD(resno);
|
|
|
|
COMPARE_STRING_FIELD(resname);
|
|
|
|
COMPARE_SCALAR_FIELD(ressortgroupref);
|
|
|
|
COMPARE_SCALAR_FIELD(resorigtbl);
|
|
|
|
COMPARE_SCALAR_FIELD(resorigcol);
|
|
|
|
COMPARE_SCALAR_FIELD(resjunk);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRangeTblRef(const RangeTblRef *a, const RangeTblRef *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(rtindex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalJoinExpr(const JoinExpr *a, const JoinExpr *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(jointype);
|
|
|
|
COMPARE_SCALAR_FIELD(isNatural);
|
|
|
|
COMPARE_NODE_FIELD(larg);
|
|
|
|
COMPARE_NODE_FIELD(rarg);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(usingClause);
|
2002-12-12 16:49:42 +01:00
|
|
|
COMPARE_NODE_FIELD(quals);
|
|
|
|
COMPARE_NODE_FIELD(alias);
|
|
|
|
COMPARE_SCALAR_FIELD(rtindex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFromExpr(const FromExpr *a, const FromExpr *b)
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(fromlist);
|
|
|
|
COMPARE_NODE_FIELD(quals);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
static bool
|
|
|
|
_equalOnConflictExpr(const OnConflictExpr *a, const OnConflictExpr *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(action);
|
|
|
|
COMPARE_NODE_FIELD(arbiterElems);
|
|
|
|
COMPARE_NODE_FIELD(arbiterWhere);
|
2015-08-06 02:44:27 +02:00
|
|
|
COMPARE_SCALAR_FIELD(constraint);
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
COMPARE_NODE_FIELD(onConflictSet);
|
|
|
|
COMPARE_NODE_FIELD(onConflictWhere);
|
|
|
|
COMPARE_SCALAR_FIELD(exclRelIndex);
|
|
|
|
COMPARE_NODE_FIELD(exclRelTlist);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2002-11-25 04:33:27 +01:00
|
|
|
|
1998-08-02 00:12:13 +02:00
|
|
|
/*
|
1999-07-29 04:45:36 +02:00
|
|
|
* Stuff from relation.h
|
1998-08-02 00:12:13 +02:00
|
|
|
*/
|
1999-07-29 04:45:36 +02:00
|
|
|
|
1998-02-13 04:27:47 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalPathKey(const PathKey *a, const PathKey *b)
|
1998-02-13 04:27:47 +01:00
|
|
|
{
|
Postpone creation of pathkeys lists to fix bug #8049.
This patch gets rid of the concept of, and infrastructure for,
non-canonical PathKeys; we now only ever create canonical pathkey lists.
The need for non-canonical pathkeys came from the desire to have
grouping_planner initialize query_pathkeys and related pathkey lists before
calling query_planner. However, since query_planner didn't actually *do*
anything with those lists before they'd been made canonical, we can get rid
of the whole mess by just not creating the lists at all until the point
where we formerly canonicalized them.
There are several ways in which we could implement that without making
query_planner itself deal with grouping/sorting features (which are
supposed to be the province of grouping_planner). I chose to add a
callback function to query_planner's API; other alternatives would have
required adding more fields to PlannerInfo, which while not bad in itself
would create an ABI break for planner-related plugins in the 9.2 release
series. This still breaks ABI for anything that calls query_planner
directly, but it seems somewhat unlikely that there are any such plugins.
I had originally conceived of this change as merely a step on the way to
fixing bug #8049 from Teun Hoogendoorn; but it turns out that this fixes
that bug all by itself, as per the added regression test. The reason is
that now get_eclass_for_sort_expr is adding the ORDER BY expression at the
end of EquivalenceClass creation not the start, and so anything that is in
a multi-member EquivalenceClass has already been created with correct
em_nullable_relids. I am suspicious that there are related scenarios in
which we still need to teach get_eclass_for_sort_expr to compute correct
nullable_relids, but am not eager to risk destabilizing either 9.2 or 9.3
to fix bugs that are only hypothetical. So for the moment, do this and
stop here.
Back-patch to 9.2 but not to earlier branches, since they don't exhibit
this bug for lack of join-clause-movement logic that depends on
em_nullable_relids being correct. (We might have to revisit that choice
if any related bugs turn up.) In 9.2, don't change the signature of
make_pathkeys_for_sortclauses nor remove canonicalize_pathkeys, so as
not to risk more plugin breakage than we have to.
2013-04-29 20:49:01 +02:00
|
|
|
/* We assume pointer equality is sufficient to compare the eclasses */
|
|
|
|
COMPARE_SCALAR_FIELD(pk_eclass);
|
2007-01-20 21:45:41 +01:00
|
|
|
COMPARE_SCALAR_FIELD(pk_opfamily);
|
|
|
|
COMPARE_SCALAR_FIELD(pk_strategy);
|
|
|
|
COMPARE_SCALAR_FIELD(pk_nulls_first);
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1998-02-13 04:27:47 +01:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRestrictInfo(const RestrictInfo *a, const RestrictInfo *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(clause);
|
2004-01-05 06:07:36 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_pushed_down);
|
2005-11-15 00:54:23 +01:00
|
|
|
COMPARE_SCALAR_FIELD(outerjoin_delayed);
|
2005-06-09 06:19:00 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(required_relids);
|
Revise parameterized-path mechanism to fix assorted issues.
This patch adjusts the treatment of parameterized paths so that all paths
with the same parameterization (same set of required outer rels) for the
same relation will have the same rowcount estimate. We cache the rowcount
estimates to ensure that property, and hopefully save a few cycles too.
Doing this makes it practical for add_path_precheck to operate without
a rowcount estimate: it need only assume that paths with different
parameterizations never dominate each other, which is close enough to
true anyway for coarse filtering, because normally a more-parameterized
path should yield fewer rows thanks to having more join clauses to apply.
In add_path, we do the full nine yards of comparing rowcount estimates
along with everything else, so that we can discard parameterized paths that
don't actually have an advantage. This fixes some issues I'd found with
add_path rejecting parameterized paths on the grounds that they were more
expensive than not-parameterized ones, even though they yielded many fewer
rows and hence would be cheaper once subsequent joining was considered.
To make the same-rowcounts assumption valid, we have to require that any
parameterized path enforce *all* join clauses that could be obtained from
the particular set of outer rels, even if not all of them are useful for
indexing. This is required at both base scans and joins. It's a good
thing anyway since the net impact is that join quals are checked at the
lowest practical level in the join tree. Hence, discard the original
rather ad-hoc mechanism for choosing parameterization joinquals, and build
a better one that has a more principled rule for when clauses can be moved.
The original rule was actually buggy anyway for lack of knowledge about
which relations are part of an outer join's outer side; getting this right
requires adding an outer_relids field to RestrictInfo.
2012-04-19 21:52:46 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(outer_relids);
|
2009-04-16 22:42:16 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(nullable_relids);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2001-06-05 07:26:05 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We ignore all the remaining fields, since they may not be set yet, and
|
|
|
|
* should be derivable from the clause anyway.
|
2001-06-05 07:26:05 +02:00
|
|
|
*/
|
2002-11-25 04:33:27 +01:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2008-10-21 22:42:53 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalPlaceHolderVar(const PlaceHolderVar *a, const PlaceHolderVar *b)
|
2008-10-21 22:42:53 +02:00
|
|
|
{
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* We intentionally do not compare phexpr. Two PlaceHolderVars with the
|
2008-10-21 22:42:53 +02:00
|
|
|
* same ID and levelsup should be considered equal even if the contained
|
2014-05-06 18:12:18 +02:00
|
|
|
* expressions have managed to mutate to different states. This will
|
2013-08-18 02:22:37 +02:00
|
|
|
* happen during final plan construction when there are nested PHVs, since
|
|
|
|
* the inner PHV will get replaced by a Param in some copies of the outer
|
|
|
|
* PHV. Another way in which it can happen is that initplan sublinks
|
|
|
|
* could get replaced by differently-numbered Params when sublink folding
|
|
|
|
* is done. (The end result of such a situation would be some
|
|
|
|
* unreferenced initplans, which is annoying but not really a problem.) On
|
|
|
|
* the same reasoning, there is no need to examine phrels.
|
2008-10-21 22:42:53 +02:00
|
|
|
*
|
|
|
|
* COMPARE_NODE_FIELD(phexpr);
|
2013-08-18 02:22:37 +02:00
|
|
|
*
|
|
|
|
* COMPARE_BITMAPSET_FIELD(phrels);
|
2008-10-21 22:42:53 +02:00
|
|
|
*/
|
|
|
|
COMPARE_SCALAR_FIELD(phid);
|
|
|
|
COMPARE_SCALAR_FIELD(phlevelsup);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-01-20 19:55:07 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSpecialJoinInfo(const SpecialJoinInfo *a, const SpecialJoinInfo *b)
|
2003-01-20 19:55:07 +01:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(min_lefthand);
|
|
|
|
COMPARE_BITMAPSET_FIELD(min_righthand);
|
|
|
|
COMPARE_BITMAPSET_FIELD(syn_lefthand);
|
|
|
|
COMPARE_BITMAPSET_FIELD(syn_righthand);
|
|
|
|
COMPARE_SCALAR_FIELD(jointype);
|
|
|
|
COMPARE_SCALAR_FIELD(lhs_strict);
|
|
|
|
COMPARE_SCALAR_FIELD(delay_upper_joins);
|
Improve planner's cost estimation in the presence of semijoins.
If we have a semijoin, say
SELECT * FROM x WHERE x1 IN (SELECT y1 FROM y)
and we're estimating the cost of a parameterized indexscan on x, the number
of repetitions of the indexscan should not be taken as the size of y; it'll
really only be the number of distinct values of y1, because the only valid
plan with y on the outside of a nestloop would require y to be unique-ified
before joining it to x. Most of the time this doesn't make that much
difference, but sometimes it can lead to drastically underestimating the
cost of the indexscan and hence choosing a bad plan, as pointed out by
David Kubečka.
Fixing this is a bit difficult because parameterized indexscans are costed
out quite early in the planning process, before we have the information
that would be needed to call estimate_num_groups() and thereby estimate the
number of distinct values of the join column(s). However we can move the
code that extracts a semijoin RHS's unique-ification columns, so that it's
done in initsplan.c rather than on-the-fly in create_unique_path(). That
shouldn't make any difference speed-wise and it's really a bit cleaner too.
The other bit of information we need is the size of the semijoin RHS,
which is easy if it's a single relation (we make those estimates before
considering indexscan costs) but problematic if it's a join relation.
The solution adopted here is just to use the product of the sizes of the
join component rels. That will generally be an overestimate, but since
estimate_num_groups() only uses this input as a clamp, an overestimate
shouldn't hurt us too badly. In any case we don't allow this new logic
to produce a value larger than we would have chosen before, so that at
worst an overestimate leaves us no wiser than we were before.
2015-03-12 02:21:00 +01:00
|
|
|
COMPARE_SCALAR_FIELD(semi_can_btree);
|
|
|
|
COMPARE_SCALAR_FIELD(semi_can_hash);
|
|
|
|
COMPARE_NODE_FIELD(semi_operators);
|
|
|
|
COMPARE_NODE_FIELD(semi_rhs_exprs);
|
2003-01-20 19:55:07 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
static bool
|
|
|
|
_equalLateralJoinInfo(const LateralJoinInfo *a, const LateralJoinInfo *b)
|
|
|
|
{
|
|
|
|
COMPARE_BITMAPSET_FIELD(lateral_lhs);
|
2013-08-18 02:22:37 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(lateral_rhs);
|
2012-08-27 04:48:55 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-01-31 22:39:25 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
|
2006-01-31 22:39:25 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(parent_relid);
|
|
|
|
COMPARE_SCALAR_FIELD(child_relid);
|
|
|
|
COMPARE_SCALAR_FIELD(parent_reltype);
|
|
|
|
COMPARE_SCALAR_FIELD(child_reltype);
|
|
|
|
COMPARE_NODE_FIELD(translated_vars);
|
|
|
|
COMPARE_SCALAR_FIELD(parent_reloid);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-10-21 22:42:53 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
|
2008-10-21 22:42:53 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(phid);
|
2013-08-18 02:22:37 +02:00
|
|
|
COMPARE_NODE_FIELD(ph_var); /* should be redundant */
|
2008-10-21 22:42:53 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(ph_eval_at);
|
2013-08-18 02:22:37 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(ph_lateral);
|
2008-10-21 22:42:53 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(ph_needed);
|
|
|
|
COMPARE_SCALAR_FIELD(ph_width);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
|
1999-02-07 01:52:12 +01:00
|
|
|
/*
|
|
|
|
* Stuff from parsenodes.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalQuery(const Query *a, const Query *b)
|
1999-02-07 01:52:12 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(commandType);
|
|
|
|
COMPARE_SCALAR_FIELD(querySource);
|
2012-03-27 21:14:13 +02:00
|
|
|
/* we intentionally ignore queryId, since it might not be set */
|
2003-05-02 22:54:36 +02:00
|
|
|
COMPARE_SCALAR_FIELD(canSetTag);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(utilityStmt);
|
|
|
|
COMPARE_SCALAR_FIELD(resultRelation);
|
|
|
|
COMPARE_SCALAR_FIELD(hasAggs);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_SCALAR_FIELD(hasWindowFuncs);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(hasSubLinks);
|
2008-08-02 23:32:01 +02:00
|
|
|
COMPARE_SCALAR_FIELD(hasDistinctOn);
|
2008-10-04 23:56:55 +02:00
|
|
|
COMPARE_SCALAR_FIELD(hasRecursive);
|
2011-02-26 00:56:23 +01:00
|
|
|
COMPARE_SCALAR_FIELD(hasModifyingCTE);
|
2009-10-28 15:55:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(hasForUpdate);
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
COMPARE_SCALAR_FIELD(hasRowSecurity);
|
2008-10-04 23:56:55 +02:00
|
|
|
COMPARE_NODE_FIELD(cteList);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(rtable);
|
|
|
|
COMPARE_NODE_FIELD(jointree);
|
|
|
|
COMPARE_NODE_FIELD(targetList);
|
2013-07-18 23:10:16 +02:00
|
|
|
COMPARE_NODE_FIELD(withCheckOptions);
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
COMPARE_NODE_FIELD(onConflict);
|
2006-08-12 04:52:06 +02:00
|
|
|
COMPARE_NODE_FIELD(returningList);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(groupClause);
|
Support GROUPING SETS, CUBE and ROLLUP.
This SQL standard functionality allows to aggregate data by different
GROUP BY clauses at once. Each grouping set returns rows with columns
grouped by in other sets set to NULL.
This could previously be achieved by doing each grouping as a separate
query, conjoined by UNION ALLs. Besides being considerably more concise,
grouping sets will in many cases be faster, requiring only one scan over
the underlying data.
The current implementation of grouping sets only supports using sorting
for input. Individual sets that share a sort order are computed in one
pass. If there are sets that don't share a sort order, additional sort &
aggregation steps are performed. These additional passes are sourced by
the previous sort step; thus avoiding repeated scans of the source data.
The code is structured in a way that adding support for purely using
hash aggregation or a mix of hashing and sorting is possible. Sorting
was chosen to be supported first, as it is the most generic method of
implementation.
Instead of, as in an earlier versions of the patch, representing the
chain of sort and aggregation steps as full blown planner and executor
nodes, all but the first sort are performed inside the aggregation node
itself. This avoids the need to do some unusual gymnastics to handle
having to return aggregated and non-aggregated tuples from underlying
nodes, as well as having to shut down underlying nodes early to limit
memory usage. The optimizer still builds Sort/Agg node to describe each
phase, but they're not part of the plan tree, but instead additional
data for the aggregation node. They're a convenient and preexisting way
to describe aggregation and sorting. The first (and possibly only) sort
step is still performed as a separate execution step. That retains
similarity with existing group by plans, makes rescans fairly simple,
avoids very deep plans (leading to slow explains) and easily allows to
avoid the sorting step if the underlying data is sorted by other means.
A somewhat ugly side of this patch is having to deal with a grammar
ambiguity between the new CUBE keyword and the cube extension/functions
named cube (and rollup). To avoid breaking existing deployments of the
cube extension it has not been renamed, neither has cube been made a
reserved keyword. Instead precedence hacking is used to make GROUP BY
cube(..) refer to the CUBE grouping sets feature, and not the function
cube(). To actually group by a function cube(), unlikely as that might
be, the function name has to be quoted.
Needs a catversion bump because stored rules may change.
Author: Andrew Gierth and Atri Sharma, with contributions from Andres Freund
Reviewed-By: Andres Freund, Noah Misch, Tom Lane, Svenne Krap, Tomas
Vondra, Erik Rijkers, Marti Raudsepp, Pavel Stehule
Discussion: CAOeZVidmVRe2jU6aMk_5qkxnB7dfmPROzM7Ur8JPW5j8Y5X-Lw@mail.gmail.com
2015-05-16 03:40:59 +02:00
|
|
|
COMPARE_NODE_FIELD(groupingSets);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(havingQual);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_NODE_FIELD(windowClause);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(distinctClause);
|
|
|
|
COMPARE_NODE_FIELD(sortClause);
|
|
|
|
COMPARE_NODE_FIELD(limitOffset);
|
|
|
|
COMPARE_NODE_FIELD(limitCount);
|
2006-04-30 20:30:40 +02:00
|
|
|
COMPARE_NODE_FIELD(rowMarks);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(setOperations);
|
2010-08-07 04:44:09 +02:00
|
|
|
COMPARE_NODE_FIELD(constraintDeps);
|
1999-02-07 01:52:12 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalInsertStmt(const InsertStmt *a, const InsertStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(cols);
|
|
|
|
COMPARE_NODE_FIELD(selectStmt);
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
COMPARE_NODE_FIELD(onConflictClause);
|
2006-08-12 04:52:06 +02:00
|
|
|
COMPARE_NODE_FIELD(returningList);
|
2010-10-16 01:53:59 +02:00
|
|
|
COMPARE_NODE_FIELD(withClause);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDeleteStmt(const DeleteStmt *a, const DeleteStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
2005-04-07 03:51:41 +02:00
|
|
|
COMPARE_NODE_FIELD(usingClause);
|
2006-08-12 04:52:06 +02:00
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_NODE_FIELD(returningList);
|
2010-10-16 01:53:59 +02:00
|
|
|
COMPARE_NODE_FIELD(withClause);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalUpdateStmt(const UpdateStmt *a, const UpdateStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(targetList);
|
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_NODE_FIELD(fromClause);
|
2006-08-12 04:52:06 +02:00
|
|
|
COMPARE_NODE_FIELD(returningList);
|
2010-10-16 01:53:59 +02:00
|
|
|
COMPARE_NODE_FIELD(withClause);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSelectStmt(const SelectStmt *a, const SelectStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(distinctClause);
|
2007-04-28 00:05:49 +02:00
|
|
|
COMPARE_NODE_FIELD(intoClause);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(targetList);
|
|
|
|
COMPARE_NODE_FIELD(fromClause);
|
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_NODE_FIELD(groupClause);
|
|
|
|
COMPARE_NODE_FIELD(havingClause);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_NODE_FIELD(windowClause);
|
2006-08-02 03:59:48 +02:00
|
|
|
COMPARE_NODE_FIELD(valuesLists);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(sortClause);
|
|
|
|
COMPARE_NODE_FIELD(limitOffset);
|
|
|
|
COMPARE_NODE_FIELD(limitCount);
|
2005-08-01 22:31:16 +02:00
|
|
|
COMPARE_NODE_FIELD(lockingClause);
|
2012-07-31 23:56:21 +02:00
|
|
|
COMPARE_NODE_FIELD(withClause);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(op);
|
|
|
|
COMPARE_SCALAR_FIELD(all);
|
|
|
|
COMPARE_NODE_FIELD(larg);
|
|
|
|
COMPARE_NODE_FIELD(rarg);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-10-05 21:11:39 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b)
|
2000-10-05 21:11:39 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(op);
|
|
|
|
COMPARE_SCALAR_FIELD(all);
|
|
|
|
COMPARE_NODE_FIELD(larg);
|
|
|
|
COMPARE_NODE_FIELD(rarg);
|
2004-05-26 06:41:50 +02:00
|
|
|
COMPARE_NODE_FIELD(colTypes);
|
2006-08-10 04:36:29 +02:00
|
|
|
COMPARE_NODE_FIELD(colTypmods);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_NODE_FIELD(colCollations);
|
2008-08-07 03:11:52 +02:00
|
|
|
COMPARE_NODE_FIELD(groupClauses);
|
2000-10-05 21:11:39 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterTableStmt(const AlterTableStmt *a, const AlterTableStmt *b)
|
1999-02-07 01:52:12 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
2004-05-05 06:48:48 +02:00
|
|
|
COMPARE_NODE_FIELD(cmds);
|
2004-08-22 02:08:28 +02:00
|
|
|
COMPARE_SCALAR_FIELD(relkind);
|
2012-01-24 00:25:04 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2004-05-05 06:48:48 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
|
2004-05-05 06:48:48 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(subtype);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(newowner);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(def);
|
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2009-07-20 04:42:28 +02:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterDomainStmt(const AlterDomainStmt *a, const AlterDomainStmt *b)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(subtype);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
2002-12-06 06:00:34 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(def);
|
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2012-01-05 18:48:55 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_grant);
|
2009-10-12 22:39:42 +02:00
|
|
|
COMPARE_SCALAR_FIELD(targtype);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(objtype);
|
|
|
|
COMPARE_NODE_FIELD(objects);
|
2004-05-26 06:41:50 +02:00
|
|
|
COMPARE_NODE_FIELD(privileges);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(grantees);
|
2003-01-24 00:39:07 +01:00
|
|
|
COMPARE_SCALAR_FIELD(grant_option);
|
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-02-19 00:11:58 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFuncWithArgs(const FuncWithArgs *a, const FuncWithArgs *b)
|
2002-02-19 00:11:58 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(funcname);
|
|
|
|
COMPARE_NODE_FIELD(funcargs);
|
|
|
|
|
|
|
|
return true;
|
2002-02-19 00:11:58 +01:00
|
|
|
}
|
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAccessPriv(const AccessPriv *a, const AccessPriv *b)
|
2009-01-22 21:16:10 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(priv_name);
|
|
|
|
COMPARE_NODE_FIELD(cols);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
|
2005-06-28 07:09:14 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(granted_roles);
|
|
|
|
COMPARE_NODE_FIELD(grantee_roles);
|
|
|
|
COMPARE_SCALAR_FIELD(is_grant);
|
|
|
|
COMPARE_SCALAR_FIELD(admin_opt);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(grantor);
|
2005-06-28 07:09:14 +02:00
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-05 21:24:49 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *a, const AlterDefaultPrivilegesStmt *b)
|
2009-10-05 21:24:49 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_NODE_FIELD(action);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-03-10 04:53:52 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDeclareCursorStmt(const DeclareCursorStmt *a, const DeclareCursorStmt *b)
|
2003-03-10 04:53:52 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(portalname);
|
|
|
|
COMPARE_SCALAR_FIELD(options);
|
|
|
|
COMPARE_NODE_FIELD(query);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalClosePortalStmt(const ClosePortalStmt *a, const ClosePortalStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(portalname);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalClusterStmt(const ClusterStmt *a, const ClusterStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_STRING_FIELD(indexname);
|
2008-11-24 09:46:04 +01:00
|
|
|
COMPARE_SCALAR_FIELD(verbose);
|
1999-02-07 01:52:12 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-01-31 02:21:39 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCopyStmt(const CopyStmt *a, const CopyStmt *b)
|
2000-01-31 02:21:39 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
2006-08-31 01:34:22 +02:00
|
|
|
COMPARE_NODE_FIELD(query);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(attlist);
|
|
|
|
COMPARE_SCALAR_FIELD(is_from);
|
Add support for piping COPY to/from an external program.
This includes backend "COPY TO/FROM PROGRAM '...'" syntax, and corresponding
psql \copy syntax. Like with reading/writing files, the backend version is
superuser-only, and in the psql version, the program is run in the client.
In the passing, the psql \copy STDIN/STDOUT syntax is subtly changed: if you
the stdin/stdout is quoted, it's now interpreted as a filename. For example,
"\copy foo from 'stdin'" now reads from a file called 'stdin', not from
standard input. Before this, there was no way to specify a filename called
stdin, stdout, pstdin or pstdout.
This creates a new function in pgport, wait_result_to_str(), which can
be used to convert the exit status of a process, as returned by wait(3),
to a human-readable string.
Etsuro Fujita, reviewed by Amit Kapila.
2013-02-27 17:17:21 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_program);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(filename);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
2000-01-31 02:21:39 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-06-29 09:35:57 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateStmt(const CreateStmt *a, const CreateStmt *b)
|
2000-06-29 09:35:57 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(tableElts);
|
|
|
|
COMPARE_NODE_FIELD(inhRelations);
|
2010-01-29 00:21:13 +01:00
|
|
|
COMPARE_NODE_FIELD(ofTypename);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(constraints);
|
2006-07-02 04:23:23 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(oncommit);
|
2004-06-18 08:14:31 +02:00
|
|
|
COMPARE_STRING_FIELD(tablespacename);
|
2010-07-26 01:21:22 +02:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2000-06-29 09:35:57 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-06-25 05:40:19 +02:00
|
|
|
static bool
|
2012-01-07 13:58:13 +01:00
|
|
|
_equalTableLikeClause(const TableLikeClause *a, const TableLikeClause *b)
|
2003-06-25 05:40:19 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
2009-10-12 21:49:24 +02:00
|
|
|
COMPARE_SCALAR_FIELD(options);
|
2003-06-25 05:40:19 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1999-07-29 04:45:36 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
|
1999-07-29 04:45:36 +02:00
|
|
|
{
|
2003-02-10 05:44:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2006-04-15 19:45:46 +02:00
|
|
|
COMPARE_SCALAR_FIELD(oldstyle);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(defnames);
|
2006-04-15 19:45:46 +02:00
|
|
|
COMPARE_NODE_FIELD(args);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(definition);
|
1999-07-29 04:45:36 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropStmt(const DropStmt *a, const DropStmt *b)
|
1999-07-29 04:45:36 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(objects);
|
2011-11-18 03:31:29 +01:00
|
|
|
COMPARE_NODE_FIELD(arguments);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(removeType);
|
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2005-11-21 00:24:12 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2012-04-06 11:21:40 +02:00
|
|
|
COMPARE_SCALAR_FIELD(concurrent);
|
1999-07-29 04:45:36 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalTruncateStmt(const TruncateStmt *a, const TruncateStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2005-01-27 04:19:37 +01:00
|
|
|
COMPARE_NODE_FIELD(relations);
|
2008-05-17 01:36:05 +02:00
|
|
|
COMPARE_SCALAR_FIELD(restart_seqs);
|
2006-03-03 04:30:54 +01:00
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
1999-02-07 01:52:12 +01:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCommentStmt(const CommentStmt *a, const CommentStmt *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(objtype);
|
|
|
|
COMPARE_NODE_FIELD(objname);
|
|
|
|
COMPARE_NODE_FIELD(objargs);
|
|
|
|
COMPARE_STRING_FIELD(comment);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-28 02:55:27 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSecLabelStmt(const SecLabelStmt *a, const SecLabelStmt *b)
|
2010-09-28 02:55:27 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(objtype);
|
|
|
|
COMPARE_NODE_FIELD(objname);
|
|
|
|
COMPARE_NODE_FIELD(objargs);
|
|
|
|
COMPARE_STRING_FIELD(provider);
|
|
|
|
COMPARE_STRING_FIELD(label);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFetchStmt(const FetchStmt *a, const FetchStmt *b)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(direction);
|
|
|
|
COMPARE_SCALAR_FIELD(howMany);
|
|
|
|
COMPARE_STRING_FIELD(portalname);
|
|
|
|
COMPARE_SCALAR_FIELD(ismove);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(idxname);
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_STRING_FIELD(accessMethod);
|
2004-06-18 08:14:31 +02:00
|
|
|
COMPARE_STRING_FIELD(tableSpace);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(indexParams);
|
2006-07-02 04:23:23 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
2009-12-07 06:22:23 +01:00
|
|
|
COMPARE_NODE_FIELD(excludeOpNames);
|
Avoid pre-determining index names during CREATE TABLE LIKE parsing.
Formerly, when trying to copy both indexes and comments, CREATE TABLE LIKE
had to pre-assign names to indexes that had comments, because it made up an
explicit CommentStmt command to apply the comment and so it had to know the
name for the index. This creates bad interactions with other indexes, as
shown in bug #6734 from Daniele Varrazzo: the preassignment logic couldn't
take any other indexes into account so it could choose a conflicting name.
To fix, add a field to IndexStmt that allows it to carry a comment to be
assigned to the new index. (This isn't a user-exposed feature of CREATE
INDEX, only an internal option.) Now we don't need preassignment of index
names in any situation.
I also took the opportunity to refactor DefineIndex to accept the IndexStmt
as such, rather than passing all its fields individually in a mile-long
parameter list.
Back-patch to 9.2, but no further, because it seems too dangerous to change
IndexStmt or DefineIndex's API in released branches. The bug exists back
to 9.0 where CREATE TABLE LIKE grew the ability to copy comments, but given
the lack of prior complaints we'll just let it go unfixed before 9.2.
2012-07-16 19:25:18 +02:00
|
|
|
COMPARE_STRING_FIELD(idxcomment);
|
2011-01-25 21:42:03 +01:00
|
|
|
COMPARE_SCALAR_FIELD(indexOid);
|
2011-07-18 17:02:48 +02:00
|
|
|
COMPARE_SCALAR_FIELD(oldNode);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(unique);
|
|
|
|
COMPARE_SCALAR_FIELD(primary);
|
|
|
|
COMPARE_SCALAR_FIELD(isconstraint);
|
2009-07-29 22:56:21 +02:00
|
|
|
COMPARE_SCALAR_FIELD(deferrable);
|
|
|
|
COMPARE_SCALAR_FIELD(initdeferred);
|
Get rid of multiple applications of transformExpr() to the same tree.
transformExpr() has for many years had provisions to do nothing when
applied to an already-transformed expression tree. However, this was
always ugly and of dubious reliability, so we'd be much better off without
it. The primary historical reason for it was that gram.y sometimes
returned multiple links to the same subexpression, which is no longer true
as of my BETWEEN fixes. We'd also grown some lazy hacks in CREATE TABLE
LIKE (failing to distinguish between raw and already-transformed index
specifications) and one or two other places.
This patch removes the need for and support for re-transforming already
transformed expressions. The index case is dealt with by adding a flag
to struct IndexStmt to indicate that it's already been transformed;
which has some benefit anyway in that tablecmds.c can now Assert that
transformation has happened rather than just assuming. The other main
reason was some rather sloppy code for array type coercion, which can
be fixed (and its performance improved too) by refactoring.
I did leave transformJoinUsingClause() still constructing expressions
containing untransformed operator nodes being applied to Vars, so that
transformExpr() still has to allow Var inputs. But that's a much narrower,
and safer, special case than before, since Vars will never appear in a raw
parse tree, and they don't have any substructure to worry about.
In passing fix some oversights in the patch that added CREATE INDEX
IF NOT EXISTS (missing processing of IndexStmt.if_not_exists). These
appear relatively harmless, but still sloppy coding practice.
2015-02-22 19:59:09 +01:00
|
|
|
COMPARE_SCALAR_FIELD(transformed);
|
2006-08-25 06:06:58 +02:00
|
|
|
COMPARE_SCALAR_FIELD(concurrent);
|
2014-11-06 10:48:33 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateFunctionStmt(const CreateFunctionStmt *a, const CreateFunctionStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
|
|
|
COMPARE_NODE_FIELD(funcname);
|
2004-01-07 00:55:19 +01:00
|
|
|
COMPARE_NODE_FIELD(parameters);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(returnType);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_NODE_FIELD(withClause);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-01-07 00:55:19 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFunctionParameter(const FunctionParameter *a, const FunctionParameter *b)
|
2004-01-07 00:55:19 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(argType);
|
2005-03-29 19:58:51 +02:00
|
|
|
COMPARE_SCALAR_FIELD(mode);
|
2008-12-04 18:51:28 +01:00
|
|
|
COMPARE_NODE_FIELD(defexpr);
|
2004-01-07 00:55:19 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-14 01:19:37 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterFunctionStmt(const AlterFunctionStmt *a, const AlterFunctionStmt *b)
|
2005-03-14 01:19:37 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(func);
|
|
|
|
COMPARE_NODE_FIELD(actions);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-09-23 01:43:43 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDoStmt(const DoStmt *a, const DoStmt *b)
|
2009-09-23 01:43:43 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRenameStmt(const RenameStmt *a, const RenameStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2005-08-01 06:03:59 +02:00
|
|
|
COMPARE_SCALAR_FIELD(renameType);
|
2012-04-18 16:43:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(relationType);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
2003-06-27 16:45:32 +02:00
|
|
|
COMPARE_NODE_FIELD(object);
|
|
|
|
COMPARE_NODE_FIELD(objarg);
|
|
|
|
COMPARE_STRING_FIELD(subname);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(newname);
|
2010-11-23 21:50:17 +01:00
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2012-01-24 00:25:04 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *a, const AlterObjectSchemaStmt *b)
|
2005-08-01 06:03:59 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(objectType);
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(object);
|
|
|
|
COMPARE_NODE_FIELD(objarg);
|
|
|
|
COMPARE_STRING_FIELD(newschema);
|
2012-01-24 00:25:04 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
|
2004-06-25 23:55:59 +02:00
|
|
|
{
|
2005-08-01 06:03:59 +02:00
|
|
|
COMPARE_SCALAR_FIELD(objectType);
|
2004-06-25 23:55:59 +02:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(object);
|
|
|
|
COMPARE_NODE_FIELD(objarg);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:17:55 +02:00
|
|
|
static bool
|
|
|
|
_equalAlterOperatorStmt(const AlterOperatorStmt *a, const AlterOperatorStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(opername);
|
|
|
|
COMPARE_NODE_FIELD(operargs);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_STRING_FIELD(rulename);
|
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_SCALAR_FIELD(event);
|
|
|
|
COMPARE_SCALAR_FIELD(instead);
|
|
|
|
COMPARE_NODE_FIELD(actions);
|
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalNotifyStmt(const NotifyStmt *a, const NotifyStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_STRING_FIELD(conditionname);
|
2010-02-16 23:34:57 +01:00
|
|
|
COMPARE_STRING_FIELD(payload);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalListenStmt(const ListenStmt *a, const ListenStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_STRING_FIELD(conditionname);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalUnlistenStmt(const UnlistenStmt *a, const UnlistenStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_STRING_FIELD(conditionname);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalTransactionStmt(const TransactionStmt *a, const TransactionStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2003-02-10 05:44:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2005-06-18 00:32:51 +02:00
|
|
|
COMPARE_STRING_FIELD(gid);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-08-15 18:36:08 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
|
2002-08-15 18:36:08 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(typevar);
|
|
|
|
COMPARE_NODE_FIELD(coldeflist);
|
2002-08-15 18:36:08 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
|
2007-04-02 05:49:42 +02:00
|
|
|
{
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
2007-04-02 05:49:42 +02:00
|
|
|
COMPARE_NODE_FIELD(vals);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(typeName);
|
|
|
|
COMPARE_NODE_FIELD(params);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-10-25 05:04:37 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterEnumStmt(const AlterEnumStmt *a, const AlterEnumStmt *b)
|
2010-10-25 05:04:37 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(typeName);
|
|
|
|
COMPARE_STRING_FIELD(newVal);
|
|
|
|
COMPARE_STRING_FIELD(newValNeighbor);
|
|
|
|
COMPARE_SCALAR_FIELD(newValIsAfter);
|
2012-09-22 18:53:31 +02:00
|
|
|
COMPARE_SCALAR_FIELD(skipIfExists);
|
2010-10-25 05:04:37 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-11-25 04:33:27 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalViewStmt(const ViewStmt *a, const ViewStmt *b)
|
2002-11-25 04:33:27 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(view);
|
|
|
|
COMPARE_NODE_FIELD(aliases);
|
|
|
|
COMPARE_NODE_FIELD(query);
|
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
2012-04-18 16:43:16 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2013-07-18 23:10:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(withCheckOption);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalLoadStmt(const LoadStmt *a, const LoadStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(filename);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-19 03:18:25 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateDomainStmt(const CreateDomainStmt *a, const CreateDomainStmt *b)
|
2002-03-19 03:18:25 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(domainname);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
COMPARE_NODE_FIELD(collClause);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(constraints);
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateOpClassStmt(const CreateOpClassStmt *a, const CreateOpClassStmt *b)
|
2002-07-30 00:14:11 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(opclassname);
|
2006-12-23 01:43:13 +01:00
|
|
|
COMPARE_NODE_FIELD(opfamilyname);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(amname);
|
|
|
|
COMPARE_NODE_FIELD(datatype);
|
|
|
|
COMPARE_NODE_FIELD(items);
|
|
|
|
COMPARE_SCALAR_FIELD(isDefault);
|
2002-07-30 00:14:11 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateOpClassItem(const CreateOpClassItem *a, const CreateOpClassItem *b)
|
2002-07-30 00:14:11 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(itemtype);
|
|
|
|
COMPARE_NODE_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_SCALAR_FIELD(number);
|
2010-11-24 20:20:39 +01:00
|
|
|
COMPARE_NODE_FIELD(order_family);
|
2007-01-23 06:07:18 +01:00
|
|
|
COMPARE_NODE_FIELD(class_args);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(storedtype);
|
2002-07-30 00:14:11 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-01-23 06:07:18 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateOpFamilyStmt(const CreateOpFamilyStmt *a, const CreateOpFamilyStmt *b)
|
2007-01-23 06:07:18 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(opfamilyname);
|
|
|
|
COMPARE_STRING_FIELD(amname);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterOpFamilyStmt(const AlterOpFamilyStmt *a, const AlterOpFamilyStmt *b)
|
2007-01-23 06:07:18 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(opfamilyname);
|
|
|
|
COMPARE_STRING_FIELD(amname);
|
|
|
|
COMPARE_SCALAR_FIELD(isDrop);
|
|
|
|
COMPARE_NODE_FIELD(items);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreatedbStmt(const CreatedbStmt *a, const CreatedbStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(dbname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-31 19:19:22 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b)
|
2005-07-31 19:19:22 +02:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(dbname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-01 23:45:19 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterDatabaseSetStmt(const AlterDatabaseSetStmt *a, const AlterDatabaseSetStmt *b)
|
2002-03-01 23:45:19 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(dbname);
|
2007-09-03 20:46:30 +02:00
|
|
|
COMPARE_NODE_FIELD(setstmt);
|
2002-03-01 23:45:19 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropdbStmt(const DropdbStmt *a, const DropdbStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(dbname);
|
2005-11-22 16:24:18 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2009-11-16 22:32:07 +01:00
|
|
|
COMPARE_SCALAR_FIELD(options);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(va_cols);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalExplainStmt(const ExplainStmt *a, const ExplainStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(query);
|
2009-07-27 01:34:18 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
static bool
|
|
|
|
_equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(query);
|
|
|
|
COMPARE_NODE_FIELD(into);
|
2013-03-04 01:23:31 +01:00
|
|
|
COMPARE_SCALAR_FIELD(relkind);
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_select_into);
|
2014-12-13 19:56:09 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-04 01:23:31 +01:00
|
|
|
static bool
|
|
|
|
_equalRefreshMatViewStmt(const RefreshMatViewStmt *a, const RefreshMatViewStmt *b)
|
|
|
|
{
|
2013-07-16 19:55:44 +02:00
|
|
|
COMPARE_SCALAR_FIELD(concurrent);
|
2013-03-04 01:23:31 +01:00
|
|
|
COMPARE_SCALAR_FIELD(skipData);
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-08 18:30:43 +01:00
|
|
|
static bool
|
|
|
|
_equalReplicaIdentityStmt(const ReplicaIdentityStmt *a, const ReplicaIdentityStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(identity_type);
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-18 15:42:44 +01:00
|
|
|
static bool
|
2014-05-06 18:12:18 +02:00
|
|
|
_equalAlterSystemStmt(const AlterSystemStmt *a, const AlterSystemStmt *b)
|
2013-12-18 15:42:44 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(setstmt);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(sequence);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
2010-08-18 20:35:21 +02:00
|
|
|
COMPARE_SCALAR_FIELD(ownerId);
|
2014-08-26 15:05:18 +02:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-03-20 08:02:11 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterSeqStmt(const AlterSeqStmt *a, const AlterSeqStmt *b)
|
2003-03-20 08:02:11 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(sequence);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
2012-01-24 00:25:04 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2003-03-20 08:02:11 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalVariableSetStmt(const VariableSetStmt *a, const VariableSetStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2007-09-03 20:46:30 +02:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_SCALAR_FIELD(is_local);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalVariableShowStmt(const VariableShowStmt *a, const VariableShowStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-04-26 18:13:15 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDiscardStmt(const DiscardStmt *a, const DiscardStmt *b)
|
2007-04-26 18:13:15 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(target);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-06-18 08:14:31 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
|
2004-06-18 08:14:31 +02:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(tablespacename);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(owner);
|
2004-06-18 08:14:31 +02:00
|
|
|
COMPARE_STRING_FIELD(location);
|
2014-01-19 02:59:31 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2004-06-18 08:14:31 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropTableSpaceStmt(const DropTableSpaceStmt *a, const DropTableSpaceStmt *b)
|
2004-06-18 08:14:31 +02:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(tablespacename);
|
2006-06-16 22:23:45 +02:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2004-06-18 08:14:31 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-05 22:54:00 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *a,
|
|
|
|
const AlterTableSpaceOptionsStmt *b)
|
2010-01-05 22:54:00 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(tablespacename);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_SCALAR_FIELD(isReset);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-19 00:56:40 +01:00
|
|
|
static bool
|
2014-08-22 01:06:17 +02:00
|
|
|
_equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *a,
|
|
|
|
const AlterTableMoveAllStmt *b)
|
2014-01-19 00:56:40 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(orig_tablespacename);
|
2014-01-24 05:52:40 +01:00
|
|
|
COMPARE_SCALAR_FIELD(objtype);
|
|
|
|
COMPARE_NODE_FIELD(roles);
|
2014-01-19 00:56:40 +01:00
|
|
|
COMPARE_STRING_FIELD(new_tablespacename);
|
|
|
|
COMPARE_SCALAR_FIELD(nowait);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateExtensionStmt(const CreateExtensionStmt *a, const CreateExtensionStmt *b)
|
2011-02-08 22:08:41 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(extname);
|
2011-03-04 22:08:24 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2011-02-08 22:08:41 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-12 03:25:20 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterExtensionStmt(const AlterExtensionStmt *a, const AlterExtensionStmt *b)
|
2011-02-12 03:25:20 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(extname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-09 17:55:32 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterExtensionContentsStmt(const AlterExtensionContentsStmt *a, const AlterExtensionContentsStmt *b)
|
2011-02-09 17:55:32 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(extname);
|
2011-02-10 23:36:44 +01:00
|
|
|
COMPARE_SCALAR_FIELD(action);
|
2011-02-09 17:55:32 +01:00
|
|
|
COMPARE_SCALAR_FIELD(objtype);
|
|
|
|
COMPARE_NODE_FIELD(objname);
|
|
|
|
COMPARE_NODE_FIELD(objargs);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-12-19 17:25:19 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateFdwStmt(const CreateFdwStmt *a, const CreateFdwStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(fdwname);
|
2011-02-19 06:06:18 +01:00
|
|
|
COMPARE_NODE_FIELD(func_options);
|
2008-12-19 17:25:19 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterFdwStmt(const AlterFdwStmt *a, const AlterFdwStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(fdwname);
|
2011-02-19 06:06:18 +01:00
|
|
|
COMPARE_NODE_FIELD(func_options);
|
2008-12-19 17:25:19 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateForeignServerStmt(const CreateForeignServerStmt *a, const CreateForeignServerStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_STRING_FIELD(servertype);
|
|
|
|
COMPARE_STRING_FIELD(version);
|
|
|
|
COMPARE_STRING_FIELD(fdwname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeignServerStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_STRING_FIELD(version);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_SCALAR_FIELD(has_version);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(user);
|
2008-12-19 17:25:19 +01:00
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(user);
|
2008-12-19 17:25:19 +01:00
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
|
2008-12-19 17:25:19 +01:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(user);
|
2008-12-19 17:25:19 +01:00
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-01-02 05:48:11 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateForeignTableStmt(const CreateForeignTableStmt *a, const CreateForeignTableStmt *b)
|
2011-01-02 05:48:11 +01:00
|
|
|
{
|
|
|
|
if (!_equalCreateStmt(&a->base, &b->base))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
COMPARE_STRING_FIELD(servername);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-10 21:01:31 +02:00
|
|
|
static bool
|
|
|
|
_equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *a, const ImportForeignSchemaStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(server_name);
|
|
|
|
COMPARE_STRING_FIELD(remote_schema);
|
|
|
|
COMPARE_STRING_FIELD(local_schema);
|
|
|
|
COMPARE_SCALAR_FIELD(list_type);
|
|
|
|
COMPARE_NODE_FIELD(table_list);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-26 16:33:14 +02:00
|
|
|
static bool
|
|
|
|
_equalCreateTransformStmt(const CreateTransformStmt *a, const CreateTransformStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
|
|
|
COMPARE_NODE_FIELD(type_name);
|
|
|
|
COMPARE_STRING_FIELD(lang);
|
|
|
|
COMPARE_NODE_FIELD(fromsql);
|
|
|
|
COMPARE_NODE_FIELD(tosql);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(trigname);
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(funcname);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_SCALAR_FIELD(row);
|
2010-10-10 19:43:33 +02:00
|
|
|
COMPARE_SCALAR_FIELD(timing);
|
2009-06-18 03:27:02 +02:00
|
|
|
COMPARE_SCALAR_FIELD(events);
|
2009-10-15 00:14:25 +02:00
|
|
|
COMPARE_NODE_FIELD(columns);
|
2009-11-20 21:38:12 +01:00
|
|
|
COMPARE_NODE_FIELD(whenClause);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(isconstraint);
|
|
|
|
COMPARE_SCALAR_FIELD(deferrable);
|
|
|
|
COMPARE_SCALAR_FIELD(initdeferred);
|
|
|
|
COMPARE_NODE_FIELD(constrrel);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
static bool
|
|
|
|
_equalCreateEventTrigStmt(const CreateEventTrigStmt *a, const CreateEventTrigStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(trigname);
|
2014-09-22 22:05:51 +02:00
|
|
|
COMPARE_STRING_FIELD(eventname);
|
2012-07-18 16:16:16 +02:00
|
|
|
COMPARE_NODE_FIELD(whenclause);
|
2015-08-06 02:44:27 +02:00
|
|
|
COMPARE_NODE_FIELD(funcname);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalAlterEventTrigStmt(const AlterEventTrigStmt *a, const AlterEventTrigStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(trigname);
|
|
|
|
COMPARE_SCALAR_FIELD(tgenabled);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2010-02-23 23:51:43 +01:00
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(plname);
|
|
|
|
COMPARE_NODE_FIELD(plhandler);
|
2009-09-23 01:43:43 +02:00
|
|
|
COMPARE_NODE_FIELD(plinline);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(plvalidator);
|
|
|
|
COMPARE_SCALAR_FIELD(pltrusted);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2005-07-26 18:38:29 +02:00
|
|
|
COMPARE_SCALAR_FIELD(stmt_type);
|
2005-06-28 07:09:14 +02:00
|
|
|
COMPARE_STRING_FIELD(role);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(role);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2005-06-28 07:09:14 +02:00
|
|
|
COMPARE_SCALAR_FIELD(action);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-01 23:45:19 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
|
2002-03-01 23:45:19 +01:00
|
|
|
{
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(role);
|
2009-10-08 00:14:26 +02:00
|
|
|
COMPARE_STRING_FIELD(database);
|
2007-09-03 20:46:30 +02:00
|
|
|
COMPARE_NODE_FIELD(setstmt);
|
2002-03-01 23:45:19 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropRoleStmt(const DropRoleStmt *a, const DropRoleStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
COMPARE_NODE_FIELD(roles);
|
2006-02-04 20:06:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalLockStmt(const LockStmt *a, const LockStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relations);
|
|
|
|
COMPARE_SCALAR_FIELD(mode);
|
2004-03-11 02:47:41 +01:00
|
|
|
COMPARE_SCALAR_FIELD(nowait);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalConstraintsSetStmt(const ConstraintsSetStmt *a, const ConstraintsSetStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(constraints);
|
|
|
|
COMPARE_SCALAR_FIELD(deferred);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalReindexStmt(const ReindexStmt *a, const ReindexStmt *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2003-02-10 05:44:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_STRING_FIELD(name);
|
2015-05-15 13:09:57 +02:00
|
|
|
COMPARE_SCALAR_FIELD(options);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-21 17:02:16 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
|
2002-03-21 17:02:16 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(schemaname);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(authrole);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(schemaElts);
|
2012-10-04 01:47:11 +02:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2002-03-21 17:02:16 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-08-19 02:11:53 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateConversionStmt(const CreateConversionStmt *a, const CreateConversionStmt *b)
|
2002-08-19 02:11:53 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(conversion_name);
|
|
|
|
COMPARE_STRING_FIELD(for_encoding_name);
|
|
|
|
COMPARE_STRING_FIELD(to_encoding_name);
|
|
|
|
COMPARE_NODE_FIELD(func_name);
|
|
|
|
COMPARE_SCALAR_FIELD(def);
|
2002-08-19 02:11:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
|
2002-08-19 02:11:53 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(sourcetype);
|
|
|
|
COMPARE_NODE_FIELD(targettype);
|
|
|
|
COMPARE_NODE_FIELD(func);
|
|
|
|
COMPARE_SCALAR_FIELD(context);
|
2008-10-31 09:39:22 +01:00
|
|
|
COMPARE_SCALAR_FIELD(inout);
|
2002-08-19 02:11:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-08-27 06:55:12 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalPrepareStmt(const PrepareStmt *a, const PrepareStmt *b)
|
2002-08-27 06:55:12 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(argtypes);
|
|
|
|
COMPARE_NODE_FIELD(query);
|
2002-08-27 06:55:12 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalExecuteStmt(const ExecuteStmt *a, const ExecuteStmt *b)
|
2002-08-27 06:55:12 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(params);
|
2002-08-27 06:55:12 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDeallocateStmt(const DeallocateStmt *a, const DeallocateStmt *b)
|
2002-08-27 06:55:12 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
2002-08-27 06:55:12 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-11-21 13:49:33 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDropOwnedStmt(const DropOwnedStmt *a, const DropOwnedStmt *b)
|
2005-11-21 13:49:33 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(roles);
|
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
2005-11-21 13:49:33 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
|
2005-11-21 13:49:33 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(roles);
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
COMPARE_NODE_FIELD(newrole);
|
2005-11-21 13:49:33 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2002-11-25 04:33:27 +01:00
|
|
|
|
2008-02-07 21:19:47 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterTSDictionaryStmt(const AlterTSDictionaryStmt *a, const AlterTSDictionaryStmt *b)
|
2008-02-07 21:19:47 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(dictname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt *a,
|
|
|
|
const AlterTSConfigurationStmt *b)
|
2008-02-07 21:19:47 +01:00
|
|
|
{
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2008-02-07 21:19:47 +01:00
|
|
|
COMPARE_NODE_FIELD(cfgname);
|
|
|
|
COMPARE_NODE_FIELD(tokentype);
|
|
|
|
COMPARE_NODE_FIELD(dicts);
|
|
|
|
COMPARE_SCALAR_FIELD(override);
|
|
|
|
COMPARE_SCALAR_FIELD(replace);
|
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
static bool
|
|
|
|
_equalCreatePolicyStmt(const CreatePolicyStmt *a, const CreatePolicyStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(policy_name);
|
|
|
|
COMPARE_NODE_FIELD(table);
|
2015-08-21 14:22:22 +02:00
|
|
|
COMPARE_STRING_FIELD(cmd_name);
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
COMPARE_NODE_FIELD(roles);
|
|
|
|
COMPARE_NODE_FIELD(qual);
|
|
|
|
COMPARE_NODE_FIELD(with_check);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalAlterPolicyStmt(const AlterPolicyStmt *a, const AlterPolicyStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(policy_name);
|
|
|
|
COMPARE_NODE_FIELD(table);
|
|
|
|
COMPARE_NODE_FIELD(roles);
|
|
|
|
COMPARE_NODE_FIELD(qual);
|
|
|
|
COMPARE_NODE_FIELD(with_check);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAExpr(const A_Expr *a, const A_Expr *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2003-02-10 05:44:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(lexpr);
|
|
|
|
COMPARE_NODE_FIELD(rexpr);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalColumnRef(const ColumnRef *a, const ColumnRef *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(fields);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalParamRef(const ParamRef *a, const ParamRef *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(number);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAConst(const A_Const *a, const A_Const *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
if (!equal(&a->val, &b->val)) /* hack for in-line Value field */
|
2000-08-12 01:45:35 +02:00
|
|
|
return false;
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalFuncCall(const FuncCall *a, const FuncCall *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(funcname);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
2009-12-15 18:57:48 +01:00
|
|
|
COMPARE_NODE_FIELD(agg_order);
|
2013-07-17 02:15:36 +02:00
|
|
|
COMPARE_NODE_FIELD(agg_filter);
|
Support ordered-set (WITHIN GROUP) aggregates.
This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.
Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.
In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.
Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane
2013-12-23 22:11:35 +01:00
|
|
|
COMPARE_SCALAR_FIELD(agg_within_group);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(agg_star);
|
|
|
|
COMPARE_SCALAR_FIELD(agg_distinct);
|
2008-07-16 03:30:23 +02:00
|
|
|
COMPARE_SCALAR_FIELD(func_variadic);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_NODE_FIELD(over);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-30 03:39:14 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAStar(const A_Star *a, const A_Star *b)
|
2008-08-30 03:39:14 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalAIndices(const A_Indices *a, const A_Indices *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(lidx);
|
|
|
|
COMPARE_NODE_FIELD(uidx);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-21 17:02:16 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalA_Indirection(const A_Indirection *a, const A_Indirection *b)
|
2002-03-21 17:02:16 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
|
|
|
COMPARE_NODE_FIELD(indirection);
|
2002-03-21 17:02:16 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-20 22:42:48 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalA_ArrayExpr(const A_ArrayExpr *a, const A_ArrayExpr *b)
|
2008-03-20 22:42:48 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(elements);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2008-03-20 22:42:48 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalResTarget(const ResTarget *a, const ResTarget *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(indirection);
|
|
|
|
COMPARE_NODE_FIELD(val);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
static bool
|
|
|
|
_equalMultiAssignRef(const MultiAssignRef *a, const MultiAssignRef *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(source);
|
|
|
|
COMPARE_SCALAR_FIELD(colno);
|
|
|
|
COMPARE_SCALAR_FIELD(ncolumns);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalTypeName(const TypeName *a, const TypeName *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(names);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_SCALAR_FIELD(typeOid);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(setof);
|
|
|
|
COMPARE_SCALAR_FIELD(pct_type);
|
2006-12-30 22:21:56 +01:00
|
|
|
COMPARE_NODE_FIELD(typmods);
|
|
|
|
COMPARE_SCALAR_FIELD(typemod);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(arrayBounds);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-03-21 17:02:16 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalTypeCast(const TypeCast *a, const TypeCast *b)
|
2002-03-21 17:02:16 +01:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(arg);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-03-21 17:02:16 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-08 22:04:18 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCollateClause(const CollateClause *a, const CollateClause *b)
|
2011-02-08 22:04:18 +01:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
2011-03-11 22:27:51 +01:00
|
|
|
COMPARE_NODE_FIELD(collname);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSortBy(const SortBy *a, const SortBy *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_NODE_FIELD(node);
|
2007-01-09 03:14:16 +01:00
|
|
|
COMPARE_SCALAR_FIELD(sortby_dir);
|
|
|
|
COMPARE_SCALAR_FIELD(sortby_nulls);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(useOp);
|
2008-09-01 22:42:46 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2002-08-05 01:49:59 +02:00
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-12-28 19:54:01 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalWindowDef(const WindowDef *a, const WindowDef *b)
|
2008-12-28 19:54:01 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_STRING_FIELD(refname);
|
|
|
|
COMPARE_NODE_FIELD(partitionClause);
|
|
|
|
COMPARE_NODE_FIELD(orderClause);
|
2008-12-31 01:08:39 +01:00
|
|
|
COMPARE_SCALAR_FIELD(frameOptions);
|
2010-02-12 18:33:21 +01:00
|
|
|
COMPARE_NODE_FIELD(startOffset);
|
|
|
|
COMPARE_NODE_FIELD(endOffset);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRangeSubselect(const RangeSubselect *a, const RangeSubselect *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
COMPARE_SCALAR_FIELD(lateral);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(subquery);
|
|
|
|
COMPARE_NODE_FIELD(alias);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRangeFunction(const RangeFunction *a, const RangeFunction *b)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
2012-08-08 01:02:54 +02:00
|
|
|
COMPARE_SCALAR_FIELD(lateral);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
COMPARE_SCALAR_FIELD(ordinality);
|
2013-12-10 15:34:37 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_rowsfrom);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
COMPARE_NODE_FIELD(functions);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(alias);
|
|
|
|
COMPARE_NODE_FIELD(coldeflist);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Redesign tablesample method API, and do extensive code review.
The original implementation of TABLESAMPLE modeled the tablesample method
API on index access methods, which wasn't a good choice because, without
specialized DDL commands, there's no way to build an extension that can
implement a TSM. (Raw inserts into system catalogs are not an acceptable
thing to do, because we can't undo them during DROP EXTENSION, nor will
pg_upgrade behave sanely.) Instead adopt an API more like procedural
language handlers or foreign data wrappers, wherein the only SQL-level
support object needed is a single handler function identified by having
a special return type. This lets us get rid of the supporting catalog
altogether, so that no custom DDL support is needed for the feature.
Adjust the API so that it can support non-constant tablesample arguments
(the original coding assumed we could evaluate the argument expressions at
ExecInitSampleScan time, which is undesirable even if it weren't outright
unsafe), and discourage sampling methods from looking at invisible tuples.
Make sure that the BERNOULLI and SYSTEM methods are genuinely repeatable
within and across queries, as required by the SQL standard, and deal more
honestly with methods that can't support that requirement.
Make a full code-review pass over the tablesample additions, and fix
assorted bugs, omissions, infelicities, and cosmetic issues (such as
failure to put the added code stanzas in a consistent ordering).
Improve EXPLAIN's output of tablesample plans, too.
Back-patch to 9.5 so that we don't have to support the original API
in production.
2015-07-25 20:39:00 +02:00
|
|
|
static bool
|
|
|
|
_equalRangeTableSample(const RangeTableSample *a, const RangeTableSample *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
|
|
|
COMPARE_NODE_FIELD(method);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_NODE_FIELD(repeatable);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalIndexElem(const IndexElem *a, const IndexElem *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(name);
|
2003-05-28 18:04:02 +02:00
|
|
|
COMPARE_NODE_FIELD(expr);
|
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
|
|
|
COMPARE_STRING_FIELD(indexcolname);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_NODE_FIELD(collation);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(opclass);
|
2007-01-09 03:14:16 +01:00
|
|
|
COMPARE_SCALAR_FIELD(ordering);
|
|
|
|
COMPARE_SCALAR_FIELD(nulls_ordering);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalColumnDef(const ColumnDef *a, const ColumnDef *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(colname);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(inhcount);
|
|
|
|
COMPARE_SCALAR_FIELD(is_local);
|
|
|
|
COMPARE_SCALAR_FIELD(is_not_null);
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_from_type);
|
2009-10-13 02:53:08 +02:00
|
|
|
COMPARE_SCALAR_FIELD(storage);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(raw_default);
|
2009-10-06 02:55:26 +02:00
|
|
|
COMPARE_NODE_FIELD(cooked_default);
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
COMPARE_NODE_FIELD(collClause);
|
|
|
|
COMPARE_SCALAR_FIELD(collOid);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(constraints);
|
2012-04-18 16:43:16 +02:00
|
|
|
COMPARE_NODE_FIELD(fdwoptions);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalConstraint(const Constraint *a, const Constraint *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(contype);
|
2009-07-30 04:45:38 +02:00
|
|
|
COMPARE_STRING_FIELD(conname);
|
|
|
|
COMPARE_SCALAR_FIELD(deferrable);
|
|
|
|
COMPARE_SCALAR_FIELD(initdeferred);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2012-04-21 04:46:20 +02:00
|
|
|
COMPARE_SCALAR_FIELD(is_no_inherit);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(raw_expr);
|
|
|
|
COMPARE_STRING_FIELD(cooked_expr);
|
|
|
|
COMPARE_NODE_FIELD(keys);
|
2009-12-07 06:22:23 +01:00
|
|
|
COMPARE_NODE_FIELD(exclusions);
|
2006-07-02 04:23:23 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2011-01-25 21:42:03 +01:00
|
|
|
COMPARE_STRING_FIELD(indexname);
|
2004-08-02 06:28:29 +02:00
|
|
|
COMPARE_STRING_FIELD(indexspace);
|
2009-12-07 06:22:23 +01:00
|
|
|
COMPARE_STRING_FIELD(access_method);
|
|
|
|
COMPARE_NODE_FIELD(where_clause);
|
2009-07-30 04:45:38 +02:00
|
|
|
COMPARE_NODE_FIELD(pktable);
|
|
|
|
COMPARE_NODE_FIELD(fk_attrs);
|
|
|
|
COMPARE_NODE_FIELD(pk_attrs);
|
|
|
|
COMPARE_SCALAR_FIELD(fk_matchtype);
|
|
|
|
COMPARE_SCALAR_FIELD(fk_upd_action);
|
|
|
|
COMPARE_SCALAR_FIELD(fk_del_action);
|
ALTER TABLE: skip FK validation when it's safe to do so
We already skip rewriting the table in these cases, but we still force a
whole table scan to validate the data. This can be skipped, and thus
we can make the whole ALTER TABLE operation just do some catalog touches
instead of scanning the table, when these two conditions hold:
(a) Old and new pg_constraint.conpfeqop match exactly. This is actually
stronger than needed; we could loosen things by way of operator
families, but it'd require a lot more effort.
(b) The functions, if any, implementing a cast from the foreign type to
the primary opcintype are the same. For this purpose, we can consider a
binary coercion equivalent to an exact type match. When the opcintype
is polymorphic, require that the old and new foreign types match
exactly. (Since ri_triggers.c does use the executor, the stronger check
for polymorphic types is no mere future-proofing. However, no core type
exercises its necessity.)
Author: Noah Misch
Committer's note: catalog version bumped due to change of the Constraint
node. I can't actually find any way to have such a node in a stored
rule, but given that we have "out" support for them, better be safe.
2012-02-27 22:28:00 +01:00
|
|
|
COMPARE_NODE_FIELD(old_conpfeqop);
|
Avoid repeated name lookups during table and index DDL.
If the name lookups come to different conclusions due to concurrent
activity, we might perform some parts of the DDL on a different table
than other parts. At least in the case of CREATE INDEX, this can be
used to cause the permissions checks to be performed against a
different table than the index creation, allowing for a privilege
escalation attack.
This changes the calling convention for DefineIndex, CreateTrigger,
transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible
(in 9.2 and newer), and AlterTable (in 9.1 and older). In addition,
CheckRelationOwnership is removed in 9.2 and newer and the calling
convention is changed in older branches. A field has also been added
to the Constraint node (FkConstraint in 8.4). Third-party code calling
these functions or using the Constraint node will require updating.
Report by Andres Freund. Patch by Robert Haas and Andres Freund,
reviewed by Tom Lane.
Security: CVE-2014-0062
2014-02-17 15:33:31 +01:00
|
|
|
COMPARE_SCALAR_FIELD(old_pktable_oid);
|
2009-07-30 04:45:38 +02:00
|
|
|
COMPARE_SCALAR_FIELD(skip_validation);
|
2011-03-23 00:10:35 +01:00
|
|
|
COMPARE_SCALAR_FIELD(initially_valid);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalDefElem(const DefElem *a, const DefElem *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2009-04-04 23:12:31 +02:00
|
|
|
COMPARE_STRING_FIELD(defnamespace);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(defname);
|
|
|
|
COMPARE_NODE_FIELD(arg);
|
2009-04-04 23:12:31 +02:00
|
|
|
COMPARE_SCALAR_FIELD(defaction);
|
2009-02-02 20:31:40 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-08-01 22:31:16 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalLockingClause(const LockingClause *a, const LockingClause *b)
|
2005-08-01 22:31:16 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(lockedRels);
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
COMPARE_SCALAR_FIELD(strength);
|
2014-10-07 22:23:34 +02:00
|
|
|
COMPARE_SCALAR_FIELD(waitPolicy);
|
2005-08-01 22:31:16 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(rtekind);
|
|
|
|
COMPARE_SCALAR_FIELD(relid);
|
2011-02-23 01:23:23 +01:00
|
|
|
COMPARE_SCALAR_FIELD(relkind);
|
2015-05-15 20:37:10 +02:00
|
|
|
COMPARE_NODE_FIELD(tablesample);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(subquery);
|
2011-12-22 22:15:57 +01:00
|
|
|
COMPARE_SCALAR_FIELD(security_barrier);
|
2008-10-04 23:56:55 +02:00
|
|
|
COMPARE_SCALAR_FIELD(jointype);
|
|
|
|
COMPARE_NODE_FIELD(joinaliasvars);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
COMPARE_NODE_FIELD(functions);
|
2013-07-29 17:38:01 +02:00
|
|
|
COMPARE_SCALAR_FIELD(funcordinality);
|
2006-08-02 03:59:48 +02:00
|
|
|
COMPARE_NODE_FIELD(values_lists);
|
2011-04-18 21:31:52 +02:00
|
|
|
COMPARE_NODE_FIELD(values_collations);
|
2008-10-04 23:56:55 +02:00
|
|
|
COMPARE_STRING_FIELD(ctename);
|
|
|
|
COMPARE_SCALAR_FIELD(ctelevelsup);
|
|
|
|
COMPARE_SCALAR_FIELD(self_reference);
|
|
|
|
COMPARE_NODE_FIELD(ctecoltypes);
|
|
|
|
COMPARE_NODE_FIELD(ctecoltypmods);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_NODE_FIELD(ctecolcollations);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(alias);
|
|
|
|
COMPARE_NODE_FIELD(eref);
|
2012-08-08 01:02:54 +02:00
|
|
|
COMPARE_SCALAR_FIELD(lateral);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(inh);
|
|
|
|
COMPARE_SCALAR_FIELD(inFromCl);
|
2004-01-15 00:01:55 +01:00
|
|
|
COMPARE_SCALAR_FIELD(requiredPerms);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(checkAsUser);
|
2009-01-22 21:16:10 +01:00
|
|
|
COMPARE_BITMAPSET_FIELD(selectedCols);
|
2015-05-08 00:20:46 +02:00
|
|
|
COMPARE_BITMAPSET_FIELD(insertedCols);
|
|
|
|
COMPARE_BITMAPSET_FIELD(updatedCols);
|
2014-04-13 03:04:58 +02:00
|
|
|
COMPARE_NODE_FIELD(securityQuals);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
static bool
|
|
|
|
_equalRangeTblFunction(const RangeTblFunction *a, const RangeTblFunction *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(funcexpr);
|
|
|
|
COMPARE_SCALAR_FIELD(funccolcount);
|
|
|
|
COMPARE_NODE_FIELD(funccolnames);
|
|
|
|
COMPARE_NODE_FIELD(funccoltypes);
|
|
|
|
COMPARE_NODE_FIELD(funccoltypmods);
|
|
|
|
COMPARE_NODE_FIELD(funccolcollations);
|
|
|
|
COMPARE_BITMAPSET_FIELD(funcparams);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Redesign tablesample method API, and do extensive code review.
The original implementation of TABLESAMPLE modeled the tablesample method
API on index access methods, which wasn't a good choice because, without
specialized DDL commands, there's no way to build an extension that can
implement a TSM. (Raw inserts into system catalogs are not an acceptable
thing to do, because we can't undo them during DROP EXTENSION, nor will
pg_upgrade behave sanely.) Instead adopt an API more like procedural
language handlers or foreign data wrappers, wherein the only SQL-level
support object needed is a single handler function identified by having
a special return type. This lets us get rid of the supporting catalog
altogether, so that no custom DDL support is needed for the feature.
Adjust the API so that it can support non-constant tablesample arguments
(the original coding assumed we could evaluate the argument expressions at
ExecInitSampleScan time, which is undesirable even if it weren't outright
unsafe), and discourage sampling methods from looking at invisible tuples.
Make sure that the BERNOULLI and SYSTEM methods are genuinely repeatable
within and across queries, as required by the SQL standard, and deal more
honestly with methods that can't support that requirement.
Make a full code-review pass over the tablesample additions, and fix
assorted bugs, omissions, infelicities, and cosmetic issues (such as
failure to put the added code stanzas in a consistent ordering).
Improve EXPLAIN's output of tablesample plans, too.
Back-patch to 9.5 so that we don't have to support the original API
in production.
2015-07-25 20:39:00 +02:00
|
|
|
static bool
|
|
|
|
_equalTableSampleClause(const TableSampleClause *a, const TableSampleClause *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(tsmhandler);
|
|
|
|
COMPARE_NODE_FIELD(args);
|
|
|
|
COMPARE_NODE_FIELD(repeatable);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-18 23:10:16 +02:00
|
|
|
static bool
|
|
|
|
_equalWithCheckOption(const WithCheckOption *a, const WithCheckOption *b)
|
|
|
|
{
|
2015-04-25 02:34:26 +02:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
|
|
|
COMPARE_STRING_FIELD(relname);
|
2015-09-15 21:49:31 +02:00
|
|
|
COMPARE_STRING_FIELD(polname);
|
2013-07-18 23:10:16 +02:00
|
|
|
COMPARE_NODE_FIELD(qual);
|
|
|
|
COMPARE_SCALAR_FIELD(cascaded);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalSortGroupClause(const SortGroupClause *a, const SortGroupClause *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(tleSortGroupRef);
|
2008-08-02 23:32:01 +02:00
|
|
|
COMPARE_SCALAR_FIELD(eqop);
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(sortop);
|
2007-01-09 03:14:16 +01:00
|
|
|
COMPARE_SCALAR_FIELD(nulls_first);
|
2010-10-31 02:55:20 +01:00
|
|
|
COMPARE_SCALAR_FIELD(hashable);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Support GROUPING SETS, CUBE and ROLLUP.
This SQL standard functionality allows to aggregate data by different
GROUP BY clauses at once. Each grouping set returns rows with columns
grouped by in other sets set to NULL.
This could previously be achieved by doing each grouping as a separate
query, conjoined by UNION ALLs. Besides being considerably more concise,
grouping sets will in many cases be faster, requiring only one scan over
the underlying data.
The current implementation of grouping sets only supports using sorting
for input. Individual sets that share a sort order are computed in one
pass. If there are sets that don't share a sort order, additional sort &
aggregation steps are performed. These additional passes are sourced by
the previous sort step; thus avoiding repeated scans of the source data.
The code is structured in a way that adding support for purely using
hash aggregation or a mix of hashing and sorting is possible. Sorting
was chosen to be supported first, as it is the most generic method of
implementation.
Instead of, as in an earlier versions of the patch, representing the
chain of sort and aggregation steps as full blown planner and executor
nodes, all but the first sort are performed inside the aggregation node
itself. This avoids the need to do some unusual gymnastics to handle
having to return aggregated and non-aggregated tuples from underlying
nodes, as well as having to shut down underlying nodes early to limit
memory usage. The optimizer still builds Sort/Agg node to describe each
phase, but they're not part of the plan tree, but instead additional
data for the aggregation node. They're a convenient and preexisting way
to describe aggregation and sorting. The first (and possibly only) sort
step is still performed as a separate execution step. That retains
similarity with existing group by plans, makes rescans fairly simple,
avoids very deep plans (leading to slow explains) and easily allows to
avoid the sorting step if the underlying data is sorted by other means.
A somewhat ugly side of this patch is having to deal with a grammar
ambiguity between the new CUBE keyword and the cube extension/functions
named cube (and rollup). To avoid breaking existing deployments of the
cube extension it has not been renamed, neither has cube been made a
reserved keyword. Instead precedence hacking is used to make GROUP BY
cube(..) refer to the CUBE grouping sets feature, and not the function
cube(). To actually group by a function cube(), unlikely as that might
be, the function name has to be quoted.
Needs a catversion bump because stored rules may change.
Author: Andrew Gierth and Atri Sharma, with contributions from Andres Freund
Reviewed-By: Andres Freund, Noah Misch, Tom Lane, Svenne Krap, Tomas
Vondra, Erik Rijkers, Marti Raudsepp, Pavel Stehule
Discussion: CAOeZVidmVRe2jU6aMk_5qkxnB7dfmPROzM7Ur8JPW5j8Y5X-Lw@mail.gmail.com
2015-05-16 03:40:59 +02:00
|
|
|
static bool
|
|
|
|
_equalGroupingSet(const GroupingSet *a, const GroupingSet *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
|
|
|
COMPARE_NODE_FIELD(content);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-12-28 19:54:01 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalWindowClause(const WindowClause *a, const WindowClause *b)
|
2008-12-28 19:54:01 +01:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_STRING_FIELD(refname);
|
|
|
|
COMPARE_NODE_FIELD(partitionClause);
|
|
|
|
COMPARE_NODE_FIELD(orderClause);
|
2008-12-31 01:08:39 +01:00
|
|
|
COMPARE_SCALAR_FIELD(frameOptions);
|
2010-02-12 18:33:21 +01:00
|
|
|
COMPARE_NODE_FIELD(startOffset);
|
|
|
|
COMPARE_NODE_FIELD(endOffset);
|
2008-12-28 19:54:01 +01:00
|
|
|
COMPARE_SCALAR_FIELD(winref);
|
|
|
|
COMPARE_SCALAR_FIELD(copiedOrder);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-30 20:30:40 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalRowMarkClause(const RowMarkClause *a, const RowMarkClause *b)
|
2006-04-30 20:30:40 +02:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(rti);
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
COMPARE_SCALAR_FIELD(strength);
|
2014-10-07 22:23:34 +02:00
|
|
|
COMPARE_SCALAR_FIELD(waitPolicy);
|
2009-10-28 15:55:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(pushedDown);
|
2006-04-30 20:30:40 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalWithClause(const WithClause *a, const WithClause *b)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(ctes);
|
|
|
|
COMPARE_SCALAR_FIELD(recursive);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
static bool
|
|
|
|
_equalInferClause(const InferClause *a, const InferClause *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(indexElems);
|
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_STRING_FIELD(conname);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalOnConflictClause(const OnConflictClause *a, const OnConflictClause *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(action);
|
|
|
|
COMPARE_NODE_FIELD(infer);
|
|
|
|
COMPARE_NODE_FIELD(targetList);
|
|
|
|
COMPARE_NODE_FIELD(whereClause);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-10-04 23:56:55 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalCommonTableExpr(const CommonTableExpr *a, const CommonTableExpr *b)
|
2008-10-04 23:56:55 +02:00
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(ctename);
|
|
|
|
COMPARE_NODE_FIELD(aliascolnames);
|
|
|
|
COMPARE_NODE_FIELD(ctequery);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
COMPARE_SCALAR_FIELD(cterecursive);
|
|
|
|
COMPARE_SCALAR_FIELD(cterefcount);
|
|
|
|
COMPARE_NODE_FIELD(ctecolnames);
|
|
|
|
COMPARE_NODE_FIELD(ctecoltypes);
|
|
|
|
COMPARE_NODE_FIELD(ctecoltypmods);
|
2011-02-08 22:04:18 +01:00
|
|
|
COMPARE_NODE_FIELD(ctecolcollations);
|
2008-10-04 23:56:55 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-02-03 15:06:56 +01:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
|
2007-02-03 15:06:56 +01:00
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(xmloption);
|
|
|
|
COMPARE_NODE_FIELD(expr);
|
2009-07-16 08:33:46 +02:00
|
|
|
COMPARE_NODE_FIELD(typeName);
|
2008-08-29 01:09:48 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
2007-02-03 15:06:56 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2002-11-25 04:33:27 +01:00
|
|
|
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
static bool
|
|
|
|
_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(roletype);
|
|
|
|
COMPARE_STRING_FIELD(rolename);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
/*
|
|
|
|
* Stuff from pg_list.h
|
|
|
|
*/
|
2002-11-25 04:33:27 +01:00
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalList(const List *a, const List *b)
|
2004-05-26 06:41:50 +02:00
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
const ListCell *item_a;
|
|
|
|
const ListCell *item_b;
|
2004-05-26 06:41:50 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Try to reject by simple scalar checks before grovelling through all the
|
|
|
|
* list elements...
|
2004-05-26 06:41:50 +02:00
|
|
|
*/
|
|
|
|
COMPARE_SCALAR_FIELD(type);
|
|
|
|
COMPARE_SCALAR_FIELD(length);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We place the switch outside the loop for the sake of efficiency; this
|
|
|
|
* may not be worth doing...
|
2004-05-26 06:41:50 +02:00
|
|
|
*/
|
|
|
|
switch (a->type)
|
|
|
|
{
|
|
|
|
case T_List:
|
|
|
|
forboth(item_a, a, item_b, b)
|
|
|
|
{
|
|
|
|
if (!equal(lfirst(item_a), lfirst(item_b)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_IntList:
|
|
|
|
forboth(item_a, a, item_b, b)
|
|
|
|
{
|
|
|
|
if (lfirst_int(item_a) != lfirst_int(item_b))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_OidList:
|
|
|
|
forboth(item_a, a, item_b, b)
|
|
|
|
{
|
|
|
|
if (lfirst_oid(item_a) != lfirst_oid(item_b))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized list node type: %d",
|
|
|
|
(int) a->type);
|
|
|
|
return false; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we got here, we should have run out of elements of both lists
|
|
|
|
*/
|
|
|
|
Assert(item_a == NULL);
|
|
|
|
Assert(item_b == NULL);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuff from value.h
|
|
|
|
*/
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
static bool
|
2011-12-07 20:46:56 +01:00
|
|
|
_equalValue(const Value *a, const Value *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(type);
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
switch (a->type)
|
|
|
|
{
|
|
|
|
case T_Integer:
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_SCALAR_FIELD(val.ival);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_Float:
|
|
|
|
case T_String:
|
2000-10-31 11:22:13 +01:00
|
|
|
case T_BitString:
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_STRING_FIELD(val.str);
|
|
|
|
break;
|
2002-08-19 02:11:53 +02:00
|
|
|
case T_Null:
|
|
|
|
/* nothing to do */
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
default:
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d", (int) a->type);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* equal
|
|
|
|
* returns whether two nodes are equal
|
|
|
|
*/
|
|
|
|
bool
|
2011-12-07 20:46:56 +01:00
|
|
|
equal(const void *a, const void *b)
|
2000-08-12 01:45:35 +02:00
|
|
|
{
|
2003-07-23 01:30:39 +02:00
|
|
|
bool retval;
|
2000-08-12 01:45:35 +02:00
|
|
|
|
|
|
|
if (a == b)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* note that a!=b, so only one of them can be NULL
|
|
|
|
*/
|
|
|
|
if (a == NULL || b == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* are they the same type of nodes?
|
|
|
|
*/
|
|
|
|
if (nodeTag(a) != nodeTag(b))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (nodeTag(a))
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
/*
|
|
|
|
* PRIMITIVE NODES
|
|
|
|
*/
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_Alias:
|
|
|
|
retval = _equalAlias(a, b);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_RangeVar:
|
|
|
|
retval = _equalRangeVar(a, b);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
2007-02-20 18:32:18 +01:00
|
|
|
case T_IntoClause:
|
|
|
|
retval = _equalIntoClause(a, b);
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_Var:
|
|
|
|
retval = _equalVar(a, b);
|
|
|
|
break;
|
|
|
|
case T_Const:
|
|
|
|
retval = _equalConst(a, b);
|
|
|
|
break;
|
|
|
|
case T_Param:
|
|
|
|
retval = _equalParam(a, b);
|
|
|
|
break;
|
1999-06-06 19:46:40 +02:00
|
|
|
case T_Aggref:
|
|
|
|
retval = _equalAggref(a, b);
|
1999-09-26 04:28:44 +02:00
|
|
|
break;
|
Support GROUPING SETS, CUBE and ROLLUP.
This SQL standard functionality allows to aggregate data by different
GROUP BY clauses at once. Each grouping set returns rows with columns
grouped by in other sets set to NULL.
This could previously be achieved by doing each grouping as a separate
query, conjoined by UNION ALLs. Besides being considerably more concise,
grouping sets will in many cases be faster, requiring only one scan over
the underlying data.
The current implementation of grouping sets only supports using sorting
for input. Individual sets that share a sort order are computed in one
pass. If there are sets that don't share a sort order, additional sort &
aggregation steps are performed. These additional passes are sourced by
the previous sort step; thus avoiding repeated scans of the source data.
The code is structured in a way that adding support for purely using
hash aggregation or a mix of hashing and sorting is possible. Sorting
was chosen to be supported first, as it is the most generic method of
implementation.
Instead of, as in an earlier versions of the patch, representing the
chain of sort and aggregation steps as full blown planner and executor
nodes, all but the first sort are performed inside the aggregation node
itself. This avoids the need to do some unusual gymnastics to handle
having to return aggregated and non-aggregated tuples from underlying
nodes, as well as having to shut down underlying nodes early to limit
memory usage. The optimizer still builds Sort/Agg node to describe each
phase, but they're not part of the plan tree, but instead additional
data for the aggregation node. They're a convenient and preexisting way
to describe aggregation and sorting. The first (and possibly only) sort
step is still performed as a separate execution step. That retains
similarity with existing group by plans, makes rescans fairly simple,
avoids very deep plans (leading to slow explains) and easily allows to
avoid the sorting step if the underlying data is sorted by other means.
A somewhat ugly side of this patch is having to deal with a grammar
ambiguity between the new CUBE keyword and the cube extension/functions
named cube (and rollup). To avoid breaking existing deployments of the
cube extension it has not been renamed, neither has cube been made a
reserved keyword. Instead precedence hacking is used to make GROUP BY
cube(..) refer to the CUBE grouping sets feature, and not the function
cube(). To actually group by a function cube(), unlikely as that might
be, the function name has to be quoted.
Needs a catversion bump because stored rules may change.
Author: Andrew Gierth and Atri Sharma, with contributions from Andres Freund
Reviewed-By: Andres Freund, Noah Misch, Tom Lane, Svenne Krap, Tomas
Vondra, Erik Rijkers, Marti Raudsepp, Pavel Stehule
Discussion: CAOeZVidmVRe2jU6aMk_5qkxnB7dfmPROzM7Ur8JPW5j8Y5X-Lw@mail.gmail.com
2015-05-16 03:40:59 +02:00
|
|
|
case T_GroupingFunc:
|
|
|
|
retval = _equalGroupingFunc(a, b);
|
|
|
|
break;
|
2008-12-28 19:54:01 +01:00
|
|
|
case T_WindowFunc:
|
|
|
|
retval = _equalWindowFunc(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_ArrayRef:
|
|
|
|
retval = _equalArrayRef(a, b);
|
|
|
|
break;
|
|
|
|
case T_FuncExpr:
|
|
|
|
retval = _equalFuncExpr(a, b);
|
|
|
|
break;
|
2009-10-08 04:39:25 +02:00
|
|
|
case T_NamedArgExpr:
|
|
|
|
retval = _equalNamedArgExpr(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_OpExpr:
|
|
|
|
retval = _equalOpExpr(a, b);
|
|
|
|
break;
|
|
|
|
case T_DistinctExpr:
|
|
|
|
retval = _equalDistinctExpr(a, b);
|
|
|
|
break;
|
2011-03-20 01:29:08 +01:00
|
|
|
case T_NullIfExpr:
|
|
|
|
retval = _equalNullIfExpr(a, b);
|
|
|
|
break;
|
2003-06-29 02:33:44 +02:00
|
|
|
case T_ScalarArrayOpExpr:
|
|
|
|
retval = _equalScalarArrayOpExpr(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_BoolExpr:
|
|
|
|
retval = _equalBoolExpr(a, b);
|
|
|
|
break;
|
1999-09-26 04:28:44 +02:00
|
|
|
case T_SubLink:
|
|
|
|
retval = _equalSubLink(a, b);
|
1999-06-06 19:46:40 +02:00
|
|
|
break;
|
2002-12-14 01:17:59 +01:00
|
|
|
case T_SubPlan:
|
|
|
|
retval = _equalSubPlan(a, b);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
2008-08-22 02:16:04 +02:00
|
|
|
case T_AlternativeSubPlan:
|
|
|
|
retval = _equalAlternativeSubPlan(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_FieldSelect:
|
|
|
|
retval = _equalFieldSelect(a, b);
|
|
|
|
break;
|
2004-06-09 21:08:20 +02:00
|
|
|
case T_FieldStore:
|
|
|
|
retval = _equalFieldStore(a, b);
|
|
|
|
break;
|
2000-06-29 09:35:57 +02:00
|
|
|
case T_RelabelType:
|
|
|
|
retval = _equalRelabelType(a, b);
|
|
|
|
break;
|
2007-06-05 23:31:09 +02:00
|
|
|
case T_CoerceViaIO:
|
|
|
|
retval = _equalCoerceViaIO(a, b);
|
|
|
|
break;
|
2007-03-28 01:21:12 +02:00
|
|
|
case T_ArrayCoerceExpr:
|
|
|
|
retval = _equalArrayCoerceExpr(a, b);
|
|
|
|
break;
|
2004-12-12 00:26:51 +01:00
|
|
|
case T_ConvertRowtypeExpr:
|
|
|
|
retval = _equalConvertRowtypeExpr(a, b);
|
|
|
|
break;
|
2011-03-11 22:27:51 +01:00
|
|
|
case T_CollateExpr:
|
|
|
|
retval = _equalCollateExpr(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_CaseExpr:
|
|
|
|
retval = _equalCaseExpr(a, b);
|
|
|
|
break;
|
|
|
|
case T_CaseWhen:
|
|
|
|
retval = _equalCaseWhen(a, b);
|
|
|
|
break;
|
2004-03-17 21:48:43 +01:00
|
|
|
case T_CaseTestExpr:
|
|
|
|
retval = _equalCaseTestExpr(a, b);
|
|
|
|
break;
|
2003-04-09 01:20:04 +02:00
|
|
|
case T_ArrayExpr:
|
|
|
|
retval = _equalArrayExpr(a, b);
|
|
|
|
break;
|
2004-05-11 00:44:49 +02:00
|
|
|
case T_RowExpr:
|
|
|
|
retval = _equalRowExpr(a, b);
|
|
|
|
break;
|
2005-12-28 02:30:02 +01:00
|
|
|
case T_RowCompareExpr:
|
|
|
|
retval = _equalRowCompareExpr(a, b);
|
|
|
|
break;
|
2003-02-16 03:30:39 +01:00
|
|
|
case T_CoalesceExpr:
|
|
|
|
retval = _equalCoalesceExpr(a, b);
|
|
|
|
break;
|
2005-06-27 00:05:42 +02:00
|
|
|
case T_MinMaxExpr:
|
|
|
|
retval = _equalMinMaxExpr(a, b);
|
|
|
|
break;
|
2006-12-24 01:29:20 +01:00
|
|
|
case T_XmlExpr:
|
|
|
|
retval = _equalXmlExpr(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_NullTest:
|
|
|
|
retval = _equalNullTest(a, b);
|
|
|
|
break;
|
|
|
|
case T_BooleanTest:
|
|
|
|
retval = _equalBooleanTest(a, b);
|
|
|
|
break;
|
2003-02-03 22:15:45 +01:00
|
|
|
case T_CoerceToDomain:
|
|
|
|
retval = _equalCoerceToDomain(a, b);
|
2002-12-12 16:49:42 +01:00
|
|
|
break;
|
2003-02-03 22:15:45 +01:00
|
|
|
case T_CoerceToDomainValue:
|
|
|
|
retval = _equalCoerceToDomainValue(a, b);
|
2002-12-12 16:49:42 +01:00
|
|
|
break;
|
2003-07-03 18:34:26 +02:00
|
|
|
case T_SetToDefault:
|
|
|
|
retval = _equalSetToDefault(a, b);
|
|
|
|
break;
|
2007-06-11 03:16:30 +02:00
|
|
|
case T_CurrentOfExpr:
|
|
|
|
retval = _equalCurrentOfExpr(a, b);
|
|
|
|
break;
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
case T_InferenceElem:
|
|
|
|
retval = _equalInferenceElem(a, b);
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_TargetEntry:
|
|
|
|
retval = _equalTargetEntry(a, b);
|
|
|
|
break;
|
2000-09-12 23:07:18 +02:00
|
|
|
case T_RangeTblRef:
|
|
|
|
retval = _equalRangeTblRef(a, b);
|
|
|
|
break;
|
2000-09-29 20:21:41 +02:00
|
|
|
case T_FromExpr:
|
|
|
|
retval = _equalFromExpr(a, b);
|
|
|
|
break;
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
case T_OnConflictExpr:
|
|
|
|
retval = _equalOnConflictExpr(a, b);
|
|
|
|
break;
|
2000-09-12 23:07:18 +02:00
|
|
|
case T_JoinExpr:
|
|
|
|
retval = _equalJoinExpr(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
/*
|
|
|
|
* RELATION NODES
|
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
case T_PathKey:
|
|
|
|
retval = _equalPathKey(a, b);
|
1999-11-23 21:07:06 +01:00
|
|
|
break;
|
2000-06-29 09:35:57 +02:00
|
|
|
case T_RestrictInfo:
|
|
|
|
retval = _equalRestrictInfo(a, b);
|
1998-02-13 04:27:47 +01:00
|
|
|
break;
|
2008-10-21 22:42:53 +02:00
|
|
|
case T_PlaceHolderVar:
|
|
|
|
retval = _equalPlaceHolderVar(a, b);
|
|
|
|
break;
|
2008-08-14 20:48:00 +02:00
|
|
|
case T_SpecialJoinInfo:
|
|
|
|
retval = _equalSpecialJoinInfo(a, b);
|
2003-01-20 19:55:07 +01:00
|
|
|
break;
|
2012-08-27 04:48:55 +02:00
|
|
|
case T_LateralJoinInfo:
|
|
|
|
retval = _equalLateralJoinInfo(a, b);
|
|
|
|
break;
|
2006-01-31 22:39:25 +01:00
|
|
|
case T_AppendRelInfo:
|
|
|
|
retval = _equalAppendRelInfo(a, b);
|
|
|
|
break;
|
2008-10-21 22:42:53 +02:00
|
|
|
case T_PlaceHolderInfo:
|
|
|
|
retval = _equalPlaceHolderInfo(a, b);
|
|
|
|
break;
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
case T_List:
|
2004-05-26 06:41:50 +02:00
|
|
|
case T_IntList:
|
|
|
|
case T_OidList:
|
|
|
|
retval = _equalList(a, b);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
2002-08-19 02:11:53 +02:00
|
|
|
|
2000-06-29 09:35:57 +02:00
|
|
|
case T_Integer:
|
|
|
|
case T_Float:
|
|
|
|
case T_String:
|
2000-10-31 11:22:13 +01:00
|
|
|
case T_BitString:
|
2002-08-19 02:11:53 +02:00
|
|
|
case T_Null:
|
2000-06-29 09:35:57 +02:00
|
|
|
retval = _equalValue(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
/*
|
|
|
|
* PARSE NODES
|
|
|
|
*/
|
1999-02-07 01:52:12 +01:00
|
|
|
case T_Query:
|
|
|
|
retval = _equalQuery(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_InsertStmt:
|
|
|
|
retval = _equalInsertStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DeleteStmt:
|
|
|
|
retval = _equalDeleteStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_UpdateStmt:
|
|
|
|
retval = _equalUpdateStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_SelectStmt:
|
|
|
|
retval = _equalSelectStmt(a, b);
|
|
|
|
break;
|
2000-10-05 21:11:39 +02:00
|
|
|
case T_SetOperationStmt:
|
|
|
|
retval = _equalSetOperationStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_AlterTableStmt:
|
|
|
|
retval = _equalAlterTableStmt(a, b);
|
|
|
|
break;
|
2004-05-05 06:48:48 +02:00
|
|
|
case T_AlterTableCmd:
|
|
|
|
retval = _equalAlterTableCmd(a, b);
|
|
|
|
break;
|
2002-12-06 06:00:34 +01:00
|
|
|
case T_AlterDomainStmt:
|
|
|
|
retval = _equalAlterDomainStmt(a, b);
|
|
|
|
break;
|
2001-06-10 01:21:55 +02:00
|
|
|
case T_GrantStmt:
|
|
|
|
retval = _equalGrantStmt(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
2005-06-28 07:09:14 +02:00
|
|
|
case T_GrantRoleStmt:
|
|
|
|
retval = _equalGrantRoleStmt(a, b);
|
|
|
|
break;
|
2009-10-05 21:24:49 +02:00
|
|
|
case T_AlterDefaultPrivilegesStmt:
|
|
|
|
retval = _equalAlterDefaultPrivilegesStmt(a, b);
|
|
|
|
break;
|
2003-03-10 04:53:52 +01:00
|
|
|
case T_DeclareCursorStmt:
|
|
|
|
retval = _equalDeclareCursorStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_ClosePortalStmt:
|
|
|
|
retval = _equalClosePortalStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ClusterStmt:
|
|
|
|
retval = _equalClusterStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CopyStmt:
|
|
|
|
retval = _equalCopyStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateStmt:
|
|
|
|
retval = _equalCreateStmt(a, b);
|
|
|
|
break;
|
2012-01-07 13:58:13 +01:00
|
|
|
case T_TableLikeClause:
|
|
|
|
retval = _equalTableLikeClause(a, b);
|
2003-06-25 05:40:19 +02:00
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_DefineStmt:
|
|
|
|
retval = _equalDefineStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DropStmt:
|
|
|
|
retval = _equalDropStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_TruncateStmt:
|
|
|
|
retval = _equalTruncateStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CommentStmt:
|
|
|
|
retval = _equalCommentStmt(a, b);
|
|
|
|
break;
|
2010-09-28 02:55:27 +02:00
|
|
|
case T_SecLabelStmt:
|
|
|
|
retval = _equalSecLabelStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_FetchStmt:
|
|
|
|
retval = _equalFetchStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_IndexStmt:
|
|
|
|
retval = _equalIndexStmt(a, b);
|
|
|
|
break;
|
2002-05-17 20:32:52 +02:00
|
|
|
case T_CreateFunctionStmt:
|
|
|
|
retval = _equalCreateFunctionStmt(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
2004-01-07 00:55:19 +01:00
|
|
|
case T_FunctionParameter:
|
|
|
|
retval = _equalFunctionParameter(a, b);
|
|
|
|
break;
|
2005-03-14 01:19:37 +01:00
|
|
|
case T_AlterFunctionStmt:
|
|
|
|
retval = _equalAlterFunctionStmt(a, b);
|
|
|
|
break;
|
2009-09-23 01:43:43 +02:00
|
|
|
case T_DoStmt:
|
|
|
|
retval = _equalDoStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_RenameStmt:
|
|
|
|
retval = _equalRenameStmt(a, b);
|
|
|
|
break;
|
2005-08-01 06:03:59 +02:00
|
|
|
case T_AlterObjectSchemaStmt:
|
|
|
|
retval = _equalAlterObjectSchemaStmt(a, b);
|
|
|
|
break;
|
2004-06-25 23:55:59 +02:00
|
|
|
case T_AlterOwnerStmt:
|
|
|
|
retval = _equalAlterOwnerStmt(a, b);
|
|
|
|
break;
|
2015-07-14 17:17:55 +02:00
|
|
|
case T_AlterOperatorStmt:
|
|
|
|
retval = _equalAlterOperatorStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_RuleStmt:
|
|
|
|
retval = _equalRuleStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_NotifyStmt:
|
|
|
|
retval = _equalNotifyStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ListenStmt:
|
|
|
|
retval = _equalListenStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_UnlistenStmt:
|
|
|
|
retval = _equalUnlistenStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_TransactionStmt:
|
|
|
|
retval = _equalTransactionStmt(a, b);
|
|
|
|
break;
|
2002-08-15 18:36:08 +02:00
|
|
|
case T_CompositeTypeStmt:
|
|
|
|
retval = _equalCompositeTypeStmt(a, b);
|
|
|
|
break;
|
2007-04-02 05:49:42 +02:00
|
|
|
case T_CreateEnumStmt:
|
|
|
|
retval = _equalCreateEnumStmt(a, b);
|
|
|
|
break;
|
2011-11-03 12:16:28 +01:00
|
|
|
case T_CreateRangeStmt:
|
|
|
|
retval = _equalCreateRangeStmt(a, b);
|
|
|
|
break;
|
2010-10-25 05:04:37 +02:00
|
|
|
case T_AlterEnumStmt:
|
|
|
|
retval = _equalAlterEnumStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_ViewStmt:
|
|
|
|
retval = _equalViewStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_LoadStmt:
|
|
|
|
retval = _equalLoadStmt(a, b);
|
|
|
|
break;
|
2002-03-19 03:18:25 +01:00
|
|
|
case T_CreateDomainStmt:
|
|
|
|
retval = _equalCreateDomainStmt(a, b);
|
|
|
|
break;
|
2002-07-30 00:14:11 +02:00
|
|
|
case T_CreateOpClassStmt:
|
|
|
|
retval = _equalCreateOpClassStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateOpClassItem:
|
|
|
|
retval = _equalCreateOpClassItem(a, b);
|
|
|
|
break;
|
2007-01-23 06:07:18 +01:00
|
|
|
case T_CreateOpFamilyStmt:
|
|
|
|
retval = _equalCreateOpFamilyStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterOpFamilyStmt:
|
|
|
|
retval = _equalAlterOpFamilyStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_CreatedbStmt:
|
|
|
|
retval = _equalCreatedbStmt(a, b);
|
|
|
|
break;
|
2005-07-31 19:19:22 +02:00
|
|
|
case T_AlterDatabaseStmt:
|
|
|
|
retval = _equalAlterDatabaseStmt(a, b);
|
|
|
|
break;
|
2002-03-01 23:45:19 +01:00
|
|
|
case T_AlterDatabaseSetStmt:
|
|
|
|
retval = _equalAlterDatabaseSetStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_DropdbStmt:
|
|
|
|
retval = _equalDropdbStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_VacuumStmt:
|
|
|
|
retval = _equalVacuumStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ExplainStmt:
|
|
|
|
retval = _equalExplainStmt(a, b);
|
|
|
|
break;
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
case T_CreateTableAsStmt:
|
|
|
|
retval = _equalCreateTableAsStmt(a, b);
|
|
|
|
break;
|
2013-03-04 01:23:31 +01:00
|
|
|
case T_RefreshMatViewStmt:
|
|
|
|
retval = _equalRefreshMatViewStmt(a, b);
|
|
|
|
break;
|
2013-11-08 18:30:43 +01:00
|
|
|
case T_ReplicaIdentityStmt:
|
|
|
|
retval = _equalReplicaIdentityStmt(a, b);
|
|
|
|
break;
|
2013-12-18 15:42:44 +01:00
|
|
|
case T_AlterSystemStmt:
|
|
|
|
retval = _equalAlterSystemStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_CreateSeqStmt:
|
|
|
|
retval = _equalCreateSeqStmt(a, b);
|
|
|
|
break;
|
2003-03-20 08:02:11 +01:00
|
|
|
case T_AlterSeqStmt:
|
|
|
|
retval = _equalAlterSeqStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_VariableSetStmt:
|
|
|
|
retval = _equalVariableSetStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_VariableShowStmt:
|
|
|
|
retval = _equalVariableShowStmt(a, b);
|
|
|
|
break;
|
2007-04-26 18:13:15 +02:00
|
|
|
case T_DiscardStmt:
|
|
|
|
retval = _equalDiscardStmt(a, b);
|
|
|
|
break;
|
2004-06-18 08:14:31 +02:00
|
|
|
case T_CreateTableSpaceStmt:
|
|
|
|
retval = _equalCreateTableSpaceStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DropTableSpaceStmt:
|
|
|
|
retval = _equalDropTableSpaceStmt(a, b);
|
|
|
|
break;
|
2010-01-05 22:54:00 +01:00
|
|
|
case T_AlterTableSpaceOptionsStmt:
|
|
|
|
retval = _equalAlterTableSpaceOptionsStmt(a, b);
|
|
|
|
break;
|
2014-08-22 01:06:17 +02:00
|
|
|
case T_AlterTableMoveAllStmt:
|
|
|
|
retval = _equalAlterTableMoveAllStmt(a, b);
|
2014-01-19 00:56:40 +01:00
|
|
|
break;
|
2011-02-08 22:08:41 +01:00
|
|
|
case T_CreateExtensionStmt:
|
|
|
|
retval = _equalCreateExtensionStmt(a, b);
|
|
|
|
break;
|
2011-02-12 03:25:20 +01:00
|
|
|
case T_AlterExtensionStmt:
|
|
|
|
retval = _equalAlterExtensionStmt(a, b);
|
|
|
|
break;
|
2011-02-10 23:36:44 +01:00
|
|
|
case T_AlterExtensionContentsStmt:
|
|
|
|
retval = _equalAlterExtensionContentsStmt(a, b);
|
2011-02-09 17:55:32 +01:00
|
|
|
break;
|
2008-12-19 17:25:19 +01:00
|
|
|
case T_CreateFdwStmt:
|
|
|
|
retval = _equalCreateFdwStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterFdwStmt:
|
|
|
|
retval = _equalAlterFdwStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateForeignServerStmt:
|
|
|
|
retval = _equalCreateForeignServerStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterForeignServerStmt:
|
|
|
|
retval = _equalAlterForeignServerStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateUserMappingStmt:
|
|
|
|
retval = _equalCreateUserMappingStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterUserMappingStmt:
|
|
|
|
retval = _equalAlterUserMappingStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DropUserMappingStmt:
|
|
|
|
retval = _equalDropUserMappingStmt(a, b);
|
|
|
|
break;
|
2011-01-02 05:48:11 +01:00
|
|
|
case T_CreateForeignTableStmt:
|
|
|
|
retval = _equalCreateForeignTableStmt(a, b);
|
|
|
|
break;
|
2014-07-10 21:01:31 +02:00
|
|
|
case T_ImportForeignSchemaStmt:
|
|
|
|
retval = _equalImportForeignSchemaStmt(a, b);
|
|
|
|
break;
|
2015-04-26 16:33:14 +02:00
|
|
|
case T_CreateTransformStmt:
|
|
|
|
retval = _equalCreateTransformStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_CreateTrigStmt:
|
|
|
|
retval = _equalCreateTrigStmt(a, b);
|
|
|
|
break;
|
2012-07-18 16:16:16 +02:00
|
|
|
case T_CreateEventTrigStmt:
|
|
|
|
retval = _equalCreateEventTrigStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterEventTrigStmt:
|
|
|
|
retval = _equalAlterEventTrigStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_CreatePLangStmt:
|
|
|
|
retval = _equalCreatePLangStmt(a, b);
|
|
|
|
break;
|
2005-06-28 07:09:14 +02:00
|
|
|
case T_CreateRoleStmt:
|
|
|
|
retval = _equalCreateRoleStmt(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
2005-06-28 07:09:14 +02:00
|
|
|
case T_AlterRoleStmt:
|
|
|
|
retval = _equalAlterRoleStmt(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
2005-06-28 07:09:14 +02:00
|
|
|
case T_AlterRoleSetStmt:
|
|
|
|
retval = _equalAlterRoleSetStmt(a, b);
|
2002-03-01 23:45:19 +01:00
|
|
|
break;
|
2005-06-28 07:09:14 +02:00
|
|
|
case T_DropRoleStmt:
|
|
|
|
retval = _equalDropRoleStmt(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
|
|
|
case T_LockStmt:
|
|
|
|
retval = _equalLockStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ConstraintsSetStmt:
|
|
|
|
retval = _equalConstraintsSetStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ReindexStmt:
|
|
|
|
retval = _equalReindexStmt(a, b);
|
|
|
|
break;
|
2000-11-05 23:50:21 +01:00
|
|
|
case T_CheckPointStmt:
|
|
|
|
retval = true;
|
|
|
|
break;
|
2002-03-21 17:02:16 +01:00
|
|
|
case T_CreateSchemaStmt:
|
|
|
|
retval = _equalCreateSchemaStmt(a, b);
|
|
|
|
break;
|
2002-08-19 02:11:53 +02:00
|
|
|
case T_CreateConversionStmt:
|
|
|
|
retval = _equalCreateConversionStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateCastStmt:
|
|
|
|
retval = _equalCreateCastStmt(a, b);
|
|
|
|
break;
|
2002-08-27 06:55:12 +02:00
|
|
|
case T_PrepareStmt:
|
|
|
|
retval = _equalPrepareStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ExecuteStmt:
|
|
|
|
retval = _equalExecuteStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DeallocateStmt:
|
|
|
|
retval = _equalDeallocateStmt(a, b);
|
|
|
|
break;
|
2005-11-21 13:49:33 +01:00
|
|
|
case T_DropOwnedStmt:
|
|
|
|
retval = _equalDropOwnedStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_ReassignOwnedStmt:
|
|
|
|
retval = _equalReassignOwnedStmt(a, b);
|
|
|
|
break;
|
2008-02-07 21:19:47 +01:00
|
|
|
case T_AlterTSDictionaryStmt:
|
|
|
|
retval = _equalAlterTSDictionaryStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterTSConfigurationStmt:
|
|
|
|
retval = _equalAlterTSConfigurationStmt(a, b);
|
|
|
|
break;
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
case T_CreatePolicyStmt:
|
|
|
|
retval = _equalCreatePolicyStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterPolicyStmt:
|
|
|
|
retval = _equalAlterPolicyStmt(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_A_Expr:
|
|
|
|
retval = _equalAExpr(a, b);
|
|
|
|
break;
|
2002-03-21 17:02:16 +01:00
|
|
|
case T_ColumnRef:
|
|
|
|
retval = _equalColumnRef(a, b);
|
|
|
|
break;
|
|
|
|
case T_ParamRef:
|
|
|
|
retval = _equalParamRef(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
|
|
|
case T_A_Const:
|
|
|
|
retval = _equalAConst(a, b);
|
|
|
|
break;
|
|
|
|
case T_FuncCall:
|
|
|
|
retval = _equalFuncCall(a, b);
|
|
|
|
break;
|
2008-08-30 03:39:14 +02:00
|
|
|
case T_A_Star:
|
|
|
|
retval = _equalAStar(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_A_Indices:
|
|
|
|
retval = _equalAIndices(a, b);
|
|
|
|
break;
|
2004-06-09 21:08:20 +02:00
|
|
|
case T_A_Indirection:
|
|
|
|
retval = _equalA_Indirection(a, b);
|
2002-03-21 17:02:16 +01:00
|
|
|
break;
|
2008-03-20 22:42:48 +01:00
|
|
|
case T_A_ArrayExpr:
|
|
|
|
retval = _equalA_ArrayExpr(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_ResTarget:
|
|
|
|
retval = _equalResTarget(a, b);
|
|
|
|
break;
|
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 T_MultiAssignRef:
|
|
|
|
retval = _equalMultiAssignRef(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_TypeCast:
|
|
|
|
retval = _equalTypeCast(a, b);
|
|
|
|
break;
|
2011-02-08 22:04:18 +01:00
|
|
|
case T_CollateClause:
|
|
|
|
retval = _equalCollateClause(a, b);
|
|
|
|
break;
|
2003-08-17 21:58:06 +02:00
|
|
|
case T_SortBy:
|
|
|
|
retval = _equalSortBy(a, b);
|
2000-08-12 01:45:35 +02:00
|
|
|
break;
|
2008-12-28 19:54:01 +01:00
|
|
|
case T_WindowDef:
|
|
|
|
retval = _equalWindowDef(a, b);
|
|
|
|
break;
|
2000-09-12 23:07:18 +02:00
|
|
|
case T_RangeSubselect:
|
|
|
|
retval = _equalRangeSubselect(a, b);
|
|
|
|
break;
|
2002-05-12 22:10:05 +02:00
|
|
|
case T_RangeFunction:
|
|
|
|
retval = _equalRangeFunction(a, b);
|
|
|
|
break;
|
Redesign tablesample method API, and do extensive code review.
The original implementation of TABLESAMPLE modeled the tablesample method
API on index access methods, which wasn't a good choice because, without
specialized DDL commands, there's no way to build an extension that can
implement a TSM. (Raw inserts into system catalogs are not an acceptable
thing to do, because we can't undo them during DROP EXTENSION, nor will
pg_upgrade behave sanely.) Instead adopt an API more like procedural
language handlers or foreign data wrappers, wherein the only SQL-level
support object needed is a single handler function identified by having
a special return type. This lets us get rid of the supporting catalog
altogether, so that no custom DDL support is needed for the feature.
Adjust the API so that it can support non-constant tablesample arguments
(the original coding assumed we could evaluate the argument expressions at
ExecInitSampleScan time, which is undesirable even if it weren't outright
unsafe), and discourage sampling methods from looking at invisible tuples.
Make sure that the BERNOULLI and SYSTEM methods are genuinely repeatable
within and across queries, as required by the SQL standard, and deal more
honestly with methods that can't support that requirement.
Make a full code-review pass over the tablesample additions, and fix
assorted bugs, omissions, infelicities, and cosmetic issues (such as
failure to put the added code stanzas in a consistent ordering).
Improve EXPLAIN's output of tablesample plans, too.
Back-patch to 9.5 so that we don't have to support the original API
in production.
2015-07-25 20:39:00 +02:00
|
|
|
case T_RangeTableSample:
|
|
|
|
retval = _equalRangeTableSample(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
case T_TypeName:
|
|
|
|
retval = _equalTypeName(a, b);
|
|
|
|
break;
|
|
|
|
case T_IndexElem:
|
|
|
|
retval = _equalIndexElem(a, b);
|
|
|
|
break;
|
|
|
|
case T_ColumnDef:
|
|
|
|
retval = _equalColumnDef(a, b);
|
|
|
|
break;
|
|
|
|
case T_Constraint:
|
|
|
|
retval = _equalConstraint(a, b);
|
|
|
|
break;
|
|
|
|
case T_DefElem:
|
|
|
|
retval = _equalDefElem(a, b);
|
|
|
|
break;
|
2005-08-01 22:31:16 +02:00
|
|
|
case T_LockingClause:
|
|
|
|
retval = _equalLockingClause(a, b);
|
|
|
|
break;
|
1999-02-07 01:52:12 +01:00
|
|
|
case T_RangeTblEntry:
|
|
|
|
retval = _equalRangeTblEntry(a, b);
|
|
|
|
break;
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
case T_RangeTblFunction:
|
|
|
|
retval = _equalRangeTblFunction(a, b);
|
|
|
|
break;
|
Redesign tablesample method API, and do extensive code review.
The original implementation of TABLESAMPLE modeled the tablesample method
API on index access methods, which wasn't a good choice because, without
specialized DDL commands, there's no way to build an extension that can
implement a TSM. (Raw inserts into system catalogs are not an acceptable
thing to do, because we can't undo them during DROP EXTENSION, nor will
pg_upgrade behave sanely.) Instead adopt an API more like procedural
language handlers or foreign data wrappers, wherein the only SQL-level
support object needed is a single handler function identified by having
a special return type. This lets us get rid of the supporting catalog
altogether, so that no custom DDL support is needed for the feature.
Adjust the API so that it can support non-constant tablesample arguments
(the original coding assumed we could evaluate the argument expressions at
ExecInitSampleScan time, which is undesirable even if it weren't outright
unsafe), and discourage sampling methods from looking at invisible tuples.
Make sure that the BERNOULLI and SYSTEM methods are genuinely repeatable
within and across queries, as required by the SQL standard, and deal more
honestly with methods that can't support that requirement.
Make a full code-review pass over the tablesample additions, and fix
assorted bugs, omissions, infelicities, and cosmetic issues (such as
failure to put the added code stanzas in a consistent ordering).
Improve EXPLAIN's output of tablesample plans, too.
Back-patch to 9.5 so that we don't have to support the original API
in production.
2015-07-25 20:39:00 +02:00
|
|
|
case T_TableSampleClause:
|
|
|
|
retval = _equalTableSampleClause(a, b);
|
|
|
|
break;
|
2013-07-18 23:10:16 +02:00
|
|
|
case T_WithCheckOption:
|
|
|
|
retval = _equalWithCheckOption(a, b);
|
|
|
|
break;
|
2008-08-02 23:32:01 +02:00
|
|
|
case T_SortGroupClause:
|
|
|
|
retval = _equalSortGroupClause(a, b);
|
2000-01-31 02:21:39 +01:00
|
|
|
break;
|
Support GROUPING SETS, CUBE and ROLLUP.
This SQL standard functionality allows to aggregate data by different
GROUP BY clauses at once. Each grouping set returns rows with columns
grouped by in other sets set to NULL.
This could previously be achieved by doing each grouping as a separate
query, conjoined by UNION ALLs. Besides being considerably more concise,
grouping sets will in many cases be faster, requiring only one scan over
the underlying data.
The current implementation of grouping sets only supports using sorting
for input. Individual sets that share a sort order are computed in one
pass. If there are sets that don't share a sort order, additional sort &
aggregation steps are performed. These additional passes are sourced by
the previous sort step; thus avoiding repeated scans of the source data.
The code is structured in a way that adding support for purely using
hash aggregation or a mix of hashing and sorting is possible. Sorting
was chosen to be supported first, as it is the most generic method of
implementation.
Instead of, as in an earlier versions of the patch, representing the
chain of sort and aggregation steps as full blown planner and executor
nodes, all but the first sort are performed inside the aggregation node
itself. This avoids the need to do some unusual gymnastics to handle
having to return aggregated and non-aggregated tuples from underlying
nodes, as well as having to shut down underlying nodes early to limit
memory usage. The optimizer still builds Sort/Agg node to describe each
phase, but they're not part of the plan tree, but instead additional
data for the aggregation node. They're a convenient and preexisting way
to describe aggregation and sorting. The first (and possibly only) sort
step is still performed as a separate execution step. That retains
similarity with existing group by plans, makes rescans fairly simple,
avoids very deep plans (leading to slow explains) and easily allows to
avoid the sorting step if the underlying data is sorted by other means.
A somewhat ugly side of this patch is having to deal with a grammar
ambiguity between the new CUBE keyword and the cube extension/functions
named cube (and rollup). To avoid breaking existing deployments of the
cube extension it has not been renamed, neither has cube been made a
reserved keyword. Instead precedence hacking is used to make GROUP BY
cube(..) refer to the CUBE grouping sets feature, and not the function
cube(). To actually group by a function cube(), unlikely as that might
be, the function name has to be quoted.
Needs a catversion bump because stored rules may change.
Author: Andrew Gierth and Atri Sharma, with contributions from Andres Freund
Reviewed-By: Andres Freund, Noah Misch, Tom Lane, Svenne Krap, Tomas
Vondra, Erik Rijkers, Marti Raudsepp, Pavel Stehule
Discussion: CAOeZVidmVRe2jU6aMk_5qkxnB7dfmPROzM7Ur8JPW5j8Y5X-Lw@mail.gmail.com
2015-05-16 03:40:59 +02:00
|
|
|
case T_GroupingSet:
|
|
|
|
retval = _equalGroupingSet(a, b);
|
|
|
|
break;
|
2008-12-28 19:54:01 +01:00
|
|
|
case T_WindowClause:
|
|
|
|
retval = _equalWindowClause(a, b);
|
|
|
|
break;
|
2006-04-30 20:30:40 +02:00
|
|
|
case T_RowMarkClause:
|
|
|
|
retval = _equalRowMarkClause(a, b);
|
|
|
|
break;
|
2008-10-04 23:56:55 +02:00
|
|
|
case T_WithClause:
|
|
|
|
retval = _equalWithClause(a, b);
|
|
|
|
break;
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
case T_InferClause:
|
|
|
|
retval = _equalInferClause(a, b);
|
|
|
|
break;
|
|
|
|
case T_OnConflictClause:
|
|
|
|
retval = _equalOnConflictClause(a, b);
|
|
|
|
break;
|
2008-10-04 23:56:55 +02:00
|
|
|
case T_CommonTableExpr:
|
|
|
|
retval = _equalCommonTableExpr(a, b);
|
|
|
|
break;
|
2002-02-19 00:11:58 +01:00
|
|
|
case T_FuncWithArgs:
|
|
|
|
retval = _equalFuncWithArgs(a, b);
|
|
|
|
break;
|
2009-01-22 21:16:10 +01:00
|
|
|
case T_AccessPriv:
|
|
|
|
retval = _equalAccessPriv(a, b);
|
|
|
|
break;
|
2007-02-03 15:06:56 +01:00
|
|
|
case T_XmlSerialize:
|
|
|
|
retval = _equalXmlSerialize(a, b);
|
|
|
|
break;
|
Allow CURRENT/SESSION_USER to be used in certain commands
Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.
This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".
The special role specifiers PUBLIC and NONE also have more consistent
handling now.
Also take the opportunity to add location tracking to user specifiers.
Authors: Kyotaro Horiguchi. Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
2015-03-09 19:41:54 +01:00
|
|
|
case T_RoleSpec:
|
|
|
|
retval = _equalRoleSpec(a, b);
|
|
|
|
break;
|
2000-06-29 09:35:57 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(a));
|
|
|
|
retval = false; /* keep compiler quiet */
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
return retval;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|