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
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
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"
|
|
|
|
|
Introduce extensible node types.
An extensible node is always tagged T_Extensible, but the extnodename
field identifies it more specifically; it may also include arbitrary
private data. Extensible nodes can be copied, tested for equality,
serialized, and deserialized, but the core system doesn't know
anything about them otherwise. Some extensions may find it useful to
include these nodes in fdw_private or custom_private lists in lieu of
arm-wrestling their data into a format that the core code can
understand.
Along the way, so as not to burden the authors of such extensible
node types too much, expose the functions for writing serialized
tokens, and for serializing and deserializing bitmapsets.
KaiGai Kohei, per a design suggested by me. Reviewed by Andres Freund
and by me, and further edited by me.
2016-02-12 15:31:16 +01:00
|
|
|
#include "nodes/extensible.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);
|
2016-12-23 19:35:11 +01:00
|
|
|
COMPARE_SCALAR_FIELD(inh);
|
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
|
|
|
}
|
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
static bool
|
|
|
|
_equalTableFunc(const TableFunc *a, const TableFunc *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(ns_uris);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(ns_names);
|
2017-03-08 16:39:37 +01:00
|
|
|
COMPARE_NODE_FIELD(docexpr);
|
|
|
|
COMPARE_NODE_FIELD(rowexpr);
|
|
|
|
COMPARE_NODE_FIELD(colnames);
|
|
|
|
COMPARE_NODE_FIELD(coltypes);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(coltypmods);
|
2017-03-08 16:39:37 +01:00
|
|
|
COMPARE_NODE_FIELD(colcollations);
|
|
|
|
COMPARE_NODE_FIELD(colexprs);
|
|
|
|
COMPARE_NODE_FIELD(coldefexprs);
|
|
|
|
COMPARE_BITMAPSET_FIELD(notnulls);
|
|
|
|
COMPARE_SCALAR_FIELD(ordinalitycol);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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);
|
Fix handling of argument and result datatypes for partial aggregation.
When doing partial aggregation, the args list of the upper (combining)
Aggref node is replaced by a Var representing the output of the partial
aggregation steps, which has either the aggregate's transition data type
or a serialized representation of that. However, nodeAgg.c blindly
continued to use the args list as an indication of the user-level argument
types. This broke resolution of polymorphic transition datatypes at
executor startup (though it accidentally failed to fail for the ANYARRAY
case, which is likely the only one anyone had tested). Moreover, the
constructed FuncExpr passed to the finalfunc contained completely wrong
information, which would have led to bogus answers or crashes for any case
where the finalfunc examined that information (which is only likely to be
with polymorphic aggregates using a non-polymorphic transition type).
As an independent bug, apply_partialaggref_adjustment neglected to resolve
a polymorphic transition datatype before assigning it as the output type
of the lower-level Aggref node. This again accidentally failed to fail
for ANYARRAY but would be unlikely to work in other cases.
To fix the first problem, record the user-level argument types in a
separate OID-list field of Aggref, and look to that rather than the args
list when asking what the argument types were. (It turns out to be
convenient to include any "direct" arguments in this list too, although
those are not currently subject to being overwritten.)
Rather than adding yet another resolve_aggregate_transtype() call to fix
the second problem, add an aggtranstype field to Aggref, and store the
resolved transition type OID there when the planner first computes it.
(By doing this in the planner and not the parser, we can allow the
aggregate's transition type to change from time to time, although no DDL
support yet exists for that.) This saves nothing of consequence for
simple non-polymorphic aggregates, but for polymorphic transition types
we save a catalog lookup during executor startup as well as several
planner lookups that are new in 9.6 due to parallel query planning.
In passing, fix an error that was introduced into count_agg_clauses_walker
some time ago: it was applying exprTypmod() to something that wasn't an
expression node at all, but a TargetEntry. exprTypmod silently returned
-1 so that there was not an obvious failure, but this broke the intended
sensitivity of aggregate space consumption estimates to the typmod of
varchar and similar data types. This part needs to be back-patched.
Catversion bump due to change of stored Aggref nodes.
Discussion: <8229.1466109074@sss.pgh.pa.us>
2016-06-18 03:44:37 +02:00
|
|
|
/* ignore aggtranstype since it might not be set yet */
|
|
|
|
COMPARE_NODE_FIELD(aggargtypes);
|
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);
|
2016-06-26 20:33:38 +02:00
|
|
|
COMPARE_SCALAR_FIELD(aggsplit);
|
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);
|
2017-02-15 00:09:47 +01:00
|
|
|
COMPARE_SCALAR_FIELD(parallel_safe);
|
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);
|
Support arrays over domains.
Allowing arrays with a domain type as their element type was left un-done
in the original domain patch, but not for any very good reason. This
omission leads to such surprising results as array_agg() not working on
a domain column, because the parser can't identify a suitable output type
for the polymorphic aggregate.
In order to fix this, first clean up the APIs of coerce_to_domain() and
some internal functions in parse_coerce.c so that we consistently pass
around a CoercionContext along with CoercionForm. Previously, we sometimes
passed an "isExplicit" boolean flag instead, which is strictly less
information; and coerce_to_domain() didn't even get that, but instead had
to reverse-engineer isExplicit from CoercionForm. That's contrary to the
documentation in primnodes.h that says that CoercionForm only affects
display and not semantics. I don't think this change fixes any live bugs,
but it makes things more consistent. The main reason for doing it though
is that now build_coercion_expression() receives ccontext, which it needs
in order to be able to recursively invoke coerce_to_target_type().
Next, reimplement ArrayCoerceExpr so that the node does not directly know
any details of what has to be done to the individual array elements while
performing the array coercion. Instead, the per-element processing is
represented by a sub-expression whose input is a source array element and
whose output is a target array element. This simplifies life in
parse_coerce.c, because it can build that sub-expression by a recursive
invocation of coerce_to_target_type(). The executor now handles the
per-element processing as a compiled expression instead of hard-wired code.
The main advantage of this is that we can use a single ArrayCoerceExpr to
handle as many as three successive steps per element: base type conversion,
typmod coercion, and domain constraint checking. The old code used two
stacked ArrayCoerceExprs to handle type + typmod coercion, which was pretty
inefficient, and adding yet another array deconstruction to do domain
constraint checking seemed very unappetizing.
In the case where we just need a single, very simple coercion function,
doing this straightforwardly leads to a noticeable increase in the
per-array-element runtime cost. Hence, add an additional shortcut evalfunc
in execExprInterp.c that skips unnecessary overhead for that specific form
of expression. The runtime speed of simple cases is within 1% or so of
where it was before, while cases that previously required two levels of
array processing are significantly faster.
Finally, create an implicit array type for every domain type, as we do for
base types, enums, etc. Everything except the array-coercion case seems
to just work without further effort.
Tom Lane, reviewed by Andrew Dunstan
Discussion: https://postgr.es/m/9852.1499791473@sss.pgh.pa.us
2017-09-30 19:40:56 +02:00
|
|
|
COMPARE_NODE_FIELD(elemexpr);
|
2007-03-28 01:21:12 +02: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(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;
|
|
|
|
}
|
|
|
|
|
2016-08-17 02:33:01 +02:00
|
|
|
static bool
|
|
|
|
_equalSQLValueFunction(const SQLValueFunction *a, const SQLValueFunction *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(op);
|
|
|
|
COMPARE_SCALAR_FIELD(type);
|
|
|
|
COMPARE_SCALAR_FIELD(typmod);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
static bool
|
|
|
|
_equalNextValueExpr(const NextValueExpr *a, const NextValueExpr *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(seqid);
|
|
|
|
COMPARE_SCALAR_FIELD(typeId);
|
|
|
|
|
|
|
|
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);
|
Improve RLS planning by marking individual quals with security levels.
In an RLS query, we must ensure that security filter quals are evaluated
before ordinary query quals, in case the latter contain "leaky" functions
that could expose the contents of sensitive rows. The original
implementation of RLS planning ensured this by pushing the scan of a
secured table into a sub-query that it marked as a security-barrier view.
Unfortunately this results in very inefficient plans in many cases, because
the sub-query cannot be flattened and gets planned independently of the
rest of the query.
To fix, drop the use of sub-queries to enforce RLS qual order, and instead
mark each qual (RestrictInfo) with a security_level field establishing its
priority for evaluation. Quals must be evaluated in security_level order,
except that "leakproof" quals can be allowed to go ahead of quals of lower
security_level, if it's helpful to do so. This has to be enforced within
the ordering of any one list of quals to be evaluated at a table scan node,
and we also have to ensure that quals are not chosen for early evaluation
(i.e., use as an index qual or TID scan qual) if they're not allowed to go
ahead of other quals at the scan node.
This is sufficient to fix the problem for RLS quals, since we only support
RLS policies on simple tables and thus RLS quals will always exist at the
table scan level only. Eventually these qual ordering rules should be
enforced for join quals as well, which would permit improving planning for
explicit security-barrier views; but that's a task for another patch.
Note that FDWs would need to be aware of these rules --- and not, for
example, send an insecure qual for remote execution --- but since we do
not yet allow RLS policies on foreign tables, the case doesn't arise.
This will need to be addressed before we can allow such policies.
Patch by me, reviewed by Stephen Frost and Dean Rasheed.
Discussion: https://postgr.es/m/8185.1477432701@sss.pgh.pa.us
2017-01-18 18:58:20 +01:00
|
|
|
COMPARE_SCALAR_FIELD(security_level);
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-21 14:48:04 +01:00
|
|
|
static bool
|
|
|
|
_equalPartitionedChildRelInfo(const PartitionedChildRelInfo *a, const PartitionedChildRelInfo *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(parent_relid);
|
|
|
|
COMPARE_NODE_FIELD(child_rels);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Introduce extensible node types.
An extensible node is always tagged T_Extensible, but the extnodename
field identifies it more specifically; it may also include arbitrary
private data. Extensible nodes can be copied, tested for equality,
serialized, and deserialized, but the core system doesn't know
anything about them otherwise. Some extensions may find it useful to
include these nodes in fdw_private or custom_private lists in lieu of
arm-wrestling their data into a format that the core code can
understand.
Along the way, so as not to burden the authors of such extensible
node types too much, expose the functions for writing serialized
tokens, and for serializing and deserializing bitmapsets.
KaiGai Kohei, per a design suggested by me. Reviewed by Andres Freund
and by me, and further edited by me.
2016-02-12 15:31:16 +01:00
|
|
|
/*
|
|
|
|
* Stuff from extensible.h
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
_equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
|
|
|
|
{
|
2016-04-06 17:34:02 +02:00
|
|
|
const ExtensibleNodeMethods *methods;
|
Introduce extensible node types.
An extensible node is always tagged T_Extensible, but the extnodename
field identifies it more specifically; it may also include arbitrary
private data. Extensible nodes can be copied, tested for equality,
serialized, and deserialized, but the core system doesn't know
anything about them otherwise. Some extensions may find it useful to
include these nodes in fdw_private or custom_private lists in lieu of
arm-wrestling their data into a format that the core code can
understand.
Along the way, so as not to burden the authors of such extensible
node types too much, expose the functions for writing serialized
tokens, and for serializing and deserializing bitmapsets.
KaiGai Kohei, per a design suggested by me. Reviewed by Andres Freund
and by me, and further edited by me.
2016-02-12 15:31:16 +01:00
|
|
|
|
|
|
|
COMPARE_STRING_FIELD(extnodename);
|
|
|
|
|
|
|
|
/* At this point, we know extnodename is the same for both nodes. */
|
|
|
|
methods = GetExtensibleNodeMethods(a->extnodename, false);
|
|
|
|
|
|
|
|
/* compare the private fields */
|
|
|
|
if (!methods->nodeEqual(a, b))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
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);
|
2016-09-13 19:54:24 +02:00
|
|
|
COMPARE_SCALAR_FIELD(hasTargetSRFs);
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(override);
|
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);
|
2015-10-05 13:38:58 +02:00
|
|
|
COMPARE_NODE_FIELD(withCheckOptions);
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
COMPARE_LOCATION_FIELD(stmt_location);
|
|
|
|
COMPARE_LOCATION_FIELD(stmt_len);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalRawStmt(const RawStmt *a, const RawStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(stmt);
|
|
|
|
COMPARE_LOCATION_FIELD(stmt_location);
|
|
|
|
COMPARE_LOCATION_FIELD(stmt_len);
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(override);
|
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);
|
2017-09-06 22:46:01 +02:00
|
|
|
COMPARE_SCALAR_FIELD(num);
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-23 20:25:34 +01:00
|
|
|
static bool
|
|
|
|
_equalAlterCollationStmt(const AlterCollationStmt *a, const AlterCollationStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(collname);
|
|
|
|
|
|
|
|
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
|
2016-12-28 18:00:00 +01:00
|
|
|
_equalObjectWithArgs(const ObjectWithArgs *a, const ObjectWithArgs *b)
|
2002-02-19 00:11:58 +01:00
|
|
|
{
|
2016-12-28 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(objname);
|
|
|
|
COMPARE_NODE_FIELD(objargs);
|
2017-03-10 05:58:48 +01:00
|
|
|
COMPARE_SCALAR_FIELD(args_unspecified);
|
2002-11-25 04:33:27 +01:00
|
|
|
|
|
|
|
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);
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
COMPARE_NODE_FIELD(partbound);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(partspec);
|
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);
|
2017-02-09 04:51:09 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
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);
|
|
|
|
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);
|
Remove objname/objargs split for referring to objects
In simpler times, it might have worked to refer to all kinds of objects
by a list of name components and an optional argument list. But this
doesn't work for all objects, which has resulted in a collection of
hacks to place various other nodes types into these fields, which have
to be unpacked at the other end. This makes it also weird to represent
lists of such things in the grammar, because they would have to be lists
of singleton lists, to make the unpacking work consistently. The other
problem is that keeping separate name and args fields makes it awkward
to deal with lists of functions.
Change that by dropping the objargs field and have objname, renamed to
object, be a generic Node, which can then be flexibly assigned and
managed using the normal Node mechanisms. In many cases it will still
be a List of names, in some cases it will be a string Value, for types
it will be the existing Typename, for functions it will now use the
existing ObjectWithArgs node type. Some of the more obscure object
types still use somewhat arbitrary nested lists.
Reviewed-by: Jim Nasby <Jim.Nasby@BlueTreble.com>
Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
2016-11-12 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(object);
|
2002-11-25 04:33:27 +01:00
|
|
|
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);
|
Remove objname/objargs split for referring to objects
In simpler times, it might have worked to refer to all kinds of objects
by a list of name components and an optional argument list. But this
doesn't work for all objects, which has resulted in a collection of
hacks to place various other nodes types into these fields, which have
to be unpacked at the other end. This makes it also weird to represent
lists of such things in the grammar, because they would have to be lists
of singleton lists, to make the unpacking work consistently. The other
problem is that keeping separate name and args fields makes it awkward
to deal with lists of functions.
Change that by dropping the objargs field and have objname, renamed to
object, be a generic Node, which can then be flexibly assigned and
managed using the normal Node mechanisms. In many cases it will still
be a List of names, in some cases it will be a string Value, for types
it will be the existing Typename, for functions it will now use the
existing ObjectWithArgs node type. Some of the more obscure object
types still use somewhat arbitrary nested lists.
Reviewed-by: Jim Nasby <Jim.Nasby@BlueTreble.com>
Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
2016-11-12 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(object);
|
2010-09-28 02:55:27 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
static bool
|
|
|
|
_equalCreateStatsStmt(const CreateStatsStmt *a, const CreateStatsStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(defnames);
|
Change CREATE STATISTICS syntax
Previously, we had the WITH clause in the middle of the command, where
you'd specify both generic options as well as statistic types. Few
people liked this, so this commit changes it to remove the WITH keyword
from that clause and makes it accept statistic types only. (We
currently don't have any generic options, but if we invent in the
future, we will gain a new WITH clause, probably at the end of the
command).
Also, the column list is now specified without parens, which makes the
whole command look more similar to a SELECT command. This change will
let us expand the command to supporting expressions (not just columns
names) as well as multiple tables and their join conditions.
Tom added lots of code comments and fixed some parts of the CREATE
STATISTICS reference page, too; more changes in this area are
forthcoming. He also fixed a potential problem in the alter_generic
regression test, reducing verbosity on a cascaded drop to avoid
dependency on message ordering, as we do in other tests.
Tom also closed a security bug: we documented that table ownership was
required in order to create a statistics object on it, but didn't
actually implement it.
Implement tab-completion for statistics objects. This can stand some
more improvement.
Authors: Alvaro Herrera, with lots of cleanup by Tom Lane
Discussion: https://postgr.es/m/20170420212426.ltvgyhnefvhixm6i@alvherre.pgsql
2017-05-12 19:59:23 +02:00
|
|
|
COMPARE_NODE_FIELD(stat_types);
|
|
|
|
COMPARE_NODE_FIELD(exprs);
|
|
|
|
COMPARE_NODE_FIELD(relations);
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-08-12 01:45:35 +02:00
|
|
|
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_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;
|
|
|
|
}
|
|
|
|
|
2016-04-05 23:38:54 +02:00
|
|
|
static bool
|
|
|
|
_equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectDependsStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(objectType);
|
|
|
|
COMPARE_NODE_FIELD(relation);
|
Remove objname/objargs split for referring to objects
In simpler times, it might have worked to refer to all kinds of objects
by a list of name components and an optional argument list. But this
doesn't work for all objects, which has resulted in a collection of
hacks to place various other nodes types into these fields, which have
to be unpacked at the other end. This makes it also weird to represent
lists of such things in the grammar, because they would have to be lists
of singleton lists, to make the unpacking work consistently. The other
problem is that keeping separate name and args fields makes it awkward
to deal with lists of functions.
Change that by dropping the objargs field and have objname, renamed to
object, be a generic Node, which can then be flexibly assigned and
managed using the normal Node mechanisms. In many cases it will still
be a List of names, in some cases it will be a string Value, for types
it will be the existing Typename, for functions it will now use the
existing ObjectWithArgs node type. Some of the more obscure object
types still use somewhat arbitrary nested lists.
Reviewed-by: Jim Nasby <Jim.Nasby@BlueTreble.com>
Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
2016-11-12 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(object);
|
2016-04-05 23:38:54 +02:00
|
|
|
COMPARE_NODE_FIELD(extname);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
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_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);
|
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(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);
|
2016-09-07 22:11:56 +02:00
|
|
|
COMPARE_STRING_FIELD(oldVal);
|
2010-10-25 05:04:37 +02:00
|
|
|
COMPARE_STRING_FIELD(newVal);
|
|
|
|
COMPARE_STRING_FIELD(newValNeighbor);
|
|
|
|
COMPARE_SCALAR_FIELD(newValIsAfter);
|
2016-09-07 22:11:56 +02:00
|
|
|
COMPARE_SCALAR_FIELD(skipIfNewValExists);
|
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_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);
|
2017-10-04 00:53:44 +02:00
|
|
|
COMPARE_NODE_FIELD(rels);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalVacuumRelation(const VacuumRelation *a, const VacuumRelation *b)
|
|
|
|
{
|
2002-11-25 04:33:27 +01:00
|
|
|
COMPARE_NODE_FIELD(relation);
|
2017-10-04 00:53:44 +02:00
|
|
|
COMPARE_SCALAR_FIELD(oid);
|
2002-11-25 04:33:27 +01:00
|
|
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(for_identity);
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(for_identity);
|
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);
|
Remove objname/objargs split for referring to objects
In simpler times, it might have worked to refer to all kinds of objects
by a list of name components and an optional argument list. But this
doesn't work for all objects, which has resulted in a collection of
hacks to place various other nodes types into these fields, which have
to be unpacked at the other end. This makes it also weird to represent
lists of such things in the grammar, because they would have to be lists
of singleton lists, to make the unpacking work consistently. The other
problem is that keeping separate name and args fields makes it awkward
to deal with lists of functions.
Change that by dropping the objargs field and have objname, renamed to
object, be a generic Node, which can then be flexibly assigned and
managed using the normal Node mechanisms. In many cases it will still
be a List of names, in some cases it will be a string Value, for types
it will be the existing Typename, for functions it will now use the
existing ObjectWithArgs node type. Some of the more obscure object
types still use somewhat arbitrary nested lists.
Reviewed-by: Jim Nasby <Jim.Nasby@BlueTreble.com>
Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
2016-11-12 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(object);
|
2011-02-09 17:55:32 +01:00
|
|
|
|
|
|
|
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);
|
2017-03-21 02:50:53 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2008-12-19 17:25:19 +01:00
|
|
|
|
|
|
|
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);
|
2017-03-21 02:50:53 +01:00
|
|
|
COMPARE_SCALAR_FIELD(if_not_exists);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(options);
|
2008-12-19 17:25:19 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-03-24 03:01:35 +01:00
|
|
|
static bool
|
|
|
|
_equalCreateAmStmt(const CreateAmStmt *a, const CreateAmStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(amname);
|
|
|
|
COMPARE_NODE_FIELD(handler_name);
|
|
|
|
COMPARE_SCALAR_FIELD(amtype);
|
|
|
|
|
|
|
|
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);
|
2016-11-04 16:49:50 +01:00
|
|
|
COMPARE_NODE_FIELD(transitionRels);
|
2002-11-25 04:33:27 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
static bool
|
|
|
|
_equalCreatePublicationStmt(const CreatePublicationStmt *a,
|
|
|
|
const CreatePublicationStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(pubname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_NODE_FIELD(tables);
|
|
|
|
COMPARE_SCALAR_FIELD(for_all_tables);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalAlterPublicationStmt(const AlterPublicationStmt *a,
|
|
|
|
const AlterPublicationStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(pubname);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
COMPARE_NODE_FIELD(tables);
|
|
|
|
COMPARE_SCALAR_FIELD(for_all_tables);
|
|
|
|
COMPARE_SCALAR_FIELD(tableAction);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalCreateSubscriptionStmt(const CreateSubscriptionStmt *a,
|
|
|
|
const CreateSubscriptionStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(subname);
|
|
|
|
COMPARE_STRING_FIELD(conninfo);
|
|
|
|
COMPARE_NODE_FIELD(publication);
|
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalAlterSubscriptionStmt(const AlterSubscriptionStmt *a,
|
|
|
|
const AlterSubscriptionStmt *b)
|
|
|
|
{
|
2017-03-23 16:44:43 +01:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
2017-01-19 18:00:00 +01:00
|
|
|
COMPARE_STRING_FIELD(subname);
|
2017-03-23 16:44:43 +01:00
|
|
|
COMPARE_STRING_FIELD(conninfo);
|
|
|
|
COMPARE_NODE_FIELD(publication);
|
2017-01-19 18:00:00 +01:00
|
|
|
COMPARE_NODE_FIELD(options);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalDropSubscriptionStmt(const DropSubscriptionStmt *a,
|
|
|
|
const DropSubscriptionStmt *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(subname);
|
|
|
|
COMPARE_SCALAR_FIELD(missing_ok);
|
2017-05-09 16:20:42 +02:00
|
|
|
COMPARE_SCALAR_FIELD(behavior);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
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);
|
2016-12-05 21:50:55 +01:00
|
|
|
COMPARE_SCALAR_FIELD(permissive);
|
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
|
|
|
{
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (!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
|
|
|
{
|
2015-12-23 03:05:16 +01:00
|
|
|
COMPARE_SCALAR_FIELD(is_slice);
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-08 16:39:37 +01:00
|
|
|
static bool
|
|
|
|
_equalRangeTableFunc(const RangeTableFunc *a, const RangeTableFunc *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(lateral);
|
|
|
|
COMPARE_NODE_FIELD(docexpr);
|
|
|
|
COMPARE_NODE_FIELD(rowexpr);
|
|
|
|
COMPARE_NODE_FIELD(namespaces);
|
|
|
|
COMPARE_NODE_FIELD(columns);
|
|
|
|
COMPARE_NODE_FIELD(alias);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalRangeTableFuncCol(const RangeTableFuncCol *a, const RangeTableFuncCol *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(colname);
|
|
|
|
COMPARE_NODE_FIELD(typeName);
|
|
|
|
COMPARE_SCALAR_FIELD(for_ordinality);
|
|
|
|
COMPARE_SCALAR_FIELD(is_not_null);
|
|
|
|
COMPARE_NODE_FIELD(colexpr);
|
|
|
|
COMPARE_NODE_FIELD(coldefexpr);
|
|
|
|
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);
|
2017-04-28 19:52:17 +02:00
|
|
|
COMPARE_SCALAR_FIELD(is_from_parent);
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(identity);
|
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);
|
2017-04-06 14:33:16 +02:00
|
|
|
COMPARE_SCALAR_FIELD(generated_when);
|
2002-11-25 04:33:27 +01:00
|
|
|
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);
|
2016-09-06 18:00:00 +02:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
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);
|
2017-06-16 09:16:11 +02:00
|
|
|
COMPARE_NODE_FIELD(tablefunc);
|
2006-08-02 03:59:48 +02:00
|
|
|
COMPARE_NODE_FIELD(values_lists);
|
2008-10-04 23:56:55 +02:00
|
|
|
COMPARE_STRING_FIELD(ctename);
|
|
|
|
COMPARE_SCALAR_FIELD(ctelevelsup);
|
|
|
|
COMPARE_SCALAR_FIELD(self_reference);
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 17:40:02 +01:00
|
|
|
COMPARE_NODE_FIELD(coltypes);
|
|
|
|
COMPARE_NODE_FIELD(coltypmods);
|
|
|
|
COMPARE_NODE_FIELD(colcollations);
|
2017-06-14 22:19:46 +02:00
|
|
|
COMPARE_STRING_FIELD(enrname);
|
|
|
|
COMPARE_SCALAR_FIELD(enrtuples);
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-04 16:49:50 +01:00
|
|
|
static bool
|
|
|
|
_equalTriggerTransition(const TriggerTransition *a, const TriggerTransition *b)
|
|
|
|
{
|
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_SCALAR_FIELD(isNew);
|
|
|
|
COMPARE_SCALAR_FIELD(isTable);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
static bool
|
Code review focused on new node types added by partitioning support.
Fix failure to check that we got a plain Const from const-simplification of
a coercion request. This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with. Add test cases around this coercion behavior.
In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner. Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types. And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.
Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.
Avoid not-per-project-style usages like !strcmp(...).
Fix assorted failures to avoid scribbling on the input of parse
transformation. I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.
Add guards against partitioning on system columns.
Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.
Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c. This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.
Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.
Consolidate duplicative code in transformPartitionBound().
Improve a couple of error messages.
Improve assorted commentary.
Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.
Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
2017-05-29 05:20:28 +02:00
|
|
|
_equalPartitionElem(const PartitionElem *a, const PartitionElem *b)
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
{
|
Code review focused on new node types added by partitioning support.
Fix failure to check that we got a plain Const from const-simplification of
a coercion request. This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with. Add test cases around this coercion behavior.
In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner. Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types. And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.
Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.
Avoid not-per-project-style usages like !strcmp(...).
Fix assorted failures to avoid scribbling on the input of parse
transformation. I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.
Add guards against partitioning on system columns.
Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.
Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c. This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.
Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.
Consolidate duplicative code in transformPartitionBound().
Improve a couple of error messages.
Improve assorted commentary.
Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.
Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
2017-05-29 05:20:28 +02:00
|
|
|
COMPARE_STRING_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(expr);
|
|
|
|
COMPARE_NODE_FIELD(collation);
|
|
|
|
COMPARE_NODE_FIELD(opclass);
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
Code review focused on new node types added by partitioning support.
Fix failure to check that we got a plain Const from const-simplification of
a coercion request. This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with. Add test cases around this coercion behavior.
In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner. Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types. And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.
Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.
Avoid not-per-project-style usages like !strcmp(...).
Fix assorted failures to avoid scribbling on the input of parse
transformation. I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.
Add guards against partitioning on system columns.
Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.
Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c. This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.
Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.
Consolidate duplicative code in transformPartitionBound().
Improve a couple of error messages.
Improve assorted commentary.
Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.
Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
2017-05-29 05:20:28 +02:00
|
|
|
_equalPartitionSpec(const PartitionSpec *a, const PartitionSpec *b)
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
{
|
Code review focused on new node types added by partitioning support.
Fix failure to check that we got a plain Const from const-simplification of
a coercion request. This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with. Add test cases around this coercion behavior.
In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner. Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types. And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.
Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.
Avoid not-per-project-style usages like !strcmp(...).
Fix assorted failures to avoid scribbling on the input of parse
transformation. I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.
Add guards against partitioning on system columns.
Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.
Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c. This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.
Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.
Consolidate duplicative code in transformPartitionBound().
Improve a couple of error messages.
Improve assorted commentary.
Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.
Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
2017-05-29 05:20:28 +02:00
|
|
|
COMPARE_STRING_FIELD(strategy);
|
|
|
|
COMPARE_NODE_FIELD(partParams);
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalPartitionBoundSpec(const PartitionBoundSpec *a, const PartitionBoundSpec *b)
|
|
|
|
{
|
|
|
|
COMPARE_SCALAR_FIELD(strategy);
|
Allow a partitioned table to have a default partition.
Any tuples that don't route to any other partition will route to the
default partition.
Jeevan Ladhe, Beena Emerson, Ashutosh Bapat, Rahila Syed, and Robert
Haas, with review and testing at various stages by (at least) Rushabh
Lathia, Keith Fiske, Amit Langote, Amul Sul, Rajkumar Raghuanshi, Sven
Kunze, Kyotaro Horiguchi, Thom Brown, Rafia Sabih, and Dilip Kumar.
Discussion: http://postgr.es/m/CAH2L28tbN4SYyhS7YV1YBWcitkqbhSWfQCy0G=apRcC_PEO-bg@mail.gmail.com
Discussion: http://postgr.es/m/CAOG9ApEYj34fWMcvBMBQ-YtqR9fTdXhdN82QEKG0SVZ6zeL1xg@mail.gmail.com
2017-09-08 23:28:04 +02:00
|
|
|
COMPARE_SCALAR_FIELD(is_default);
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
COMPARE_NODE_FIELD(listdatums);
|
|
|
|
COMPARE_NODE_FIELD(lowerdatums);
|
|
|
|
COMPARE_NODE_FIELD(upperdatums);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalPartitionRangeDatum(const PartitionRangeDatum *a, const PartitionRangeDatum *b)
|
|
|
|
{
|
Use MINVALUE/MAXVALUE instead of UNBOUNDED for range partition bounds.
Previously, UNBOUNDED meant no lower bound when used in the FROM list,
and no upper bound when used in the TO list, which was OK for
single-column range partitioning, but problematic with multiple
columns. For example, an upper bound of (10.0, UNBOUNDED) would not be
collocated with a lower bound of (10.0, UNBOUNDED), thus making it
difficult or impossible to define contiguous multi-column range
partitions in some cases.
Fix this by using MINVALUE and MAXVALUE instead of UNBOUNDED to
represent a partition column that is unbounded below or above
respectively. This syntax removes any ambiguity, and ensures that if
one partition's lower bound equals another partition's upper bound,
then the partitions are contiguous.
Also drop the constraint prohibiting finite values after an unbounded
column, and just document the fact that any values after MINVALUE or
MAXVALUE are ignored. Previously it was necessary to repeat UNBOUNDED
multiple times, which was needlessly verbose.
Note: Forces a post-PG 10 beta2 initdb.
Report by Amul Sul, original patch by Amit Langote with some
additional hacking by me.
Discussion: https://postgr.es/m/CAAJ_b947mowpLdxL3jo3YLKngRjrq9+Ej4ymduQTfYR+8=YAYQ@mail.gmail.com
2017-07-21 10:20:47 +02:00
|
|
|
COMPARE_SCALAR_FIELD(kind);
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
COMPARE_NODE_FIELD(value);
|
|
|
|
COMPARE_LOCATION_FIELD(location);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
|
|
|
|
{
|
|
|
|
COMPARE_NODE_FIELD(name);
|
|
|
|
COMPARE_NODE_FIELD(bound);
|
|
|
|
|
|
|
|
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;
|
2017-03-08 16:39:37 +01:00
|
|
|
case T_TableFunc:
|
|
|
|
retval = _equalTableFunc(a, b);
|
|
|
|
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;
|
2016-08-17 02:33:01 +02:00
|
|
|
case T_SQLValueFunction:
|
|
|
|
retval = _equalSQLValueFunction(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;
|
2017-04-06 14:33:16 +02:00
|
|
|
case T_NextValueExpr:
|
|
|
|
retval = _equalNextValueExpr(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;
|
2006-01-31 22:39:25 +01:00
|
|
|
case T_AppendRelInfo:
|
|
|
|
retval = _equalAppendRelInfo(a, b);
|
|
|
|
break;
|
2017-03-21 14:48:04 +01:00
|
|
|
case T_PartitionedChildRelInfo:
|
|
|
|
retval = _equalPartitionedChildRelInfo(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
|
|
|
|
Introduce extensible node types.
An extensible node is always tagged T_Extensible, but the extnodename
field identifies it more specifically; it may also include arbitrary
private data. Extensible nodes can be copied, tested for equality,
serialized, and deserialized, but the core system doesn't know
anything about them otherwise. Some extensions may find it useful to
include these nodes in fdw_private or custom_private lists in lieu of
arm-wrestling their data into a format that the core code can
understand.
Along the way, so as not to burden the authors of such extensible
node types too much, expose the functions for writing serialized
tokens, and for serializing and deserializing bitmapsets.
KaiGai Kohei, per a design suggested by me. Reviewed by Andres Freund
and by me, and further edited by me.
2016-02-12 15:31:16 +01:00
|
|
|
/*
|
|
|
|
* EXTENSIBLE NODES
|
|
|
|
*/
|
|
|
|
case T_ExtensibleNode:
|
|
|
|
retval = _equalExtensibleNode(a, b);
|
|
|
|
break;
|
|
|
|
|
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;
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
case T_RawStmt:
|
|
|
|
retval = _equalRawStmt(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;
|
2017-03-23 20:25:34 +01:00
|
|
|
case T_AlterCollationStmt:
|
|
|
|
retval = _equalAlterCollationStmt(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;
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
case T_CreateStatsStmt:
|
|
|
|
retval = _equalCreateStatsStmt(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;
|
2016-04-05 23:38:54 +02:00
|
|
|
case T_AlterObjectDependsStmt:
|
|
|
|
retval = _equalAlterObjectDependsStmt(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;
|
2017-10-04 00:53:44 +02:00
|
|
|
case T_VacuumRelation:
|
|
|
|
retval = _equalVacuumRelation(a, b);
|
|
|
|
break;
|
2000-08-12 01:45:35 +02:00
|
|
|
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;
|
2016-03-24 03:01:35 +01:00
|
|
|
case T_CreateAmStmt:
|
|
|
|
retval = _equalCreateAmStmt(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;
|
2017-01-19 18:00:00 +01:00
|
|
|
case T_CreatePublicationStmt:
|
|
|
|
retval = _equalCreatePublicationStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterPublicationStmt:
|
|
|
|
retval = _equalAlterPublicationStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_CreateSubscriptionStmt:
|
|
|
|
retval = _equalCreateSubscriptionStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_AlterSubscriptionStmt:
|
|
|
|
retval = _equalAlterSubscriptionStmt(a, b);
|
|
|
|
break;
|
|
|
|
case T_DropSubscriptionStmt:
|
|
|
|
retval = _equalDropSubscriptionStmt(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;
|
2017-03-08 16:39:37 +01:00
|
|
|
case T_RangeTableFunc:
|
|
|
|
retval = _equalRangeTableFunc(a, b);
|
|
|
|
break;
|
|
|
|
case T_RangeTableFuncCol:
|
|
|
|
retval = _equalRangeTableFuncCol(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;
|
2016-12-28 18:00:00 +01:00
|
|
|
case T_ObjectWithArgs:
|
|
|
|
retval = _equalObjectWithArgs(a, b);
|
2002-02-19 00:11:58 +01:00
|
|
|
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;
|
2016-11-04 16:49:50 +01:00
|
|
|
case T_TriggerTransition:
|
|
|
|
retval = _equalTriggerTransition(a, b);
|
|
|
|
break;
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
case T_PartitionElem:
|
|
|
|
retval = _equalPartitionElem(a, b);
|
|
|
|
break;
|
Code review focused on new node types added by partitioning support.
Fix failure to check that we got a plain Const from const-simplification of
a coercion request. This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with. Add test cases around this coercion behavior.
In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner. Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types. And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.
Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.
Avoid not-per-project-style usages like !strcmp(...).
Fix assorted failures to avoid scribbling on the input of parse
transformation. I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.
Add guards against partitioning on system columns.
Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.
Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c. This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.
Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.
Consolidate duplicative code in transformPartitionBound().
Improve a couple of error messages.
Improve assorted commentary.
Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.
Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
2017-05-29 05:20:28 +02:00
|
|
|
case T_PartitionSpec:
|
|
|
|
retval = _equalPartitionSpec(a, b);
|
|
|
|
break;
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
case T_PartitionBoundSpec:
|
|
|
|
retval = _equalPartitionBoundSpec(a, b);
|
|
|
|
break;
|
|
|
|
case T_PartitionRangeDatum:
|
|
|
|
retval = _equalPartitionRangeDatum(a, b);
|
|
|
|
break;
|
|
|
|
case T_PartitionCmd:
|
|
|
|
retval = _equalPartitionCmd(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
|
|
|
}
|