2007-06-24 00:12:52 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* parse_utilcmd.c
|
|
|
|
* Perform parse analysis work for various utility commands
|
|
|
|
*
|
|
|
|
* Formerly we did this work during parse_analyze() in analyze.c. However
|
|
|
|
* that is fairly unsafe in the presence of querytree caching, since any
|
|
|
|
* database state that we depend on in making the transformations might be
|
|
|
|
* obsolete by the time the utility command is executed; and utility commands
|
|
|
|
* have no infrastructure for holding locks or rechecking plan validity.
|
|
|
|
* Hence these functions are now called at the start of execution of their
|
|
|
|
* respective utility commands.
|
|
|
|
*
|
|
|
|
* NOTE: in general we must avoid scribbling on the passed-in raw parse
|
|
|
|
* tree, since it might be in a plan cache. The simplest solution is
|
|
|
|
* a quick copyObject() call before manipulating the query tree.
|
|
|
|
*
|
|
|
|
*
|
2018-01-03 05:30:12 +01:00
|
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
2007-06-24 00:12:52 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/parser/parse_utilcmd.c
|
2007-06-24 00:12:52 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
#include "access/amapi.h"
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2007-12-02 00:44:44 +01:00
|
|
|
#include "access/reloptions.h"
|
|
|
|
#include "catalog/dependency.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/namespace.h"
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
#include "catalog/pg_am.h"
|
2011-03-26 21:35:25 +01:00
|
|
|
#include "catalog/pg_collation.h"
|
2009-07-29 22:56:21 +02:00
|
|
|
#include "catalog/pg_constraint.h"
|
2007-07-17 07:02:03 +02:00
|
|
|
#include "catalog/pg_opclass.h"
|
2009-12-07 06:22:23 +01:00
|
|
|
#include "catalog/pg_operator.h"
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
#include "catalog/pg_statistic_ext.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2009-10-12 21:49:24 +02:00
|
|
|
#include "commands/comment.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "commands/defrem.h"
|
2017-04-06 14:33:16 +02:00
|
|
|
#include "commands/sequence.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "commands/tablecmds.h"
|
2007-07-17 07:02:03 +02:00
|
|
|
#include "commands/tablespace.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "nodes/makefuncs.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
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
|
|
|
#include "optimizer/planner.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "parser/analyze.h"
|
|
|
|
#include "parser/parse_clause.h"
|
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
|
|
|
#include "parser/parse_coerce.h"
|
2011-03-20 01:29:08 +01:00
|
|
|
#include "parser/parse_collate.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "parser/parse_expr.h"
|
|
|
|
#include "parser/parse_relation.h"
|
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
|
|
|
#include "parser/parse_target.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "parser/parse_type.h"
|
|
|
|
#include "parser/parse_utilcmd.h"
|
2009-07-12 19:12:34 +02:00
|
|
|
#include "parser/parser.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "rewrite/rewriteManip.h"
|
|
|
|
#include "utils/acl.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
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
|
|
|
#include "utils/ruleutils.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
#include "utils/syscache.h"
|
2010-01-29 00:21:13 +01:00
|
|
|
#include "utils/typcache.h"
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* State shared by transformCreateStmt and its subroutines */
|
|
|
|
typedef struct
|
|
|
|
{
|
2011-01-25 21:42:03 +01:00
|
|
|
ParseState *pstate; /* overall parser state */
|
2011-01-02 05:48:11 +01:00
|
|
|
const char *stmtType; /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
|
2007-06-24 00:12:52 +02:00
|
|
|
RangeVar *relation; /* relation to create */
|
|
|
|
Relation rel; /* opened/locked rel, if ALTER */
|
|
|
|
List *inhRelations; /* relations to inherit from */
|
2013-03-12 22:37:07 +01:00
|
|
|
bool isforeign; /* true if CREATE/ALTER FOREIGN TABLE */
|
2007-06-24 00:12:52 +02:00
|
|
|
bool isalter; /* true if altering existing table */
|
|
|
|
bool hasoids; /* does relation have an OID column? */
|
|
|
|
List *columns; /* ColumnDef items */
|
|
|
|
List *ckconstraints; /* CHECK constraints */
|
|
|
|
List *fkconstraints; /* FOREIGN KEY constraints */
|
|
|
|
List *ixconstraints; /* index-creating constraints */
|
2007-07-17 07:02:03 +02:00
|
|
|
List *inh_indexes; /* cloned indexes from INCLUDING INDEXES */
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
List *extstats; /* cloned extended statistics */
|
2007-06-24 00:12:52 +02:00
|
|
|
List *blist; /* "before list" of things to do before
|
|
|
|
* creating the table */
|
|
|
|
List *alist; /* "after list" of things to do after creating
|
|
|
|
* the table */
|
|
|
|
IndexStmt *pkey; /* PRIMARY KEY index, if any */
|
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
|
|
|
bool ispartitioned; /* true if table is partitioned */
|
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
|
|
|
PartitionBoundSpec *partbound; /* transformed FOR VALUES */
|
2017-12-08 18:13:04 +01:00
|
|
|
bool ofType; /* true if statement contains OF typename */
|
2007-06-24 00:12:52 +02:00
|
|
|
} CreateStmtContext;
|
|
|
|
|
|
|
|
/* State shared by transformCreateSchemaStmt and its subroutines */
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
|
|
|
|
char *schemaname; /* name of schema */
|
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
|
|
|
RoleSpec *authrole; /* owner of schema */
|
2007-06-24 00:12:52 +02:00
|
|
|
List *sequences; /* CREATE SEQUENCE items */
|
|
|
|
List *tables; /* CREATE TABLE items */
|
|
|
|
List *views; /* CREATE VIEW items */
|
|
|
|
List *indexes; /* CREATE INDEX items */
|
|
|
|
List *triggers; /* CREATE TRIGGER items */
|
|
|
|
List *grants; /* GRANT items */
|
|
|
|
} CreateSchemaStmtContext;
|
|
|
|
|
|
|
|
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformColumnDefinition(CreateStmtContext *cxt,
|
2007-06-24 00:12:52 +02:00
|
|
|
ColumnDef *column);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformTableConstraint(CreateStmtContext *cxt,
|
2007-06-24 00:12:52 +02:00
|
|
|
Constraint *constraint);
|
2012-01-07 13:58:13 +01:00
|
|
|
static void transformTableLikeClause(CreateStmtContext *cxt,
|
2012-06-10 21:20:04 +02:00
|
|
|
TableLikeClause *table_like_clause);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformOfType(CreateStmtContext *cxt,
|
2010-02-26 03:01:40 +01:00
|
|
|
TypeName *ofTypename);
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
|
|
|
|
Oid heapRelid, Oid source_statsid);
|
2011-03-26 21:35:25 +01:00
|
|
|
static List *get_collation(Oid collation, Oid actual_datatype);
|
2007-07-17 07:02:03 +02:00
|
|
|
static List *get_opclass(Oid opclass, Oid actual_datatype);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformIndexConstraints(CreateStmtContext *cxt);
|
2007-07-17 07:02:03 +02:00
|
|
|
static IndexStmt *transformIndexConstraint(Constraint *constraint,
|
2007-11-15 22:14:46 +01:00
|
|
|
CreateStmtContext *cxt);
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
static void transformExtendedStatistics(CreateStmtContext *cxt);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformFKConstraints(CreateStmtContext *cxt,
|
2007-06-24 00:12:52 +02:00
|
|
|
bool skipValidation,
|
|
|
|
bool isAddConstraint);
|
2015-12-16 13:43:56 +01:00
|
|
|
static void transformCheckConstraints(CreateStmtContext *cxt,
|
2016-06-10 00:02:36 +02:00
|
|
|
bool skipValidation);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformConstraintAttrs(CreateStmtContext *cxt,
|
2011-04-10 17:42:00 +02:00
|
|
|
List *constraintList);
|
2011-01-25 21:42:03 +01:00
|
|
|
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
|
2007-06-24 00:12:52 +02:00
|
|
|
static void setSchemaName(char *context_schema, char **stmt_schema_name);
|
2017-02-16 14:37:37 +01:00
|
|
|
static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
|
2017-09-16 03:15:55 +02:00
|
|
|
static void validateInfiniteBounds(ParseState *pstate, List *blist);
|
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
|
|
|
static Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
const char *colName, Oid colType, int32 colTypmod);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformCreateStmt -
|
|
|
|
* parse analysis for CREATE TABLE
|
|
|
|
*
|
|
|
|
* Returns a List of utility commands to be done in sequence. One of these
|
|
|
|
* will be the transformed CreateStmt, but there may be additional actions
|
|
|
|
* to be done before and after the actual DefineRelation() call.
|
|
|
|
*
|
2013-04-20 17:04:41 +02:00
|
|
|
* SQL allows constraints to be scattered all over, so thumb through
|
2007-06-24 00:12:52 +02:00
|
|
|
* the columns and collect all constraints into one place.
|
|
|
|
* If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
|
|
|
|
* then expand those into multiple IndexStmt blocks.
|
|
|
|
* - thomas 1997-12-02
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
|
|
|
{
|
|
|
|
ParseState *pstate;
|
|
|
|
CreateStmtContext cxt;
|
|
|
|
List *result;
|
|
|
|
List *save_alist;
|
|
|
|
ListCell *elements;
|
2011-04-25 22:55:11 +02:00
|
|
|
Oid namespaceid;
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
Oid existing_relid;
|
2015-03-18 18:48:02 +01:00
|
|
|
ParseCallbackState pcbstate;
|
2015-10-06 03:19:16 +02:00
|
|
|
bool like_found = false;
|
2017-08-03 19:09:15 +02:00
|
|
|
bool is_foreign_table = IsA(stmt, CreateForeignTableStmt);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
|
|
|
|
* overkill, but easy.)
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2017-03-09 21:18:59 +01:00
|
|
|
stmt = copyObject(stmt);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2015-03-18 18:48:02 +01:00
|
|
|
/* Set up pstate */
|
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
pstate->p_sourcetext = queryString;
|
|
|
|
|
2011-04-25 22:55:11 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Look up the creation namespace. This also checks permissions on the
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
* target namespace, locks it against concurrent drops, checks for a
|
|
|
|
* preexisting relation in that namespace with the same name, and updates
|
2015-02-03 08:48:45 +01:00
|
|
|
* stmt->relation->relpersistence if the selected namespace is temporary.
|
2011-04-25 22:55:11 +02:00
|
|
|
*/
|
2015-03-18 18:48:02 +01:00
|
|
|
setup_parser_errposition_callback(&pcbstate, pstate,
|
|
|
|
stmt->relation->location);
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
namespaceid =
|
|
|
|
RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
|
|
|
|
&existing_relid);
|
2015-03-18 18:48:02 +01:00
|
|
|
cancel_parser_errposition_callback(&pcbstate);
|
2011-04-25 22:55:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the relation already exists and the user specified "IF NOT EXISTS",
|
|
|
|
* bail out with a NOTICE.
|
|
|
|
*/
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
if (stmt->if_not_exists && OidIsValid(existing_relid))
|
2011-04-25 22:55:11 +02:00
|
|
|
{
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
ereport(NOTICE,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_TABLE),
|
|
|
|
errmsg("relation \"%s\" already exists, skipping",
|
|
|
|
stmt->relation->relname)));
|
|
|
|
return NIL;
|
2011-04-25 22:55:11 +02:00
|
|
|
}
|
|
|
|
|
2007-08-27 05:36:08 +02:00
|
|
|
/*
|
|
|
|
* If the target relation name isn't schema-qualified, make it so. This
|
|
|
|
* prevents some corner cases in which added-on rewritten commands might
|
2007-11-15 22:14:46 +01:00
|
|
|
* think they should apply to other relations that have the same name and
|
2014-05-06 18:12:18 +02:00
|
|
|
* are earlier in the search path. But a local temp table is effectively
|
2010-12-13 18:34:26 +01:00
|
|
|
* specified to be in pg_temp, so no need for anything extra in that case.
|
2007-08-27 05:36:08 +02:00
|
|
|
*/
|
2010-12-13 18:34:26 +01:00
|
|
|
if (stmt->relation->schemaname == NULL
|
|
|
|
&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
|
2007-08-27 05:36:08 +02:00
|
|
|
stmt->relation->schemaname = get_namespace_name(namespaceid);
|
|
|
|
|
2015-03-18 18:48:02 +01:00
|
|
|
/* Set up CreateStmtContext */
|
2011-01-25 21:42:03 +01:00
|
|
|
cxt.pstate = pstate;
|
2011-01-02 05:48:11 +01:00
|
|
|
if (IsA(stmt, CreateForeignTableStmt))
|
2013-03-12 22:37:07 +01:00
|
|
|
{
|
2011-01-02 05:48:11 +01:00
|
|
|
cxt.stmtType = "CREATE FOREIGN TABLE";
|
2013-03-12 22:37:07 +01:00
|
|
|
cxt.isforeign = true;
|
|
|
|
}
|
2011-01-02 05:48:11 +01:00
|
|
|
else
|
2013-03-12 22:37:07 +01:00
|
|
|
{
|
2011-01-02 05:48:11 +01:00
|
|
|
cxt.stmtType = "CREATE TABLE";
|
2013-03-12 22:37:07 +01:00
|
|
|
cxt.isforeign = false;
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt.relation = stmt->relation;
|
|
|
|
cxt.rel = NULL;
|
|
|
|
cxt.inhRelations = stmt->inhRelations;
|
|
|
|
cxt.isalter = false;
|
|
|
|
cxt.columns = NIL;
|
|
|
|
cxt.ckconstraints = NIL;
|
|
|
|
cxt.fkconstraints = NIL;
|
|
|
|
cxt.ixconstraints = NIL;
|
2007-07-17 07:02:03 +02:00
|
|
|
cxt.inh_indexes = NIL;
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
cxt.extstats = NIL;
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt.blist = NIL;
|
|
|
|
cxt.alist = NIL;
|
|
|
|
cxt.pkey = NULL;
|
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
|
|
|
cxt.ispartitioned = stmt->partspec != NULL;
|
2017-12-08 18:13:04 +01:00
|
|
|
cxt.partbound = stmt->partbound;
|
|
|
|
cxt.ofType = (stmt->ofTypename != NULL);
|
2015-04-26 03:37:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Notice that we allow OIDs here only for plain tables, even though
|
|
|
|
* foreign tables also support them. This is necessary because the
|
|
|
|
* default_with_oids GUC must apply only to plain tables and not any other
|
|
|
|
* relkind; doing otherwise would break existing pg_dump files. We could
|
|
|
|
* allow explicit "WITH OIDS" while not allowing default_with_oids to
|
|
|
|
* affect other relkinds, but it would complicate interpretOidsOption(),
|
|
|
|
* and right now there's no WITH OIDS option in CREATE FOREIGN TABLE
|
|
|
|
* anyway.
|
|
|
|
*/
|
|
|
|
cxt.hasoids = interpretOidsOption(stmt->options, !cxt.isforeign);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2010-02-26 03:01:40 +01:00
|
|
|
Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
|
2010-01-29 00:21:13 +01:00
|
|
|
|
|
|
|
if (stmt->ofTypename)
|
2011-01-25 21:42:03 +01:00
|
|
|
transformOfType(&cxt, stmt->ofTypename);
|
2010-01-29 00:21:13 +01:00
|
|
|
|
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
|
|
|
if (stmt->partspec)
|
|
|
|
{
|
|
|
|
if (stmt->inhRelations && !stmt->partbound)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("cannot create partitioned table as inheritance child")));
|
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
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* Run through each primary element in the table creation clause. Separate
|
2016-12-22 22:23:33 +01:00
|
|
|
* column defs from constraints, and do preliminary analysis.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
foreach(elements, stmt->tableElts)
|
|
|
|
{
|
|
|
|
Node *element = lfirst(elements);
|
|
|
|
|
|
|
|
switch (nodeTag(element))
|
|
|
|
{
|
|
|
|
case T_ColumnDef:
|
2011-01-25 21:42:03 +01:00
|
|
|
transformColumnDefinition(&cxt, (ColumnDef *) element);
|
2007-06-24 00:12:52 +02:00
|
|
|
break;
|
|
|
|
|
2016-12-22 22:23:33 +01:00
|
|
|
case T_Constraint:
|
|
|
|
transformTableConstraint(&cxt, (Constraint *) element);
|
2007-06-24 00:12:52 +02:00
|
|
|
break;
|
|
|
|
|
2016-12-22 22:23:33 +01:00
|
|
|
case T_TableLikeClause:
|
|
|
|
like_found = true;
|
|
|
|
transformTableLikeClause(&cxt, (TableLikeClause *) element);
|
2015-10-06 03:19:16 +02:00
|
|
|
break;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(element));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 22:23:33 +01:00
|
|
|
/*
|
|
|
|
* If we had any LIKE tables, they may require creation of an OID column
|
|
|
|
* even though the command's own WITH clause didn't ask for one (or,
|
|
|
|
* perhaps, even specifically rejected having one). Insert a WITH option
|
|
|
|
* to ensure that happens. We prepend to the list because the first oid
|
|
|
|
* option will be honored, and we want to override anything already there.
|
|
|
|
* (But note that DefineRelation will override this again to add an OID
|
|
|
|
* column if one appears in an inheritance parent table.)
|
|
|
|
*/
|
|
|
|
if (like_found && cxt.hasoids)
|
2015-10-06 03:19:16 +02:00
|
|
|
stmt->options = lcons(makeDefElem("oids",
|
2016-12-22 22:23:33 +01:00
|
|
|
(Node *) makeInteger(true), -1),
|
2016-09-06 18:00:00 +02:00
|
|
|
stmt->options);
|
2016-06-10 00:02:36 +02:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* transformIndexConstraints wants cxt.alist to contain only index
|
|
|
|
* statements, so transfer anything we already have into save_alist.
|
|
|
|
*/
|
|
|
|
save_alist = cxt.alist;
|
|
|
|
cxt.alist = NIL;
|
|
|
|
|
|
|
|
Assert(stmt->constraints == NIL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Postprocess constraints that give rise to index definitions.
|
|
|
|
*/
|
2011-01-25 21:42:03 +01:00
|
|
|
transformIndexConstraints(&cxt);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Postprocess foreign-key constraints.
|
|
|
|
*/
|
2011-01-25 21:42:03 +01:00
|
|
|
transformFKConstraints(&cxt, true, false);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2015-12-16 13:43:56 +01:00
|
|
|
/*
|
|
|
|
* Postprocess check constraints.
|
|
|
|
*/
|
2017-08-03 19:09:15 +02:00
|
|
|
transformCheckConstraints(&cxt, !is_foreign_table ? true : false);
|
2015-12-16 13:43:56 +01:00
|
|
|
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
/*
|
|
|
|
* Postprocess extended statistics.
|
|
|
|
*/
|
|
|
|
transformExtendedStatistics(&cxt);
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* Output results.
|
|
|
|
*/
|
|
|
|
stmt->tableElts = cxt.columns;
|
|
|
|
stmt->constraints = cxt.ckconstraints;
|
|
|
|
|
|
|
|
result = lappend(cxt.blist, stmt);
|
|
|
|
result = list_concat(result, cxt.alist);
|
|
|
|
result = list_concat(result, save_alist);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-06-12 01:00:01 +02:00
|
|
|
/*
|
|
|
|
* generateSerialExtraStmts
|
|
|
|
* Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
|
|
|
|
* to create the sequence for a serial or identity column.
|
|
|
|
*
|
|
|
|
* This includes determining the name the sequence will have. The caller
|
|
|
|
* can ask to get back the name components by passing non-null pointers
|
|
|
|
* for snamespace_p and sname_p.
|
|
|
|
*/
|
2017-04-06 14:33:16 +02:00
|
|
|
static void
|
|
|
|
generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
|
|
|
|
Oid seqtypid, List *seqoptions, bool for_identity,
|
|
|
|
char **snamespace_p, char **sname_p)
|
|
|
|
{
|
|
|
|
ListCell *option;
|
2017-05-17 22:31:56 +02:00
|
|
|
DefElem *nameEl = NULL;
|
2017-04-06 14:33:16 +02:00
|
|
|
Oid snamespaceid;
|
|
|
|
char *snamespace;
|
|
|
|
char *sname;
|
|
|
|
CreateSeqStmt *seqstmt;
|
|
|
|
AlterSeqStmt *altseqstmt;
|
|
|
|
List *attnamelist;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine namespace and name to use for the sequence.
|
|
|
|
*
|
|
|
|
* First, check if a sequence name was passed in as an option. This is
|
|
|
|
* used by pg_dump. Else, generate a name.
|
|
|
|
*
|
|
|
|
* Although we use ChooseRelationName, it's not guaranteed that the
|
2017-05-17 22:31:56 +02:00
|
|
|
* selected sequence name won't conflict; given sufficiently long field
|
|
|
|
* names, two different serial columns in the same table could be assigned
|
|
|
|
* the same sequence name, and we'd not notice since we aren't creating
|
|
|
|
* the sequence quite yet. In practice this seems quite unlikely to be a
|
|
|
|
* problem, especially since few people would need two serial columns in
|
|
|
|
* one table.
|
2017-04-06 14:33:16 +02:00
|
|
|
*/
|
|
|
|
foreach(option, seqoptions)
|
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
DefElem *defel = lfirst_node(DefElem, option);
|
2017-04-06 14:33:16 +02:00
|
|
|
|
|
|
|
if (strcmp(defel->defname, "sequence_name") == 0)
|
|
|
|
{
|
|
|
|
if (nameEl)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
|
|
|
nameEl = defel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nameEl)
|
|
|
|
{
|
2017-05-17 22:31:56 +02:00
|
|
|
RangeVar *rv = makeRangeVarFromNameList(castNode(List, nameEl->arg));
|
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
snamespace = rv->schemaname;
|
2017-06-12 01:00:01 +02:00
|
|
|
if (!snamespace)
|
|
|
|
{
|
|
|
|
/* Given unqualified SEQUENCE NAME, select namespace */
|
|
|
|
if (cxt->rel)
|
|
|
|
snamespaceid = RelationGetNamespace(cxt->rel);
|
|
|
|
else
|
|
|
|
snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
|
|
|
|
snamespace = get_namespace_name(snamespaceid);
|
|
|
|
}
|
2017-04-06 14:33:16 +02:00
|
|
|
sname = rv->relname;
|
2017-06-12 01:00:01 +02:00
|
|
|
/* Remove the SEQUENCE NAME item from seqoptions */
|
2017-04-06 14:33:16 +02:00
|
|
|
seqoptions = list_delete_ptr(seqoptions, nameEl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cxt->rel)
|
|
|
|
snamespaceid = RelationGetNamespace(cxt->rel);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
|
|
|
|
RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
|
|
|
|
}
|
|
|
|
snamespace = get_namespace_name(snamespaceid);
|
|
|
|
sname = ChooseRelationName(cxt->relation->relname,
|
|
|
|
column->colname,
|
|
|
|
"seq",
|
|
|
|
snamespaceid);
|
|
|
|
}
|
|
|
|
|
|
|
|
ereport(DEBUG1,
|
|
|
|
(errmsg("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
|
|
|
|
cxt->stmtType, sname,
|
|
|
|
cxt->relation->relname, column->colname)));
|
|
|
|
|
|
|
|
/*
|
2017-05-17 22:31:56 +02:00
|
|
|
* Build a CREATE SEQUENCE command to create the sequence object, and add
|
|
|
|
* it to the list of things to be done before this CREATE/ALTER TABLE.
|
2017-04-06 14:33:16 +02:00
|
|
|
*/
|
|
|
|
seqstmt = makeNode(CreateSeqStmt);
|
|
|
|
seqstmt->for_identity = for_identity;
|
|
|
|
seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
|
|
|
|
seqstmt->options = seqoptions;
|
2017-05-17 22:31:56 +02:00
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
/*
|
|
|
|
* If a sequence data type was specified, add it to the options. Prepend
|
|
|
|
* to the list rather than append; in case a user supplied their own AS
|
|
|
|
* clause, the "redundant options" error will point to their occurrence,
|
|
|
|
* not our synthetic one.
|
|
|
|
*/
|
|
|
|
if (seqtypid)
|
2017-06-12 01:00:01 +02:00
|
|
|
seqstmt->options = lcons(makeDefElem("as",
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
(Node *) makeTypeNameFromOid(seqtypid, -1),
|
2017-06-12 01:00:01 +02:00
|
|
|
-1),
|
2017-04-06 14:33:16 +02:00
|
|
|
seqstmt->options);
|
|
|
|
|
|
|
|
/*
|
2017-05-17 22:31:56 +02:00
|
|
|
* If this is ALTER ADD COLUMN, make sure the sequence will be owned by
|
|
|
|
* the table's owner. The current user might be someone else (perhaps a
|
|
|
|
* superuser, or someone who's only a member of the owning role), but the
|
|
|
|
* SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
|
|
|
|
* exactly the same owning role.
|
2017-04-06 14:33:16 +02:00
|
|
|
*/
|
|
|
|
if (cxt->rel)
|
|
|
|
seqstmt->ownerId = cxt->rel->rd_rel->relowner;
|
|
|
|
else
|
|
|
|
seqstmt->ownerId = InvalidOid;
|
|
|
|
|
|
|
|
cxt->blist = lappend(cxt->blist, seqstmt);
|
|
|
|
|
2018-02-02 20:20:50 +01:00
|
|
|
/*
|
|
|
|
* Store the identity sequence name that we decided on. ALTER TABLE
|
|
|
|
* ... ADD COLUMN ... IDENTITY needs this so that it can fill the new
|
|
|
|
* column with values from the sequence, while the association of the
|
|
|
|
* sequence with the table is not set until after the ALTER TABLE.
|
|
|
|
*/
|
|
|
|
column->identitySequence = seqstmt->sequence;
|
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
/*
|
2017-05-17 22:31:56 +02:00
|
|
|
* Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
|
|
|
|
* owned by this column, and add it to the list of things to be done after
|
|
|
|
* this CREATE/ALTER TABLE.
|
2017-04-06 14:33:16 +02:00
|
|
|
*/
|
|
|
|
altseqstmt = makeNode(AlterSeqStmt);
|
|
|
|
altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
|
|
|
|
attnamelist = list_make3(makeString(snamespace),
|
|
|
|
makeString(cxt->relation->relname),
|
|
|
|
makeString(column->colname));
|
|
|
|
altseqstmt->options = list_make1(makeDefElem("owned_by",
|
|
|
|
(Node *) attnamelist, -1));
|
|
|
|
altseqstmt->for_identity = for_identity;
|
|
|
|
|
|
|
|
cxt->alist = lappend(cxt->alist, altseqstmt);
|
|
|
|
|
|
|
|
if (snamespace_p)
|
|
|
|
*snamespace_p = snamespace;
|
|
|
|
if (sname_p)
|
|
|
|
*sname_p = sname;
|
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* transformColumnDefinition -
|
|
|
|
* transform a single ColumnDef within CREATE TABLE
|
|
|
|
* Also used in ALTER TABLE ADD COLUMN
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
bool is_serial;
|
|
|
|
bool saw_nullable;
|
|
|
|
bool saw_default;
|
2017-04-06 14:33:16 +02:00
|
|
|
bool saw_identity;
|
2007-06-24 00:12:52 +02:00
|
|
|
ListCell *clist;
|
|
|
|
|
|
|
|
cxt->columns = lappend(cxt->columns, column);
|
|
|
|
|
|
|
|
/* Check for SERIAL pseudo-types */
|
|
|
|
is_serial = false;
|
2010-01-29 00:21:13 +01:00
|
|
|
if (column->typeName
|
|
|
|
&& list_length(column->typeName->names) == 1
|
|
|
|
&& !column->typeName->pct_type)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2009-07-16 08:33:46 +02:00
|
|
|
char *typname = strVal(linitial(column->typeName->names));
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2011-06-22 04:52:52 +02:00
|
|
|
if (strcmp(typname, "smallserial") == 0 ||
|
|
|
|
strcmp(typname, "serial2") == 0)
|
|
|
|
{
|
|
|
|
is_serial = true;
|
|
|
|
column->typeName->names = NIL;
|
|
|
|
column->typeName->typeOid = INT2OID;
|
|
|
|
}
|
|
|
|
else if (strcmp(typname, "serial") == 0 ||
|
2012-06-10 21:20:04 +02:00
|
|
|
strcmp(typname, "serial4") == 0)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
is_serial = true;
|
2009-07-16 08:33:46 +02:00
|
|
|
column->typeName->names = NIL;
|
|
|
|
column->typeName->typeOid = INT4OID;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
else if (strcmp(typname, "bigserial") == 0 ||
|
|
|
|
strcmp(typname, "serial8") == 0)
|
|
|
|
{
|
|
|
|
is_serial = true;
|
2009-07-16 08:33:46 +02:00
|
|
|
column->typeName->names = NIL;
|
|
|
|
column->typeName->typeOid = INT8OID;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
2008-03-21 23:10:56 +01:00
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* We have to reject "serial[]" explicitly, because once we've set
|
|
|
|
* typeid, LookupTypeName won't notice arrayBounds. We don't need any
|
|
|
|
* special coding for serial(typmod) though.
|
2008-03-21 23:10:56 +01:00
|
|
|
*/
|
2009-07-16 08:33:46 +02:00
|
|
|
if (is_serial && column->typeName->arrayBounds != NIL)
|
2008-03-21 23:10:56 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2009-07-30 04:45:38 +02:00
|
|
|
errmsg("array of serial is not implemented"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
column->typeName->location)));
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Do necessary work on the column type declaration */
|
2010-01-29 00:21:13 +01:00
|
|
|
if (column->typeName)
|
2011-01-25 21:42:03 +01:00
|
|
|
transformColumnType(cxt, column);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/* Special actions for SERIAL pseudo-types */
|
|
|
|
if (is_serial)
|
|
|
|
{
|
|
|
|
char *snamespace;
|
|
|
|
char *sname;
|
|
|
|
char *qstring;
|
|
|
|
A_Const *snamenode;
|
2008-04-29 16:59:17 +02:00
|
|
|
TypeCast *castnode;
|
2007-06-24 00:12:52 +02:00
|
|
|
FuncCall *funccallnode;
|
2017-04-06 14:33:16 +02:00
|
|
|
Constraint *constraint;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
generateSerialExtraStmts(cxt, column,
|
|
|
|
column->typeName->typeOid, NIL, false,
|
|
|
|
&snamespace, &sname);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create appropriate constraints for SERIAL. We do this in full,
|
|
|
|
* rather than shortcutting, so that we will detect any conflicting
|
|
|
|
* constraints the user wrote (like a different DEFAULT).
|
|
|
|
*
|
|
|
|
* Create an expression tree representing the function call
|
|
|
|
* nextval('sequencename'). We cannot reduce the raw tree to cooked
|
|
|
|
* form until after the sequence is created, but there's no need to do
|
|
|
|
* so.
|
|
|
|
*/
|
|
|
|
qstring = quote_qualified_identifier(snamespace, sname);
|
|
|
|
snamenode = makeNode(A_Const);
|
|
|
|
snamenode->val.type = T_String;
|
|
|
|
snamenode->val.val.str = qstring;
|
2008-08-29 01:09:48 +02:00
|
|
|
snamenode->location = -1;
|
2008-04-29 16:59:17 +02:00
|
|
|
castnode = makeNode(TypeCast);
|
2009-07-16 08:33:46 +02:00
|
|
|
castnode->typeName = SystemTypeName("regclass");
|
2008-04-29 16:59:17 +02:00
|
|
|
castnode->arg = (Node *) snamenode;
|
2008-08-29 01:09:48 +02:00
|
|
|
castnode->location = -1;
|
2013-07-01 20:41:33 +02:00
|
|
|
funccallnode = makeFuncCall(SystemFuncName("nextval"),
|
|
|
|
list_make1(castnode),
|
|
|
|
-1);
|
2007-06-24 00:12:52 +02:00
|
|
|
constraint = makeNode(Constraint);
|
|
|
|
constraint->contype = CONSTR_DEFAULT;
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->location = -1;
|
2007-06-24 00:12:52 +02:00
|
|
|
constraint->raw_expr = (Node *) funccallnode;
|
|
|
|
constraint->cooked_expr = NULL;
|
|
|
|
column->constraints = lappend(column->constraints, constraint);
|
|
|
|
|
|
|
|
constraint = makeNode(Constraint);
|
|
|
|
constraint->contype = CONSTR_NOTNULL;
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->location = -1;
|
2007-06-24 00:12:52 +02:00
|
|
|
column->constraints = lappend(column->constraints, constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process column constraints, if any... */
|
2011-01-25 21:42:03 +01:00
|
|
|
transformConstraintAttrs(cxt, column->constraints);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
saw_nullable = false;
|
|
|
|
saw_default = false;
|
2017-04-06 14:33:16 +02:00
|
|
|
saw_identity = false;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
foreach(clist, column->constraints)
|
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
Constraint *constraint = lfirst_node(Constraint, clist);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
switch (constraint->contype)
|
|
|
|
{
|
|
|
|
case CONSTR_NULL:
|
|
|
|
if (saw_nullable && column->is_not_null)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
|
2009-07-30 04:45:38 +02:00
|
|
|
column->colname, cxt->relation->relname),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->location)));
|
2017-08-16 06:22:32 +02:00
|
|
|
column->is_not_null = false;
|
2007-06-24 00:12:52 +02:00
|
|
|
saw_nullable = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_NOTNULL:
|
|
|
|
if (saw_nullable && !column->is_not_null)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
|
2009-07-30 04:45:38 +02:00
|
|
|
column->colname, cxt->relation->relname),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->location)));
|
2017-08-16 06:22:32 +02:00
|
|
|
column->is_not_null = true;
|
2007-06-24 00:12:52 +02:00
|
|
|
saw_nullable = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_DEFAULT:
|
|
|
|
if (saw_default)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
|
2009-07-30 04:45:38 +02:00
|
|
|
column->colname, cxt->relation->relname),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->location)));
|
2007-06-24 00:12:52 +02:00
|
|
|
column->raw_default = constraint->raw_expr;
|
|
|
|
Assert(constraint->cooked_expr == NULL);
|
|
|
|
saw_default = true;
|
|
|
|
break;
|
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
case CONSTR_IDENTITY:
|
2017-05-17 22:31:56 +02:00
|
|
|
{
|
|
|
|
Type ctype;
|
|
|
|
Oid typeOid;
|
2017-04-06 14:33:16 +02:00
|
|
|
|
2017-12-08 18:13:04 +01:00
|
|
|
if (cxt->ofType)
|
|
|
|
ereport(ERROR,
|
2018-01-31 22:45:37 +01:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("identity columns are not supported on typed tables")));
|
2017-12-08 18:13:04 +01:00
|
|
|
if (cxt->partbound)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2017-12-09 11:40:31 +01:00
|
|
|
errmsg("identity columns are not supported on partitions")));
|
2017-12-08 18:13:04 +01:00
|
|
|
|
2017-05-17 22:31:56 +02:00
|
|
|
ctype = typenameType(cxt->pstate, column->typeName, NULL);
|
|
|
|
typeOid = HeapTupleGetOid(ctype);
|
|
|
|
ReleaseSysCache(ctype);
|
2017-04-06 14:33:16 +02:00
|
|
|
|
2017-05-17 22:31:56 +02:00
|
|
|
if (saw_identity)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
column->colname, cxt->relation->relname),
|
2017-05-17 22:31:56 +02:00
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2017-04-06 14:33:16 +02:00
|
|
|
|
2017-05-17 22:31:56 +02:00
|
|
|
generateSerialExtraStmts(cxt, column,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
typeOid, constraint->options, true,
|
2017-05-17 22:31:56 +02:00
|
|
|
NULL, NULL);
|
2017-04-06 14:33:16 +02:00
|
|
|
|
2017-05-17 22:31:56 +02:00
|
|
|
column->identity = constraint->generated_when;
|
|
|
|
saw_identity = true;
|
2017-08-16 06:22:32 +02:00
|
|
|
column->is_not_null = true;
|
2017-05-17 22:31:56 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-04-06 14:33:16 +02:00
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
case CONSTR_CHECK:
|
2014-12-17 23:00:53 +01:00
|
|
|
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_PRIMARY:
|
2013-03-12 22:37:07 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2014-12-17 23:00:53 +01:00
|
|
|
errmsg("primary key constraints are not supported on foreign tables"),
|
2013-03-12 22:37:07 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2014-12-17 23:00:53 +01:00
|
|
|
/* FALL THRU */
|
2009-12-07 06:22:23 +01:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
case CONSTR_UNIQUE:
|
2013-03-12 22:37:07 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2014-12-17 23:00:53 +01:00
|
|
|
errmsg("unique constraints are not supported on foreign tables"),
|
2013-03-12 22:37:07 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2007-06-24 00:12:52 +02:00
|
|
|
if (constraint->keys == NIL)
|
|
|
|
constraint->keys = list_make1(makeString(column->colname));
|
|
|
|
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
case CONSTR_EXCLUSION:
|
|
|
|
/* grammar does not allow EXCLUDE as a column constraint */
|
|
|
|
elog(ERROR, "column exclusion constraints are not supported");
|
2007-06-24 00:12:52 +02:00
|
|
|
break;
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_FOREIGN:
|
2013-03-12 22:37:07 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2014-12-17 23:00:53 +01:00
|
|
|
errmsg("foreign key constraints are not supported on foreign tables"),
|
2013-03-12 22:37:07 +01:00
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2013-05-29 22:58:43 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
/*
|
|
|
|
* Fill in the current attribute's name and throw it into the
|
|
|
|
* list of FK constraints to be processed later.
|
|
|
|
*/
|
|
|
|
constraint->fk_attrs = list_make1(makeString(column->colname));
|
|
|
|
cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
case CONSTR_ATTR_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_NOT_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_DEFERRED:
|
|
|
|
case CONSTR_ATTR_IMMEDIATE:
|
|
|
|
/* transformConstraintAttrs took care of these */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized constraint type: %d",
|
|
|
|
constraint->contype);
|
|
|
|
break;
|
|
|
|
}
|
2017-04-06 14:33:16 +02:00
|
|
|
|
|
|
|
if (saw_default && saw_identity)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
|
|
|
|
column->colname, cxt->relation->relname),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
2011-08-05 19:24:03 +02:00
|
|
|
|
|
|
|
/*
|
2013-03-12 22:37:07 +01:00
|
|
|
* If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
|
|
|
|
* per-column foreign data wrapper options to this column after creation.
|
2011-08-05 19:24:03 +02:00
|
|
|
*/
|
|
|
|
if (column->fdwoptions != NIL)
|
|
|
|
{
|
|
|
|
AlterTableStmt *stmt;
|
2012-06-10 21:20:04 +02:00
|
|
|
AlterTableCmd *cmd;
|
2011-08-05 19:24:03 +02:00
|
|
|
|
|
|
|
cmd = makeNode(AlterTableCmd);
|
|
|
|
cmd->subtype = AT_AlterColumnGenericOptions;
|
|
|
|
cmd->name = column->colname;
|
|
|
|
cmd->def = (Node *) column->fdwoptions;
|
|
|
|
cmd->behavior = DROP_RESTRICT;
|
|
|
|
cmd->missing_ok = false;
|
|
|
|
|
|
|
|
stmt = makeNode(AlterTableStmt);
|
|
|
|
stmt->relation = cxt->relation;
|
|
|
|
stmt->cmds = NIL;
|
|
|
|
stmt->relkind = OBJECT_FOREIGN_TABLE;
|
|
|
|
stmt->cmds = lappend(stmt->cmds, cmd);
|
|
|
|
|
|
|
|
cxt->alist = lappend(cxt->alist, stmt);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformTableConstraint
|
|
|
|
* transform a Constraint node within CREATE TABLE or ALTER TABLE
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
switch (constraint->contype)
|
|
|
|
{
|
|
|
|
case CONSTR_PRIMARY:
|
2014-12-17 23:00:53 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("primary key constraints are not supported on foreign tables"),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
|
|
|
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
case CONSTR_UNIQUE:
|
2014-12-17 23:00:53 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("unique constraints are not supported on foreign tables"),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
|
|
|
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
case CONSTR_EXCLUSION:
|
2014-12-17 23:00:53 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("exclusion constraints are not supported on foreign tables"),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
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
|
|
|
if (cxt->ispartitioned)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("exclusion constraints are not supported on partitioned tables"),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_CHECK:
|
|
|
|
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_FOREIGN:
|
2014-12-17 23:00:53 +01:00
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("foreign key constraints are not supported on foreign tables"),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
constraint->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
|
|
|
|
break;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
case CONSTR_NULL:
|
|
|
|
case CONSTR_NOTNULL:
|
|
|
|
case CONSTR_DEFAULT:
|
|
|
|
case CONSTR_ATTR_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_NOT_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_DEFERRED:
|
|
|
|
case CONSTR_ATTR_IMMEDIATE:
|
|
|
|
elog(ERROR, "invalid context for constraint type %d",
|
|
|
|
constraint->contype);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized constraint type: %d",
|
|
|
|
constraint->contype);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-01-07 13:58:13 +01:00
|
|
|
* transformTableLikeClause
|
2007-06-24 00:12:52 +02:00
|
|
|
*
|
2012-01-07 13:58:13 +01:00
|
|
|
* Change the LIKE <srctable> portion of a CREATE TABLE statement into
|
2007-06-24 00:12:52 +02:00
|
|
|
* column definitions which recreate the user defined column portions of
|
2012-01-07 13:58:13 +01:00
|
|
|
* <srctable>.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
static void
|
2012-01-07 13:58:13 +01:00
|
|
|
transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
AttrNumber parent_attno;
|
|
|
|
Relation relation;
|
|
|
|
TupleDesc tupleDesc;
|
|
|
|
TupleConstr *constr;
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
AttrNumber *attmap;
|
2007-06-24 00:12:52 +02:00
|
|
|
AclResult aclresult;
|
2009-10-12 21:49:24 +02:00
|
|
|
char *comment;
|
2012-03-03 15:03:05 +01:00
|
|
|
ParseCallbackState pcbstate;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2013-03-12 22:37:07 +01:00
|
|
|
setup_parser_errposition_callback(&pcbstate, cxt->pstate,
|
|
|
|
table_like_clause->relation->location);
|
|
|
|
|
|
|
|
/* we could support LIKE in many cases, but worry about it another day */
|
|
|
|
if (cxt->isforeign)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("LIKE is not supported for creating foreign tables")));
|
2012-03-03 15:03:05 +01:00
|
|
|
|
|
|
|
relation = relation_openrv(table_like_clause->relation, AccessShareLock);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
if (relation->rd_rel->relkind != RELKIND_RELATION &&
|
|
|
|
relation->rd_rel->relkind != RELKIND_VIEW &&
|
2013-03-04 01:23:31 +01:00
|
|
|
relation->rd_rel->relkind != RELKIND_MATVIEW &&
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
|
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
|
|
|
relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
|
|
|
|
relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
|
2007-06-24 00:12:52 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2013-07-05 21:25:51 +02:00
|
|
|
errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
RelationGetRelationName(relation))));
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2012-03-03 15:03:05 +01:00
|
|
|
cancel_parser_errposition_callback(&pcbstate);
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
2012-03-03 15:03:05 +01:00
|
|
|
* Check for privileges
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2012-03-03 15:03:05 +01:00
|
|
|
if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
|
|
|
{
|
|
|
|
aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
|
|
|
|
ACL_USAGE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 15:26:34 +01:00
|
|
|
aclcheck_error(aclresult, OBJECT_TYPE,
|
2012-03-03 15:03:05 +01:00
|
|
|
RelationGetRelationName(relation));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
|
2012-06-10 21:20:04 +02:00
|
|
|
ACL_SELECT);
|
2012-03-03 15:03:05 +01:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 15:26:34 +01:00
|
|
|
aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
|
2012-03-03 15:03:05 +01:00
|
|
|
RelationGetRelationName(relation));
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
tupleDesc = RelationGetDescr(relation);
|
|
|
|
constr = tupleDesc->constr;
|
|
|
|
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Initialize column number map for map_variable_attnos(). We need this
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
* since dropped columns in the source table aren't copied, so the new
|
|
|
|
* table can have different column numbers.
|
|
|
|
*/
|
|
|
|
attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts);
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Insert the copied attributes into the cxt for the new table definition.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
for (parent_attno = 1; parent_attno <= tupleDesc->natts;
|
|
|
|
parent_attno++)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
|
|
|
|
parent_attno - 1);
|
2007-06-24 00:12:52 +02:00
|
|
|
char *attributeName = NameStr(attribute->attname);
|
|
|
|
ColumnDef *def;
|
|
|
|
|
|
|
|
/*
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
* Ignore dropped columns in the parent. attmap entry is left zero.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
if (attribute->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new column, which is marked as NOT inherited.
|
|
|
|
*
|
|
|
|
* For constraints, ONLY the NOT NULL constraint is inherited by the
|
|
|
|
* new column definition per SQL99.
|
|
|
|
*/
|
|
|
|
def = makeNode(ColumnDef);
|
|
|
|
def->colname = pstrdup(attributeName);
|
2009-07-16 08:33:46 +02:00
|
|
|
def->typeName = makeTypeNameFromOid(attribute->atttypid,
|
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
|
|
|
attribute->atttypmod);
|
2007-06-24 00:12:52 +02:00
|
|
|
def->inhcount = 0;
|
|
|
|
def->is_local = true;
|
|
|
|
def->is_not_null = attribute->attnotnull;
|
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
|
|
|
def->is_from_type = false;
|
2017-04-28 19:52:17 +02:00
|
|
|
def->is_from_parent = false;
|
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
|
|
|
def->storage = 0;
|
2007-06-24 00:12:52 +02:00
|
|
|
def->raw_default = NULL;
|
|
|
|
def->cooked_default = 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
|
|
|
def->collClause = NULL;
|
|
|
|
def->collOid = attribute->attcollation;
|
2007-06-24 00:12:52 +02:00
|
|
|
def->constraints = NIL;
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
def->location = -1;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add to column list
|
|
|
|
*/
|
|
|
|
cxt->columns = lappend(cxt->columns, def);
|
|
|
|
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
attmap[parent_attno - 1] = list_length(cxt->columns);
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* Copy default, if present and the default has been requested
|
|
|
|
*/
|
2009-10-12 21:49:24 +02:00
|
|
|
if (attribute->atthasdef &&
|
2012-01-07 13:58:13 +01:00
|
|
|
(table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS))
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2009-10-06 02:55:26 +02:00
|
|
|
Node *this_default = NULL;
|
2007-06-24 00:12:52 +02:00
|
|
|
AttrDefault *attrdef;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Find default in constraint structure */
|
|
|
|
Assert(constr != NULL);
|
|
|
|
attrdef = constr->defval;
|
|
|
|
for (i = 0; i < constr->num_defval; i++)
|
|
|
|
{
|
|
|
|
if (attrdef[i].adnum == parent_attno)
|
|
|
|
{
|
2009-10-06 02:55:26 +02:00
|
|
|
this_default = stringToNode(attrdef[i].adbin);
|
2007-06-24 00:12:52 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Assert(this_default != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If default expr could contain any vars, we'd need to fix 'em,
|
|
|
|
* but it can't; so default is ready to apply to child.
|
|
|
|
*/
|
|
|
|
|
2009-10-06 02:55:26 +02:00
|
|
|
def->cooked_default = this_default;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
2009-10-12 21:49:24 +02:00
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
/*
|
|
|
|
* Copy identity if requested
|
|
|
|
*/
|
|
|
|
if (attribute->attidentity &&
|
|
|
|
(table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY))
|
|
|
|
{
|
2017-05-17 22:31:56 +02:00
|
|
|
Oid seq_relid;
|
2017-04-06 14:33:16 +02:00
|
|
|
List *seq_options;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find sequence owned by old column; extract sequence parameters;
|
|
|
|
* build new create sequence command
|
|
|
|
*/
|
|
|
|
seq_relid = getOwnedSequence(RelationGetRelid(relation), attribute->attnum);
|
|
|
|
seq_options = sequence_options(seq_relid);
|
|
|
|
generateSerialExtraStmts(cxt, def,
|
|
|
|
InvalidOid, seq_options, true,
|
|
|
|
NULL, NULL);
|
|
|
|
def->identity = attribute->attidentity;
|
|
|
|
}
|
|
|
|
|
2009-10-12 21:49:24 +02:00
|
|
|
/* Likewise, copy storage if requested */
|
2012-01-07 13:58:13 +01:00
|
|
|
if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE)
|
2009-10-12 21:49:24 +02:00
|
|
|
def->storage = attribute->attstorage;
|
2009-10-13 02:53:08 +02:00
|
|
|
else
|
|
|
|
def->storage = 0;
|
2009-10-12 21:49:24 +02:00
|
|
|
|
|
|
|
/* Likewise, copy comment if requested */
|
2012-01-07 13:58:13 +01:00
|
|
|
if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
|
2009-11-14 00:49:23 +01:00
|
|
|
(comment = GetComment(attribute->attrelid,
|
|
|
|
RelationRelationId,
|
|
|
|
attribute->attnum)) != NULL)
|
2009-10-12 21:49:24 +02:00
|
|
|
{
|
|
|
|
CommentStmt *stmt = makeNode(CommentStmt);
|
|
|
|
|
|
|
|
stmt->objtype = OBJECT_COLUMN;
|
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
|
|
|
stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
makeString(cxt->relation->relname),
|
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
|
|
|
makeString(def->colname));
|
2009-10-12 21:49:24 +02:00
|
|
|
stmt->comment = comment;
|
|
|
|
|
|
|
|
cxt->alist = lappend(cxt->alist, stmt);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
|
2015-10-06 03:19:16 +02:00
|
|
|
/* We use oids if at least one LIKE'ed table has oids. */
|
2016-12-22 22:23:33 +01:00
|
|
|
cxt->hasoids |= relation->rd_rel->relhasoids;
|
2015-10-06 03:19:16 +02:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Copy CHECK constraints if requested, being careful to adjust attribute
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
* numbers so they match the child.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2012-01-07 13:58:13 +01:00
|
|
|
if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
|
2009-11-14 00:49:23 +01:00
|
|
|
tupleDesc->constr)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
int ccnum;
|
|
|
|
|
|
|
|
for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
|
|
|
|
{
|
|
|
|
char *ccname = tupleDesc->constr->check[ccnum].ccname;
|
|
|
|
char *ccbin = tupleDesc->constr->check[ccnum].ccbin;
|
|
|
|
Constraint *n = makeNode(Constraint);
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
Node *ccbin_node;
|
|
|
|
bool found_whole_row;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
ccbin_node = map_variable_attnos(stringToNode(ccbin),
|
|
|
|
1, 0,
|
|
|
|
attmap, tupleDesc->natts,
|
2017-08-03 17:21:29 +02:00
|
|
|
InvalidOid, &found_whole_row);
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We reject whole-row variables because the whole point of LIKE
|
|
|
|
* is that the new table's rowtype might later diverge from the
|
|
|
|
* parent's. So, while translation might be possible right now,
|
|
|
|
* it wouldn't be possible to guarantee it would work in future.
|
|
|
|
*/
|
|
|
|
if (found_whole_row)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot convert whole-row table reference"),
|
|
|
|
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
|
|
|
|
ccname,
|
|
|
|
RelationGetRelationName(relation))));
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
n->contype = CONSTR_CHECK;
|
2009-07-30 04:45:38 +02:00
|
|
|
n->location = -1;
|
|
|
|
n->conname = pstrdup(ccname);
|
2007-06-24 00:12:52 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = nodeToString(ccbin_node);
|
2009-07-30 04:45:38 +02:00
|
|
|
cxt->ckconstraints = lappend(cxt->ckconstraints, n);
|
2009-10-12 21:49:24 +02:00
|
|
|
|
|
|
|
/* Copy comment on constraint */
|
2012-01-07 13:58:13 +01:00
|
|
|
if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
|
2012-04-03 07:11:51 +02:00
|
|
|
(comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
n->conname, false),
|
2009-11-14 00:49:23 +01:00
|
|
|
ConstraintRelationId,
|
|
|
|
0)) != NULL)
|
2009-10-12 21:49:24 +02:00
|
|
|
{
|
|
|
|
CommentStmt *stmt = makeNode(CommentStmt);
|
|
|
|
|
2014-12-23 13:06:44 +01:00
|
|
|
stmt->objtype = OBJECT_TABCONSTRAINT;
|
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
|
|
|
stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
makeString(cxt->relation->relname),
|
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
|
|
|
makeString(n->conname));
|
2009-10-12 21:49:24 +02:00
|
|
|
stmt->comment = comment;
|
|
|
|
|
|
|
|
cxt->alist = lappend(cxt->alist, stmt);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/*
|
|
|
|
* Likewise, copy indexes if requested
|
|
|
|
*/
|
2012-01-07 13:58:13 +01:00
|
|
|
if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
|
2009-10-12 21:49:24 +02:00
|
|
|
relation->rd_rel->relhasindex)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
|
|
|
List *parent_indexes;
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
parent_indexes = RelationGetIndexList(relation);
|
|
|
|
|
|
|
|
foreach(l, parent_indexes)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid parent_index_oid = lfirst_oid(l);
|
|
|
|
Relation parent_index;
|
|
|
|
IndexStmt *index_stmt;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
parent_index = index_open(parent_index_oid, AccessShareLock);
|
|
|
|
|
|
|
|
/* Build CREATE INDEX statement to recreate the parent_index */
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
index_stmt = generateClonedIndexStmt(cxt->relation, InvalidOid,
|
|
|
|
parent_index,
|
2018-02-19 20:59:37 +01:00
|
|
|
attmap, tupleDesc->natts, NULL);
|
2007-07-17 07:02:03 +02:00
|
|
|
|
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
|
|
|
/* Copy comment on index, if requested */
|
2012-01-07 13:58:13 +01:00
|
|
|
if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
|
2009-10-12 21:49:24 +02:00
|
|
|
{
|
|
|
|
comment = GetComment(parent_index_oid, RelationRelationId, 0);
|
2009-12-23 00:54:17 +01:00
|
|
|
|
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
|
|
|
/*
|
|
|
|
* We make use of IndexStmt's idxcomment option, so as not to
|
|
|
|
* need to know now what name the index will have.
|
|
|
|
*/
|
|
|
|
index_stmt->idxcomment = comment;
|
2009-10-12 21:49:24 +02:00
|
|
|
}
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/* Save it in the inh_indexes list for the time being */
|
2007-07-17 07:02:03 +02:00
|
|
|
cxt->inh_indexes = lappend(cxt->inh_indexes, index_stmt);
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
index_close(parent_index, AccessShareLock);
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
/*
|
|
|
|
* Likewise, copy extended statistics if requested
|
|
|
|
*/
|
|
|
|
if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS)
|
|
|
|
{
|
|
|
|
List *parent_extstats;
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
parent_extstats = RelationGetStatExtList(relation);
|
|
|
|
|
|
|
|
foreach(l, parent_extstats)
|
|
|
|
{
|
|
|
|
Oid parent_stat_oid = lfirst_oid(l);
|
|
|
|
CreateStatsStmt *stats_stmt;
|
|
|
|
|
|
|
|
stats_stmt = generateClonedExtStatsStmt(cxt->relation,
|
|
|
|
RelationGetRelid(relation),
|
|
|
|
parent_stat_oid);
|
|
|
|
|
|
|
|
/* Copy comment on statistics object, if requested */
|
|
|
|
if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
|
|
|
|
{
|
|
|
|
comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We make use of CreateStatsStmt's stxcomment option, so as
|
|
|
|
* not to need to know now what name the statistics will have.
|
|
|
|
*/
|
|
|
|
stats_stmt->stxcomment = comment;
|
|
|
|
}
|
|
|
|
|
|
|
|
cxt->extstats = lappend(cxt->extstats, stats_stmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_free(parent_extstats);
|
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* Close the parent rel, but keep our AccessShareLock on it until xact
|
2014-05-06 18:12:18 +02:00
|
|
|
* commit. That will prevent someone else from deleting or ALTERing the
|
2007-06-24 00:12:52 +02:00
|
|
|
* parent before the child is committed.
|
|
|
|
*/
|
|
|
|
heap_close(relation, NoLock);
|
|
|
|
}
|
|
|
|
|
2010-01-29 00:21:13 +01:00
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
|
2010-01-29 00:21:13 +01:00
|
|
|
{
|
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
int i;
|
|
|
|
Oid ofTypeId;
|
|
|
|
|
|
|
|
AssertArg(ofTypename);
|
|
|
|
|
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
|
|
|
tuple = typenameType(NULL, ofTypename, NULL);
|
2011-04-21 03:35:15 +02:00
|
|
|
check_of_type(tuple);
|
2010-01-29 00:21:13 +01:00
|
|
|
ofTypeId = HeapTupleGetOid(tuple);
|
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
|
|
|
ofTypename->typeOid = ofTypeId; /* cached for later */
|
2010-01-29 00:21:13 +01:00
|
|
|
|
|
|
|
tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
|
|
|
|
for (i = 0; i < tupdesc->natts; i++)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
|
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
|
|
|
ColumnDef *n;
|
2010-01-29 00:21:13 +01:00
|
|
|
|
2010-09-26 13:41:03 +02:00
|
|
|
if (attr->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
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
|
|
|
n = makeNode(ColumnDef);
|
2010-02-03 06:46:37 +01:00
|
|
|
n->colname = pstrdup(NameStr(attr->attname));
|
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
|
|
|
n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod);
|
|
|
|
n->inhcount = 0;
|
2010-01-29 00:21:13 +01:00
|
|
|
n->is_local = true;
|
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
|
|
|
n->is_not_null = false;
|
2010-01-29 00:21:13 +01:00
|
|
|
n->is_from_type = true;
|
2017-04-28 19:52:17 +02:00
|
|
|
n->is_from_parent = false;
|
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
|
|
|
n->storage = 0;
|
|
|
|
n->raw_default = NULL;
|
|
|
|
n->cooked_default = NULL;
|
|
|
|
n->collClause = NULL;
|
|
|
|
n->collOid = attr->attcollation;
|
|
|
|
n->constraints = NIL;
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
n->location = -1;
|
2010-01-29 00:21:13 +01:00
|
|
|
cxt->columns = lappend(cxt->columns, n);
|
|
|
|
}
|
|
|
|
DecrTupleDescRefCount(tupdesc);
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
2007-12-02 00:44:44 +01:00
|
|
|
* Generate an IndexStmt node using information from an already existing index
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
* "source_idx", for the rel identified either by heapRel or heapRelid.
|
|
|
|
*
|
|
|
|
* Attribute numbers should be adjusted according to attmap.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
IndexStmt *
|
|
|
|
generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, Relation source_idx,
|
2018-02-19 20:59:37 +01:00
|
|
|
const AttrNumber *attmap, int attmap_length, Oid *constraintOid)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2007-12-02 00:44:44 +01:00
|
|
|
Oid source_relid = RelationGetRelid(source_idx);
|
2007-11-15 22:14:46 +01:00
|
|
|
HeapTuple ht_idxrel;
|
2007-12-02 00:44:44 +01:00
|
|
|
HeapTuple ht_idx;
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
HeapTuple ht_am;
|
2007-11-15 22:14:46 +01:00
|
|
|
Form_pg_class idxrelrec;
|
2007-12-02 00:44:44 +01:00
|
|
|
Form_pg_index idxrec;
|
2007-11-15 22:14:46 +01:00
|
|
|
Form_pg_am amrec;
|
2011-03-26 21:35:25 +01:00
|
|
|
oidvector *indcollation;
|
2007-12-02 00:44:44 +01:00
|
|
|
oidvector *indclass;
|
|
|
|
IndexStmt *index;
|
|
|
|
List *indexprs;
|
2007-11-15 22:14:46 +01:00
|
|
|
ListCell *indexpr_item;
|
|
|
|
Oid indrelid;
|
|
|
|
int keyno;
|
|
|
|
Oid keycoltype;
|
2007-12-02 00:44:44 +01:00
|
|
|
Datum datum;
|
2007-11-15 22:14:46 +01:00
|
|
|
bool isnull;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
Assert((heapRel == NULL && OidIsValid(heapRelid)) ||
|
|
|
|
(heapRel != NULL && !OidIsValid(heapRelid)));
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/*
|
|
|
|
* Fetch pg_class tuple of source index. We can't use the copy in the
|
|
|
|
* relcache entry because it doesn't include optional fields.
|
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(source_relid));
|
2007-12-02 00:44:44 +01:00
|
|
|
if (!HeapTupleIsValid(ht_idxrel))
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u", source_relid);
|
|
|
|
idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/* Fetch pg_index tuple for source index from relcache entry */
|
|
|
|
ht_idx = source_idx->rd_indextuple;
|
2007-07-17 07:02:03 +02:00
|
|
|
idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
|
|
|
|
indrelid = idxrec->indrelid;
|
|
|
|
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
/* Fetch the pg_am tuple of the index' access method */
|
|
|
|
ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
|
|
|
|
if (!HeapTupleIsValid(ht_am))
|
|
|
|
elog(ERROR, "cache lookup failed for access method %u",
|
|
|
|
idxrelrec->relam);
|
|
|
|
amrec = (Form_pg_am) GETSTRUCT(ht_am);
|
2007-12-02 00:44:44 +01:00
|
|
|
|
2011-03-26 21:35:25 +01:00
|
|
|
/* Extract indcollation from the pg_index tuple */
|
|
|
|
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
|
|
|
Anum_pg_index_indcollation, &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
indcollation = (oidvector *) DatumGetPointer(datum);
|
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
/* Extract indclass from the pg_index tuple */
|
2007-12-02 00:44:44 +01:00
|
|
|
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
|
|
|
Anum_pg_index_indclass, &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
indclass = (oidvector *) DatumGetPointer(datum);
|
|
|
|
|
|
|
|
/* Begin building the IndexStmt */
|
2007-07-17 07:02:03 +02:00
|
|
|
index = makeNode(IndexStmt);
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
index->relation = heapRel;
|
|
|
|
index->relationId = heapRelid;
|
2007-12-02 00:44:44 +01:00
|
|
|
index->accessMethod = pstrdup(NameStr(amrec->amname));
|
2008-02-07 18:09:51 +01:00
|
|
|
if (OidIsValid(idxrelrec->reltablespace))
|
|
|
|
index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
|
|
|
|
else
|
|
|
|
index->tableSpace = NULL;
|
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
|
|
|
index->excludeOpNames = NIL;
|
|
|
|
index->idxcomment = NULL;
|
2011-01-25 21:42:03 +01:00
|
|
|
index->indexOid = InvalidOid;
|
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
|
|
|
index->oldNode = InvalidOid;
|
2007-07-17 07:02:03 +02:00
|
|
|
index->unique = idxrec->indisunique;
|
|
|
|
index->primary = idxrec->indisprimary;
|
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
|
|
|
index->transformed = true; /* don't need transformIndexStmt */
|
2007-12-02 00:44:44 +01:00
|
|
|
index->concurrent = false;
|
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
|
|
|
index->if_not_exists = false;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
2007-07-17 07:02:03 +02:00
|
|
|
* We don't try to preserve the name of the source index; instead, just
|
2016-07-28 19:26:58 +02:00
|
|
|
* let DefineIndex() choose a reasonable name. (If we tried to preserve
|
|
|
|
* the name, we'd get duplicate-relation-name failures unless the source
|
|
|
|
* table was in a different schema.)
|
2007-07-17 07:02:03 +02:00
|
|
|
*/
|
|
|
|
index->idxname = NULL;
|
|
|
|
|
|
|
|
/*
|
2009-12-07 06:22:23 +01:00
|
|
|
* If the index is marked PRIMARY or has an exclusion condition, it's
|
|
|
|
* certainly from a constraint; else, if it's not marked UNIQUE, it
|
|
|
|
* certainly isn't. If it is or might be from a constraint, we have to
|
|
|
|
* fetch the pg_constraint record.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2011-01-25 23:51:59 +01:00
|
|
|
if (index->primary || index->unique || idxrec->indisexclusion)
|
2009-07-29 22:56:21 +02:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
Oid constraintId = get_index_constraint(source_relid);
|
2009-07-29 22:56:21 +02:00
|
|
|
|
|
|
|
if (OidIsValid(constraintId))
|
|
|
|
{
|
|
|
|
HeapTuple ht_constr;
|
|
|
|
Form_pg_constraint conrec;
|
|
|
|
|
2018-02-19 20:59:37 +01:00
|
|
|
if (constraintOid)
|
|
|
|
*constraintOid = constraintId;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
ht_constr = SearchSysCache1(CONSTROID,
|
2010-02-26 03:01:40 +01:00
|
|
|
ObjectIdGetDatum(constraintId));
|
2009-07-29 22:56:21 +02:00
|
|
|
if (!HeapTupleIsValid(ht_constr))
|
|
|
|
elog(ERROR, "cache lookup failed for constraint %u",
|
|
|
|
constraintId);
|
|
|
|
conrec = (Form_pg_constraint) GETSTRUCT(ht_constr);
|
|
|
|
|
|
|
|
index->isconstraint = true;
|
|
|
|
index->deferrable = conrec->condeferrable;
|
|
|
|
index->initdeferred = conrec->condeferred;
|
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
/* If it's an exclusion constraint, we need the operator names */
|
2011-01-25 23:51:59 +01:00
|
|
|
if (idxrec->indisexclusion)
|
2009-12-07 06:22:23 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
Datum *elems;
|
|
|
|
int nElems;
|
|
|
|
int i;
|
2009-12-07 06:22:23 +01:00
|
|
|
|
|
|
|
Assert(conrec->contype == CONSTRAINT_EXCLUSION);
|
|
|
|
/* Extract operator OIDs from the pg_constraint tuple */
|
|
|
|
datum = SysCacheGetAttr(CONSTROID, ht_constr,
|
|
|
|
Anum_pg_constraint_conexclop,
|
|
|
|
&isnull);
|
|
|
|
if (isnull)
|
|
|
|
elog(ERROR, "null conexclop for constraint %u",
|
|
|
|
constraintId);
|
|
|
|
|
|
|
|
deconstruct_array(DatumGetArrayTypeP(datum),
|
|
|
|
OIDOID, sizeof(Oid), true, 'i',
|
|
|
|
&elems, NULL, &nElems);
|
|
|
|
|
|
|
|
for (i = 0; i < nElems; i++)
|
|
|
|
{
|
|
|
|
Oid operid = DatumGetObjectId(elems[i]);
|
|
|
|
HeapTuple opertup;
|
|
|
|
Form_pg_operator operform;
|
|
|
|
char *oprname;
|
|
|
|
char *nspname;
|
|
|
|
List *namelist;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
opertup = SearchSysCache1(OPEROID,
|
|
|
|
ObjectIdGetDatum(operid));
|
2009-12-07 06:22:23 +01:00
|
|
|
if (!HeapTupleIsValid(opertup))
|
|
|
|
elog(ERROR, "cache lookup failed for operator %u",
|
|
|
|
operid);
|
|
|
|
operform = (Form_pg_operator) GETSTRUCT(opertup);
|
|
|
|
oprname = pstrdup(NameStr(operform->oprname));
|
|
|
|
/* For simplicity we always schema-qualify the op name */
|
|
|
|
nspname = get_namespace_name(operform->oprnamespace);
|
|
|
|
namelist = list_make2(makeString(nspname),
|
|
|
|
makeString(oprname));
|
|
|
|
index->excludeOpNames = lappend(index->excludeOpNames,
|
|
|
|
namelist);
|
|
|
|
ReleaseSysCache(opertup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-29 22:56:21 +02:00
|
|
|
ReleaseSysCache(ht_constr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
index->isconstraint = false;
|
|
|
|
}
|
2007-12-02 00:44:44 +01:00
|
|
|
else
|
2009-07-29 22:56:21 +02:00
|
|
|
index->isconstraint = false;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
/* Get the index expressions, if any */
|
2007-12-02 00:44:44 +01:00
|
|
|
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
|
|
|
Anum_pg_index_indexprs, &isnull);
|
|
|
|
if (!isnull)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2007-07-17 07:02:03 +02:00
|
|
|
char *exprsString;
|
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
exprsString = TextDatumGetCString(datum);
|
2007-07-17 07:02:03 +02:00
|
|
|
indexprs = (List *) stringToNode(exprsString);
|
|
|
|
}
|
2007-12-02 00:44:44 +01:00
|
|
|
else
|
|
|
|
indexprs = NIL;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/* Build the list of IndexElem */
|
|
|
|
index->indexParams = NIL;
|
2018-04-07 22:00:39 +02:00
|
|
|
index->indexIncludingParams = NIL;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
indexpr_item = list_head(indexprs);
|
2018-04-07 22:00:39 +02:00
|
|
|
for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
IndexElem *iparam;
|
2007-07-17 07:02:03 +02:00
|
|
|
AttrNumber attnum = idxrec->indkey.values[keyno];
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
|
|
|
|
keyno);
|
2007-12-02 00:44:44 +01:00
|
|
|
int16 opt = source_idx->rd_indoption[keyno];
|
2016-04-08 20:52:13 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam = makeNode(IndexElem);
|
|
|
|
|
|
|
|
if (AttributeNumberIsValid(attnum))
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2007-07-17 07:02:03 +02:00
|
|
|
/* Simple index column */
|
|
|
|
char *attname;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2018-02-12 23:30:30 +01:00
|
|
|
attname = get_attname(indrelid, attnum, false);
|
2007-07-17 07:02:03 +02:00
|
|
|
keycoltype = get_atttype(indrelid, attnum);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam->name = attname;
|
|
|
|
iparam->expr = NULL;
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
else
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
|
|
|
/* Expressional index */
|
|
|
|
Node *indexkey;
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
bool found_whole_row;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
if (indexpr_item == NULL)
|
|
|
|
elog(ERROR, "too few entries in indexprs list");
|
|
|
|
indexkey = (Node *) lfirst(indexpr_item);
|
2007-12-02 00:44:44 +01:00
|
|
|
indexpr_item = lnext(indexpr_item);
|
|
|
|
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
/* Adjust Vars to match new table's column numbering */
|
|
|
|
indexkey = map_variable_attnos(indexkey,
|
|
|
|
1, 0,
|
|
|
|
attmap, attmap_length,
|
2017-08-03 17:21:29 +02:00
|
|
|
InvalidOid, &found_whole_row);
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
|
|
|
|
/* As in transformTableLikeClause, reject whole-row variables */
|
|
|
|
if (found_whole_row)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot convert whole-row table reference"),
|
|
|
|
errdetail("Index \"%s\" contains a whole-row table reference.",
|
|
|
|
RelationGetRelationName(source_idx))));
|
2007-12-02 00:44:44 +01:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam->name = NULL;
|
|
|
|
iparam->expr = indexkey;
|
|
|
|
|
|
|
|
keycoltype = exprType(indexkey);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
Adjust naming of indexes and their columns per recent discussion.
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N". Digits are
appended to this name if needed to make the column name unique within the
index. (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails. Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)
Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN. Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)
An example of the results:
regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
Column | Type | Definition
--------+---------+------------
f1 | integer | f1
lower | text | lower(f2)
btree, for table "public.foo"
2009-12-23 03:35:25 +01:00
|
|
|
/* Copy the original index column name */
|
2017-08-20 20:19:07 +02:00
|
|
|
iparam->indexcolname = pstrdup(NameStr(attr->attname));
|
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
|
|
|
|
2011-03-26 21:35:25 +01:00
|
|
|
/* Add the collation name, if non-default */
|
|
|
|
iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
|
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/* Add the operator class name, if non-default */
|
|
|
|
iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam->ordering = SORTBY_DEFAULT;
|
|
|
|
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
|
|
|
|
|
|
|
|
/* Adjust options if necessary */
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
if (source_idx->rd_amroutine->amcanorder)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2007-12-02 00:44:44 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If it supports sort ordering, copy DESC and NULLS opts. Don't
|
|
|
|
* set non-default settings unnecessarily, though, so as to
|
|
|
|
* improve the chance of recognizing equivalence to constraint
|
|
|
|
* indexes.
|
2007-12-02 00:44:44 +01:00
|
|
|
*/
|
2007-07-17 07:02:03 +02:00
|
|
|
if (opt & INDOPTION_DESC)
|
2007-12-02 00:44:44 +01:00
|
|
|
{
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam->ordering = SORTBY_DESC;
|
2007-12-02 00:44:44 +01:00
|
|
|
if ((opt & INDOPTION_NULLS_FIRST) == 0)
|
|
|
|
iparam->nulls_ordering = SORTBY_NULLS_LAST;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opt & INDOPTION_NULLS_FIRST)
|
|
|
|
iparam->nulls_ordering = SORTBY_NULLS_FIRST;
|
|
|
|
}
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
index->indexParams = lappend(index->indexParams, iparam);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
/* Handle included columns separately */
|
|
|
|
for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
|
|
|
|
{
|
|
|
|
IndexElem *iparam;
|
|
|
|
AttrNumber attnum = idxrec->indkey.values[keyno];
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
|
|
|
|
keyno);
|
|
|
|
|
|
|
|
iparam = makeNode(IndexElem);
|
|
|
|
|
|
|
|
if (AttributeNumberIsValid(attnum))
|
|
|
|
{
|
|
|
|
/* Simple index column */
|
|
|
|
char *attname;
|
|
|
|
|
|
|
|
attname = get_attname(indrelid, attnum, false);
|
|
|
|
keycoltype = get_atttype(indrelid, attnum);
|
|
|
|
|
|
|
|
iparam->name = attname;
|
|
|
|
iparam->expr = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("expressions are not supported in included columns")));
|
|
|
|
|
|
|
|
/* Copy the original index column name */
|
|
|
|
iparam->indexcolname = pstrdup(NameStr(attr->attname));
|
|
|
|
|
|
|
|
index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
|
|
|
|
}
|
2007-12-02 00:44:44 +01:00
|
|
|
/* Copy reloptions if any */
|
|
|
|
datum = SysCacheGetAttr(RELOID, ht_idxrel,
|
|
|
|
Anum_pg_class_reloptions, &isnull);
|
|
|
|
if (!isnull)
|
|
|
|
index->options = untransformRelOptions(datum);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/* If it's a partial index, decompile and append the predicate */
|
2007-12-02 00:44:44 +01:00
|
|
|
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
|
|
|
Anum_pg_index_indpred, &isnull);
|
|
|
|
if (!isnull)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
|
|
|
char *pred_str;
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
Node *pred_tree;
|
|
|
|
bool found_whole_row;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
/* Convert text string to node tree */
|
2008-03-25 23:42:46 +01:00
|
|
|
pred_str = TextDatumGetCString(datum);
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
pred_tree = (Node *) stringToNode(pred_str);
|
|
|
|
|
|
|
|
/* Adjust Vars to match new table's column numbering */
|
|
|
|
pred_tree = map_variable_attnos(pred_tree,
|
|
|
|
1, 0,
|
|
|
|
attmap, attmap_length,
|
2017-08-03 17:21:29 +02:00
|
|
|
InvalidOid, &found_whole_row);
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
|
|
|
|
/* As in transformTableLikeClause, reject whole-row variables */
|
|
|
|
if (found_whole_row)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot convert whole-row table reference"),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errdetail("Index \"%s\" contains a whole-row table reference.",
|
|
|
|
RelationGetRelationName(source_idx))));
|
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (that
is, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE or
table inheritance produced incorrect results: the copied Var still claimed
to have the rowtype of the source table, rather than the created table.
For the LIKE case, it seems reasonable to just throw error for this
situation, since the point of LIKE is that the new table is not permanently
coupled to the old, so there's no reason to assume its rowtype will stay
compatible. In the inheritance case, we should ideally allow such
constraints, but doing so will require nontrivial refactoring of CREATE
TABLE processing (because we'd need to know the OID of the new table's
rowtype before we adjust inherited CHECK constraints). In view of the lack
of previous complaints, that doesn't seem worth the risk in a back-patched
bug fix, so just make it throw error for the inheritance case as well.
Along the way, replace change_varattnos_of_a_node() with a more robust
function map_variable_attnos(), which is capable of being extended to
handle insertion of ConvertRowtypeExpr whenever we get around to fixing
the inheritance case nicely, and in the meantime it returns a failure
indication to the caller so that a helpful message with some context can be
thrown. Also, this code will do the right thing with subselects (if we
ever allow them in CHECK or indexes), and it range-checks varattnos before
using them to index into the map array.
Per report from Sergey Konoplev. Back-patch to all supported branches.
2012-06-30 22:43:50 +02:00
|
|
|
|
|
|
|
index->whereClause = pred_tree;
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/* Clean up */
|
|
|
|
ReleaseSysCache(ht_idxrel);
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
ReleaseSysCache(ht_am);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
return index;
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
/*
|
|
|
|
* Generate a CreateStatsStmt node using information from an already existing
|
|
|
|
* extended statistic "source_statsid", for the rel identified by heapRel and
|
|
|
|
* heapRelid.
|
|
|
|
*/
|
|
|
|
static CreateStatsStmt *
|
|
|
|
generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
|
|
|
|
Oid source_statsid)
|
|
|
|
{
|
|
|
|
HeapTuple ht_stats;
|
|
|
|
Form_pg_statistic_ext statsrec;
|
|
|
|
CreateStatsStmt *stats;
|
|
|
|
List *stat_types = NIL;
|
|
|
|
List *def_names = NIL;
|
|
|
|
bool isnull;
|
|
|
|
Datum datum;
|
|
|
|
ArrayType *arr;
|
|
|
|
char *enabled;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Assert(OidIsValid(heapRelid));
|
|
|
|
Assert(heapRel != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch pg_statistic_ext tuple of source statistics object.
|
|
|
|
*/
|
|
|
|
ht_stats = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(source_statsid));
|
|
|
|
if (!HeapTupleIsValid(ht_stats))
|
|
|
|
elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
|
|
|
|
statsrec = (Form_pg_statistic_ext) GETSTRUCT(ht_stats);
|
|
|
|
|
|
|
|
/* Determine which statistics types exist */
|
|
|
|
datum = SysCacheGetAttr(STATEXTOID, ht_stats,
|
|
|
|
Anum_pg_statistic_ext_stxkind, &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
arr = DatumGetArrayTypeP(datum);
|
|
|
|
if (ARR_NDIM(arr) != 1 ||
|
|
|
|
ARR_HASNULL(arr) ||
|
|
|
|
ARR_ELEMTYPE(arr) != CHAROID)
|
|
|
|
elog(ERROR, "stxkind is not a 1-D char array");
|
|
|
|
enabled = (char *) ARR_DATA_PTR(arr);
|
|
|
|
for (i = 0; i < ARR_DIMS(arr)[0]; i++)
|
|
|
|
{
|
|
|
|
if (enabled[i] == STATS_EXT_NDISTINCT)
|
|
|
|
stat_types = lappend(stat_types, makeString("ndistinct"));
|
|
|
|
else if (enabled[i] == STATS_EXT_DEPENDENCIES)
|
|
|
|
stat_types = lappend(stat_types, makeString("dependencies"));
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine which columns the statistics are on */
|
|
|
|
for (i = 0; i < statsrec->stxkeys.dim1; i++)
|
|
|
|
{
|
|
|
|
ColumnRef *cref = makeNode(ColumnRef);
|
|
|
|
AttrNumber attnum = statsrec->stxkeys.values[i];
|
|
|
|
|
|
|
|
cref->fields = list_make1(makeString(get_attname(heapRelid,
|
|
|
|
attnum, false)));
|
|
|
|
cref->location = -1;
|
|
|
|
|
|
|
|
def_names = lappend(def_names, cref);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* finally, build the output node */
|
|
|
|
stats = makeNode(CreateStatsStmt);
|
|
|
|
stats->defnames = NULL;
|
|
|
|
stats->stat_types = stat_types;
|
|
|
|
stats->exprs = def_names;
|
|
|
|
stats->relations = list_make1(heapRel);
|
|
|
|
stats->stxcomment = NULL;
|
|
|
|
stats->if_not_exists = false;
|
|
|
|
|
|
|
|
/* Clean up */
|
|
|
|
ReleaseSysCache(ht_stats);
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
}
|
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/*
|
2011-03-26 21:35:25 +01:00
|
|
|
* get_collation - fetch qualified name of a collation
|
|
|
|
*
|
|
|
|
* If collation is InvalidOid or is the default for the given actual_datatype,
|
|
|
|
* then the return value is NIL.
|
|
|
|
*/
|
|
|
|
static List *
|
|
|
|
get_collation(Oid collation, Oid actual_datatype)
|
|
|
|
{
|
|
|
|
List *result;
|
|
|
|
HeapTuple ht_coll;
|
|
|
|
Form_pg_collation coll_rec;
|
|
|
|
char *nsp_name;
|
|
|
|
char *coll_name;
|
|
|
|
|
|
|
|
if (!OidIsValid(collation))
|
|
|
|
return NIL; /* easy case */
|
|
|
|
if (collation == get_typcollation(actual_datatype))
|
|
|
|
return NIL; /* just let it default */
|
|
|
|
|
|
|
|
ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
|
|
|
|
if (!HeapTupleIsValid(ht_coll))
|
|
|
|
elog(ERROR, "cache lookup failed for collation %u", collation);
|
|
|
|
coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
|
|
|
|
|
|
|
|
/* For simplicity, we always schema-qualify the name */
|
|
|
|
nsp_name = get_namespace_name(coll_rec->collnamespace);
|
|
|
|
coll_name = pstrdup(NameStr(coll_rec->collname));
|
|
|
|
result = list_make2(makeString(nsp_name), makeString(coll_name));
|
|
|
|
|
|
|
|
ReleaseSysCache(ht_coll);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_opclass - fetch qualified name of an index operator class
|
2007-07-17 07:02:03 +02:00
|
|
|
*
|
|
|
|
* If the opclass is the default for the given actual_datatype, then
|
|
|
|
* the return value is NIL.
|
|
|
|
*/
|
|
|
|
static List *
|
|
|
|
get_opclass(Oid opclass, Oid actual_datatype)
|
|
|
|
{
|
2011-03-26 21:35:25 +01:00
|
|
|
List *result = NIL;
|
2007-11-15 22:14:46 +01:00
|
|
|
HeapTuple ht_opc;
|
|
|
|
Form_pg_opclass opc_rec;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
|
2007-07-17 07:02:03 +02:00
|
|
|
if (!HeapTupleIsValid(ht_opc))
|
|
|
|
elog(ERROR, "cache lookup failed for opclass %u", opclass);
|
|
|
|
opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
2007-12-02 00:44:44 +01:00
|
|
|
/* For simplicity, we always schema-qualify the name */
|
2007-11-15 22:14:46 +01:00
|
|
|
char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
|
2007-12-02 00:44:44 +01:00
|
|
|
char *opc_name = pstrdup(NameStr(opc_rec->opcname));
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
result = list_make2(makeString(nsp_name), makeString(opc_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCache(ht_opc);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformIndexConstraints
|
2009-12-07 06:22:23 +01:00
|
|
|
* Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
|
2007-12-02 00:44:44 +01:00
|
|
|
* We also merge in any index definitions arising from
|
2007-07-17 07:02:03 +02:00
|
|
|
* LIKE ... INCLUDING INDEXES.
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformIndexConstraints(CreateStmtContext *cxt)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
|
|
|
IndexStmt *index;
|
|
|
|
List *indexlist = NIL;
|
|
|
|
ListCell *lc;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/*
|
|
|
|
* Run through the constraints that need to generate an index. For PRIMARY
|
2009-12-07 06:22:23 +01:00
|
|
|
* KEY, mark each column as NOT NULL and create an index. For UNIQUE or
|
|
|
|
* EXCLUDE, create an index as for PRIMARY KEY, but do not insist on NOT
|
|
|
|
* NULL.
|
2007-07-17 07:02:03 +02:00
|
|
|
*/
|
|
|
|
foreach(lc, cxt->ixconstraints)
|
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
Constraint *constraint = lfirst_node(Constraint, lc);
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
Assert(constraint->contype == CONSTR_PRIMARY ||
|
2009-12-07 06:22:23 +01:00
|
|
|
constraint->contype == CONSTR_UNIQUE ||
|
|
|
|
constraint->contype == CONSTR_EXCLUSION);
|
2007-12-02 00:44:44 +01:00
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
index = transformIndexConstraint(constraint, cxt);
|
2007-12-02 00:44:44 +01:00
|
|
|
|
|
|
|
indexlist = lappend(indexlist, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add in any indexes defined by LIKE ... INCLUDING INDEXES */
|
|
|
|
foreach(lc, cxt->inh_indexes)
|
|
|
|
{
|
|
|
|
index = (IndexStmt *) lfirst(lc);
|
|
|
|
|
|
|
|
if (index->primary)
|
|
|
|
{
|
|
|
|
if (cxt->pkey != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("multiple primary keys for table \"%s\" are not allowed",
|
|
|
|
cxt->relation->relname)));
|
|
|
|
cxt->pkey = index;
|
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
indexlist = lappend(indexlist, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan the index list and remove any redundant index specifications. This
|
|
|
|
* can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
|
2013-05-29 22:58:43 +02:00
|
|
|
* strict reading of SQL would suggest raising an error instead, but that
|
|
|
|
* strikes me as too anal-retentive. - tgl 2001-02-14
|
2007-06-24 00:12:52 +02:00
|
|
|
*
|
|
|
|
* XXX in ALTER TABLE case, it'd be nice to look for duplicate
|
|
|
|
* pre-existing indexes, too.
|
|
|
|
*/
|
|
|
|
Assert(cxt->alist == NIL);
|
|
|
|
if (cxt->pkey != NULL)
|
|
|
|
{
|
|
|
|
/* Make sure we keep the PKEY index in preference to others... */
|
|
|
|
cxt->alist = list_make1(cxt->pkey);
|
|
|
|
}
|
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
foreach(lc, indexlist)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
bool keep = true;
|
|
|
|
ListCell *k;
|
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
index = lfirst(lc);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/* if it's pkey, it's already in cxt->alist */
|
|
|
|
if (index == cxt->pkey)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
foreach(k, cxt->alist)
|
|
|
|
{
|
|
|
|
IndexStmt *priorindex = lfirst(k);
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
if (equal(index->indexParams, priorindex->indexParams) &&
|
2018-04-07 22:00:39 +02:00
|
|
|
equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
|
2007-12-02 00:44:44 +01:00
|
|
|
equal(index->whereClause, priorindex->whereClause) &&
|
2009-12-07 06:22:23 +01:00
|
|
|
equal(index->excludeOpNames, priorindex->excludeOpNames) &&
|
2009-07-29 22:56:21 +02:00
|
|
|
strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
|
|
|
|
index->deferrable == priorindex->deferrable &&
|
|
|
|
index->initdeferred == priorindex->initdeferred)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2007-12-02 00:44:44 +01:00
|
|
|
priorindex->unique |= index->unique;
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* If the prior index is as yet unnamed, and this one is
|
|
|
|
* named, then transfer the name to the prior index. This
|
|
|
|
* ensures that if we have named and unnamed constraints,
|
|
|
|
* we'll use (at least one of) the names for the index.
|
|
|
|
*/
|
|
|
|
if (priorindex->idxname == NULL)
|
|
|
|
priorindex->idxname = index->idxname;
|
|
|
|
keep = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keep)
|
|
|
|
cxt->alist = lappend(cxt->alist, index);
|
|
|
|
}
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
|
|
|
|
2007-12-02 00:44:44 +01:00
|
|
|
/*
|
|
|
|
* transformIndexConstraint
|
2009-12-07 06:22:23 +01:00
|
|
|
* Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
|
2007-12-02 00:44:44 +01:00
|
|
|
* transformIndexConstraints.
|
|
|
|
*/
|
2007-07-17 07:02:03 +02:00
|
|
|
static IndexStmt *
|
|
|
|
transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
IndexStmt *index;
|
2009-12-07 06:22:23 +01:00
|
|
|
ListCell *lc;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
index = makeNode(IndexStmt);
|
2007-12-02 00:44:44 +01:00
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
index->unique = (constraint->contype != CONSTR_EXCLUSION);
|
2007-07-17 07:02:03 +02:00
|
|
|
index->primary = (constraint->contype == CONSTR_PRIMARY);
|
|
|
|
if (index->primary)
|
|
|
|
{
|
|
|
|
if (cxt->pkey != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("multiple primary keys for table \"%s\" are not allowed",
|
|
|
|
cxt->relation->relname),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
2007-07-17 07:02:03 +02:00
|
|
|
cxt->pkey = index;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In ALTER TABLE case, a primary index might already exist, but
|
|
|
|
* DefineIndex will check for it.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
index->isconstraint = true;
|
2009-07-29 22:56:21 +02:00
|
|
|
index->deferrable = constraint->deferrable;
|
|
|
|
index->initdeferred = constraint->initdeferred;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
if (constraint->conname != NULL)
|
|
|
|
index->idxname = pstrdup(constraint->conname);
|
2007-07-17 07:02:03 +02:00
|
|
|
else
|
2007-11-15 22:14:46 +01:00
|
|
|
index->idxname = NULL; /* DefineIndex will choose name */
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
index->relation = cxt->relation;
|
2009-12-07 06:22:23 +01:00
|
|
|
index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
|
2007-07-17 07:02:03 +02:00
|
|
|
index->options = constraint->options;
|
|
|
|
index->tableSpace = constraint->indexspace;
|
2009-12-07 06:22:23 +01:00
|
|
|
index->whereClause = constraint->where_clause;
|
2007-07-17 07:02:03 +02:00
|
|
|
index->indexParams = NIL;
|
2018-04-07 22:00:39 +02:00
|
|
|
index->indexIncludingParams = NIL;
|
2009-12-07 06:22:23 +01:00
|
|
|
index->excludeOpNames = NIL;
|
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
|
|
|
index->idxcomment = NULL;
|
2011-01-25 21:42:03 +01:00
|
|
|
index->indexOid = InvalidOid;
|
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
|
|
|
index->oldNode = InvalidOid;
|
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
|
|
|
index->transformed = false;
|
2007-07-17 07:02:03 +02:00
|
|
|
index->concurrent = false;
|
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
|
|
|
index->if_not_exists = false;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2011-01-25 21:42:03 +01:00
|
|
|
/*
|
|
|
|
* If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
|
|
|
|
* verify it's usable, then extract the implied column name list. (We
|
2011-04-10 17:42:00 +02:00
|
|
|
* will not actually need the column name list at runtime, but we need it
|
|
|
|
* now to check for duplicate column entries below.)
|
2011-01-25 21:42:03 +01:00
|
|
|
*/
|
|
|
|
if (constraint->indexname != NULL)
|
|
|
|
{
|
|
|
|
char *index_name = constraint->indexname;
|
|
|
|
Relation heap_rel = cxt->rel;
|
|
|
|
Oid index_oid;
|
|
|
|
Relation index_rel;
|
|
|
|
Form_pg_index index_form;
|
|
|
|
oidvector *indclass;
|
|
|
|
Datum indclassDatum;
|
|
|
|
bool isnull;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Grammar should not allow this with explicit column list */
|
|
|
|
Assert(constraint->keys == NIL);
|
|
|
|
|
|
|
|
/* Grammar should only allow PRIMARY and UNIQUE constraints */
|
|
|
|
Assert(constraint->contype == CONSTR_PRIMARY ||
|
|
|
|
constraint->contype == CONSTR_UNIQUE);
|
|
|
|
|
|
|
|
/* Must be ALTER, not CREATE, but grammar doesn't enforce that */
|
|
|
|
if (!cxt->isalter)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot use an existing index in CREATE TABLE"),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/* Look for the index in the same schema as the table */
|
|
|
|
index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
|
|
|
|
|
|
|
|
if (!OidIsValid(index_oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("index \"%s\" does not exist", index_name),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/* Open the index (this will throw an error if it is not an index) */
|
|
|
|
index_rel = index_open(index_oid, AccessShareLock);
|
|
|
|
index_form = index_rel->rd_index;
|
|
|
|
|
|
|
|
/* Check that it does not have an associated constraint already */
|
|
|
|
if (OidIsValid(get_index_constraint(index_oid)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("index \"%s\" is already associated with a constraint",
|
|
|
|
index_name),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/* Perform validity checks on the index */
|
|
|
|
if (index_form->indrelid != RelationGetRelid(heap_rel))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("index \"%s\" does not belong to table \"%s\"",
|
|
|
|
index_name, RelationGetRelationName(heap_rel)),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
if (!IndexIsValid(index_form))
|
2011-01-25 21:42:03 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("index \"%s\" is not valid", index_name),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
if (!index_form->indisunique)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("\"%s\" is not a unique index", index_name),
|
2011-06-21 23:33:20 +02:00
|
|
|
errdetail("Cannot create a primary key or unique constraint using such an index."),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
if (RelationGetIndexExpressions(index_rel) != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("index \"%s\" contains expressions", index_name),
|
2011-06-21 23:33:20 +02:00
|
|
|
errdetail("Cannot create a primary key or unique constraint using such an index."),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
if (RelationGetIndexPredicate(index_rel) != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("\"%s\" is a partial index", index_name),
|
2011-06-21 23:33:20 +02:00
|
|
|
errdetail("Cannot create a primary key or unique constraint using such an index."),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* It's probably unsafe to change a deferred index to non-deferred. (A
|
|
|
|
* non-constraint index couldn't be deferred anyway, so this case
|
2011-01-25 21:42:03 +01:00
|
|
|
* should never occur; no need to sweat, but let's check it.)
|
|
|
|
*/
|
|
|
|
if (!index_form->indimmediate && !constraint->deferrable)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("\"%s\" is a deferrable index", index_name),
|
|
|
|
errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Insist on it being a btree. That's the only kind that supports
|
2011-01-25 21:42:03 +01:00
|
|
|
* uniqueness at the moment anyway; but we must have an index that
|
|
|
|
* exactly matches what you'd get from plain ADD CONSTRAINT syntax,
|
|
|
|
* else dump and reload will produce a different index (breaking
|
|
|
|
* pg_upgrade in particular).
|
|
|
|
*/
|
2016-03-24 03:01:35 +01:00
|
|
|
if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
|
2011-01-25 21:42:03 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2011-07-04 23:01:35 +02:00
|
|
|
errmsg("index \"%s\" is not a btree", index_name),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/* Must get indclass the hard way */
|
|
|
|
indclassDatum = SysCacheGetAttr(INDEXRELID, index_rel->rd_indextuple,
|
|
|
|
Anum_pg_index_indclass, &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
indclass = (oidvector *) DatumGetPointer(indclassDatum);
|
|
|
|
|
|
|
|
for (i = 0; i < index_form->indnatts; i++)
|
|
|
|
{
|
2012-06-25 00:51:46 +02:00
|
|
|
int16 attnum = index_form->indkey.values[i];
|
2011-01-25 21:42:03 +01:00
|
|
|
Form_pg_attribute attform;
|
2011-04-10 17:42:00 +02:00
|
|
|
char *attname;
|
|
|
|
Oid defopclass;
|
2011-01-25 21:42:03 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We shouldn't see attnum == 0 here, since we already rejected
|
2014-05-06 18:12:18 +02:00
|
|
|
* expression indexes. If we do, SystemAttributeDefinition will
|
2011-04-10 17:42:00 +02:00
|
|
|
* throw an error.
|
2011-01-25 21:42:03 +01:00
|
|
|
*/
|
|
|
|
if (attnum > 0)
|
|
|
|
{
|
|
|
|
Assert(attnum <= heap_rel->rd_att->natts);
|
2017-08-20 20:19:07 +02:00
|
|
|
attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
|
2011-01-25 21:42:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
attform = SystemAttributeDefinition(attnum,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
heap_rel->rd_rel->relhasoids);
|
2011-01-25 21:42:03 +01:00
|
|
|
attname = pstrdup(NameStr(attform->attname));
|
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
if (i < index_form->indnkeyatts)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Insist on default opclass and sort options. While the
|
|
|
|
* index would still work as a constraint with non-default
|
|
|
|
* settings, it might not provide exactly the same uniqueness
|
|
|
|
* semantics as you'd get from a normally-created constraint;
|
|
|
|
* and there's also the dump/reload problem mentioned above.
|
|
|
|
*/
|
|
|
|
defopclass = GetDefaultOpClass(attform->atttypid,
|
|
|
|
index_rel->rd_rel->relam);
|
|
|
|
if (indclass->values[i] != defopclass ||
|
|
|
|
index_rel->rd_indoption[i] != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("index \"%s\" does not have default sorting behavior", index_name),
|
|
|
|
errdetail("Cannot create a primary key or unique constraint using such an index."),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
2011-01-25 21:42:03 +01:00
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
constraint->keys = lappend(constraint->keys, makeString(attname));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
constraint->including = lappend(constraint->including, makeString(attname));
|
2011-01-25 21:42:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the index relation but keep the lock */
|
|
|
|
relation_close(index_rel, NoLock);
|
|
|
|
|
|
|
|
index->indexOid = index_oid;
|
|
|
|
}
|
|
|
|
|
2007-07-17 07:02:03 +02:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* If it's an EXCLUDE constraint, the grammar returns a list of pairs of
|
|
|
|
* IndexElems and operator names. We have to break that apart into
|
2009-12-07 06:22:23 +01:00
|
|
|
* separate lists.
|
|
|
|
*/
|
|
|
|
if (constraint->contype == CONSTR_EXCLUSION)
|
|
|
|
{
|
|
|
|
foreach(lc, constraint->exclusions)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
List *pair = (List *) lfirst(lc);
|
|
|
|
IndexElem *elem;
|
|
|
|
List *opname;
|
2009-12-07 06:22:23 +01:00
|
|
|
|
|
|
|
Assert(list_length(pair) == 2);
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
elem = linitial_node(IndexElem, pair);
|
|
|
|
opname = lsecond_node(List, pair);
|
2009-12-07 06:22:23 +01:00
|
|
|
|
|
|
|
index->indexParams = lappend(index->indexParams, elem);
|
|
|
|
index->excludeOpNames = lappend(index->excludeOpNames, opname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For UNIQUE and PRIMARY KEY, we just have a list of column names.
|
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Make sure referenced keys exist. If we are making a PRIMARY KEY index,
|
|
|
|
* also make sure they are NOT NULL, if possible. (Although we could leave
|
|
|
|
* it to DefineIndex to mark the columns NOT NULL, it's more efficient to
|
|
|
|
* get it right the first time.)
|
2007-07-17 07:02:03 +02:00
|
|
|
*/
|
2018-04-07 22:00:39 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
foreach(lc, constraint->keys)
|
|
|
|
{
|
|
|
|
char *key = strVal(lfirst(lc));
|
|
|
|
bool found = false;
|
|
|
|
ColumnDef *column = NULL;
|
|
|
|
ListCell *columns;
|
|
|
|
IndexElem *iparam;
|
|
|
|
|
|
|
|
/* Make sure referenced column exist. */
|
|
|
|
foreach(columns, cxt->columns)
|
|
|
|
{
|
|
|
|
column = castNode(ColumnDef, lfirst(columns));
|
|
|
|
if (strcmp(column->colname, key) == 0)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
/* found column in the new table; force it to be NOT NULL */
|
|
|
|
if (constraint->contype == CONSTR_PRIMARY)
|
|
|
|
column->is_not_null = true;
|
|
|
|
}
|
|
|
|
else if (SystemAttributeByName(key, cxt->hasoids) != NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* column will be a system column in the new table, so accept
|
|
|
|
* it. System columns can't ever be null, so no need to worry
|
|
|
|
* about PRIMARY/NOT NULL constraint.
|
|
|
|
*/
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
else if (cxt->inhRelations)
|
|
|
|
{
|
|
|
|
/* try inherited tables */
|
|
|
|
ListCell *inher;
|
|
|
|
|
|
|
|
foreach(inher, cxt->inhRelations)
|
|
|
|
{
|
|
|
|
RangeVar *inh = castNode(RangeVar, lfirst(inher));
|
|
|
|
Relation rel;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
rel = heap_openrv(inh, AccessShareLock);
|
|
|
|
/* check user requested inheritance from valid relkind */
|
|
|
|
if (rel->rd_rel->relkind != RELKIND_RELATION &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("inherited relation \"%s\" is not a table or foreign table",
|
|
|
|
inh->relname)));
|
|
|
|
for (count = 0; count < rel->rd_att->natts; count++)
|
|
|
|
{
|
|
|
|
Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
|
|
|
|
count);
|
|
|
|
char *inhname = NameStr(inhattr->attname);
|
|
|
|
|
|
|
|
if (inhattr->attisdropped)
|
|
|
|
continue;
|
|
|
|
if (strcmp(key, inhname) == 0)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We currently have no easy way to force an
|
|
|
|
* inherited column to be NOT NULL at creation, if
|
|
|
|
* its parent wasn't so already. We leave it to
|
|
|
|
* DefineIndex to fix things up in this case.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
heap_close(rel, NoLock);
|
|
|
|
if (found)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In the ALTER TABLE case, don't complain about index keys not
|
|
|
|
* created in the command; they may well exist already.
|
|
|
|
* DefineIndex will complain about them if not, and will also take
|
|
|
|
* care of marking them NOT NULL.
|
|
|
|
*/
|
|
|
|
if (!found && !cxt->isalter)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("column \"%s\" named in key does not exist", key),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
|
|
|
|
/* Check for PRIMARY KEY(foo, foo) */
|
|
|
|
foreach(columns, index->indexParams)
|
|
|
|
{
|
|
|
|
iparam = (IndexElem *) lfirst(columns);
|
|
|
|
if (iparam->name && strcmp(key, iparam->name) == 0)
|
|
|
|
{
|
|
|
|
if (index->primary)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
|
|
errmsg("column \"%s\" appears twice in primary key constraint",
|
|
|
|
key),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
|
|
errmsg("column \"%s\" appears twice in unique constraint",
|
|
|
|
key),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK, add it to the index definition */
|
|
|
|
iparam = makeNode(IndexElem);
|
|
|
|
iparam->name = pstrdup(key);
|
|
|
|
iparam->expr = NULL;
|
|
|
|
iparam->indexcolname = NULL;
|
|
|
|
iparam->collation = NIL;
|
|
|
|
iparam->opclass = NIL;
|
|
|
|
iparam->ordering = SORTBY_DEFAULT;
|
|
|
|
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
|
|
|
|
index->indexParams = lappend(index->indexParams, iparam);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add included columns to index definition */
|
|
|
|
foreach(lc, constraint->including)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
2009-12-07 06:22:23 +01:00
|
|
|
char *key = strVal(lfirst(lc));
|
2007-07-17 07:02:03 +02:00
|
|
|
bool found = false;
|
|
|
|
ColumnDef *column = NULL;
|
|
|
|
ListCell *columns;
|
2009-12-07 06:22:23 +01:00
|
|
|
IndexElem *iparam;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
foreach(columns, cxt->columns)
|
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
column = lfirst_node(ColumnDef, columns);
|
2007-07-17 07:02:03 +02:00
|
|
|
if (strcmp(column->colname, key) == 0)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
if (SystemAttributeByName(key, cxt->hasoids) != NULL)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
2018-04-07 22:00:39 +02:00
|
|
|
/*
|
|
|
|
* column will be a system column in the new table, so accept
|
|
|
|
* it. System columns can't ever be null, so no need to worry
|
|
|
|
* about PRIMARY/NOT NULL constraint.
|
|
|
|
*/
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
else if (cxt->inhRelations)
|
|
|
|
{
|
|
|
|
/* try inherited tables */
|
|
|
|
ListCell *inher;
|
2007-07-17 07:02:03 +02:00
|
|
|
|
2018-04-07 22:00:39 +02:00
|
|
|
foreach(inher, cxt->inhRelations)
|
|
|
|
{
|
|
|
|
RangeVar *inh = lfirst_node(RangeVar, inher);
|
|
|
|
Relation rel;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
rel = heap_openrv(inh, AccessShareLock);
|
|
|
|
/* check user requested inheritance from valid relkind */
|
|
|
|
if (rel->rd_rel->relkind != RELKIND_RELATION &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("inherited relation \"%s\" is not a table or foreign table",
|
|
|
|
inh->relname)));
|
|
|
|
for (count = 0; count < rel->rd_att->natts; count++)
|
2007-07-17 07:02:03 +02:00
|
|
|
{
|
2018-04-07 22:00:39 +02:00
|
|
|
Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
|
|
|
|
count);
|
|
|
|
char *inhname = NameStr(inhattr->attname);
|
|
|
|
|
|
|
|
if (inhattr->attisdropped)
|
|
|
|
continue;
|
|
|
|
if (strcmp(key, inhname) == 0)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We currently have no easy way to force an
|
|
|
|
* inherited column to be NOT NULL at creation, if
|
|
|
|
* its parent wasn't so already. We leave it to
|
|
|
|
* DefineIndex to fix things up in this case.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
2018-04-07 22:00:39 +02:00
|
|
|
heap_close(rel, NoLock);
|
|
|
|
if (found)
|
|
|
|
break;
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In the ALTER TABLE case, don't complain about index keys not
|
2007-11-15 22:14:46 +01:00
|
|
|
* created in the command; they may well exist already. DefineIndex
|
|
|
|
* will complain about them if not, and will also take care of marking
|
|
|
|
* them NOT NULL.
|
2007-07-17 07:02:03 +02:00
|
|
|
*/
|
|
|
|
if (!found && !cxt->isalter)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
2011-01-25 21:42:03 +01:00
|
|
|
errmsg("column \"%s\" named in key does not exist", key),
|
|
|
|
parser_errposition(cxt->pstate, constraint->location)));
|
2007-07-17 07:02:03 +02:00
|
|
|
|
|
|
|
/* OK, add it to the index definition */
|
|
|
|
iparam = makeNode(IndexElem);
|
|
|
|
iparam->name = pstrdup(key);
|
|
|
|
iparam->expr = NULL;
|
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
|
|
|
iparam->indexcolname = NULL;
|
2011-03-26 21:35:25 +01:00
|
|
|
iparam->collation = NIL;
|
2007-07-17 07:02:03 +02:00
|
|
|
iparam->opclass = NIL;
|
2018-04-07 22:00:39 +02:00
|
|
|
index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
|
2007-07-17 07:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
/*
|
|
|
|
* transformExtendedStatistics
|
|
|
|
* Handle extended statistic objects
|
|
|
|
*
|
2018-03-06 17:17:13 +01:00
|
|
|
* Right now, there's nothing to do here, so we just append the list to
|
|
|
|
* the existing "after" list.
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
transformExtendedStatistics(CreateStmtContext *cxt)
|
|
|
|
{
|
|
|
|
cxt->alist = list_concat(cxt->alist, cxt->extstats);
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:43:56 +01:00
|
|
|
/*
|
|
|
|
* transformCheckConstraints
|
|
|
|
* handle CHECK constraints
|
|
|
|
*
|
|
|
|
* Right now, there's nothing to do here when called from ALTER TABLE,
|
|
|
|
* but the other constraint-transformation functions are called in both
|
|
|
|
* the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
|
|
|
|
* don't do anything if we're not authorized to skip validation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
|
|
|
|
{
|
|
|
|
ListCell *ckclist;
|
|
|
|
|
|
|
|
if (cxt->ckconstraints == NIL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
2017-08-03 19:09:15 +02:00
|
|
|
* If creating a new table (but not a foreign table), we can safely skip
|
2017-08-14 23:29:33 +02:00
|
|
|
* validation of check constraints, and nonetheless mark them valid. (This
|
|
|
|
* will override any user-supplied NOT VALID flag.)
|
2015-12-16 13:43:56 +01:00
|
|
|
*/
|
|
|
|
if (skipValidation)
|
|
|
|
{
|
|
|
|
foreach(ckclist, cxt->ckconstraints)
|
|
|
|
{
|
|
|
|
Constraint *constraint = (Constraint *) lfirst(ckclist);
|
|
|
|
|
|
|
|
constraint->skip_validation = true;
|
|
|
|
constraint->initially_valid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* transformFKConstraints
|
|
|
|
* handle FOREIGN KEY constraints
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformFKConstraints(CreateStmtContext *cxt,
|
2007-06-24 00:12:52 +02:00
|
|
|
bool skipValidation, bool isAddConstraint)
|
|
|
|
{
|
|
|
|
ListCell *fkclist;
|
|
|
|
|
|
|
|
if (cxt->fkconstraints == NIL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If CREATE TABLE or adding a column with NULL default, we can safely
|
2011-06-16 01:05:11 +02:00
|
|
|
* skip validation of FK constraints, and nonetheless mark them valid.
|
|
|
|
* (This will override any user-supplied NOT VALID flag.)
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
if (skipValidation)
|
|
|
|
{
|
|
|
|
foreach(fkclist, cxt->fkconstraints)
|
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
Constraint *constraint = (Constraint *) lfirst(fkclist);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
constraint->skip_validation = true;
|
2011-04-10 17:42:00 +02:00
|
|
|
constraint->initially_valid = true;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
|
|
|
|
* CONSTRAINT command to execute after the basic command is complete. (If
|
|
|
|
* called from ADD CONSTRAINT, that routine will add the FK constraints to
|
|
|
|
* its own subcommand list.)
|
|
|
|
*
|
|
|
|
* Note: the ADD CONSTRAINT command must also execute after any index
|
|
|
|
* creation commands. Thus, this should run after
|
|
|
|
* transformIndexConstraints, so that the CREATE INDEX commands are
|
|
|
|
* already in cxt->alist.
|
|
|
|
*/
|
|
|
|
if (!isAddConstraint)
|
|
|
|
{
|
|
|
|
AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
|
|
|
|
|
|
|
|
alterstmt->relation = cxt->relation;
|
|
|
|
alterstmt->cmds = NIL;
|
|
|
|
alterstmt->relkind = OBJECT_TABLE;
|
|
|
|
|
|
|
|
foreach(fkclist, cxt->fkconstraints)
|
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
Constraint *constraint = (Constraint *) lfirst(fkclist);
|
2007-06-24 00:12:52 +02:00
|
|
|
AlterTableCmd *altercmd = makeNode(AlterTableCmd);
|
|
|
|
|
|
|
|
altercmd->subtype = AT_ProcessedConstraint;
|
|
|
|
altercmd->name = NULL;
|
2009-07-30 04:45:38 +02:00
|
|
|
altercmd->def = (Node *) constraint;
|
2007-06-24 00:12:52 +02:00
|
|
|
alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
cxt->alist = lappend(cxt->alist, alterstmt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-07-28 07:22:24 +02:00
|
|
|
* transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
|
2007-06-24 00:12:52 +02:00
|
|
|
*
|
|
|
|
* Note: this is a no-op for an index not using either index expressions or
|
2014-05-06 18:12:18 +02:00
|
|
|
* a predicate expression. There are several code paths that create indexes
|
2007-06-24 00:12:52 +02:00
|
|
|
* without bothering to call this, because they know they don't have any
|
|
|
|
* such expressions to deal with.
|
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
|
|
|
*
|
|
|
|
* To avoid race conditions, it's important that this function rely only on
|
|
|
|
* the passed-in relid (and not on stmt->relation) to determine the target
|
|
|
|
* relation.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
IndexStmt *
|
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
|
|
|
transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
ParseState *pstate;
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
ListCell *l;
|
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
|
|
|
Relation rel;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
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
|
|
|
/* Nothing to do if statement already transformed. */
|
|
|
|
if (stmt->transformed)
|
|
|
|
return stmt;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* We must not scribble on the passed-in IndexStmt, so copy it. (This is
|
|
|
|
* overkill, but easy.)
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2017-03-09 21:18:59 +01:00
|
|
|
stmt = copyObject(stmt);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/* Set up pstate */
|
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
pstate->p_sourcetext = queryString;
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Put the parent table into the rtable so that the expressions can refer
|
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
|
|
|
* to its fields without qualification. Caller is responsible for locking
|
|
|
|
* relation, but we still need to open it.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
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
|
|
|
rel = relation_open(relid, NoLock);
|
|
|
|
rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/* no to join list, yes to namespaces */
|
|
|
|
addRTEtoQuery(pstate, rte, false, true, true);
|
|
|
|
|
|
|
|
/* take care of the where clause */
|
|
|
|
if (stmt->whereClause)
|
2011-04-07 08:34:57 +02:00
|
|
|
{
|
2007-06-24 00:12:52 +02:00
|
|
|
stmt->whereClause = transformWhereClause(pstate,
|
|
|
|
stmt->whereClause,
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
EXPR_KIND_INDEX_PREDICATE,
|
2007-06-24 00:12:52 +02:00
|
|
|
"WHERE");
|
2011-04-07 08:34:57 +02:00
|
|
|
/* we have to fix its collations too */
|
|
|
|
assign_expr_collations(pstate, stmt->whereClause);
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/* take care of any index expressions */
|
|
|
|
foreach(l, stmt->indexParams)
|
|
|
|
{
|
|
|
|
IndexElem *ielem = (IndexElem *) lfirst(l);
|
|
|
|
|
|
|
|
if (ielem->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
|
|
|
/* Extract preliminary index col name before transforming expr */
|
|
|
|
if (ielem->indexcolname == NULL)
|
|
|
|
ielem->indexcolname = FigureIndexColname(ielem->expr);
|
|
|
|
|
|
|
|
/* Now do parse transformation of the expression */
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
ielem->expr = transformExpr(pstate, ielem->expr,
|
|
|
|
EXPR_KIND_INDEX_EXPRESSION);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
/* We have to fix its collations too */
|
|
|
|
assign_expr_collations(pstate, ielem->expr);
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* transformExpr() should have already rejected subqueries,
|
2016-09-13 19:54:24 +02:00
|
|
|
* aggregates, window functions, and SRFs, based on the EXPR_KIND_
|
|
|
|
* for an index expression.
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
*
|
|
|
|
* DefineIndex() will make more checks.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* Check that only the base rel is mentioned. (This should be dead code
|
|
|
|
* now that add_missing_from is history.)
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
if (list_length(pstate->p_rtable) != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
|
|
|
errmsg("index expressions and predicates can refer only to the table being indexed")));
|
|
|
|
|
|
|
|
free_parsestate(pstate);
|
|
|
|
|
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
|
|
|
/* Close relation */
|
2007-06-24 00:12:52 +02:00
|
|
|
heap_close(rel, NoLock);
|
|
|
|
|
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
|
|
|
/* Mark statement as successfully transformed */
|
|
|
|
stmt->transformed = true;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
return stmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformRuleStmt -
|
|
|
|
* transform a CREATE RULE Statement. The action is a list of parse
|
|
|
|
* trees which is transformed into a list of query trees, and we also
|
|
|
|
* transform the WHERE clause if any.
|
|
|
|
*
|
|
|
|
* actions and whereClause are output parameters that receive the
|
|
|
|
* transformed results.
|
|
|
|
*
|
|
|
|
* Note that we must not scribble on the passed-in RuleStmt, so we do
|
|
|
|
* copyObject() on the actions and WHERE clause.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
transformRuleStmt(RuleStmt *stmt, const char *queryString,
|
|
|
|
List **actions, Node **whereClause)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
ParseState *pstate;
|
|
|
|
RangeTblEntry *oldrte;
|
|
|
|
RangeTblEntry *newrte;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* To avoid deadlock, make sure the first thing we do is grab
|
2014-05-06 18:12:18 +02:00
|
|
|
* AccessExclusiveLock on the target relation. This will be needed by
|
2007-06-24 00:12:52 +02:00
|
|
|
* DefineQueryRewrite(), and we don't want to grab a lesser lock
|
|
|
|
* beforehand.
|
|
|
|
*/
|
|
|
|
rel = heap_openrv(stmt->relation, AccessExclusiveLock);
|
|
|
|
|
2013-03-04 01:23:31 +01:00
|
|
|
if (rel->rd_rel->relkind == RELKIND_MATVIEW)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("rules on materialized views are not supported")));
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/* Set up pstate */
|
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
pstate->p_sourcetext = queryString;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
|
|
|
|
* Set up their RTEs in the main pstate for use in parsing the rule
|
|
|
|
* qualification.
|
|
|
|
*/
|
|
|
|
oldrte = addRangeTableEntryForRelation(pstate, rel,
|
2009-11-06 00:24:27 +01:00
|
|
|
makeAlias("old", NIL),
|
2007-06-24 00:12:52 +02:00
|
|
|
false, false);
|
|
|
|
newrte = addRangeTableEntryForRelation(pstate, rel,
|
2009-11-06 00:24:27 +01:00
|
|
|
makeAlias("new", NIL),
|
2007-06-24 00:12:52 +02:00
|
|
|
false, false);
|
|
|
|
/* Must override addRangeTableEntry's default access-check flags */
|
|
|
|
oldrte->requiredPerms = 0;
|
|
|
|
newrte->requiredPerms = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* They must be in the namespace too for lookup purposes, but only add the
|
|
|
|
* one(s) that are relevant for the current kind of rule. In an UPDATE
|
|
|
|
* rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
|
|
|
|
* there's no need to be so picky for INSERT & DELETE. We do not add them
|
|
|
|
* to the joinlist.
|
|
|
|
*/
|
|
|
|
switch (stmt->event)
|
|
|
|
{
|
|
|
|
case CMD_SELECT:
|
|
|
|
addRTEtoQuery(pstate, oldrte, false, true, true);
|
|
|
|
break;
|
|
|
|
case CMD_UPDATE:
|
|
|
|
addRTEtoQuery(pstate, oldrte, false, true, true);
|
|
|
|
addRTEtoQuery(pstate, newrte, false, true, true);
|
|
|
|
break;
|
|
|
|
case CMD_INSERT:
|
|
|
|
addRTEtoQuery(pstate, newrte, false, true, true);
|
|
|
|
break;
|
|
|
|
case CMD_DELETE:
|
|
|
|
addRTEtoQuery(pstate, oldrte, false, true, true);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized event type: %d",
|
|
|
|
(int) stmt->event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* take care of the where clause */
|
|
|
|
*whereClause = transformWhereClause(pstate,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
(Node *) copyObject(stmt->whereClause),
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
EXPR_KIND_WHERE,
|
2007-06-24 00:12:52 +02:00
|
|
|
"WHERE");
|
2011-04-07 08:34:57 +02:00
|
|
|
/* we have to fix its collations too */
|
|
|
|
assign_expr_collations(pstate, *whereClause);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
/* this is probably dead code without add_missing_from: */
|
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 (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
|
2007-06-24 00:12:52 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("rule WHERE condition cannot contain references to other relations")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 'instead nothing' rules with a qualification need a query rangetable so
|
|
|
|
* the rewrite handler can add the negated rule qualification to the
|
|
|
|
* original query. We create a query with the new command type CMD_NOTHING
|
|
|
|
* here that is treated specially by the rewrite system.
|
|
|
|
*/
|
|
|
|
if (stmt->actions == NIL)
|
|
|
|
{
|
|
|
|
Query *nothing_qry = makeNode(Query);
|
|
|
|
|
|
|
|
nothing_qry->commandType = CMD_NOTHING;
|
|
|
|
nothing_qry->rtable = pstate->p_rtable;
|
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
|
|
|
nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
*actions = list_make1(nothing_qry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
List *newactions = NIL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transform each statement, like parse_sub_analyze()
|
|
|
|
*/
|
|
|
|
foreach(l, stmt->actions)
|
|
|
|
{
|
|
|
|
Node *action = (Node *) lfirst(l);
|
|
|
|
ParseState *sub_pstate = make_parsestate(NULL);
|
|
|
|
Query *sub_qry,
|
|
|
|
*top_subqry;
|
|
|
|
bool has_old,
|
|
|
|
has_new;
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Since outer ParseState isn't parent of inner, have to pass down
|
|
|
|
* the query text by hand.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
sub_pstate->p_sourcetext = queryString;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up OLD/NEW in the rtable for this statement. The entries
|
|
|
|
* are added only to relnamespace, not varnamespace, because we
|
|
|
|
* don't want them to be referred to by unqualified field names
|
|
|
|
* nor "*" in the rule actions. We decide later whether to put
|
|
|
|
* them in the joinlist.
|
|
|
|
*/
|
|
|
|
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
|
2009-11-06 00:24:27 +01:00
|
|
|
makeAlias("old", NIL),
|
2007-06-24 00:12:52 +02:00
|
|
|
false, false);
|
|
|
|
newrte = addRangeTableEntryForRelation(sub_pstate, rel,
|
2009-11-06 00:24:27 +01:00
|
|
|
makeAlias("new", NIL),
|
2007-06-24 00:12:52 +02:00
|
|
|
false, false);
|
|
|
|
oldrte->requiredPerms = 0;
|
|
|
|
newrte->requiredPerms = 0;
|
|
|
|
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
|
|
|
|
addRTEtoQuery(sub_pstate, newrte, false, true, false);
|
|
|
|
|
|
|
|
/* Transform the rule action statement */
|
|
|
|
top_subqry = transformStmt(sub_pstate,
|
|
|
|
(Node *) copyObject(action));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We cannot support utility-statement actions (eg NOTIFY) with
|
|
|
|
* nonempty rule WHERE conditions, because there's no way to make
|
|
|
|
* the utility action execute conditionally.
|
|
|
|
*/
|
|
|
|
if (top_subqry->commandType == CMD_UTILITY &&
|
|
|
|
*whereClause != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the action is INSERT...SELECT, OLD/NEW have been pushed down
|
|
|
|
* into the SELECT, and that's what we need to look at. (Ugly
|
|
|
|
* kluge ... try to fix this when we redesign querytrees.)
|
|
|
|
*/
|
|
|
|
sub_qry = getInsertSelectQuery(top_subqry, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the sub_qry is a setop, we cannot attach any qualifications
|
|
|
|
* to it, because the planner won't notice them. This could
|
|
|
|
* perhaps be relaxed someday, but for now, we may as well reject
|
|
|
|
* such a rule immediately.
|
|
|
|
*/
|
|
|
|
if (sub_qry->setOperations != NULL && *whereClause != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate action's use of OLD/NEW, qual too
|
|
|
|
*/
|
|
|
|
has_old =
|
|
|
|
rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
|
|
|
|
rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
|
|
|
|
has_new =
|
|
|
|
rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
|
|
|
|
rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
|
|
|
|
|
|
|
|
switch (stmt->event)
|
|
|
|
{
|
|
|
|
case CMD_SELECT:
|
|
|
|
if (has_old)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("ON SELECT rule cannot use OLD")));
|
|
|
|
if (has_new)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("ON SELECT rule cannot use NEW")));
|
|
|
|
break;
|
|
|
|
case CMD_UPDATE:
|
|
|
|
/* both are OK */
|
|
|
|
break;
|
|
|
|
case CMD_INSERT:
|
|
|
|
if (has_old)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("ON INSERT rule cannot use OLD")));
|
|
|
|
break;
|
|
|
|
case CMD_DELETE:
|
|
|
|
if (has_new)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("ON DELETE rule cannot use NEW")));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized event type: %d",
|
|
|
|
(int) stmt->event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-10-16 01:53:59 +02:00
|
|
|
/*
|
|
|
|
* OLD/NEW are not allowed in WITH queries, because they would
|
|
|
|
* amount to outer references for the WITH, which we disallow.
|
|
|
|
* However, they were already in the outer rangetable when we
|
|
|
|
* analyzed the query, so we have to check.
|
|
|
|
*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Note that in the INSERT...SELECT case, we need to examine the
|
|
|
|
* CTE lists of both top_subqry and sub_qry.
|
2010-10-16 01:53:59 +02:00
|
|
|
*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Note that we aren't digging into the body of the query looking
|
|
|
|
* for WITHs in nested sub-SELECTs. A WITH down there can
|
|
|
|
* legitimately refer to OLD/NEW, because it'd be an
|
2010-10-16 01:53:59 +02:00
|
|
|
* indirect-correlated outer reference.
|
|
|
|
*/
|
|
|
|
if (rangeTableEntry_used((Node *) top_subqry->cteList,
|
|
|
|
PRS2_OLD_VARNO, 0) ||
|
|
|
|
rangeTableEntry_used((Node *) sub_qry->cteList,
|
2011-04-10 17:42:00 +02:00
|
|
|
PRS2_OLD_VARNO, 0))
|
2010-10-16 01:53:59 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot refer to OLD within WITH query")));
|
|
|
|
if (rangeTableEntry_used((Node *) top_subqry->cteList,
|
|
|
|
PRS2_NEW_VARNO, 0) ||
|
|
|
|
rangeTableEntry_used((Node *) sub_qry->cteList,
|
|
|
|
PRS2_NEW_VARNO, 0))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot refer to NEW within WITH query")));
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
/*
|
|
|
|
* For efficiency's sake, add OLD to the rule action's jointree
|
|
|
|
* only if it was actually referenced in the statement or qual.
|
|
|
|
*
|
|
|
|
* For INSERT, NEW is not really a relation (only a reference to
|
|
|
|
* the to-be-inserted tuple) and should never be added to the
|
|
|
|
* jointree.
|
|
|
|
*
|
|
|
|
* For UPDATE, we treat NEW as being another kind of reference to
|
|
|
|
* OLD, because it represents references to *transformed* tuples
|
|
|
|
* of the existing relation. It would be wrong to enter NEW
|
|
|
|
* separately in the jointree, since that would cause a double
|
|
|
|
* join of the updated relation. It's also wrong to fail to make
|
|
|
|
* a jointree entry if only NEW and not OLD is mentioned.
|
|
|
|
*/
|
|
|
|
if (has_old || (has_new && stmt->event == CMD_UPDATE))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If sub_qry is a setop, manipulating its jointree will do no
|
|
|
|
* good at all, because the jointree is dummy. (This should be
|
|
|
|
* a can't-happen case because of prior tests.)
|
|
|
|
*/
|
|
|
|
if (sub_qry->setOperations != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
|
|
|
|
/* hack so we can use addRTEtoQuery() */
|
|
|
|
sub_pstate->p_rtable = sub_qry->rtable;
|
|
|
|
sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
|
|
|
|
addRTEtoQuery(sub_pstate, oldrte, true, false, false);
|
|
|
|
sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
newactions = lappend(newactions, top_subqry);
|
|
|
|
|
|
|
|
free_parsestate(sub_pstate);
|
|
|
|
}
|
|
|
|
|
|
|
|
*actions = newactions;
|
|
|
|
}
|
|
|
|
|
|
|
|
free_parsestate(pstate);
|
|
|
|
|
|
|
|
/* Close relation, but keep the exclusive lock */
|
|
|
|
heap_close(rel, NoLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformAlterTableStmt -
|
|
|
|
* parse analysis for ALTER TABLE
|
|
|
|
*
|
|
|
|
* Returns a List of utility commands to be done in sequence. One of these
|
|
|
|
* will be the transformed AlterTableStmt, but there may be additional actions
|
|
|
|
* to be done before and after the actual AlterTable() call.
|
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
|
|
|
*
|
|
|
|
* To avoid race conditions, it's important that this function rely only on
|
|
|
|
* the passed-in relid (and not on stmt->relation) to determine the target
|
|
|
|
* relation.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
List *
|
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
|
|
|
transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|
|
|
const char *queryString)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
ParseState *pstate;
|
|
|
|
CreateStmtContext cxt;
|
|
|
|
List *result;
|
|
|
|
List *save_alist;
|
|
|
|
ListCell *lcmd,
|
|
|
|
*l;
|
|
|
|
List *newcmds = NIL;
|
|
|
|
bool skipValidation = true;
|
|
|
|
AlterTableCmd *newcmd;
|
2015-04-03 22:33:05 +02:00
|
|
|
RangeTblEntry *rte;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* We must not scribble on the passed-in AlterTableStmt, so copy it. (This
|
|
|
|
* is overkill, but easy.)
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
2017-03-09 21:18:59 +01:00
|
|
|
stmt = copyObject(stmt);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
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
|
|
|
/* Caller is responsible for locking the relation */
|
|
|
|
rel = relation_open(relid, NoLock);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2015-04-03 22:33:05 +02:00
|
|
|
/* Set up pstate */
|
2007-06-24 00:12:52 +02:00
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
pstate->p_sourcetext = queryString;
|
2015-04-03 22:33:05 +02:00
|
|
|
rte = addRangeTableEntryForRelation(pstate,
|
|
|
|
rel,
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
true);
|
|
|
|
addRTEtoQuery(pstate, rte, false, true, true);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2015-04-03 22:33:05 +02:00
|
|
|
/* Set up CreateStmtContext */
|
2011-01-25 21:42:03 +01:00
|
|
|
cxt.pstate = pstate;
|
2013-03-12 22:37:07 +01:00
|
|
|
if (stmt->relkind == OBJECT_FOREIGN_TABLE)
|
|
|
|
{
|
|
|
|
cxt.stmtType = "ALTER FOREIGN TABLE";
|
|
|
|
cxt.isforeign = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cxt.stmtType = "ALTER TABLE";
|
|
|
|
cxt.isforeign = false;
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt.relation = stmt->relation;
|
|
|
|
cxt.rel = rel;
|
|
|
|
cxt.inhRelations = NIL;
|
|
|
|
cxt.isalter = true;
|
|
|
|
cxt.hasoids = false; /* need not be right */
|
|
|
|
cxt.columns = NIL;
|
|
|
|
cxt.ckconstraints = NIL;
|
|
|
|
cxt.fkconstraints = NIL;
|
|
|
|
cxt.ixconstraints = NIL;
|
2007-07-17 07:02:03 +02:00
|
|
|
cxt.inh_indexes = NIL;
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
cxt.extstats = NIL;
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt.blist = NIL;
|
|
|
|
cxt.alist = NIL;
|
|
|
|
cxt.pkey = NULL;
|
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
|
|
|
cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
|
|
|
|
cxt.partbound = NULL;
|
2017-12-08 18:13:04 +01:00
|
|
|
cxt.ofType = false;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The only subtypes that currently require parse transformation handling
|
2015-04-03 22:33:05 +02:00
|
|
|
* are ADD COLUMN, ADD CONSTRAINT and SET DATA TYPE. These largely re-use
|
|
|
|
* code from CREATE TABLE.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
foreach(lcmd, stmt->cmds)
|
|
|
|
{
|
|
|
|
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
|
|
|
|
|
|
|
|
switch (cmd->subtype)
|
|
|
|
{
|
|
|
|
case AT_AddColumn:
|
2008-12-07 00:22:46 +01:00
|
|
|
case AT_AddColumnToView:
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2017-02-21 17:33:07 +01:00
|
|
|
ColumnDef *def = castNode(ColumnDef, cmd->def);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2011-01-25 21:42:03 +01:00
|
|
|
transformColumnDefinition(&cxt, def);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the column has a non-null default, we can't skip
|
|
|
|
* validation of foreign keys.
|
|
|
|
*/
|
2008-04-24 22:46:49 +02:00
|
|
|
if (def->raw_default != NULL)
|
2007-06-24 00:12:52 +02:00
|
|
|
skipValidation = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All constraints are processed in other ways. Remove the
|
|
|
|
* original list
|
|
|
|
*/
|
|
|
|
def->constraints = NIL;
|
|
|
|
|
2008-04-24 22:46:49 +02:00
|
|
|
newcmds = lappend(newcmds, cmd);
|
2007-06-24 00:12:52 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-04-03 22:33:05 +02:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
case AT_AddConstraint:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The original AddConstraint cmd node doesn't go to newcmds
|
|
|
|
*/
|
|
|
|
if (IsA(cmd->def, Constraint))
|
2009-07-30 04:45:38 +02:00
|
|
|
{
|
2011-01-25 21:42:03 +01:00
|
|
|
transformTableConstraint(&cxt, (Constraint *) cmd->def);
|
2009-07-30 04:45:38 +02:00
|
|
|
if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
|
|
|
|
skipValidation = false;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(cmd->def));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AT_ProcessedConstraint:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Already-transformed ADD CONSTRAINT, so just make it look
|
|
|
|
* like the standard case.
|
|
|
|
*/
|
|
|
|
cmd->subtype = AT_AddConstraint;
|
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
break;
|
|
|
|
|
2015-04-03 22:33:05 +02:00
|
|
|
case AT_AlterColumnType:
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
ColumnDef *def = (ColumnDef *) cmd->def;
|
2017-04-06 14:33:16 +02:00
|
|
|
AttrNumber attnum;
|
2015-04-03 22:33:05 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For ALTER COLUMN TYPE, transform the USING clause if
|
|
|
|
* one was specified.
|
|
|
|
*/
|
|
|
|
if (def->raw_default)
|
|
|
|
{
|
|
|
|
def->cooked_default =
|
|
|
|
transformExpr(pstate, def->raw_default,
|
|
|
|
EXPR_KIND_ALTER_COL_TRANSFORM);
|
|
|
|
}
|
|
|
|
|
2017-04-06 14:33:16 +02:00
|
|
|
/*
|
|
|
|
* For identity column, create ALTER SEQUENCE command to
|
|
|
|
* change the data type of the sequence.
|
|
|
|
*/
|
|
|
|
attnum = get_attnum(relid, cmd->name);
|
2017-05-17 22:31:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if attribute not found, something will error about it
|
|
|
|
* later
|
|
|
|
*/
|
2017-04-06 14:33:16 +02:00
|
|
|
if (attnum != InvalidAttrNumber && get_attidentity(relid, attnum))
|
|
|
|
{
|
|
|
|
Oid seq_relid = getOwnedSequence(relid, attnum);
|
|
|
|
Oid typeOid = typenameTypeId(pstate, def->typeName);
|
|
|
|
AlterSeqStmt *altseqstmt = makeNode(AlterSeqStmt);
|
|
|
|
|
|
|
|
altseqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
get_rel_name(seq_relid),
|
2017-04-06 14:33:16 +02:00
|
|
|
-1);
|
|
|
|
altseqstmt->options = list_make1(makeDefElem("as", (Node *) makeTypeNameFromOid(typeOid, -1), -1));
|
|
|
|
altseqstmt->for_identity = true;
|
|
|
|
cxt.blist = lappend(cxt.blist, altseqstmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case AT_AddIdentity:
|
|
|
|
{
|
2017-05-17 22:31:56 +02:00
|
|
|
Constraint *def = castNode(Constraint, cmd->def);
|
|
|
|
ColumnDef *newdef = makeNode(ColumnDef);
|
2017-04-06 14:33:16 +02:00
|
|
|
AttrNumber attnum;
|
|
|
|
|
|
|
|
newdef->colname = cmd->name;
|
|
|
|
newdef->identity = def->generated_when;
|
|
|
|
cmd->def = (Node *) newdef;
|
|
|
|
|
|
|
|
attnum = get_attnum(relid, cmd->name);
|
2017-05-17 22:31:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if attribute not found, something will error about it
|
|
|
|
* later
|
|
|
|
*/
|
2017-04-06 14:33:16 +02:00
|
|
|
if (attnum != InvalidAttrNumber)
|
|
|
|
generateSerialExtraStmts(&cxt, newdef,
|
|
|
|
get_atttype(relid, attnum),
|
|
|
|
def->options, true,
|
|
|
|
NULL, NULL);
|
|
|
|
|
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case AT_SetIdentity:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Create an ALTER SEQUENCE statement for the internal
|
|
|
|
* sequence of the identity column.
|
|
|
|
*/
|
|
|
|
ListCell *lc;
|
|
|
|
List *newseqopts = NIL;
|
|
|
|
List *newdef = NIL;
|
|
|
|
List *seqlist;
|
|
|
|
AttrNumber attnum;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Split options into those handled by ALTER SEQUENCE and
|
|
|
|
* those for ALTER TABLE proper.
|
|
|
|
*/
|
|
|
|
foreach(lc, castNode(List, cmd->def))
|
|
|
|
{
|
2017-05-17 22:31:56 +02:00
|
|
|
DefElem *def = lfirst_node(DefElem, lc);
|
2017-04-06 14:33:16 +02:00
|
|
|
|
|
|
|
if (strcmp(def->defname, "generated") == 0)
|
|
|
|
newdef = lappend(newdef, def);
|
|
|
|
else
|
|
|
|
newseqopts = lappend(newseqopts, def);
|
|
|
|
}
|
|
|
|
|
|
|
|
attnum = get_attnum(relid, cmd->name);
|
|
|
|
|
|
|
|
if (attnum)
|
|
|
|
{
|
|
|
|
seqlist = getOwnedSequences(relid, attnum);
|
|
|
|
if (seqlist)
|
|
|
|
{
|
|
|
|
AlterSeqStmt *seqstmt;
|
|
|
|
Oid seq_relid;
|
|
|
|
|
|
|
|
seqstmt = makeNode(AlterSeqStmt);
|
|
|
|
seq_relid = linitial_oid(seqlist);
|
|
|
|
seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
get_rel_name(seq_relid), -1);
|
2017-04-06 14:33:16 +02:00
|
|
|
seqstmt->options = newseqopts;
|
|
|
|
seqstmt->for_identity = true;
|
|
|
|
seqstmt->missing_ok = false;
|
|
|
|
|
|
|
|
cxt.alist = lappend(cxt.alist, seqstmt);
|
|
|
|
}
|
|
|
|
}
|
2017-05-17 22:31:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If column was not found or was not an identity column,
|
|
|
|
* we just let the ALTER TABLE command error out later.
|
|
|
|
*/
|
2017-04-06 14:33:16 +02:00
|
|
|
|
|
|
|
cmd->def = (Node *) newdef;
|
2015-04-03 22:33:05 +02:00
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
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 AT_AttachPartition:
|
2017-02-16 14:37:37 +01:00
|
|
|
case AT_DetachPartition:
|
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
|
|
|
{
|
|
|
|
PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
|
|
|
|
|
2017-02-16 14:37:37 +01:00
|
|
|
transformPartitionCmd(&cxt, partcmd);
|
|
|
|
/* assign transformed value of the partition bound */
|
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
|
|
|
partcmd->bound = cxt.partbound;
|
|
|
|
}
|
|
|
|
|
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
break;
|
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
default:
|
|
|
|
newcmds = lappend(newcmds, cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformIndexConstraints wants cxt.alist to contain only index
|
2007-12-02 00:44:44 +01:00
|
|
|
* statements, so transfer anything we already have into save_alist
|
2007-06-24 00:12:52 +02:00
|
|
|
* immediately.
|
|
|
|
*/
|
|
|
|
save_alist = cxt.alist;
|
|
|
|
cxt.alist = NIL;
|
|
|
|
|
2015-12-16 13:43:56 +01:00
|
|
|
/* Postprocess constraints */
|
2011-01-25 21:42:03 +01:00
|
|
|
transformIndexConstraints(&cxt);
|
|
|
|
transformFKConstraints(&cxt, skipValidation, true);
|
2015-12-16 13:43:56 +01:00
|
|
|
transformCheckConstraints(&cxt, false);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Push any index-creation commands into the ALTER, so that they can be
|
|
|
|
* scheduled nicely by tablecmds.c. Note that tablecmds.c assumes that
|
2011-01-25 21:42:03 +01:00
|
|
|
* the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
|
|
|
|
* subcommand has already been through transformIndexStmt.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
foreach(l, cxt.alist)
|
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
IndexStmt *idxstmt = lfirst_node(IndexStmt, l);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
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
|
|
|
idxstmt = transformIndexStmt(relid, idxstmt, queryString);
|
2007-06-24 00:12:52 +02:00
|
|
|
newcmd = makeNode(AlterTableCmd);
|
2011-01-25 21:42:03 +01:00
|
|
|
newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
|
|
|
|
newcmd->def = (Node *) idxstmt;
|
2007-06-24 00:12:52 +02:00
|
|
|
newcmds = lappend(newcmds, newcmd);
|
|
|
|
}
|
|
|
|
cxt.alist = NIL;
|
|
|
|
|
|
|
|
/* Append any CHECK or FK constraints to the commands list */
|
|
|
|
foreach(l, cxt.ckconstraints)
|
|
|
|
{
|
|
|
|
newcmd = makeNode(AlterTableCmd);
|
|
|
|
newcmd->subtype = AT_AddConstraint;
|
|
|
|
newcmd->def = (Node *) lfirst(l);
|
|
|
|
newcmds = lappend(newcmds, newcmd);
|
|
|
|
}
|
|
|
|
foreach(l, cxt.fkconstraints)
|
|
|
|
{
|
|
|
|
newcmd = makeNode(AlterTableCmd);
|
|
|
|
newcmd->subtype = AT_AddConstraint;
|
|
|
|
newcmd->def = (Node *) lfirst(l);
|
|
|
|
newcmds = lappend(newcmds, newcmd);
|
|
|
|
}
|
|
|
|
|
Clone extended stats in CREATE TABLE (LIKE INCLUDING ALL)
The LIKE INCLUDING ALL clause to CREATE TABLE intuitively indicates
cloning of extended statistics on the source table, but it failed to do
so. Patch it up so that it does. Also include an INCLUDING STATISTICS
option to the LIKE clause, so that the behavior can be requested
individually, or excluded individually.
While at it, reorder the INCLUDING options, both in code and in docs, in
alphabetical order which makes more sense than feature-implementation
order that was previously used.
Backpatch this to Postgres 10, where extended statistics were
introduced, because this is seen as an oversight in a fresh feature
which is better to get consistent from the get-go instead of changing
only in pg11.
In pg11, comments on statistics objects are cloned too. In pg10 they
are not, because I (Álvaro) was too coward to change the parse node as
required to support it. Also, in pg10 I chose not to renumber the
parser symbols for the various INCLUDING options in LIKE, for the same
reason. Any corresponding user-visible changes (docs) are backpatched,
though.
Reported-by: Stephen Froehlich
Author: David Rowley
Reviewed-by: Álvaro Herrera, Tomas Vondra
Discussion: https://postgr.es/m/CY1PR0601MB1927315B45667A1B679D0FD5E5EF0@CY1PR0601MB1927.namprd06.prod.outlook.com
2018-03-05 23:37:19 +01:00
|
|
|
/* Append extended statistic objects */
|
|
|
|
transformExtendedStatistics(&cxt);
|
|
|
|
|
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
|
|
|
/* Close rel */
|
2007-06-24 00:12:52 +02:00
|
|
|
relation_close(rel, NoLock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Output results.
|
|
|
|
*/
|
|
|
|
stmt->cmds = newcmds;
|
|
|
|
|
|
|
|
result = lappend(cxt.blist, stmt);
|
|
|
|
result = list_concat(result, cxt.alist);
|
|
|
|
result = list_concat(result, save_alist);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Preprocess a list of column constraint clauses
|
|
|
|
* to attach constraint attributes to their primary constraint nodes
|
|
|
|
* and detect inconsistent/misplaced constraint attributes.
|
|
|
|
*
|
2009-07-29 22:56:21 +02:00
|
|
|
* NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
|
2011-06-30 01:39:33 +02:00
|
|
|
* EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
|
|
|
|
* supported for other constraint types.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
Constraint *lastprimarycon = NULL;
|
2007-06-24 00:12:52 +02:00
|
|
|
bool saw_deferrability = false;
|
|
|
|
bool saw_initially = false;
|
|
|
|
ListCell *clist;
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
#define SUPPORTS_ATTRS(node) \
|
|
|
|
((node) != NULL && \
|
|
|
|
((node)->contype == CONSTR_PRIMARY || \
|
|
|
|
(node)->contype == CONSTR_UNIQUE || \
|
2009-12-07 06:22:23 +01:00
|
|
|
(node)->contype == CONSTR_EXCLUSION || \
|
2009-07-30 04:45:38 +02:00
|
|
|
(node)->contype == CONSTR_FOREIGN))
|
2009-07-29 22:56:21 +02:00
|
|
|
|
2007-06-24 00:12:52 +02:00
|
|
|
foreach(clist, constraintList)
|
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
Constraint *con = (Constraint *) lfirst(clist);
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
if (!IsA(con, Constraint))
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(con));
|
|
|
|
switch (con->contype)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_ATTR_DEFERRABLE:
|
|
|
|
if (!SUPPORTS_ATTRS(lastprimarycon))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("misplaced DEFERRABLE clause"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
if (saw_deferrability)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
saw_deferrability = true;
|
|
|
|
lastprimarycon->deferrable = true;
|
|
|
|
break;
|
2009-07-29 22:56:21 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_ATTR_NOT_DEFERRABLE:
|
|
|
|
if (!SUPPORTS_ATTRS(lastprimarycon))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("misplaced NOT DEFERRABLE clause"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
if (saw_deferrability)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
saw_deferrability = true;
|
|
|
|
lastprimarycon->deferrable = false;
|
|
|
|
if (saw_initially &&
|
|
|
|
lastprimarycon->initdeferred)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
break;
|
2009-07-29 22:56:21 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_ATTR_DEFERRED:
|
|
|
|
if (!SUPPORTS_ATTRS(lastprimarycon))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("misplaced INITIALLY DEFERRED clause"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
if (saw_initially)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
saw_initially = true;
|
|
|
|
lastprimarycon->initdeferred = true;
|
2007-06-24 00:12:52 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
/*
|
|
|
|
* If only INITIALLY DEFERRED appears, assume DEFERRABLE
|
|
|
|
*/
|
|
|
|
if (!saw_deferrability)
|
|
|
|
lastprimarycon->deferrable = true;
|
|
|
|
else if (!lastprimarycon->deferrable)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
break;
|
2009-07-29 22:56:21 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_ATTR_IMMEDIATE:
|
|
|
|
if (!SUPPORTS_ATTRS(lastprimarycon))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("misplaced INITIALLY IMMEDIATE clause"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
if (saw_initially)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
|
2011-01-25 21:42:03 +01:00
|
|
|
parser_errposition(cxt->pstate, con->location)));
|
2009-07-30 04:45:38 +02:00
|
|
|
saw_initially = true;
|
|
|
|
lastprimarycon->initdeferred = false;
|
|
|
|
break;
|
2009-07-29 22:56:21 +02:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
default:
|
|
|
|
/* Otherwise it's not an attribute */
|
|
|
|
lastprimarycon = con;
|
|
|
|
/* reset flags for new primary node */
|
|
|
|
saw_deferrability = false;
|
|
|
|
saw_initially = false;
|
|
|
|
break;
|
2007-06-24 00:12:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Special handling of type definition for a column
|
|
|
|
*/
|
|
|
|
static void
|
2011-01-25 21:42:03 +01:00
|
|
|
transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
|
2007-06-24 00:12:52 +02:00
|
|
|
{
|
|
|
|
/*
|
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
|
|
|
* All we really need to do here is verify that the type is valid,
|
|
|
|
* including any collation spec that might be present.
|
2007-06-24 00:12:52 +02:00
|
|
|
*/
|
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
|
|
|
Type ctype = typenameType(cxt->pstate, column->typeName, NULL);
|
|
|
|
|
|
|
|
if (column->collClause)
|
|
|
|
{
|
|
|
|
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
|
|
|
|
|
2011-04-11 21:28:45 +02:00
|
|
|
LookupCollation(cxt->pstate,
|
2011-06-09 20:32:50 +02:00
|
|
|
column->collClause->collname,
|
|
|
|
column->collClause->location);
|
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
|
|
|
/* Complain if COLLATE is applied to an uncollatable type */
|
|
|
|
if (!OidIsValid(typtup->typcollation))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("collations are not supported by type %s",
|
|
|
|
format_type_be(HeapTupleGetOid(ctype))),
|
|
|
|
parser_errposition(cxt->pstate,
|
|
|
|
column->collClause->location)));
|
|
|
|
}
|
2007-06-24 00:12:52 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(ctype);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformCreateSchemaStmt -
|
|
|
|
* analyzes the CREATE SCHEMA statement
|
|
|
|
*
|
|
|
|
* Split the schema element list into individual commands and place
|
|
|
|
* them in the result list in an order such that there are no forward
|
|
|
|
* references (e.g. GRANT to a table created later in the list). Note
|
|
|
|
* that the logic we use for determining forward references is
|
|
|
|
* presently quite incomplete.
|
|
|
|
*
|
2013-04-20 17:04:41 +02:00
|
|
|
* SQL also allows constraints to make forward references, so thumb through
|
2007-06-24 00:12:52 +02:00
|
|
|
* the table columns and move forward references to a posterior alter-table
|
|
|
|
* command.
|
|
|
|
*
|
|
|
|
* The result is a list of parse nodes that still need to be analyzed ---
|
|
|
|
* but we can't analyze the later commands until we've executed the earlier
|
|
|
|
* ones, because of possible inter-object references.
|
|
|
|
*
|
|
|
|
* Note: this breaks the rules a little bit by modifying schema-name fields
|
|
|
|
* within passed-in structs. However, the transformation would be the same
|
|
|
|
* if done over, so it should be all right to scribble on the input to this
|
|
|
|
* extent.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
transformCreateSchemaStmt(CreateSchemaStmt *stmt)
|
|
|
|
{
|
|
|
|
CreateSchemaStmtContext cxt;
|
|
|
|
List *result;
|
|
|
|
ListCell *elements;
|
|
|
|
|
|
|
|
cxt.stmtType = "CREATE SCHEMA";
|
|
|
|
cxt.schemaname = stmt->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
|
|
|
cxt.authrole = (RoleSpec *) stmt->authrole;
|
2007-06-24 00:12:52 +02:00
|
|
|
cxt.sequences = NIL;
|
|
|
|
cxt.tables = NIL;
|
|
|
|
cxt.views = NIL;
|
|
|
|
cxt.indexes = NIL;
|
|
|
|
cxt.triggers = NIL;
|
|
|
|
cxt.grants = NIL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run through each schema element in the schema element list. Separate
|
|
|
|
* statements by type, and do preliminary analysis.
|
|
|
|
*/
|
|
|
|
foreach(elements, stmt->schemaElts)
|
|
|
|
{
|
|
|
|
Node *element = lfirst(elements);
|
|
|
|
|
|
|
|
switch (nodeTag(element))
|
|
|
|
{
|
|
|
|
case T_CreateSeqStmt:
|
|
|
|
{
|
|
|
|
CreateSeqStmt *elp = (CreateSeqStmt *) element;
|
|
|
|
|
|
|
|
setSchemaName(cxt.schemaname, &elp->sequence->schemaname);
|
|
|
|
cxt.sequences = lappend(cxt.sequences, element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_CreateStmt:
|
|
|
|
{
|
|
|
|
CreateStmt *elp = (CreateStmt *) element;
|
|
|
|
|
|
|
|
setSchemaName(cxt.schemaname, &elp->relation->schemaname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX todo: deal with constraints
|
|
|
|
*/
|
|
|
|
cxt.tables = lappend(cxt.tables, element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_ViewStmt:
|
|
|
|
{
|
|
|
|
ViewStmt *elp = (ViewStmt *) element;
|
|
|
|
|
|
|
|
setSchemaName(cxt.schemaname, &elp->view->schemaname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX todo: deal with references between views
|
|
|
|
*/
|
|
|
|
cxt.views = lappend(cxt.views, element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_IndexStmt:
|
|
|
|
{
|
|
|
|
IndexStmt *elp = (IndexStmt *) element;
|
|
|
|
|
|
|
|
setSchemaName(cxt.schemaname, &elp->relation->schemaname);
|
|
|
|
cxt.indexes = lappend(cxt.indexes, element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_CreateTrigStmt:
|
|
|
|
{
|
|
|
|
CreateTrigStmt *elp = (CreateTrigStmt *) element;
|
|
|
|
|
|
|
|
setSchemaName(cxt.schemaname, &elp->relation->schemaname);
|
|
|
|
cxt.triggers = lappend(cxt.triggers, element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_GrantStmt:
|
|
|
|
cxt.grants = lappend(cxt.grants, element);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(element));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = NIL;
|
|
|
|
result = list_concat(result, cxt.sequences);
|
|
|
|
result = list_concat(result, cxt.tables);
|
|
|
|
result = list_concat(result, cxt.views);
|
|
|
|
result = list_concat(result, cxt.indexes);
|
|
|
|
result = list_concat(result, cxt.triggers);
|
|
|
|
result = list_concat(result, cxt.grants);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setSchemaName
|
|
|
|
* Set or check schema name in an element of a CREATE SCHEMA command
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
setSchemaName(char *context_schema, char **stmt_schema_name)
|
|
|
|
{
|
|
|
|
if (*stmt_schema_name == NULL)
|
|
|
|
*stmt_schema_name = context_schema;
|
|
|
|
else if (strcmp(context_schema, *stmt_schema_name) != 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
|
|
|
|
errmsg("CREATE specifies a schema (%s) "
|
|
|
|
"different from the one being created (%s)",
|
|
|
|
*stmt_schema_name, context_schema)));
|
|
|
|
}
|
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
|
|
|
|
|
|
|
/*
|
2017-02-16 14:37:37 +01:00
|
|
|
* transformPartitionCmd
|
|
|
|
* Analyze the ATTACH/DETACH PARTITION command
|
|
|
|
*
|
|
|
|
* In case of the ATTACH PARTITION command, cxt->partbound is set to the
|
|
|
|
* transformed value of cmd->bound.
|
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 void
|
2017-02-16 14:37:37 +01:00
|
|
|
transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
|
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
|
|
|
{
|
|
|
|
Relation parentRel = cxt->rel;
|
|
|
|
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
switch (parentRel->rd_rel->relkind)
|
|
|
|
{
|
|
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
|
|
/* transform the partition bound, if any */
|
|
|
|
Assert(RelationGetPartitionKey(parentRel) != NULL);
|
|
|
|
if (cmd->bound != NULL)
|
|
|
|
cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
|
|
|
|
cmd->bound);
|
|
|
|
break;
|
|
|
|
case RELKIND_PARTITIONED_INDEX:
|
|
|
|
/* nothing to check */
|
|
|
|
Assert(cmd->bound == NULL);
|
|
|
|
break;
|
|
|
|
case RELKIND_RELATION:
|
|
|
|
/* the table must be partitioned */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("table \"%s\" is not partitioned",
|
|
|
|
RelationGetRelationName(parentRel))));
|
|
|
|
break;
|
|
|
|
case RELKIND_INDEX:
|
|
|
|
/* the index must be partitioned */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("index \"%s\" is not partitioned",
|
|
|
|
RelationGetRelationName(parentRel))));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* parser shouldn't let this case through */
|
|
|
|
elog(ERROR, "\"%s\" is not a partitioned table or index",
|
|
|
|
RelationGetRelationName(parentRel));
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transformPartitionBound
|
|
|
|
*
|
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
|
|
|
* Transform a partition bound specification
|
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
|
|
|
PartitionBoundSpec *
|
|
|
|
transformPartitionBound(ParseState *pstate, Relation parent,
|
|
|
|
PartitionBoundSpec *spec)
|
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
|
|
|
PartitionBoundSpec *result_spec;
|
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
|
|
|
PartitionKey key = RelationGetPartitionKey(parent);
|
|
|
|
char strategy = get_partition_strategy(key);
|
|
|
|
int partnatts = get_partition_natts(key);
|
|
|
|
List *partexprs = get_partition_exprs(key);
|
|
|
|
|
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
|
|
|
/* Avoid scribbling on input */
|
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
|
|
|
result_spec = copyObject(spec);
|
|
|
|
|
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
|
|
|
if (spec->is_default)
|
|
|
|
{
|
Add hash partitioning.
Hash partitioning is useful when you want to partition a growing data
set evenly. This can be useful to keep table sizes reasonable, which
makes maintenance operations such as VACUUM faster, or to enable
partition-wise join.
At present, we still depend on constraint exclusion for partitioning
pruning, and the shape of the partition constraints for hash
partitioning is such that that doesn't work. Work is underway to fix
that, which should both improve performance and make partitioning
pruning work with hash partitioning.
Amul Sul, reviewed and tested by Dilip Kumar, Ashutosh Bapat, Yugo
Nagata, Rajkumar Raghuwanshi, Jesper Pedersen, and by me. A few
final tweaks also by me.
Discussion: http://postgr.es/m/CAAJ_b96fhpJAP=ALbETmeLk1Uni_GFZD938zgenhF49qgDTjaQ@mail.gmail.com
2017-11-10 00:07:25 +01:00
|
|
|
if (strategy == PARTITION_STRATEGY_HASH)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("a hash-partitioned table may not have a default partition")));
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
* In case of the default partition, parser had no way to identify the
|
|
|
|
* partition strategy. Assign the parent's strategy to the default
|
|
|
|
* partition bound spec.
|
|
|
|
*/
|
|
|
|
result_spec->strategy = strategy;
|
|
|
|
|
|
|
|
return result_spec;
|
|
|
|
}
|
|
|
|
|
Add hash partitioning.
Hash partitioning is useful when you want to partition a growing data
set evenly. This can be useful to keep table sizes reasonable, which
makes maintenance operations such as VACUUM faster, or to enable
partition-wise join.
At present, we still depend on constraint exclusion for partitioning
pruning, and the shape of the partition constraints for hash
partitioning is such that that doesn't work. Work is underway to fix
that, which should both improve performance and make partitioning
pruning work with hash partitioning.
Amul Sul, reviewed and tested by Dilip Kumar, Ashutosh Bapat, Yugo
Nagata, Rajkumar Raghuwanshi, Jesper Pedersen, and by me. A few
final tweaks also by me.
Discussion: http://postgr.es/m/CAAJ_b96fhpJAP=ALbETmeLk1Uni_GFZD938zgenhF49qgDTjaQ@mail.gmail.com
2017-11-10 00:07:25 +01:00
|
|
|
if (strategy == PARTITION_STRATEGY_HASH)
|
|
|
|
{
|
|
|
|
if (spec->strategy != PARTITION_STRATEGY_HASH)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("invalid bound specification for a hash partition"),
|
|
|
|
parser_errposition(pstate, exprLocation((Node *) spec))));
|
|
|
|
|
|
|
|
if (spec->modulus <= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("modulus for hash partition must be a positive integer")));
|
|
|
|
|
|
|
|
Assert(spec->remainder >= 0);
|
|
|
|
|
|
|
|
if (spec->remainder >= spec->modulus)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("remainder for hash partition must be less than modulus")));
|
|
|
|
}
|
|
|
|
else if (strategy == PARTITION_STRATEGY_LIST)
|
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
|
|
|
{
|
|
|
|
ListCell *cell;
|
|
|
|
char *colname;
|
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
|
|
|
Oid coltype;
|
|
|
|
int32 coltypmod;
|
|
|
|
|
|
|
|
if (spec->strategy != PARTITION_STRATEGY_LIST)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("invalid bound specification for a list partition"),
|
|
|
|
parser_errposition(pstate, exprLocation((Node *) spec))));
|
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
|
|
|
|
|
|
|
/* Get the only column's name in case we need to output an error */
|
|
|
|
if (key->partattrs[0] != 0)
|
2018-02-12 23:30:30 +01:00
|
|
|
colname = get_attname(RelationGetRelid(parent),
|
|
|
|
key->partattrs[0], false);
|
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
|
|
|
else
|
|
|
|
colname = deparse_expression((Node *) linitial(partexprs),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
deparse_context_for(RelationGetRelationName(parent),
|
|
|
|
RelationGetRelid(parent)),
|
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
|
|
|
false, false);
|
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
|
|
|
/* Need its type data too */
|
|
|
|
coltype = get_partition_col_typid(key, 0);
|
|
|
|
coltypmod = get_partition_col_typmod(key, 0);
|
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
|
|
|
|
|
|
|
result_spec->listdatums = NIL;
|
|
|
|
foreach(cell, spec->listdatums)
|
|
|
|
{
|
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
|
|
|
A_Const *con = castNode(A_Const, lfirst(cell));
|
|
|
|
Const *value;
|
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
|
|
|
ListCell *cell2;
|
|
|
|
bool duplicate;
|
|
|
|
|
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
|
|
|
value = transformPartitionBoundValue(pstate, con,
|
|
|
|
colname, coltype, coltypmod);
|
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
|
|
|
|
|
|
|
/* Don't add to the result if the value is a duplicate */
|
|
|
|
duplicate = false;
|
|
|
|
foreach(cell2, result_spec->listdatums)
|
|
|
|
{
|
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
|
|
|
Const *value2 = castNode(Const, lfirst(cell2));
|
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
|
|
|
|
|
|
|
if (equal(value, value2))
|
|
|
|
{
|
|
|
|
duplicate = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (duplicate)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
result_spec->listdatums = lappend(result_spec->listdatums,
|
|
|
|
value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strategy == PARTITION_STRATEGY_RANGE)
|
|
|
|
{
|
|
|
|
ListCell *cell1,
|
|
|
|
*cell2;
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
|
|
|
|
if (spec->strategy != PARTITION_STRATEGY_RANGE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("invalid bound specification for a range partition"),
|
|
|
|
parser_errposition(pstate, exprLocation((Node *) spec))));
|
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
|
|
|
|
|
|
|
if (list_length(spec->lowerdatums) != partnatts)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("FROM must specify exactly one value per partitioning column")));
|
|
|
|
if (list_length(spec->upperdatums) != partnatts)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("TO must specify exactly one value per partitioning column")));
|
|
|
|
|
2017-09-16 03:15:55 +02:00
|
|
|
/*
|
|
|
|
* Once we see MINVALUE or MAXVALUE for one column, the remaining
|
|
|
|
* columns must be the same.
|
|
|
|
*/
|
|
|
|
validateInfiniteBounds(pstate, spec->lowerdatums);
|
|
|
|
validateInfiniteBounds(pstate, spec->upperdatums);
|
|
|
|
|
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
|
|
|
/* Transform all the constants */
|
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
|
|
|
i = j = 0;
|
|
|
|
result_spec->lowerdatums = result_spec->upperdatums = NIL;
|
|
|
|
forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
|
|
|
|
{
|
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
|
|
|
PartitionRangeDatum *ldatum = (PartitionRangeDatum *) lfirst(cell1);
|
|
|
|
PartitionRangeDatum *rdatum = (PartitionRangeDatum *) lfirst(cell2);
|
|
|
|
char *colname;
|
|
|
|
Oid coltype;
|
|
|
|
int32 coltypmod;
|
|
|
|
A_Const *con;
|
|
|
|
Const *value;
|
|
|
|
|
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
|
|
|
/* Get the column's name in case we need to output an error */
|
|
|
|
if (key->partattrs[i] != 0)
|
2018-02-12 23:30:30 +01:00
|
|
|
colname = get_attname(RelationGetRelid(parent),
|
|
|
|
key->partattrs[i], false);
|
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
|
|
|
else
|
|
|
|
{
|
|
|
|
colname = deparse_expression((Node *) list_nth(partexprs, j),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
deparse_context_for(RelationGetRelationName(parent),
|
|
|
|
RelationGetRelid(parent)),
|
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
|
|
|
false, false);
|
|
|
|
++j;
|
|
|
|
}
|
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
|
|
|
/* Need its type data too */
|
|
|
|
coltype = get_partition_col_typid(key, i);
|
|
|
|
coltypmod = get_partition_col_typmod(key, i);
|
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
|
|
|
if (ldatum->value)
|
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
|
|
|
con = castNode(A_Const, ldatum->value);
|
|
|
|
value = transformPartitionBoundValue(pstate, con,
|
|
|
|
colname,
|
|
|
|
coltype, coltypmod);
|
|
|
|
if (value->constisnull)
|
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
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("cannot specify NULL in range bound")));
|
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
|
|
|
ldatum = copyObject(ldatum); /* don't scribble on input */
|
|
|
|
ldatum->value = (Node *) value;
|
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
|
|
|
if (rdatum->value)
|
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
|
|
|
con = castNode(A_Const, rdatum->value);
|
|
|
|
value = transformPartitionBoundValue(pstate, con,
|
|
|
|
colname,
|
|
|
|
coltype, coltypmod);
|
|
|
|
if (value->constisnull)
|
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
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("cannot specify NULL in range bound")));
|
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
|
|
|
rdatum = copyObject(rdatum); /* don't scribble on input */
|
|
|
|
rdatum->value = (Node *) value;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
result_spec->lowerdatums = lappend(result_spec->lowerdatums,
|
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
|
|
|
ldatum);
|
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
|
|
|
result_spec->upperdatums = lappend(result_spec->upperdatums,
|
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
|
|
|
rdatum);
|
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
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
|
|
|
|
|
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
|
|
|
return result_spec;
|
|
|
|
}
|
|
|
|
|
2017-09-16 03:15:55 +02:00
|
|
|
/*
|
|
|
|
* validateInfiniteBounds
|
|
|
|
*
|
|
|
|
* Check that a MAXVALUE or MINVALUE specification in a partition bound is
|
|
|
|
* followed only by more of the same.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
validateInfiniteBounds(ParseState *pstate, List *blist)
|
|
|
|
{
|
Add hash partitioning.
Hash partitioning is useful when you want to partition a growing data
set evenly. This can be useful to keep table sizes reasonable, which
makes maintenance operations such as VACUUM faster, or to enable
partition-wise join.
At present, we still depend on constraint exclusion for partitioning
pruning, and the shape of the partition constraints for hash
partitioning is such that that doesn't work. Work is underway to fix
that, which should both improve performance and make partitioning
pruning work with hash partitioning.
Amul Sul, reviewed and tested by Dilip Kumar, Ashutosh Bapat, Yugo
Nagata, Rajkumar Raghuwanshi, Jesper Pedersen, and by me. A few
final tweaks also by me.
Discussion: http://postgr.es/m/CAAJ_b96fhpJAP=ALbETmeLk1Uni_GFZD938zgenhF49qgDTjaQ@mail.gmail.com
2017-11-10 00:07:25 +01:00
|
|
|
ListCell *lc;
|
2017-09-16 03:15:55 +02:00
|
|
|
PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
|
|
|
|
|
|
|
|
foreach(lc, blist)
|
|
|
|
{
|
|
|
|
PartitionRangeDatum *prd = castNode(PartitionRangeDatum, lfirst(lc));
|
|
|
|
|
|
|
|
if (kind == prd->kind)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (kind)
|
|
|
|
{
|
|
|
|
case PARTITION_RANGE_DATUM_VALUE:
|
|
|
|
kind = prd->kind;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PARTITION_RANGE_DATUM_MAXVALUE:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("every bound following MAXVALUE must also be MAXVALUE"),
|
|
|
|
parser_errposition(pstate, exprLocation((Node *) prd))));
|
|
|
|
|
|
|
|
case PARTITION_RANGE_DATUM_MINVALUE:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("every bound following MINVALUE must also be MINVALUE"),
|
|
|
|
parser_errposition(pstate, exprLocation((Node *) prd))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
* Transform one constant in a partition bound spec
|
|
|
|
*/
|
|
|
|
static Const *
|
|
|
|
transformPartitionBoundValue(ParseState *pstate, A_Const *con,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
const char *colName, Oid colType, int32 colTypmod)
|
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
|
|
|
{
|
|
|
|
Node *value;
|
|
|
|
|
|
|
|
/* Make it into a Const */
|
|
|
|
value = (Node *) make_const(pstate, &con->val, con->location);
|
|
|
|
|
|
|
|
/* Coerce to correct type */
|
|
|
|
value = coerce_to_target_type(pstate,
|
|
|
|
value, exprType(value),
|
|
|
|
colType,
|
|
|
|
colTypmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
|
|
|
|
|
|
|
if (value == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("specified value cannot be cast to type %s for column \"%s\"",
|
|
|
|
format_type_be(colType), colName),
|
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
|
|
|
parser_errposition(pstate, con->location)));
|
|
|
|
|
|
|
|
/* Simplify the expression, in case we had a coercion */
|
|
|
|
if (!IsA(value, Const))
|
|
|
|
value = (Node *) expression_planner((Expr *) value);
|
|
|
|
|
|
|
|
/* Fail if we don't have a constant (i.e., non-immutable coercion) */
|
|
|
|
if (!IsA(value, Const))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
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:35:54 +02:00
|
|
|
errmsg("specified value cannot be cast to type %s for column \"%s\"",
|
|
|
|
format_type_be(colType), colName),
|
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
|
|
|
errdetail("The cast requires a non-immutable conversion."),
|
|
|
|
errhint("Try putting the literal value in single quotes."),
|
|
|
|
parser_errposition(pstate, con->location)));
|
|
|
|
|
|
|
|
return (Const *) value;
|
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
|
|
|
}
|