1996-07-09 08:22:35 +02:00
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
|
* heap.c
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* code to create and destroy POSTGRES heap relations
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2018-01-03 05:30:12 +01:00
|
|
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
|
* src/backend/catalog/heap.c
|
1999-02-02 04:45:56 +01:00
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
* INTERFACE ROUTINES
|
1997-11-28 05:40:40 +01:00
|
|
|
|
* heap_create() - Create an uncataloged heap relation
|
1997-11-28 18:28:02 +01:00
|
|
|
|
* heap_create_with_catalog() - Create a cataloged relation
|
1999-12-10 04:56:14 +01:00
|
|
|
|
* heap_drop_with_catalog() - Removes named relation from catalogs
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this code taken from access/heap/create.c, which contains
|
1998-08-06 07:13:14 +02:00
|
|
|
|
* the old heap_create_with_catalog, amcreate, and amdestroy.
|
1997-11-28 05:40:40 +01:00
|
|
|
|
* those routines will soon call these routines using the function
|
|
|
|
|
* manager,
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* just like the poorly named "NewXXX" routines do. The
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* "New" routines are all going to die soon, once and for all!
|
|
|
|
|
* -cim 1/13/91
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
|
#include "access/htup_details.h"
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
|
#include "access/multixact.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
|
#include "access/sysattr.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
|
#include "access/transam.h"
|
|
|
|
|
#include "access/xact.h"
|
2014-11-06 12:52:08 +01:00
|
|
|
|
#include "access/xlog.h"
|
2013-12-19 22:10:01 +01:00
|
|
|
|
#include "catalog/binary_upgrade.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "catalog/catalog.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
|
#include "catalog/dependency.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "catalog/heap.h"
|
|
|
|
|
#include "catalog/index.h"
|
2010-11-25 17:48:49 +01:00
|
|
|
|
#include "catalog/objectaccess.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 "catalog/partition.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "catalog/pg_attrdef.h"
|
2011-02-12 14:54:13 +01:00
|
|
|
|
#include "catalog/pg_collation.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
|
#include "catalog/pg_constraint.h"
|
2016-02-11 21:51:28 +01:00
|
|
|
|
#include "catalog/pg_constraint_fn.h"
|
2011-01-02 05:48:11 +01:00
|
|
|
|
#include "catalog/pg_foreign_table.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "catalog/pg_inherits.h"
|
2005-04-14 22:03:27 +02:00
|
|
|
|
#include "catalog/pg_namespace.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 "catalog/pg_opclass.h"
|
|
|
|
|
#include "catalog/pg_partitioned_table.h"
|
1999-11-28 03:03:04 +01:00
|
|
|
|
#include "catalog/pg_statistic.h"
|
2017-03-23 13:36:36 +01:00
|
|
|
|
#include "catalog/pg_subscription_rel.h"
|
2007-10-12 20:55:12 +02:00
|
|
|
|
#include "catalog/pg_tablespace.h"
|
1999-10-04 04:12:26 +02:00
|
|
|
|
#include "catalog/pg_type.h"
|
2008-03-27 04:57:34 +01:00
|
|
|
|
#include "catalog/pg_type_fn.h"
|
2008-11-19 11:34:52 +01:00
|
|
|
|
#include "catalog/storage.h"
|
2012-11-28 16:35:01 +01:00
|
|
|
|
#include "catalog/storage_xlog.h"
|
2002-11-10 00:56:39 +01:00
|
|
|
|
#include "commands/tablecmds.h"
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
#include "commands/typecmds.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
|
#include "executor/executor.h"
|
2000-01-16 20:57:00 +01:00
|
|
|
|
#include "miscadmin.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
|
#include "nodes/nodeFuncs.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
|
#include "optimizer/clauses.h"
|
1999-10-04 01:55:40 +02:00
|
|
|
|
#include "optimizer/var.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
|
#include "optimizer/planner.h"
|
2002-05-13 01:43:04 +02:00
|
|
|
|
#include "parser/parse_coerce.h"
|
2011-03-20 01:29:08 +01:00
|
|
|
|
#include "parser/parse_collate.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
|
#include "parser/parse_expr.h"
|
1999-10-04 01:55:40 +02:00
|
|
|
|
#include "parser/parse_relation.h"
|
2017-04-28 20:00:58 +02:00
|
|
|
|
#include "storage/lmgr.h"
|
2011-06-08 12:47:21 +02:00
|
|
|
|
#include "storage/predicate.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "storage/smgr.h"
|
2009-10-05 21:24:49 +02:00
|
|
|
|
#include "utils/acl.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
#include "utils/builtins.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
|
#include "utils/datum.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
|
#include "utils/fmgroids.h"
|
2002-03-03 18:47:56 +01:00
|
|
|
|
#include "utils/inval.h"
|
2000-12-22 20:21:37 +01:00
|
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
|
#include "utils/rel.h"
|
2014-10-08 23:10:47 +02:00
|
|
|
|
#include "utils/ruleutils.h"
|
2008-03-26 19:48:59 +01:00
|
|
|
|
#include "utils/snapmgr.h"
|
2008-03-26 22:10:39 +01:00
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
#include "utils/tqual.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
2015-03-11 03:33:25 +01:00
|
|
|
|
/* Potentially set by pg_upgrade_support functions */
|
2011-01-08 03:25:34 +01:00
|
|
|
|
Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid;
|
|
|
|
|
Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid;
|
2010-02-03 02:14:17 +01:00
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
|
static void AddNewRelationTuple(Relation pg_class_desc,
|
2001-10-25 07:50:21 +02:00
|
|
|
|
Relation new_rel_desc,
|
2010-01-29 00:21:13 +01:00
|
|
|
|
Oid new_rel_oid,
|
|
|
|
|
Oid new_type_oid,
|
|
|
|
|
Oid reloftype,
|
2005-08-26 05:08:15 +02:00
|
|
|
|
Oid relowner,
|
2006-07-02 04:23:23 +02:00
|
|
|
|
char relkind,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
Datum relacl,
|
2006-07-04 00:45:41 +02:00
|
|
|
|
Datum reloptions);
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
static ObjectAddress AddNewRelationType(const char *typeName,
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Oid typeNamespace,
|
|
|
|
|
Oid new_rel_oid,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
char new_rel_kind,
|
Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER
TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row. However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes). Problem identified by Cott Lang.
Back-patch to 8.1. The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1. Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
2009-02-24 02:38:10 +01:00
|
|
|
|
Oid ownerid,
|
2009-09-27 00:42:03 +02:00
|
|
|
|
Oid new_row_type,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
Oid new_array_type);
|
2004-08-28 23:05:26 +02:00
|
|
|
|
static void RelationRemoveInheritance(Oid relid);
|
2017-10-31 15:34:31 +01:00
|
|
|
|
static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
bool is_validated, bool is_local, int inhcount,
|
2013-03-18 03:55:14 +01:00
|
|
|
|
bool is_no_inherit, bool is_internal);
|
|
|
|
|
static void StoreConstraints(Relation rel, List *cooked_constraints,
|
2013-05-29 22:58:43 +02:00
|
|
|
|
bool is_internal);
|
2017-10-31 15:34:31 +01:00
|
|
|
|
static bool MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
bool allow_merge, bool is_local,
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
bool is_initially_valid,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
bool is_no_inherit);
|
2002-03-03 18:47:56 +01:00
|
|
|
|
static void SetRelationNumChecks(Relation rel, int numchecks);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
static Node *cookConstraint(ParseState *pstate,
|
|
|
|
|
Node *raw_constraint,
|
|
|
|
|
char *relname);
|
2006-06-29 18:07:29 +02:00
|
|
|
|
static List *insert_ordered_unique_oid(List *list, Oid datum);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* XXX UGLY HARD CODED BADNESS FOLLOWS XXX
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* these should all be moved to someplace in the lib/catalog
|
|
|
|
|
* module, if not obliterated first.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note:
|
2001-05-07 02:43:27 +02:00
|
|
|
|
* Should the system special case these attributes in the future?
|
|
|
|
|
* Advantage: consume much less space in the ATTRIBUTE relation.
|
|
|
|
|
* Disadvantage: special cases will be all over the place.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2010-01-22 17:40:19 +01:00
|
|
|
|
/*
|
2011-08-05 19:24:03 +02:00
|
|
|
|
* The initializers below do not include trailing variable length fields,
|
2010-01-22 17:40:19 +01:00
|
|
|
|
* but that's OK - we're never going to reference anything beyond the
|
|
|
|
|
* fixed-size portion of the structure anyway.
|
|
|
|
|
*/
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a1 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
SelfItemPointerAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
false, 'p', 's', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a2 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"oid"}, OIDOID, 0, sizeof(Oid),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
ObjectIdAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a3 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
MinTransactionIdAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a4 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
MinCommandIdAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a5 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
MaxTransactionIdAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static FormData_pg_attribute a6 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
MaxCommandIdAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
1996-07-09 08:22:35 +02:00
|
|
|
|
};
|
|
|
|
|
|
2000-10-11 23:28:19 +02:00
|
|
|
|
/*
|
2001-05-07 02:43:27 +02:00
|
|
|
|
* We decided to call this attribute "tableoid" rather than say
|
|
|
|
|
* "classoid" on the basis that in the future there may be more than one
|
|
|
|
|
* table of a particular class/type. In any case table is still the word
|
|
|
|
|
* used in SQL.
|
|
|
|
|
*/
|
2000-07-03 00:01:27 +02:00
|
|
|
|
static FormData_pg_attribute a7 = {
|
2010-01-22 17:40:19 +01:00
|
|
|
|
0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
|
2001-05-07 02:43:27 +02:00
|
|
|
|
TableOidAttributeNumber, 0, -1, -1,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
true, 'p', 'i', true, false, false, '\0', false, true, 0
|
2000-07-03 00:01:27 +02:00
|
|
|
|
};
|
|
|
|
|
|
2005-07-28 09:38:33 +02:00
|
|
|
|
static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
2001-05-07 02:43:27 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function returns a Form_pg_attribute pointer for a system attribute.
|
2003-07-21 03:59:11 +02:00
|
|
|
|
* Note that we elog if the presented attno is invalid, which would only
|
|
|
|
|
* happen if there's a problem upstream.
|
2001-05-07 02:43:27 +02:00
|
|
|
|
*/
|
|
|
|
|
Form_pg_attribute
|
2001-08-10 20:57:42 +02:00
|
|
|
|
SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
|
2001-05-07 02:43:27 +02:00
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
|
if (attno >= 0 || attno < -(int) lengthof(SysAtt))
|
2003-07-21 03:59:11 +02:00
|
|
|
|
elog(ERROR, "invalid system attribute number %d", attno);
|
2001-08-10 20:57:42 +02:00
|
|
|
|
if (attno == ObjectIdAttributeNumber && !relhasoids)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
elog(ERROR, "invalid system attribute number %d", attno);
|
2001-05-07 02:43:27 +02:00
|
|
|
|
return SysAtt[-attno - 1];
|
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
2001-10-23 00:47:57 +02:00
|
|
|
|
/*
|
|
|
|
|
* If the given name is a system attribute name, return a Form_pg_attribute
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* pointer for a prototype definition. If not, return NULL.
|
2001-10-23 00:47:57 +02:00
|
|
|
|
*/
|
|
|
|
|
Form_pg_attribute
|
|
|
|
|
SystemAttributeByName(const char *attname, bool relhasoids)
|
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
|
int j;
|
2001-10-23 00:47:57 +02:00
|
|
|
|
|
|
|
|
|
for (j = 0; j < (int) lengthof(SysAtt); j++)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_attribute att = SysAtt[j];
|
|
|
|
|
|
|
|
|
|
if (relhasoids || att->attnum != ObjectIdAttributeNumber)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(NameStr(att->attname), attname) == 0)
|
|
|
|
|
return att;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* XXX END OF UGLY HARD CODED BADNESS XXX
|
2000-07-03 00:01:27 +02:00
|
|
|
|
* ---------------------------------------------------------------- */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-11-28 05:40:40 +01:00
|
|
|
|
* heap_create - Create an uncataloged heap relation
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2005-08-12 03:36:05 +02:00
|
|
|
|
* Note API change: the caller must now always provide the OID
|
2011-07-18 17:02:48 +02:00
|
|
|
|
* to use for the relation. The relfilenode may (and, normally,
|
|
|
|
|
* should) be left unspecified.
|
2005-04-14 03:38:22 +02:00
|
|
|
|
*
|
2001-08-10 20:57:42 +02:00
|
|
|
|
* rel->rd_rel is initialized by RelationBuildLocalRelation,
|
|
|
|
|
* and is mostly zeroes at return.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
Relation
|
2002-03-31 08:26:32 +02:00
|
|
|
|
heap_create(const char *relname,
|
2002-03-26 20:17:02 +01:00
|
|
|
|
Oid relnamespace,
|
2004-06-18 08:14:31 +02:00
|
|
|
|
Oid reltablespace,
|
2005-04-14 03:38:22 +02:00
|
|
|
|
Oid relid,
|
2011-07-18 17:02:48 +02:00
|
|
|
|
Oid relfilenode,
|
1999-02-02 04:45:56 +01:00
|
|
|
|
TupleDesc tupDesc,
|
2004-08-31 19:10:36 +02:00
|
|
|
|
char relkind,
|
2010-12-13 18:34:26 +01:00
|
|
|
|
char relpersistence,
|
2002-04-27 23:24:34 +02:00
|
|
|
|
bool shared_relation,
|
2013-06-03 16:22:31 +02:00
|
|
|
|
bool mapped_relation,
|
|
|
|
|
bool allow_system_table_mods)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
2004-08-31 19:10:36 +02:00
|
|
|
|
bool create_storage;
|
2001-06-29 23:08:25 +02:00
|
|
|
|
Relation rel;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2005-08-12 03:36:05 +02:00
|
|
|
|
/* The caller must have provided an OID for the relation. */
|
|
|
|
|
Assert(OidIsValid(relid));
|
|
|
|
|
|
2013-06-03 16:22:31 +02:00
|
|
|
|
/*
|
Refine our definition of what constitutes a system relation.
Although user-defined relations can't be directly created in
pg_catalog, it's possible for them to end up there, because you can
create them in some other schema and then use ALTER TABLE .. SET SCHEMA
to move them there. Previously, such relations couldn't afterwards
be manipulated, because IsSystemRelation()/IsSystemClass() rejected
all attempts to modify objects in the pg_catalog schema, regardless
of their origin. With this patch, they now reject only those
objects in pg_catalog which were created at initdb-time, allowing
most operations on user-created tables in pg_catalog to proceed
normally.
This patch also adds new functions IsCatalogRelation() and
IsCatalogClass(), which is similar to IsSystemRelation() and
IsSystemClass() but with a slightly narrower definition: only TOAST
tables of system catalogs are included, rather than *all* TOAST tables.
This is currently used only for making decisions about when
invalidation messages need to be sent, but upcoming logical decoding
patches will find other uses for this information.
Andres Freund, with some modifications by me.
2013-11-29 02:57:20 +01:00
|
|
|
|
* Don't allow creating relations in pg_catalog directly, even though it
|
|
|
|
|
* is allowed to move user defined relations there. Semantics with search
|
|
|
|
|
* paths including pg_catalog are too confusing for now.
|
|
|
|
|
*
|
|
|
|
|
* But allow creating indexes on relations in pg_catalog even if
|
|
|
|
|
* allow_system_table_mods = off, upper layers already guarantee it's on a
|
|
|
|
|
* user defined relation, not a system one.
|
2013-06-03 16:22:31 +02:00
|
|
|
|
*/
|
|
|
|
|
if (!allow_system_table_mods &&
|
Refine our definition of what constitutes a system relation.
Although user-defined relations can't be directly created in
pg_catalog, it's possible for them to end up there, because you can
create them in some other schema and then use ALTER TABLE .. SET SCHEMA
to move them there. Previously, such relations couldn't afterwards
be manipulated, because IsSystemRelation()/IsSystemClass() rejected
all attempts to modify objects in the pg_catalog schema, regardless
of their origin. With this patch, they now reject only those
objects in pg_catalog which were created at initdb-time, allowing
most operations on user-created tables in pg_catalog to proceed
normally.
This patch also adds new functions IsCatalogRelation() and
IsCatalogClass(), which is similar to IsSystemRelation() and
IsSystemClass() but with a slightly narrower definition: only TOAST
tables of system catalogs are included, rather than *all* TOAST tables.
This is currently used only for making decisions about when
invalidation messages need to be sent, but upcoming logical decoding
patches will find other uses for this information.
Andres Freund, with some modifications by me.
2013-11-29 02:57:20 +01:00
|
|
|
|
((IsSystemNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
|
|
|
|
|
IsToastNamespace(relnamespace)) &&
|
2013-06-03 16:22:31 +02:00
|
|
|
|
IsNormalProcessingMode())
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
|
errmsg("permission denied to create \"%s.%s\"",
|
|
|
|
|
get_namespace_name(relnamespace), relname),
|
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("System catalog modifications are currently disallowed.")));
|
2013-06-03 16:22:31 +02:00
|
|
|
|
|
2004-08-31 19:10:36 +02:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Decide if we need storage or not, and handle a couple other special
|
|
|
|
|
* cases for particular relkinds.
|
2004-08-31 19:10:36 +02:00
|
|
|
|
*/
|
|
|
|
|
switch (relkind)
|
|
|
|
|
{
|
|
|
|
|
case RELKIND_VIEW:
|
|
|
|
|
case RELKIND_COMPOSITE_TYPE:
|
2011-01-02 05:48:11 +01:00
|
|
|
|
case RELKIND_FOREIGN_TABLE:
|
2017-03-31 22:28:30 +02:00
|
|
|
|
case RELKIND_PARTITIONED_TABLE:
|
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
|
|
|
|
case RELKIND_PARTITIONED_INDEX:
|
2004-08-31 19:10:36 +02:00
|
|
|
|
create_storage = false;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
|
2004-08-31 19:10:36 +02:00
|
|
|
|
/*
|
|
|
|
|
* Force reltablespace to zero if the relation has no physical
|
|
|
|
|
* storage. This is mainly just for cleanliness' sake.
|
|
|
|
|
*/
|
|
|
|
|
reltablespace = InvalidOid;
|
|
|
|
|
break;
|
|
|
|
|
case RELKIND_SEQUENCE:
|
|
|
|
|
create_storage = true;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
|
2004-08-31 19:10:36 +02:00
|
|
|
|
/*
|
|
|
|
|
* Force reltablespace to zero for sequences, since we don't
|
|
|
|
|
* support moving them around into different tablespaces.
|
|
|
|
|
*/
|
|
|
|
|
reltablespace = InvalidOid;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
create_storage = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-18 17:02:48 +02:00
|
|
|
|
/*
|
|
|
|
|
* Unless otherwise requested, the physical ID (relfilenode) is initially
|
|
|
|
|
* the same as the logical ID (OID). When the caller did specify a
|
|
|
|
|
* relfilenode, it already exists; do not attempt to create it.
|
|
|
|
|
*/
|
|
|
|
|
if (OidIsValid(relfilenode))
|
|
|
|
|
create_storage = false;
|
|
|
|
|
else
|
|
|
|
|
relfilenode = relid;
|
|
|
|
|
|
2004-07-11 21:52:52 +02:00
|
|
|
|
/*
|
|
|
|
|
* Never allow a pg_class entry to explicitly specify the database's
|
2004-08-29 07:07:03 +02:00
|
|
|
|
* default tablespace in reltablespace; force it to zero instead. This
|
|
|
|
|
* ensures that if the database is cloned with a different default
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* tablespace, the pg_class entry will still match where CREATE DATABASE
|
|
|
|
|
* will put the physically copied relation.
|
2004-07-11 21:52:52 +02:00
|
|
|
|
*
|
|
|
|
|
* Yes, this is a bit of a hack.
|
|
|
|
|
*/
|
|
|
|
|
if (reltablespace == MyDatabaseTableSpace)
|
|
|
|
|
reltablespace = InvalidOid;
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2001-06-29 23:08:25 +02:00
|
|
|
|
* build the relcache entry.
|
2000-06-28 05:33:33 +02:00
|
|
|
|
*/
|
2002-03-26 20:17:02 +01:00
|
|
|
|
rel = RelationBuildLocalRelation(relname,
|
|
|
|
|
relnamespace,
|
|
|
|
|
tupDesc,
|
2004-06-18 08:14:31 +02:00
|
|
|
|
relid,
|
2011-07-18 17:02:48 +02:00
|
|
|
|
relfilenode,
|
2004-06-18 08:14:31 +02:00
|
|
|
|
reltablespace,
|
2010-02-07 21:48:13 +01:00
|
|
|
|
shared_relation,
|
2010-12-13 18:34:26 +01:00
|
|
|
|
mapped_relation,
|
2012-06-14 15:47:30 +02:00
|
|
|
|
relpersistence,
|
|
|
|
|
relkind);
|
2000-07-02 06:46:09 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2008-08-11 13:05:11 +02:00
|
|
|
|
* Have the storage manager create the relation's disk file, if needed.
|
|
|
|
|
*
|
2008-11-19 11:34:52 +01:00
|
|
|
|
* We only create the main fork here, other forks will be created on
|
|
|
|
|
* demand.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-07-11 21:52:52 +02:00
|
|
|
|
if (create_storage)
|
|
|
|
|
{
|
2005-01-10 21:02:24 +01:00
|
|
|
|
RelationOpenSmgr(rel);
|
2010-12-13 18:34:26 +01:00
|
|
|
|
RelationCreateStorage(rel->rd_node, relpersistence);
|
2004-07-11 21:52:52 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
|
return rel;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-11-28 18:28:02 +01:00
|
|
|
|
* heap_create_with_catalog - Create a cataloged relation
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2005-07-14 00:46:09 +02:00
|
|
|
|
* this is done in multiple steps:
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* 1) CheckAttributeNamesTypes() is used to make certain the tuple
|
|
|
|
|
* descriptor contains a valid set of attribute names and types
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2002-03-26 20:17:02 +01:00
|
|
|
|
* 2) pg_class is opened and get_relname_relid()
|
2000-01-16 20:57:00 +01:00
|
|
|
|
* performs a scan to ensure that no relation with the
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* same name already exists.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2001-02-12 21:07:21 +01:00
|
|
|
|
* 3) heap_create() is called to create the new relation on disk.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2005-08-12 03:36:05 +02:00
|
|
|
|
* 4) TypeCreate() is called to define a new type corresponding
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* to the new relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2005-08-12 03:36:05 +02:00
|
|
|
|
* 5) AddNewRelationTuple() is called to register the
|
|
|
|
|
* relation in pg_class.
|
|
|
|
|
*
|
2001-02-12 21:07:21 +01:00
|
|
|
|
* 6) AddNewAttributeTuples() is called to register the
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* new relation's schema in pg_attribute.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* 7) StoreConstraints is called () - vadim 08/22/97
|
|
|
|
|
*
|
|
|
|
|
* 8) the relations are closed and the new relation's oid
|
|
|
|
|
* is returned.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* CheckAttributeNamesTypes
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this is used to make certain the tuple descriptor contains a
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* valid set of attribute names and datatypes. a problem simply
|
2003-07-21 03:59:11 +02:00
|
|
|
|
* generates ereport(ERROR) which aborts the current transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
2002-12-16 19:39:22 +01:00
|
|
|
|
void
|
2010-02-07 21:48:13 +01:00
|
|
|
|
CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
|
|
|
|
|
bool allow_system_table_mods)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
2000-03-17 03:36:41 +01:00
|
|
|
|
int i;
|
|
|
|
|
int j;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
int natts = tupdesc->natts;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-12-16 19:39:22 +01:00
|
|
|
|
/* Sanity check on column count */
|
|
|
|
|
if (natts < 0 || natts > MaxHeapAttributeNumber)
|
2003-07-20 23:56:35 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_TOO_MANY_COLUMNS),
|
|
|
|
|
errmsg("tables can have at most %d columns",
|
|
|
|
|
MaxHeapAttributeNumber)));
|
2002-12-16 19:39:22 +01:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
|
|
|
|
* first check for collision with system attribute names
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*
|
2002-08-29 02:17:06 +02:00
|
|
|
|
* Skip this for a view or type relation, since those don't have system
|
2002-08-15 18:36:08 +02:00
|
|
|
|
* attributes.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2002-08-15 18:36:08 +02:00
|
|
|
|
if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
|
2002-05-22 17:35:43 +02:00
|
|
|
|
{
|
2002-05-22 09:46:58 +02:00
|
|
|
|
for (i = 0; i < natts; i++)
|
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
|
|
|
|
|
|
|
|
|
|
if (SystemAttributeByName(NameStr(attr->attname),
|
2002-09-02 03:05:06 +02:00
|
|
|
|
tupdesc->tdhasoid) != NULL)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
|
|
|
|
errmsg("column name \"%s\" conflicts with a system column name",
|
2017-08-20 20:19:07 +02:00
|
|
|
|
NameStr(attr->attname))));
|
2002-05-22 17:35:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
|
|
|
|
* next check for repeated attribute names
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2000-03-17 03:36:41 +01:00
|
|
|
|
for (i = 1; i < natts; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
2000-03-17 03:36:41 +01:00
|
|
|
|
for (j = 0; j < i; j++)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
|
if (strcmp(NameStr(TupleDescAttr(tupdesc, j)->attname),
|
|
|
|
|
NameStr(TupleDescAttr(tupdesc, i)->attname)) == 0)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
2007-06-04 00:16:03 +02:00
|
|
|
|
errmsg("column name \"%s\" specified more than once",
|
2017-08-20 20:19:07 +02:00
|
|
|
|
NameStr(TupleDescAttr(tupdesc, j)->attname))));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
2002-08-05 04:30:50 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* next check the attribute types
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < natts; i++)
|
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
|
CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname),
|
|
|
|
|
TupleDescAttr(tupdesc, i)->atttypid,
|
|
|
|
|
TupleDescAttr(tupdesc, i)->attcollation,
|
2011-04-10 17:42:00 +02:00
|
|
|
|
NIL, /* assume we're creating a new rowtype */
|
2010-02-07 21:48:13 +01:00
|
|
|
|
allow_system_table_mods);
|
2002-12-16 19:39:22 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* CheckAttributeType
|
|
|
|
|
*
|
|
|
|
|
* Verify that the proposed datatype of an attribute is legal.
|
2011-03-28 21:44:54 +02:00
|
|
|
|
* This is needed mainly because there are types (and pseudo-types)
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* in the catalogs that we do not support as elements of real tuples.
|
2011-03-28 21:44:54 +02:00
|
|
|
|
* We also check some other properties required of a table column.
|
|
|
|
|
*
|
|
|
|
|
* If the attribute is being proposed for addition to an existing table or
|
|
|
|
|
* composite type, pass a one-element list of the rowtype OID as
|
|
|
|
|
* containing_rowtypes. When checking a to-be-created rowtype, it's
|
|
|
|
|
* sufficient to pass NIL, because there could not be any recursive reference
|
|
|
|
|
* to a not-yet-existing rowtype.
|
2002-12-16 19:39:22 +01:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
2011-03-28 21:44:54 +02:00
|
|
|
|
CheckAttributeType(const char *attname,
|
|
|
|
|
Oid atttypid, Oid attcollation,
|
|
|
|
|
List *containing_rowtypes,
|
2010-02-07 21:48:13 +01:00
|
|
|
|
bool allow_system_table_mods)
|
2002-12-16 19:39:22 +01:00
|
|
|
|
{
|
|
|
|
|
char att_typtype = get_typtype(atttypid);
|
2011-03-28 21:44:54 +02:00
|
|
|
|
Oid att_typelem;
|
2002-12-16 19:39:22 +01:00
|
|
|
|
|
2017-01-25 15:27:09 +01:00
|
|
|
|
if (att_typtype == TYPTYPE_PSEUDO)
|
2003-03-23 06:14:37 +01:00
|
|
|
|
{
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* Refuse any attempt to create a pseudo-type column, except for a
|
2010-02-26 03:01:40 +01:00
|
|
|
|
* special hack for pg_statistic: allow ANYARRAY when modifying system
|
|
|
|
|
* catalogs (this allows creating pg_statistic and cloning it during
|
|
|
|
|
* VACUUM FULL)
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
*/
|
2010-02-07 21:48:13 +01:00
|
|
|
|
if (atttypid != ANYARRAYOID || !allow_system_table_mods)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
2003-09-25 08:58:07 +02:00
|
|
|
|
errmsg("column \"%s\" has pseudo-type %s",
|
2003-07-21 03:59:11 +02:00
|
|
|
|
attname, format_type_be(atttypid))));
|
2003-03-23 06:14:37 +01:00
|
|
|
|
}
|
2011-06-03 00:37:57 +02:00
|
|
|
|
else if (att_typtype == TYPTYPE_DOMAIN)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If it's a domain, recurse to check its base type.
|
|
|
|
|
*/
|
|
|
|
|
CheckAttributeType(attname, getBaseType(atttypid), attcollation,
|
|
|
|
|
containing_rowtypes,
|
|
|
|
|
allow_system_table_mods);
|
|
|
|
|
}
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
else if (att_typtype == TYPTYPE_COMPOSITE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2011-06-03 00:37:57 +02:00
|
|
|
|
* For a composite type, recurse into its attributes.
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
*/
|
2007-11-15 22:14:46 +01:00
|
|
|
|
Relation relation;
|
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
int i;
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
|
2011-03-28 21:44:54 +02:00
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* Check for self-containment. Eventually we might be able to allow
|
2011-03-28 21:44:54 +02:00
|
|
|
|
* this (just return without complaint, if so) but it's not clear how
|
|
|
|
|
* many other places would require anti-recursion defenses before it
|
|
|
|
|
* would be safe to allow tables to contain their own rowtype.
|
|
|
|
|
*/
|
|
|
|
|
if (list_member_oid(containing_rowtypes, atttypid))
|
|
|
|
|
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("composite type %s cannot be made a member of itself",
|
|
|
|
|
format_type_be(atttypid))));
|
2011-03-28 21:44:54 +02:00
|
|
|
|
|
|
|
|
|
containing_rowtypes = lcons_oid(atttypid, containing_rowtypes);
|
|
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);
|
|
|
|
|
|
|
|
|
|
tupdesc = RelationGetDescr(relation);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < tupdesc->natts; i++)
|
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
|
|
|
|
|
if (attr->attisdropped)
|
|
|
|
|
continue;
|
2011-03-28 21:44:54 +02:00
|
|
|
|
CheckAttributeType(NameStr(attr->attname),
|
|
|
|
|
attr->atttypid, attr->attcollation,
|
|
|
|
|
containing_rowtypes,
|
2010-02-07 21:48:13 +01:00
|
|
|
|
allow_system_table_mods);
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
relation_close(relation, AccessShareLock);
|
2011-03-28 21:44:54 +02:00
|
|
|
|
|
|
|
|
|
containing_rowtypes = list_delete_first(containing_rowtypes);
|
|
|
|
|
}
|
|
|
|
|
else if (OidIsValid((att_typelem = get_element_type(atttypid))))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Must recurse into array types, too, in case they are composite.
|
|
|
|
|
*/
|
|
|
|
|
CheckAttributeType(attname, att_typelem, attcollation,
|
|
|
|
|
containing_rowtypes,
|
|
|
|
|
allow_system_table_mods);
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
}
|
2011-03-04 22:39:44 +01:00
|
|
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
|
* This might not be strictly invalid per SQL standard, but it is pretty
|
|
|
|
|
* useless, and it cannot be dumped, so we must disallow it.
|
2011-03-04 22:39:44 +01:00
|
|
|
|
*/
|
2011-03-28 21:44:54 +02:00
|
|
|
|
if (!OidIsValid(attcollation) && type_is_collatable(atttypid))
|
2011-04-10 17:42:00 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
|
errmsg("no collation was derived for column \"%s\" with collatable type %s",
|
|
|
|
|
attname, format_type_be(atttypid)),
|
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
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
/*
|
|
|
|
|
* InsertPgAttributeTuple
|
|
|
|
|
* Construct and insert a new tuple in pg_attribute.
|
|
|
|
|
*
|
|
|
|
|
* Caller has already opened and locked pg_attribute. new_attribute is the
|
2010-01-22 17:40:19 +01:00
|
|
|
|
* attribute to insert (but we ignore attacl and attoptions, which are always
|
|
|
|
|
* initialized to NULL).
|
2008-11-14 02:57:42 +01:00
|
|
|
|
*
|
2017-02-01 23:18:36 +01:00
|
|
|
|
* indstate is the index state for CatalogTupleInsertWithInfo. It can be
|
|
|
|
|
* passed as NULL, in which case we'll fetch the necessary info. (Don't do
|
|
|
|
|
* this when inserting multiple attributes, because it's a tad more
|
|
|
|
|
* expensive.)
|
2008-11-14 02:57:42 +01:00
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|
|
|
|
Form_pg_attribute new_attribute,
|
|
|
|
|
CatalogIndexState indstate)
|
|
|
|
|
{
|
|
|
|
|
Datum values[Natts_pg_attribute];
|
|
|
|
|
bool nulls[Natts_pg_attribute];
|
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
|
|
/* This is a tad tedious, but way cleaner than what we used to do... */
|
|
|
|
|
memset(values, 0, sizeof(values));
|
|
|
|
|
memset(nulls, false, sizeof(nulls));
|
|
|
|
|
|
|
|
|
|
values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid);
|
|
|
|
|
values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname);
|
|
|
|
|
values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid);
|
|
|
|
|
values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget);
|
|
|
|
|
values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen);
|
|
|
|
|
values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum);
|
|
|
|
|
values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims);
|
|
|
|
|
values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(new_attribute->attcacheoff);
|
|
|
|
|
values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod);
|
|
|
|
|
values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval);
|
|
|
|
|
values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage);
|
|
|
|
|
values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign);
|
|
|
|
|
values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull);
|
|
|
|
|
values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef);
|
2018-03-28 02:13:52 +02:00
|
|
|
|
values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(new_attribute->atthasmissing);
|
2017-04-06 14:33:16 +02:00
|
|
|
|
values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(new_attribute->attidentity);
|
2008-11-14 02:57:42 +01:00
|
|
|
|
values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
|
|
|
|
|
values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
|
|
|
|
|
values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
|
2011-02-08 22:04:18 +01:00
|
|
|
|
values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation);
|
2008-11-14 02:57:42 +01:00
|
|
|
|
|
2010-01-22 17:40:19 +01:00
|
|
|
|
/* start out with empty permissions and empty options */
|
2009-01-22 21:16:10 +01:00
|
|
|
|
nulls[Anum_pg_attribute_attacl - 1] = true;
|
2010-01-22 17:40:19 +01:00
|
|
|
|
nulls[Anum_pg_attribute_attoptions - 1] = true;
|
2011-08-05 19:24:03 +02:00
|
|
|
|
nulls[Anum_pg_attribute_attfdwoptions - 1] = true;
|
2018-03-28 02:13:52 +02:00
|
|
|
|
nulls[Anum_pg_attribute_attmissingval - 1] = true;
|
2009-01-22 21:16:10 +01:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
|
|
|
|
|
|
|
|
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
|
|
|
if (indstate != NULL)
|
2017-02-01 23:18:36 +01:00
|
|
|
|
CatalogTupleInsertWithInfo(pg_attribute_rel, tup, indstate);
|
2008-11-14 02:57:42 +01:00
|
|
|
|
else
|
2017-02-01 23:18:36 +01:00
|
|
|
|
CatalogTupleInsert(pg_attribute_rel, tup);
|
2008-11-14 02:57:42 +01:00
|
|
|
|
|
|
|
|
|
heap_freetuple(tup);
|
|
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* AddNewAttributeTuples
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this registers the new relation's schema by adding
|
|
|
|
|
* tuples to pg_attribute.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
AddNewAttributeTuples(Oid new_rel_oid,
|
2001-08-10 20:57:42 +02:00
|
|
|
|
TupleDesc tupdesc,
|
2004-03-23 20:35:17 +01:00
|
|
|
|
char relkind,
|
|
|
|
|
bool oidislocal,
|
|
|
|
|
int oidinhcount)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
2008-11-14 02:57:42 +01:00
|
|
|
|
Form_pg_attribute attr;
|
2000-03-17 03:36:41 +01:00
|
|
|
|
int i;
|
1998-08-19 04:04:17 +02:00
|
|
|
|
Relation rel;
|
2002-08-05 05:29:17 +02:00
|
|
|
|
CatalogIndexState indstate;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
int natts = tupdesc->natts;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
ObjectAddress myself,
|
|
|
|
|
referenced;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2002-08-05 05:29:17 +02:00
|
|
|
|
* open pg_attribute and its indexes.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2005-04-14 22:03:27 +02:00
|
|
|
|
rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-08-05 05:29:17 +02:00
|
|
|
|
indstate = CatalogOpenIndexes(rel);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* First we add the user attributes. This is also a convenient place to
|
2011-04-22 23:43:18 +02:00
|
|
|
|
* add dependencies on their datatypes and collations.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < natts; i++)
|
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
|
attr = TupleDescAttr(tupdesc, i);
|
2001-01-01 22:33:31 +01:00
|
|
|
|
/* Fill in the correct relation OID */
|
2008-11-14 02:57:42 +01:00
|
|
|
|
attr->attrelid = new_rel_oid;
|
2001-01-01 22:33:31 +01:00
|
|
|
|
/* Make sure these are OK, too */
|
2008-11-14 02:57:42 +01:00
|
|
|
|
attr->attstattarget = -1;
|
|
|
|
|
attr->attcacheoff = -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
InsertPgAttributeTuple(rel, attr, indstate);
|
2002-07-17 00:12:20 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
/* Add dependency info */
|
2005-04-14 03:38:22 +02:00
|
|
|
|
myself.classId = RelationRelationId;
|
2002-07-17 00:12:20 +02:00
|
|
|
|
myself.objectId = new_rel_oid;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
myself.objectSubId = i + 1;
|
2005-04-14 03:38:22 +02:00
|
|
|
|
referenced.classId = TypeRelationId;
|
2008-11-14 02:57:42 +01:00
|
|
|
|
referenced.objectId = attr->atttypid;
|
2002-07-17 00:12:20 +02:00
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
2011-02-12 14:54:13 +01:00
|
|
|
|
|
2011-04-22 23:43:18 +02:00
|
|
|
|
/* The default collation is pinned, so don't bother recording it */
|
|
|
|
|
if (OidIsValid(attr->attcollation) &&
|
|
|
|
|
attr->attcollation != DEFAULT_COLLATION_OID)
|
2011-02-12 14:54:13 +01:00
|
|
|
|
{
|
|
|
|
|
referenced.classId = CollationRelationId;
|
|
|
|
|
referenced.objectId = attr->attcollation;
|
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Next we add the system attributes. Skip OID if rel has no OIDs. Skip
|
|
|
|
|
* all for a view or type relation. We don't bother with making datatype
|
|
|
|
|
* dependencies here, since presumably all these types are pinned.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2002-08-15 18:36:08 +02:00
|
|
|
|
if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
|
2002-05-22 17:35:43 +02:00
|
|
|
|
{
|
2008-11-14 02:57:42 +01:00
|
|
|
|
for (i = 0; i < (int) lengthof(SysAtt); i++)
|
2001-08-10 20:57:42 +02:00
|
|
|
|
{
|
2008-11-14 02:57:42 +01:00
|
|
|
|
FormData_pg_attribute attStruct;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
/* skip OID where appropriate */
|
|
|
|
|
if (!tupdesc->tdhasoid &&
|
|
|
|
|
SysAtt[i]->attnum == ObjectIdAttributeNumber)
|
|
|
|
|
continue;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
memcpy(&attStruct, (char *) SysAtt[i], sizeof(FormData_pg_attribute));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
/* Fill in the correct relation OID in the copied tuple */
|
|
|
|
|
attStruct.attrelid = new_rel_oid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-11-14 02:57:42 +01:00
|
|
|
|
/* Fill in correct inheritance info for the OID column */
|
|
|
|
|
if (attStruct.attnum == ObjectIdAttributeNumber)
|
|
|
|
|
{
|
|
|
|
|
attStruct.attislocal = oidislocal;
|
|
|
|
|
attStruct.attinhcount = oidinhcount;
|
2002-05-22 09:46:58 +02:00
|
|
|
|
}
|
2008-11-14 02:57:42 +01:00
|
|
|
|
|
|
|
|
|
InsertPgAttributeTuple(rel, &attStruct, indstate);
|
2001-08-10 20:57:42 +02:00
|
|
|
|
}
|
2002-05-22 17:35:43 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2002-07-17 00:12:20 +02:00
|
|
|
|
* clean up
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2002-08-05 05:29:17 +02:00
|
|
|
|
CatalogCloseIndexes(indstate);
|
2001-06-12 07:55:50 +02:00
|
|
|
|
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-07-04 00:45:41 +02:00
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InsertPgClassTuple
|
|
|
|
|
*
|
|
|
|
|
* Construct and insert a new tuple in pg_class.
|
|
|
|
|
*
|
|
|
|
|
* Caller has already opened and locked pg_class.
|
|
|
|
|
* Tuple data is taken from new_rel_desc->rd_rel, except for the
|
|
|
|
|
* variable-width fields which are not present in a cached reldesc.
|
2009-10-05 21:24:49 +02:00
|
|
|
|
* relacl and reloptions are passed in Datum form (to avoid having
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* to reference the data types in heap.h). Pass (Datum) 0 to set them
|
2009-10-05 21:24:49 +02:00
|
|
|
|
* to NULL.
|
2006-07-04 00:45:41 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
InsertPgClassTuple(Relation pg_class_desc,
|
|
|
|
|
Relation new_rel_desc,
|
|
|
|
|
Oid new_rel_oid,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
Datum relacl,
|
2006-07-04 00:45:41 +02:00
|
|
|
|
Datum reloptions)
|
|
|
|
|
{
|
|
|
|
|
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
|
|
|
|
Datum values[Natts_pg_class];
|
2008-11-02 02:45:28 +01:00
|
|
|
|
bool nulls[Natts_pg_class];
|
2006-07-04 00:45:41 +02:00
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
|
|
/* This is a tad tedious, but way cleaner than what we used to do... */
|
|
|
|
|
memset(values, 0, sizeof(values));
|
2008-11-02 02:45:28 +01:00
|
|
|
|
memset(nulls, false, sizeof(nulls));
|
2006-07-04 00:45:41 +02:00
|
|
|
|
|
|
|
|
|
values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
|
|
|
|
|
values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
|
|
|
|
|
values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
|
2010-01-29 00:21:13 +01:00
|
|
|
|
values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
|
|
|
|
|
values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
|
|
|
|
|
values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
|
|
|
|
|
values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
|
|
|
|
|
values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
|
|
|
|
|
values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
|
2011-10-14 23:23:01 +02:00
|
|
|
|
values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
|
|
|
|
|
values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
|
|
|
|
|
values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
|
2010-12-13 18:34:26 +01:00
|
|
|
|
values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
|
|
|
|
|
values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
|
|
|
|
|
values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
|
|
|
|
|
values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids);
|
|
|
|
|
values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
|
2008-11-09 22:24:33 +01:00
|
|
|
|
values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
|
Code review for row security.
Buildfarm member tick identified an issue where the policies in the
relcache for a relation were were being replaced underneath a running
query, leading to segfaults while processing the policies to be added
to a query. Similar to how TupleDesc RuleLocks are handled, add in a
equalRSDesc() function to check if the policies have actually changed
and, if not, swap back the rsdesc field (using the original instead of
the temporairly built one; the whole structure is swapped and then
specific fields swapped back). This now passes a CLOBBER_CACHE_ALWAYS
for me and should resolve the buildfarm error.
In addition to addressing this, add a new chapter in Data Definition
under Privileges which explains row security and provides examples of
its usage, change \d to always list policies (even if row security is
disabled- but note that it is disabled, or enabled with no policies),
rework check_role_for_policy (it really didn't need the entire policy,
but it did need to be using has_privs_of_role()), and change the field
in pg_class to relrowsecurity from relhasrowsecurity, based on
Heikki's suggestion. Also from Heikki, only issue SET ROW_SECURITY in
pg_restore when talking to a 9.5+ server, list Bypass RLS in \du, and
document --enable-row-security options for pg_dump and pg_restore.
Lastly, fix a number of minor whitespace and typo issues from Heikki,
Dimitri, add a missing #include, per Peter E, fix a few minor
variable-assigned-but-not-used and resource leak issues from Coverity
and add tab completion for role attribute bypassrls as well.
2014-09-24 22:32:22 +02:00
|
|
|
|
values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity);
|
2015-10-05 03:05:08 +02:00
|
|
|
|
values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
|
2013-05-06 19:26:51 +02:00
|
|
|
|
values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
|
2013-11-08 18:30:43 +01:00
|
|
|
|
values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident);
|
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
|
|
|
|
values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition);
|
2018-03-21 14:13:24 +01:00
|
|
|
|
values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
|
values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
|
2009-10-05 21:24:49 +02:00
|
|
|
|
if (relacl != (Datum) 0)
|
|
|
|
|
values[Anum_pg_class_relacl - 1] = relacl;
|
|
|
|
|
else
|
|
|
|
|
nulls[Anum_pg_class_relacl - 1] = true;
|
2006-07-04 00:45:41 +02:00
|
|
|
|
if (reloptions != (Datum) 0)
|
|
|
|
|
values[Anum_pg_class_reloptions - 1] = reloptions;
|
|
|
|
|
else
|
2008-11-02 02:45:28 +01:00
|
|
|
|
nulls[Anum_pg_class_reloptions - 1] = true;
|
2006-07-04 00:45:41 +02: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
|
|
|
|
/* relpartbound is set by updating this tuple, if necessary */
|
|
|
|
|
nulls[Anum_pg_class_relpartbound - 1] = true;
|
|
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* The new tuple must have the oid already chosen for the rel. Sure would
|
2006-10-04 02:30:14 +02:00
|
|
|
|
* be embarrassing to do this sort of thing in polite company.
|
2006-07-04 00:45:41 +02:00
|
|
|
|
*/
|
|
|
|
|
HeapTupleSetOid(tup, new_rel_oid);
|
|
|
|
|
|
|
|
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleInsert(pg_class_desc, tup);
|
2006-07-04 00:45:41 +02:00
|
|
|
|
|
|
|
|
|
heap_freetuple(tup);
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
/* --------------------------------
|
1999-02-02 04:45:56 +01:00
|
|
|
|
* AddNewRelationTuple
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* this registers the new relation in the catalogs by
|
|
|
|
|
* adding a tuple to pg_class.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
1999-02-02 04:45:56 +01:00
|
|
|
|
AddNewRelationTuple(Relation pg_class_desc,
|
1999-05-25 18:15:34 +02:00
|
|
|
|
Relation new_rel_desc,
|
|
|
|
|
Oid new_rel_oid,
|
2001-02-12 21:07:21 +01:00
|
|
|
|
Oid new_type_oid,
|
2010-01-29 00:21:13 +01:00
|
|
|
|
Oid reloftype,
|
2005-08-26 05:08:15 +02:00
|
|
|
|
Oid relowner,
|
2006-07-02 04:23:23 +02:00
|
|
|
|
char relkind,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
Datum relacl,
|
2006-07-04 00:45:41 +02:00
|
|
|
|
Datum reloptions)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Form_pg_class new_rel_reltup;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* first we update some of the information in our uncataloged relation's
|
|
|
|
|
* relation descriptor.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
|
|
|
|
new_rel_reltup = new_rel_desc->rd_rel;
|
|
|
|
|
|
2001-05-07 02:43:27 +02:00
|
|
|
|
switch (relkind)
|
|
|
|
|
{
|
|
|
|
|
case RELKIND_RELATION:
|
2013-03-04 01:23:31 +01:00
|
|
|
|
case RELKIND_MATVIEW:
|
2001-05-07 02:43:27 +02:00
|
|
|
|
case RELKIND_INDEX:
|
|
|
|
|
case RELKIND_TOASTVALUE:
|
2004-12-01 20:00:56 +01:00
|
|
|
|
/* The relation is real, but as yet empty */
|
|
|
|
|
new_rel_reltup->relpages = 0;
|
|
|
|
|
new_rel_reltup->reltuples = 0;
|
2011-10-14 23:23:01 +02:00
|
|
|
|
new_rel_reltup->relallvisible = 0;
|
2001-05-07 02:43:27 +02:00
|
|
|
|
break;
|
|
|
|
|
case RELKIND_SEQUENCE:
|
2004-12-01 20:00:56 +01:00
|
|
|
|
/* Sequences always have a known size */
|
2001-05-07 02:43:27 +02:00
|
|
|
|
new_rel_reltup->relpages = 1;
|
|
|
|
|
new_rel_reltup->reltuples = 1;
|
2011-10-14 23:23:01 +02:00
|
|
|
|
new_rel_reltup->relallvisible = 0;
|
2001-05-07 02:43:27 +02:00
|
|
|
|
break;
|
2004-12-01 20:00:56 +01:00
|
|
|
|
default:
|
|
|
|
|
/* Views, etc, have no disk storage */
|
2001-05-07 02:43:27 +02:00
|
|
|
|
new_rel_reltup->relpages = 0;
|
|
|
|
|
new_rel_reltup->reltuples = 0;
|
2011-10-14 23:23:01 +02:00
|
|
|
|
new_rel_reltup->relallvisible = 0;
|
2001-05-07 02:43:27 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
|
/* Initialize relfrozenxid and relminmxid */
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
if (relkind == RELKIND_RELATION ||
|
2013-03-04 01:23:31 +01:00
|
|
|
|
relkind == RELKIND_MATVIEW ||
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
relkind == RELKIND_TOASTVALUE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Initialize to the minimum XID that could put tuples in the table.
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* We know that no xacts older than RecentXmin are still running, so
|
|
|
|
|
* that will do.
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
*/
|
2007-09-08 22:31:15 +02:00
|
|
|
|
new_rel_reltup->relfrozenxid = RecentXmin;
|
2013-05-29 22:58:43 +02:00
|
|
|
|
|
Improve concurrency of foreign key locking
This patch introduces two additional lock modes for tuples: "SELECT FOR
KEY SHARE" and "SELECT FOR NO KEY UPDATE". These don't block each
other, in contrast with already existing "SELECT FOR SHARE" and "SELECT
FOR UPDATE". UPDATE commands that do not modify the values stored in
the columns that are part of the key of the tuple now grab a SELECT FOR
NO KEY UPDATE lock on the tuple, allowing them to proceed concurrently
with tuple locks of the FOR KEY SHARE variety.
Foreign key triggers now use FOR KEY SHARE instead of FOR SHARE; this
means the concurrency improvement applies to them, which is the whole
point of this patch.
The added tuple lock semantics require some rejiggering of the multixact
module, so that the locking level that each transaction is holding can
be stored alongside its Xid. Also, multixacts now need to persist
across server restarts and crashes, because they can now represent not
only tuple locks, but also tuple updates. This means we need more
careful tracking of lifetime of pg_multixact SLRU files; since they now
persist longer, we require more infrastructure to figure out when they
can be removed. pg_upgrade also needs to be careful to copy
pg_multixact files over from the old server to the new, or at least part
of multixact.c state, depending on the versions of the old and new
servers.
Tuple time qualification rules (HeapTupleSatisfies routines) need to be
careful not to consider tuples with the "is multi" infomask bit set as
being only locked; they might need to look up MultiXact values (i.e.
possibly do pg_multixact I/O) to find out the Xid that updated a tuple,
whereas they previously were assured to only use information readily
available from the tuple header. This is considered acceptable, because
the extra I/O would involve cases that would previously cause some
commands to block waiting for concurrent transactions to finish.
Another important change is the fact that locking tuples that have
previously been updated causes the future versions to be marked as
locked, too; this is essential for correctness of foreign key checks.
This causes additional WAL-logging, also (there was previously a single
WAL record for a locked tuple; now there are as many as updated copies
of the tuple there exist.)
With all this in place, contention related to tuples being checked by
foreign key rules should be much reduced.
As a bonus, the old behavior that a subtransaction grabbing a stronger
tuple lock than the parent (sub)transaction held on a given tuple and
later aborting caused the weaker lock to be lost, has been fixed.
Many new spec files were added for isolation tester framework, to ensure
overall behavior is sane. There's probably room for several more tests.
There were several reviewers of this patch; in particular, Noah Misch
and Andres Freund spent considerable time in it. Original idea for the
patch came from Simon Riggs, after a problem report by Joel Jacobson.
Most code is from me, with contributions from Marti Raudsepp, Alexander
Shulgin, Noah Misch and Andres Freund.
This patch was discussed in several pgsql-hackers threads; the most
important start at the following message-ids:
AANLkTimo9XVcEzfiBR-ut3KVNDkjm2Vxh+t8kAmWjPuv@mail.gmail.com
1290721684-sup-3951@alvh.no-ip.org
1294953201-sup-2099@alvh.no-ip.org
1320343602-sup-2290@alvh.no-ip.org
1339690386-sup-8927@alvh.no-ip.org
4FE5FF020200002500048A3D@gw.wicourts.gov
4FEAB90A0200002500048B7D@gw.wicourts.gov
2013-01-23 16:04:59 +01:00
|
|
|
|
/*
|
|
|
|
|
* Similarly, initialize the minimum Multixact to the first value that
|
|
|
|
|
* could possibly be stored in tuples in the table. Running
|
|
|
|
|
* transactions could reuse values from their local cache, so we are
|
|
|
|
|
* careful to consider all currently running multis.
|
|
|
|
|
*
|
|
|
|
|
* XXX this could be refined further, but is it worth the hassle?
|
|
|
|
|
*/
|
|
|
|
|
new_rel_reltup->relminmxid = GetOldestMultiXactId();
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* Other relation types will not contain XIDs, so set relfrozenxid to
|
|
|
|
|
* InvalidTransactionId. (Note: a sequence does contain a tuple, but
|
|
|
|
|
* we force its xmin to be FrozenTransactionId always; see
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
* commands/sequence.c.)
|
|
|
|
|
*/
|
|
|
|
|
new_rel_reltup->relfrozenxid = InvalidTransactionId;
|
2014-01-10 22:03:18 +01:00
|
|
|
|
new_rel_reltup->relminmxid = InvalidMultiXactId;
|
Fix recently-understood problems with handling of XID freezing, particularly
in PITR scenarios. We now WAL-log the replacement of old XIDs with
FrozenTransactionId, so that such replacement is guaranteed to propagate to
PITR slave databases. Also, rather than relying on hint-bit updates to be
preserved, pg_clog is not truncated until all instances of an XID are known to
have been replaced by FrozenTransactionId. Add new GUC variables and
pg_autovacuum columns to allow management of the freezing policy, so that
users can trade off the size of pg_clog against the amount of freezing work
done. Revise the already-existing code that forces autovacuum of tables
approaching the wraparound point to make it more bulletproof; also, revise the
autovacuum logic so that anti-wraparound vacuuming is done per-table rather
than per-database. initdb forced because of changes in pg_class, pg_database,
and pg_autovacuum catalogs. Heikki Linnakangas, Simon Riggs, and Tom Lane.
2006-11-05 23:42:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-08-26 05:08:15 +02:00
|
|
|
|
new_rel_reltup->relowner = relowner;
|
2001-02-12 21:07:21 +01:00
|
|
|
|
new_rel_reltup->reltype = new_type_oid;
|
2010-01-29 00:21:13 +01:00
|
|
|
|
new_rel_reltup->reloftype = reloftype;
|
1997-09-07 07:04:48 +02: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
|
|
|
|
/* relispartition is always set by updating this tuple later */
|
|
|
|
|
new_rel_reltup->relispartition = false;
|
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
|
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
|
|
|
|
|
2006-07-04 00:45:41 +02:00
|
|
|
|
/* Now build and insert the tuple */
|
2009-10-05 21:24:49 +02:00
|
|
|
|
InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
|
|
|
|
|
relacl, reloptions);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1999-02-02 04:45:56 +01:00
|
|
|
|
* AddNewRelationType -
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2004-04-01 23:28:47 +02:00
|
|
|
|
* define a composite type corresponding to the new relation
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
static ObjectAddress
|
2002-03-29 20:06:29 +01:00
|
|
|
|
AddNewRelationType(const char *typeName,
|
|
|
|
|
Oid typeNamespace,
|
|
|
|
|
Oid new_rel_oid,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
char new_rel_kind,
|
Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER
TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row. However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes). Problem identified by Cott Lang.
Back-patch to 8.1. The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1. Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
2009-02-24 02:38:10 +01:00
|
|
|
|
Oid ownerid,
|
2009-09-27 00:42:03 +02:00
|
|
|
|
Oid new_row_type,
|
2007-11-15 22:14:46 +01:00
|
|
|
|
Oid new_array_type)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
2005-08-12 03:36:05 +02:00
|
|
|
|
return
|
2010-02-26 03:01:40 +01:00
|
|
|
|
TypeCreate(new_row_type, /* optional predetermined OID */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
typeName, /* type name */
|
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
|
|
|
|
typeNamespace, /* type namespace */
|
2005-10-15 04:49:52 +02:00
|
|
|
|
new_rel_oid, /* relation oid */
|
2005-08-12 03:36:05 +02:00
|
|
|
|
new_rel_kind, /* relation kind */
|
Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER
TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row. However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes). Problem identified by Cott Lang.
Back-patch to 8.1. The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1. Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
2009-02-24 02:38:10 +01:00
|
|
|
|
ownerid, /* owner's ID */
|
2005-10-15 04:49:52 +02:00
|
|
|
|
-1, /* internal size (varlena) */
|
2007-04-02 05:49:42 +02:00
|
|
|
|
TYPTYPE_COMPOSITE, /* type-type (composite) */
|
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
|
|
|
|
TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
|
2008-07-30 21:35:13 +02:00
|
|
|
|
false, /* composite types are never preferred */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
DEFAULT_TYPDELIM, /* default array delimiter */
|
2005-10-15 04:49:52 +02:00
|
|
|
|
F_RECORD_IN, /* input procedure */
|
2005-08-12 03:36:05 +02:00
|
|
|
|
F_RECORD_OUT, /* output procedure */
|
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
|
|
|
|
F_RECORD_RECV, /* receive procedure */
|
|
|
|
|
F_RECORD_SEND, /* send procedure */
|
2006-12-30 22:21:56 +01:00
|
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2005-10-15 04:49:52 +02:00
|
|
|
|
InvalidOid, /* analyze procedure - default */
|
|
|
|
|
InvalidOid, /* array element type - irrelevant */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
false, /* this is not an array type */
|
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
|
|
|
|
new_array_type, /* array type if any */
|
2005-10-15 04:49:52 +02:00
|
|
|
|
InvalidOid, /* domain base type - irrelevant */
|
|
|
|
|
NULL, /* default value - none */
|
|
|
|
|
NULL, /* default binary representation */
|
|
|
|
|
false, /* passed by reference */
|
|
|
|
|
'd', /* alignment - must be the largest! */
|
|
|
|
|
'x', /* fully TOASTable */
|
|
|
|
|
-1, /* typmod */
|
|
|
|
|
0, /* array dimensions for typBaseType */
|
2011-02-08 22:04:18 +01:00
|
|
|
|
false, /* Type NOT NULL */
|
2011-04-22 23:43:18 +02:00
|
|
|
|
InvalidOid); /* rowtypes never have a collation */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
1997-11-28 18:28:02 +01:00
|
|
|
|
* heap_create_with_catalog
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* creates a new cataloged relation. see comments above.
|
2009-10-05 21:24:49 +02:00
|
|
|
|
*
|
|
|
|
|
* Arguments:
|
|
|
|
|
* relname: name to give to new rel
|
|
|
|
|
* relnamespace: OID of namespace it goes in
|
|
|
|
|
* reltablespace: OID of tablespace it goes in
|
|
|
|
|
* relid: OID to assign to new rel, or InvalidOid to select a new OID
|
|
|
|
|
* reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one
|
2012-03-08 21:52:26 +01:00
|
|
|
|
* reloftypeid: if a typed table, OID of underlying type; else InvalidOid
|
2009-10-05 21:24:49 +02:00
|
|
|
|
* ownerid: OID of new rel's owner
|
|
|
|
|
* tupdesc: tuple descriptor (source of column definitions)
|
|
|
|
|
* cooked_constraints: list of precooked check constraints and defaults
|
|
|
|
|
* relkind: relkind for new rel
|
2012-03-08 21:52:26 +01:00
|
|
|
|
* relpersistence: rel's persistence status (permanent, temp, or unlogged)
|
2017-08-16 06:22:32 +02:00
|
|
|
|
* shared_relation: true if it's to be a shared relation
|
|
|
|
|
* mapped_relation: true if the relation will use the relfilenode map
|
|
|
|
|
* oidislocal: true if oid column (if any) should be marked attislocal
|
2009-10-05 21:24:49 +02:00
|
|
|
|
* oidinhcount: attinhcount to assign to oid column (if any)
|
|
|
|
|
* oncommit: ON COMMIT marking (only relevant if it's a temp table)
|
|
|
|
|
* reloptions: reloptions in Datum form, or (Datum) 0 if none
|
2017-08-16 06:22:32 +02:00
|
|
|
|
* use_user_acl: true if should look for user-defined default permissions;
|
|
|
|
|
* if false, relacl is always set NULL
|
|
|
|
|
* allow_system_table_mods: true to allow creation in system namespaces
|
2015-03-03 18:03:33 +01:00
|
|
|
|
* is_internal: is this a system-generated catalog?
|
2009-10-05 21:24:49 +02:00
|
|
|
|
*
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
* Output parameters:
|
|
|
|
|
* typaddress: if not null, gets the object address of the new pg_type entry
|
|
|
|
|
*
|
2009-10-05 21:24:49 +02:00
|
|
|
|
* Returns the OID of the new relation
|
1996-07-09 08:22:35 +02:00
|
|
|
|
* --------------------------------
|
|
|
|
|
*/
|
|
|
|
|
Oid
|
2002-03-31 08:26:32 +02:00
|
|
|
|
heap_create_with_catalog(const char *relname,
|
2002-03-26 20:17:02 +01:00
|
|
|
|
Oid relnamespace,
|
2004-06-18 08:14:31 +02:00
|
|
|
|
Oid reltablespace,
|
2005-04-14 03:38:22 +02:00
|
|
|
|
Oid relid,
|
2009-09-27 00:42:03 +02:00
|
|
|
|
Oid reltypeid,
|
2010-01-29 00:21:13 +01:00
|
|
|
|
Oid reloftypeid,
|
2005-08-26 05:08:15 +02:00
|
|
|
|
Oid ownerid,
|
1998-08-06 07:13:14 +02:00
|
|
|
|
TupleDesc tupdesc,
|
2008-05-10 01:32:05 +02:00
|
|
|
|
List *cooked_constraints,
|
1999-02-02 04:45:56 +01:00
|
|
|
|
char relkind,
|
2010-12-13 18:34:26 +01:00
|
|
|
|
char relpersistence,
|
2002-04-27 23:24:34 +02:00
|
|
|
|
bool shared_relation,
|
2010-02-07 21:48:13 +01:00
|
|
|
|
bool mapped_relation,
|
2004-03-23 20:35:17 +01:00
|
|
|
|
bool oidislocal,
|
|
|
|
|
int oidinhcount,
|
2002-11-11 23:19:25 +01:00
|
|
|
|
OnCommitAction oncommit,
|
2006-07-04 00:45:41 +02:00
|
|
|
|
Datum reloptions,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
bool use_user_acl,
|
2012-10-23 23:07:26 +02:00
|
|
|
|
bool allow_system_table_mods,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
bool is_internal,
|
2018-03-21 14:13:24 +01:00
|
|
|
|
Oid relrewrite,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
ObjectAddress *typaddress)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Relation pg_class_desc;
|
|
|
|
|
Relation new_rel_desc;
|
2009-10-05 21:24:49 +02:00
|
|
|
|
Acl *relacl;
|
2010-07-26 01:21:22 +02:00
|
|
|
|
Oid existing_relid;
|
2007-05-12 02:55:00 +02:00
|
|
|
|
Oid old_type_oid;
|
2001-02-12 21:07:21 +01:00
|
|
|
|
Oid new_type_oid;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
ObjectAddress new_type_addr;
|
2007-11-15 22:14:46 +01:00
|
|
|
|
Oid new_array_oid = InvalidOid;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
2005-08-12 03:36:05 +02:00
|
|
|
|
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
|
|
|
|
* sanity checks
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
|
Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
|
CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2010-07-26 01:21:22 +02:00
|
|
|
|
/*
|
2011-04-25 22:55:11 +02:00
|
|
|
|
* This would fail later on anyway, if the relation already exists. But
|
|
|
|
|
* by catching it here we can emit a nicer error message.
|
2010-07-26 01:21:22 +02:00
|
|
|
|
*/
|
|
|
|
|
existing_relid = get_relname_relid(relname, relnamespace);
|
|
|
|
|
if (existing_relid != InvalidOid)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_TABLE),
|
|
|
|
|
errmsg("relation \"%s\" already exists", relname)));
|
2002-09-04 22:31:48 +02:00
|
|
|
|
|
2007-05-12 02:55:00 +02:00
|
|
|
|
/*
|
|
|
|
|
* Since we are going to create a rowtype as well, also check for
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* collision with an existing type name. If there is one and it's an
|
|
|
|
|
* autogenerated array, we can rename it out of the way; otherwise we can
|
|
|
|
|
* at least give a good error message.
|
2007-05-12 02:55:00 +02:00
|
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
|
old_type_oid = GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
|
CStringGetDatum(relname),
|
|
|
|
|
ObjectIdGetDatum(relnamespace));
|
2007-05-12 02:55:00 +02:00
|
|
|
|
if (OidIsValid(old_type_oid))
|
|
|
|
|
{
|
|
|
|
|
if (!moveArrayTypeName(old_type_oid, relname, relnamespace))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
|
errmsg("type \"%s\" already exists", relname),
|
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
|
|
|
|
errhint("A relation has an associated type of the same name, "
|
|
|
|
|
"so you must use a name that doesn't conflict "
|
|
|
|
|
"with any existing type.")));
|
2007-05-12 02:55:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-12 20:55:12 +02:00
|
|
|
|
/*
|
2010-02-07 21:48:13 +01:00
|
|
|
|
* Shared relations must be in pg_global (last-ditch check)
|
2007-10-12 20:55:12 +02:00
|
|
|
|
*/
|
2010-02-07 21:48:13 +01:00
|
|
|
|
if (shared_relation && reltablespace != GLOBALTABLESPACE_OID)
|
|
|
|
|
elog(ERROR, "shared relations must be placed in pg_global tablespace");
|
2007-10-12 20:55:12 +02:00
|
|
|
|
|
2010-02-03 02:14:17 +01:00
|
|
|
|
/*
|
|
|
|
|
* Allocate an OID for the relation, unless we were told what to use.
|
|
|
|
|
*
|
|
|
|
|
* The OID will be the relfilenode as well, so make sure it doesn't
|
|
|
|
|
* collide with either pg_class OIDs or existing physical files.
|
|
|
|
|
*/
|
|
|
|
|
if (!OidIsValid(relid))
|
2010-01-06 04:04:03 +01:00
|
|
|
|
{
|
2014-12-17 23:00:53 +01:00
|
|
|
|
/* Use binary-upgrade override for pg_class.oid/relfilenode? */
|
2011-04-25 18:00:21 +02:00
|
|
|
|
if (IsBinaryUpgrade &&
|
2010-02-03 02:14:17 +01:00
|
|
|
|
(relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
|
2013-03-04 01:23:31 +01:00
|
|
|
|
relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW ||
|
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
|
|
|
|
relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE ||
|
|
|
|
|
relkind == RELKIND_PARTITIONED_TABLE))
|
2010-02-03 02:14:17 +01:00
|
|
|
|
{
|
2014-08-26 04:19:05 +02:00
|
|
|
|
if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("pg_class heap OID value not set when in binary upgrade mode")));
|
|
|
|
|
|
2011-01-08 03:25:34 +01:00
|
|
|
|
relid = binary_upgrade_next_heap_pg_class_oid;
|
|
|
|
|
binary_upgrade_next_heap_pg_class_oid = InvalidOid;
|
2010-02-03 02:14:17 +01:00
|
|
|
|
}
|
2014-08-26 04:19:05 +02:00
|
|
|
|
/* There might be no TOAST table, so we have to test for it. */
|
2011-04-25 18:00:21 +02:00
|
|
|
|
else if (IsBinaryUpgrade &&
|
|
|
|
|
OidIsValid(binary_upgrade_next_toast_pg_class_oid) &&
|
2010-02-03 02:14:17 +01:00
|
|
|
|
relkind == RELKIND_TOASTVALUE)
|
|
|
|
|
{
|
2011-01-08 03:25:34 +01:00
|
|
|
|
relid = binary_upgrade_next_toast_pg_class_oid;
|
|
|
|
|
binary_upgrade_next_toast_pg_class_oid = InvalidOid;
|
2010-02-03 02:14:17 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
2010-08-13 22:10:54 +02:00
|
|
|
|
relid = GetNewRelFileNode(reltablespace, pg_class_desc,
|
2010-12-13 18:34:26 +01:00
|
|
|
|
relpersistence);
|
2010-01-06 04:04:03 +01:00
|
|
|
|
}
|
2005-08-12 03:36:05 +02:00
|
|
|
|
|
2009-10-05 21:24:49 +02:00
|
|
|
|
/*
|
|
|
|
|
* Determine the relation's initial permissions.
|
|
|
|
|
*/
|
|
|
|
|
if (use_user_acl)
|
|
|
|
|
{
|
|
|
|
|
switch (relkind)
|
|
|
|
|
{
|
|
|
|
|
case RELKIND_RELATION:
|
|
|
|
|
case RELKIND_VIEW:
|
2013-03-04 01:23:31 +01:00
|
|
|
|
case RELKIND_MATVIEW:
|
2011-01-02 05:48:11 +01:00
|
|
|
|
case RELKIND_FOREIGN_TABLE:
|
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 RELKIND_PARTITIONED_TABLE:
|
2017-10-12 00:35:19 +02:00
|
|
|
|
relacl = get_user_default_acl(OBJECT_TABLE, ownerid,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
relnamespace);
|
|
|
|
|
break;
|
|
|
|
|
case RELKIND_SEQUENCE:
|
2017-10-12 00:35:19 +02:00
|
|
|
|
relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
relnamespace);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
relacl = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
relacl = NULL;
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Create the relcache entry (mostly dummy at this point) and the physical
|
|
|
|
|
* disk file. (If we fail further down, it's the smgr's responsibility to
|
|
|
|
|
* remove the disk file again.)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2002-04-27 23:24:34 +02:00
|
|
|
|
new_rel_desc = heap_create(relname,
|
|
|
|
|
relnamespace,
|
2004-06-18 08:14:31 +02:00
|
|
|
|
reltablespace,
|
2005-04-14 03:38:22 +02:00
|
|
|
|
relid,
|
2011-07-18 17:02:48 +02:00
|
|
|
|
InvalidOid,
|
2002-04-27 23:24:34 +02:00
|
|
|
|
tupdesc,
|
2004-08-31 19:10:36 +02:00
|
|
|
|
relkind,
|
2010-12-13 18:34:26 +01:00
|
|
|
|
relpersistence,
|
2002-04-27 23:24:34 +02:00
|
|
|
|
shared_relation,
|
2013-06-03 16:22:31 +02:00
|
|
|
|
mapped_relation,
|
|
|
|
|
allow_system_table_mods);
|
1999-02-02 04:45:56 +01:00
|
|
|
|
|
2005-08-12 03:36:05 +02:00
|
|
|
|
Assert(relid == RelationGetRelid(new_rel_desc));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2018-03-21 14:13:24 +01:00
|
|
|
|
new_rel_desc->rd_rel->relrewrite = relrewrite;
|
|
|
|
|
|
2005-08-12 03:36:05 +02:00
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* Decide whether to create an array type over the relation's rowtype. We
|
|
|
|
|
* do not create any array types for system catalogs (ie, those made
|
2013-07-05 21:25:51 +02:00
|
|
|
|
* during initdb). We do not create them where the use of a relation as
|
|
|
|
|
* such is an implementation detail: toast tables, sequences and indexes.
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
*/
|
|
|
|
|
if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
|
|
|
|
|
relkind == RELKIND_VIEW ||
|
2013-03-04 01:23:31 +01:00
|
|
|
|
relkind == RELKIND_MATVIEW ||
|
2011-01-02 05:48:11 +01:00
|
|
|
|
relkind == RELKIND_FOREIGN_TABLE ||
|
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
|
|
|
|
relkind == RELKIND_COMPOSITE_TYPE ||
|
|
|
|
|
relkind == RELKIND_PARTITIONED_TABLE))
|
2009-12-24 23:09:24 +01:00
|
|
|
|
new_array_oid = AssignTypeArrayOid();
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since defining a relation also defines a complex type, we add a new
|
2010-02-26 03:01:40 +01:00
|
|
|
|
* system type corresponding to the new relation. The OID of the type can
|
|
|
|
|
* be preselected by the caller, but if reltypeid is InvalidOid, we'll
|
|
|
|
|
* generate a new OID for it.
|
2005-08-12 03:36:05 +02:00
|
|
|
|
*
|
2007-05-12 02:55:00 +02:00
|
|
|
|
* NOTE: we could get a unique-index failure here, in case someone else is
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* creating the same type name in parallel but hadn't committed yet when
|
|
|
|
|
* we checked for a duplicate name above.
|
2005-08-12 03:36:05 +02:00
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
new_type_addr = AddNewRelationType(relname,
|
|
|
|
|
relnamespace,
|
|
|
|
|
relid,
|
|
|
|
|
relkind,
|
|
|
|
|
ownerid,
|
|
|
|
|
reltypeid,
|
|
|
|
|
new_array_oid);
|
|
|
|
|
new_type_oid = new_type_addr.objectId;
|
|
|
|
|
if (typaddress)
|
|
|
|
|
*typaddress = new_type_addr;
|
2007-11-15 22:14:46 +01:00
|
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
/*
|
|
|
|
|
* Now make the array type if wanted.
|
|
|
|
|
*/
|
|
|
|
|
if (OidIsValid(new_array_oid))
|
|
|
|
|
{
|
|
|
|
|
char *relarrayname;
|
|
|
|
|
|
|
|
|
|
relarrayname = makeArrayTypeName(relname, relnamespace);
|
|
|
|
|
|
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
|
|
|
|
TypeCreate(new_array_oid, /* force the type's OID to this */
|
2007-11-15 22:14:46 +01:00
|
|
|
|
relarrayname, /* Array type name */
|
|
|
|
|
relnamespace, /* Same namespace as parent */
|
|
|
|
|
InvalidOid, /* Not composite, no relationOid */
|
|
|
|
|
0, /* relkind, also N/A here */
|
Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER
TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row. However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes). Problem identified by Cott Lang.
Back-patch to 8.1. The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1. Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
2009-02-24 02:38:10 +01:00
|
|
|
|
ownerid, /* owner's ID */
|
2007-11-15 22:14:46 +01:00
|
|
|
|
-1, /* Internal size (varlena) */
|
|
|
|
|
TYPTYPE_BASE, /* Not composite - typelem is */
|
2009-06-11 16:49:15 +02:00
|
|
|
|
TYPCATEGORY_ARRAY, /* type-category (array) */
|
2008-07-30 21:35:13 +02:00
|
|
|
|
false, /* array types are never preferred */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
DEFAULT_TYPDELIM, /* default array delimiter */
|
2007-11-15 22:14:46 +01:00
|
|
|
|
F_ARRAY_IN, /* array input proc */
|
|
|
|
|
F_ARRAY_OUT, /* array output proc */
|
|
|
|
|
F_ARRAY_RECV, /* array recv (bin) proc */
|
|
|
|
|
F_ARRAY_SEND, /* array send (bin) proc */
|
|
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2012-03-04 02:20:19 +01:00
|
|
|
|
F_ARRAY_TYPANALYZE, /* array analyze procedure */
|
2007-11-15 22:14:46 +01:00
|
|
|
|
new_type_oid, /* array element type - the rowtype */
|
|
|
|
|
true, /* yes, this is an array type */
|
|
|
|
|
InvalidOid, /* this has no array type */
|
|
|
|
|
InvalidOid, /* domain base type - irrelevant */
|
|
|
|
|
NULL, /* default value - none */
|
|
|
|
|
NULL, /* default binary representation */
|
|
|
|
|
false, /* passed by reference */
|
|
|
|
|
'd', /* alignment - must be the largest! */
|
|
|
|
|
'x', /* fully TOASTable */
|
|
|
|
|
-1, /* typmod */
|
|
|
|
|
0, /* array dimensions for typBaseType */
|
2011-02-08 22:04:18 +01:00
|
|
|
|
false, /* Type NOT NULL */
|
2011-04-22 23:43:18 +02:00
|
|
|
|
InvalidOid); /* rowtypes never have a collation */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
|
|
|
|
|
pfree(relarrayname);
|
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
|
|
|
|
* now create an entry in pg_class for the relation.
|
2001-02-12 21:07:21 +01:00
|
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* NOTE: we could get a unique-index failure here, in case someone else is
|
|
|
|
|
* creating the same relation name in parallel but hadn't committed yet
|
|
|
|
|
* when we checked for a duplicate name above.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
1999-02-02 04:45:56 +01:00
|
|
|
|
AddNewRelationTuple(pg_class_desc,
|
1999-05-25 18:15:34 +02:00
|
|
|
|
new_rel_desc,
|
2005-08-12 03:36:05 +02:00
|
|
|
|
relid,
|
2001-02-12 21:07:21 +01:00
|
|
|
|
new_type_oid,
|
2010-01-29 00:21:13 +01:00
|
|
|
|
reloftypeid,
|
2005-08-26 05:08:15 +02:00
|
|
|
|
ownerid,
|
2006-07-02 04:23:23 +02:00
|
|
|
|
relkind,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
PointerGetDatum(relacl),
|
2006-07-04 00:45:41 +02:00
|
|
|
|
reloptions);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* now add tuples to pg_attribute for the attributes in our new relation.
|
2001-02-12 21:07:21 +01:00
|
|
|
|
*/
|
2005-08-12 03:36:05 +02:00
|
|
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
|
2004-03-23 20:35:17 +01:00
|
|
|
|
oidislocal, oidinhcount);
|
2001-02-12 21:07:21 +01:00
|
|
|
|
|
2002-07-18 18:47:26 +02:00
|
|
|
|
/*
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
* Make a dependency link to force the relation to be deleted if its
|
2010-02-26 03:01:40 +01:00
|
|
|
|
* namespace is. Also make a dependency link to its owner, as well as
|
|
|
|
|
* dependencies for any roles mentioned in the default ACL.
|
2005-07-07 22:40:02 +02:00
|
|
|
|
*
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
* For composite types, these dependencies are tracked for the pg_type
|
2007-05-14 22:24:41 +02:00
|
|
|
|
* entry, so we needn't record them here. Likewise, TOAST tables don't
|
|
|
|
|
* need a namespace dependency (they live in a pinned namespace) nor an
|
2010-02-26 03:01:40 +01:00
|
|
|
|
* owner dependency (they depend indirectly through the parent table), nor
|
2011-02-08 22:08:41 +01:00
|
|
|
|
* should they have any ACL entries. The same applies for extension
|
|
|
|
|
* dependencies.
|
2009-10-05 21:24:49 +02:00
|
|
|
|
*
|
2007-05-14 22:24:41 +02:00
|
|
|
|
* Also, skip this in bootstrap mode, since we don't make dependencies
|
|
|
|
|
* while bootstrapping.
|
2002-07-18 18:47:26 +02:00
|
|
|
|
*/
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
if (relkind != RELKIND_COMPOSITE_TYPE &&
|
2007-05-14 22:24:41 +02:00
|
|
|
|
relkind != RELKIND_TOASTVALUE &&
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
!IsBootstrapProcessingMode())
|
2002-07-18 18:47:26 +02:00
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
|
ObjectAddress myself,
|
|
|
|
|
referenced;
|
2002-07-18 18:47:26 +02:00
|
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
|
myself.classId = RelationRelationId;
|
2005-08-12 03:36:05 +02:00
|
|
|
|
myself.objectId = relid;
|
2002-07-18 18:47:26 +02:00
|
|
|
|
myself.objectSubId = 0;
|
2005-04-14 22:03:27 +02:00
|
|
|
|
referenced.classId = NamespaceRelationId;
|
2002-07-18 18:47:26 +02:00
|
|
|
|
referenced.objectId = relnamespace;
|
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
2005-07-07 22:40:02 +02:00
|
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
recordDependencyOnOwner(RelationRelationId, relid, ownerid);
|
2009-10-05 21:24:49 +02:00
|
|
|
|
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
|
recordDependencyOnCurrentExtension(&myself, false);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
2010-01-29 00:21:13 +01:00
|
|
|
|
if (reloftypeid)
|
|
|
|
|
{
|
|
|
|
|
referenced.classId = TypeRelationId;
|
|
|
|
|
referenced.objectId = reloftypeid;
|
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-05 21:24:49 +02:00
|
|
|
|
if (relacl != NULL)
|
|
|
|
|
{
|
|
|
|
|
int nnewmembers;
|
|
|
|
|
Oid *newmembers;
|
|
|
|
|
|
|
|
|
|
nnewmembers = aclmembers(relacl, &newmembers);
|
|
|
|
|
updateAclDependencies(RelationRelationId, relid, 0,
|
2010-04-05 03:09:53 +02:00
|
|
|
|
ownerid,
|
2009-10-05 21:24:49 +02:00
|
|
|
|
0, NULL,
|
|
|
|
|
nnewmembers, newmembers);
|
|
|
|
|
}
|
2002-07-18 18:47:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-25 17:48:49 +01:00
|
|
|
|
/* Post creation hook for new relation */
|
2013-03-07 02:52:06 +01:00
|
|
|
|
InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
|
2010-11-25 17:48:49 +01:00
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Store any supplied constraints and defaults.
|
2002-03-03 18:47:56 +01:00
|
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
|
* NB: this may do a CommandCounterIncrement and rebuild the relcache
|
|
|
|
|
* entry, so the relation must be valid and self-consistent at this point.
|
|
|
|
|
* In particular, there are not yet constraints and defaults anywhere.
|
2002-03-03 18:47:56 +01:00
|
|
|
|
*/
|
2013-03-18 03:55:14 +01:00
|
|
|
|
StoreConstraints(new_rel_desc, cooked_constraints, is_internal);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-11-11 23:19:25 +01:00
|
|
|
|
/*
|
|
|
|
|
* If there's a special on-commit action, remember it
|
|
|
|
|
*/
|
|
|
|
|
if (oncommit != ONCOMMIT_NOOP)
|
2005-08-12 03:36:05 +02:00
|
|
|
|
register_on_commit_action(relid, oncommit);
|
2002-11-11 23:19:25 +01:00
|
|
|
|
|
2017-03-31 22:28:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Unlogged objects need an init fork, except for partitioned tables which
|
|
|
|
|
* have no storage at all.
|
|
|
|
|
*/
|
|
|
|
|
if (relpersistence == RELPERSISTENCE_UNLOGGED &&
|
|
|
|
|
relkind != RELKIND_PARTITIONED_TABLE)
|
2012-05-11 15:46:42 +02:00
|
|
|
|
heap_create_init_fork(new_rel_desc);
|
2010-12-29 12:48:53 +01:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* ok, the relation has been cataloged, so close our relations and return
|
|
|
|
|
* the OID of the newly created relation.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2000-04-12 19:17:23 +02:00
|
|
|
|
heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
|
1999-09-18 21:08:25 +02:00
|
|
|
|
heap_close(pg_class_desc, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2005-08-12 03:36:05 +02:00
|
|
|
|
return relid;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-11 15:46:42 +02:00
|
|
|
|
/*
|
|
|
|
|
* Set up an init fork for an unlogged table so that it can be correctly
|
2016-12-08 20:09:09 +01:00
|
|
|
|
* reinitialized on restart. An immediate sync is required even if the
|
|
|
|
|
* page has been logged, because the write did not go through
|
|
|
|
|
* shared_buffers and therefore a concurrent checkpoint may have moved
|
|
|
|
|
* the redo pointer past our xlog record. Recovery may as well remove it
|
|
|
|
|
* while replaying, for example, XLOG_DBASE_CREATE or XLOG_TBLSPC_CREATE
|
|
|
|
|
* record. Therefore, logging is necessary even if wal_level=minimal.
|
2012-05-11 15:46:42 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
heap_create_init_fork(Relation rel)
|
|
|
|
|
{
|
2017-03-31 22:28:30 +02:00
|
|
|
|
Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
|
|
|
|
|
rel->rd_rel->relkind == RELKIND_MATVIEW ||
|
|
|
|
|
rel->rd_rel->relkind == RELKIND_TOASTVALUE);
|
2012-05-11 15:46:42 +02:00
|
|
|
|
RelationOpenSmgr(rel);
|
|
|
|
|
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
|
2016-12-08 20:09:09 +01:00
|
|
|
|
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
|
2012-05-11 15:46:42 +02:00
|
|
|
|
smgrimmedsync(rel->rd_smgr, INIT_FORKNUM);
|
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
|
* RelationRemoveInheritance
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*
|
2002-07-12 20:43:19 +02:00
|
|
|
|
* Formerly, this routine checked for child relations and aborted the
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* deletion if any were found. Now we rely on the dependency mechanism
|
|
|
|
|
* to check for or delete child relations. By the time we get here,
|
2002-07-20 00:21:17 +02:00
|
|
|
|
* there are no children and we need only remove any pg_inherits rows
|
|
|
|
|
* linking this relation to its parent(s).
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
|
static void
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RelationRemoveInheritance(Oid relid)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Relation catalogRelation;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
SysScanDesc scan;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
ScanKeyData key;
|
|
|
|
|
HeapTuple tuple;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&key,
|
|
|
|
|
Anum_pg_inherits_inhrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
2004-08-28 23:05:26 +02:00
|
|
|
|
ObjectIdGetDatum(relid));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 1, &key);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(catalogRelation, &tuple->t_self);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
|
systable_endscan(scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
|
heap_close(catalogRelation, RowExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-26 20:17:02 +01:00
|
|
|
|
/*
|
1999-02-02 04:45:56 +01:00
|
|
|
|
* DeleteRelationTuple
|
2002-07-14 23:08:08 +02:00
|
|
|
|
*
|
|
|
|
|
* Remove pg_class row for the given relid.
|
|
|
|
|
*
|
|
|
|
|
* Note: this is shared by relation deletion and index deletion. It's
|
|
|
|
|
* not intended for use anyplace else.
|
1996-07-09 08:22:35 +02:00
|
|
|
|
*/
|
2002-07-14 23:08:08 +02:00
|
|
|
|
void
|
|
|
|
|
DeleteRelationTuple(Oid relid)
|
1996-07-09 08:22:35 +02:00
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Relation pg_class_desc;
|
|
|
|
|
HeapTuple tup;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* Grab an appropriate lock on the pg_class relation */
|
2005-04-14 22:03:27 +02:00
|
|
|
|
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
|
tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
1998-08-19 04:04:17 +02:00
|
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u", relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* delete the relation tuple from pg_class, and finish up */
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(pg_class_desc, &tup->t_self);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
ReleaseSysCache(tup);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
heap_close(pg_class_desc, RowExclusiveLock);
|
1999-09-23 19:03:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/*
|
|
|
|
|
* DeleteAttributeTuples
|
1999-09-23 19:03:39 +02:00
|
|
|
|
*
|
2002-07-14 23:08:08 +02:00
|
|
|
|
* Remove pg_attribute rows for the given relid.
|
|
|
|
|
*
|
|
|
|
|
* Note: this is shared by relation deletion and index deletion. It's
|
|
|
|
|
* not intended for use anyplace else.
|
1999-09-23 19:03:39 +02:00
|
|
|
|
*/
|
1999-09-24 02:25:33 +02:00
|
|
|
|
void
|
2002-07-14 23:08:08 +02:00
|
|
|
|
DeleteAttributeTuples(Oid relid)
|
1999-09-24 02:25:33 +02:00
|
|
|
|
{
|
2002-07-14 23:08:08 +02:00
|
|
|
|
Relation attrel;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
SysScanDesc scan;
|
2002-07-14 23:08:08 +02:00
|
|
|
|
ScanKeyData key[1];
|
|
|
|
|
HeapTuple atttup;
|
1999-09-23 19:03:39 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* Grab an appropriate lock on the pg_attribute relation */
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attrel = heap_open(AttributeRelationId, RowExclusiveLock);
|
1999-09-23 19:03:39 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* Use the index to scan only attributes of the target relation */
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
|
Anum_pg_attribute_attrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(relid));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 1, key);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* Delete all the matching tuples */
|
|
|
|
|
while ((atttup = systable_getnext(scan)) != NULL)
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(attrel, &atttup->t_self);
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
|
|
2002-07-14 23:08:08 +02:00
|
|
|
|
/* Clean up after the scan */
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
heap_close(attrel, RowExclusiveLock);
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-24 19:39:37 +02:00
|
|
|
|
/*
|
|
|
|
|
* DeleteSystemAttributeTuples
|
|
|
|
|
*
|
|
|
|
|
* Remove pg_attribute rows for system columns of the given relid.
|
|
|
|
|
*
|
|
|
|
|
* Note: this is only used when converting a table to a view. Views don't
|
|
|
|
|
* have system columns, so we should remove them from pg_attribute.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
DeleteSystemAttributeTuples(Oid relid)
|
|
|
|
|
{
|
|
|
|
|
Relation attrel;
|
|
|
|
|
SysScanDesc scan;
|
|
|
|
|
ScanKeyData key[2];
|
|
|
|
|
HeapTuple atttup;
|
|
|
|
|
|
|
|
|
|
/* Grab an appropriate lock on the pg_attribute relation */
|
|
|
|
|
attrel = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* Use the index to scan only system attributes of the target relation */
|
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
|
Anum_pg_attribute_attrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(relid));
|
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
|
Anum_pg_attribute_attnum,
|
|
|
|
|
BTLessEqualStrategyNumber, F_INT2LE,
|
|
|
|
|
Int16GetDatum(0));
|
|
|
|
|
|
|
|
|
|
scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 2, key);
|
2012-10-24 19:39:37 +02:00
|
|
|
|
|
|
|
|
|
/* Delete all the matching tuples */
|
|
|
|
|
while ((atttup = systable_getnext(scan)) != NULL)
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(attrel, &atttup->t_self);
|
2012-10-24 19:39:37 +02:00
|
|
|
|
|
|
|
|
|
/* Clean up after the scan */
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
heap_close(attrel, RowExclusiveLock);
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
|
/*
|
|
|
|
|
* RemoveAttributeById
|
|
|
|
|
*
|
|
|
|
|
* This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
|
2003-05-12 02:17:03 +02:00
|
|
|
|
* deleted in pg_attribute. We also remove pg_statistic entries for it.
|
|
|
|
|
* (Everything else needed, such as getting rid of any pg_attrdef entry,
|
|
|
|
|
* is handled by dependency.c.)
|
2002-08-02 20:15:10 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|
|
|
|
{
|
|
|
|
|
Relation rel;
|
|
|
|
|
Relation attr_rel;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
Form_pg_attribute attStruct;
|
|
|
|
|
char newattname[NAMEDATALEN];
|
|
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Grab an exclusive lock on the target table, which we will NOT release
|
|
|
|
|
* until end of transaction. (In the simple case where we are directly
|
|
|
|
|
* dropping this column, AlterTableDropColumn already did this ... but
|
|
|
|
|
* when cascading from a drop of some other object, we may not have any
|
|
|
|
|
* lock.)
|
2002-08-02 20:15:10 +02:00
|
|
|
|
*/
|
2002-08-29 02:17:06 +02:00
|
|
|
|
rel = relation_open(relid, AccessExclusiveLock);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
|
tuple = SearchSysCacheCopy2(ATTNUM,
|
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
|
Int16GetDatum(attnum));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
2003-07-21 03:59:11 +02:00
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
2002-08-02 20:15:10 +02:00
|
|
|
|
attnum, relid);
|
|
|
|
|
attStruct = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
if (attnum < 0)
|
|
|
|
|
{
|
|
|
|
|
/* System attribute (probably OID) ... just delete the row */
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(attr_rel, &tuple->t_self);
|
2004-03-23 20:35:17 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Dropping user attributes is lots harder */
|
2003-05-12 02:17:03 +02:00
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
/* Mark the attribute as dropped */
|
|
|
|
|
attStruct->attisdropped = true;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
/*
|
|
|
|
|
* Set the type OID to invalid. A dropped attribute's type link
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* cannot be relied on (once the attribute is dropped, the type might
|
|
|
|
|
* be too). Fortunately we do not need the type row --- the only
|
|
|
|
|
* really essential information is the type's typlen and typalign,
|
|
|
|
|
* which are preserved in the attribute's attlen and attalign. We set
|
|
|
|
|
* atttypid to zero here as a means of catching code that incorrectly
|
|
|
|
|
* expects it to be valid.
|
2004-03-23 20:35:17 +01:00
|
|
|
|
*/
|
|
|
|
|
attStruct->atttypid = InvalidOid;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
/* Remove any NOT NULL constraint the column may have */
|
|
|
|
|
attStruct->attnotnull = false;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
/* We don't want to keep stats for it anymore */
|
|
|
|
|
attStruct->attstattarget = 0;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Change the column name to something that isn't likely to conflict
|
2004-08-29 07:07:03 +02:00
|
|
|
|
*/
|
2004-03-23 20:35:17 +01:00
|
|
|
|
snprintf(newattname, sizeof(newattname),
|
|
|
|
|
"........pg.dropped.%d........", attnum);
|
|
|
|
|
namestrcpy(&(attStruct->attname), newattname);
|
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
|
2004-03-23 20:35:17 +01:00
|
|
|
|
}
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Because updating the pg_attribute row will trigger a relcache flush for
|
|
|
|
|
* the target relation, we need not do anything else to notify other
|
|
|
|
|
* backends of the change.
|
2002-08-02 20:15:10 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
heap_close(attr_rel, RowExclusiveLock);
|
|
|
|
|
|
2004-03-23 20:35:17 +01:00
|
|
|
|
if (attnum > 0)
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RemoveStatistics(relid, attnum);
|
2003-05-12 02:17:03 +02:00
|
|
|
|
|
2002-08-29 02:17:06 +02:00
|
|
|
|
relation_close(rel, NoLock);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2002-07-15 18:33:32 +02:00
|
|
|
|
/*
|
|
|
|
|
* RemoveAttrDefault
|
|
|
|
|
*
|
|
|
|
|
* If the specified relation/attribute has a default, remove it.
|
|
|
|
|
* (If no default, raise error if complain is true, else return quietly.)
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RemoveAttrDefault(Oid relid, AttrNumber attnum,
|
2012-01-26 15:24:54 +01:00
|
|
|
|
DropBehavior behavior, bool complain, bool internal)
|
2002-07-15 18:33:32 +02:00
|
|
|
|
{
|
|
|
|
|
Relation attrdef_rel;
|
|
|
|
|
ScanKeyData scankeys[2];
|
|
|
|
|
SysScanDesc scan;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attrdef_rel = heap_open(AttrDefaultRelationId, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&scankeys[0],
|
|
|
|
|
Anum_pg_attrdef_adrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(relid));
|
|
|
|
|
ScanKeyInit(&scankeys[1],
|
|
|
|
|
Anum_pg_attrdef_adnum,
|
|
|
|
|
BTEqualStrategyNumber, F_INT2EQ,
|
|
|
|
|
Int16GetDatum(attnum));
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 2, scankeys);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
/* There should be at most one matching tuple, but we loop anyway */
|
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
|
ObjectAddress object;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
object.classId = AttrDefaultRelationId;
|
2002-07-20 07:16:59 +02:00
|
|
|
|
object.objectId = HeapTupleGetOid(tuple);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
object.objectSubId = 0;
|
|
|
|
|
|
2012-01-26 15:24:54 +01:00
|
|
|
|
performDeletion(&object, behavior,
|
|
|
|
|
internal ? PERFORM_DELETION_INTERNAL : 0);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
heap_close(attrdef_rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
if (complain && !found)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
|
2002-07-15 18:33:32 +02:00
|
|
|
|
relid, attnum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* RemoveAttrDefaultById
|
|
|
|
|
*
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* Remove a pg_attrdef entry specified by OID. This is the guts of
|
2002-07-15 18:33:32 +02:00
|
|
|
|
* attribute-default removal. Note it should be called via performDeletion,
|
|
|
|
|
* not directly.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RemoveAttrDefaultById(Oid attrdefId)
|
|
|
|
|
{
|
|
|
|
|
Relation attrdef_rel;
|
|
|
|
|
Relation attr_rel;
|
2002-08-02 23:54:34 +02:00
|
|
|
|
Relation myrel;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
ScanKeyData scankeys[1];
|
|
|
|
|
SysScanDesc scan;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
Oid myrelid;
|
|
|
|
|
AttrNumber myattnum;
|
|
|
|
|
|
|
|
|
|
/* Grab an appropriate lock on the pg_attrdef relation */
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attrdef_rel = heap_open(AttrDefaultRelationId, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2002-08-02 23:54:34 +02:00
|
|
|
|
/* Find the pg_attrdef tuple */
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&scankeys[0],
|
|
|
|
|
ObjectIdAttributeNumber,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(attrdefId));
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 1, scankeys);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
tuple = systable_getnext(scan);
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
2003-07-20 23:56:35 +02:00
|
|
|
|
elog(ERROR, "could not find tuple for attrdef %u", attrdefId);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;
|
|
|
|
|
myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
|
|
|
|
|
|
2002-08-02 23:54:34 +02:00
|
|
|
|
/* Get an exclusive lock on the relation owning the attribute */
|
2002-08-29 02:17:06 +02:00
|
|
|
|
myrel = relation_open(myrelid, AccessExclusiveLock);
|
2002-08-02 23:54:34 +02:00
|
|
|
|
|
|
|
|
|
/* Now we can delete the pg_attrdef row */
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(attrdef_rel, &tuple->t_self);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
heap_close(attrdef_rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* Fix the pg_attribute row */
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
|
tuple = SearchSysCacheCopy2(ATTNUM,
|
|
|
|
|
ObjectIdGetDatum(myrelid),
|
|
|
|
|
Int16GetDatum(myattnum));
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
2003-07-20 23:56:35 +02:00
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
|
|
|
myattnum, myrelid);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;
|
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2002-08-02 23:54:34 +02:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Our update of the pg_attribute row will force a relcache rebuild, so
|
|
|
|
|
* there's nothing else to do here.
|
2002-08-02 23:54:34 +02:00
|
|
|
|
*/
|
2002-07-15 18:33:32 +02:00
|
|
|
|
heap_close(attr_rel, RowExclusiveLock);
|
2002-08-02 23:54:34 +02:00
|
|
|
|
|
|
|
|
|
/* Keep lock on attribute's rel until end of xact */
|
2002-08-29 02:17:06 +02:00
|
|
|
|
relation_close(myrel, NoLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-08-28 23:05:26 +02:00
|
|
|
|
/*
|
|
|
|
|
* heap_drop_with_catalog - removes specified relation from catalogs
|
2001-06-18 18:13:21 +02:00
|
|
|
|
*
|
2002-07-12 20:43:19 +02:00
|
|
|
|
* Note that this routine is not responsible for dropping objects that are
|
|
|
|
|
* linked to the pg_class entry via dependencies (for example, indexes and
|
|
|
|
|
* constraints). Those are deleted by the dependency-tracing logic in
|
|
|
|
|
* dependency.c before control gets here. In general, therefore, this routine
|
|
|
|
|
* should never be called directly; go through performDeletion() instead.
|
1996-11-06 08:31:26 +01:00
|
|
|
|
*/
|
|
|
|
|
void
|
2004-08-28 23:05:26 +02:00
|
|
|
|
heap_drop_with_catalog(Oid relid)
|
1996-11-06 08:31:26 +01:00
|
|
|
|
{
|
1998-08-19 04:04:17 +02:00
|
|
|
|
Relation rel;
|
2017-04-11 15:08:36 +02:00
|
|
|
|
HeapTuple tuple;
|
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
|
|
|
|
Oid parentOid = InvalidOid,
|
|
|
|
|
defaultPartOid = InvalidOid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2017-04-11 15:08:36 +02:00
|
|
|
|
* To drop a partition safely, we must grab exclusive lock on its parent,
|
|
|
|
|
* because another backend might be about to execute a query on the parent
|
2017-05-17 22:31:56 +02:00
|
|
|
|
* table. If it relies on previously cached partition descriptor, then it
|
|
|
|
|
* could attempt to access the just-dropped relation as its partition. We
|
|
|
|
|
* must therefore take a table lock strong enough to prevent all queries
|
|
|
|
|
* on the table from proceeding until we commit and send out a
|
2018-03-21 16:03:35 +01:00
|
|
|
|
* shared-cache-inval notice that will make them update their partition
|
|
|
|
|
* descriptors.
|
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-04-11 15:08:36 +02:00
|
|
|
|
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
2017-11-28 01:22:08 +01:00
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u", relid);
|
2017-04-11 15:08:36 +02:00
|
|
|
|
if (((Form_pg_class) GETSTRUCT(tuple))->relispartition)
|
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
|
|
|
|
{
|
|
|
|
|
parentOid = get_partition_parent(relid);
|
2017-04-28 20:00:58 +02:00
|
|
|
|
LockRelationOid(parentOid, AccessExclusiveLock);
|
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 this is not the default partition, dropping it will change the
|
|
|
|
|
* default partition's partition constraint, so we must lock it.
|
|
|
|
|
*/
|
|
|
|
|
defaultPartOid = get_default_partition_oid(parentOid);
|
|
|
|
|
if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
|
|
|
|
|
LockRelationOid(defaultPartOid, AccessExclusiveLock);
|
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-04-11 15:08:36 +02:00
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Open and lock the relation.
|
|
|
|
|
*/
|
|
|
|
|
rel = relation_open(relid, AccessExclusiveLock);
|
|
|
|
|
|
2008-11-29 01:13:21 +01:00
|
|
|
|
/*
|
|
|
|
|
* There can no longer be anyone *else* touching the relation, but we
|
2011-04-10 17:42:00 +02:00
|
|
|
|
* might still have open queries or cursors, or pending trigger events, in
|
|
|
|
|
* our own session.
|
2008-11-29 01:13:21 +01:00
|
|
|
|
*/
|
2011-02-15 21:49:54 +01:00
|
|
|
|
CheckTableNotInUse(rel, "DROP TABLE");
|
2008-11-29 01:13:21 +01:00
|
|
|
|
|
2011-06-08 12:47:21 +02:00
|
|
|
|
/*
|
|
|
|
|
* This effectively deletes all rows in the table, and may be done in a
|
|
|
|
|
* serializable transaction. In that case we must record a rw-conflict in
|
|
|
|
|
* to this transaction from each transaction holding a predicate lock on
|
|
|
|
|
* the table.
|
|
|
|
|
*/
|
|
|
|
|
CheckTableForSerializableConflictIn(rel);
|
|
|
|
|
|
2011-01-02 05:48:11 +01:00
|
|
|
|
/*
|
|
|
|
|
* Delete pg_foreign_table tuple first.
|
|
|
|
|
*/
|
|
|
|
|
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
|
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
|
Relation rel;
|
|
|
|
|
HeapTuple tuple;
|
2011-01-02 05:48:11 +01:00
|
|
|
|
|
|
|
|
|
rel = heap_open(ForeignTableRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid));
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
|
elog(ERROR, "cache lookup failed for foreign table %u", relid);
|
|
|
|
|
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(rel, &tuple->t_self);
|
2011-01-02 05:48:11 +01:00
|
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
|
|
|
}
|
|
|
|
|
|
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 a partitioned table, delete the pg_partitioned_table tuple.
|
|
|
|
|
*/
|
|
|
|
|
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
|
|
|
|
RemovePartitionKeyByRelId(relid);
|
|
|
|
|
|
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 the relation being dropped is the default partition itself,
|
|
|
|
|
* invalidate its entry in pg_partitioned_table.
|
|
|
|
|
*/
|
|
|
|
|
if (relid == defaultPartOid)
|
|
|
|
|
update_default_partition_oid(parentOid, InvalidOid);
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2008-08-11 13:05:11 +02:00
|
|
|
|
* Schedule unlinking of the relation's physical files at commit.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
if (rel->rd_rel->relkind != RELKIND_VIEW &&
|
2011-01-02 05:48:11 +01:00
|
|
|
|
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
|
2017-03-31 22:28:30 +02:00
|
|
|
|
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
|
|
|
|
|
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
|
2004-08-28 23:05:26 +02:00
|
|
|
|
{
|
2008-11-19 11:34:52 +01:00
|
|
|
|
RelationDropStorage(rel);
|
2004-08-28 23:05:26 +02:00
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Close relcache entry, but *keep* AccessExclusiveLock on the relation
|
|
|
|
|
* until transaction commit. This ensures no one else will try to do
|
|
|
|
|
* something with the doomed relation.
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
relation_close(rel, NoLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2017-03-23 13:36:36 +01:00
|
|
|
|
/*
|
|
|
|
|
* Remove any associated relation synchronization states.
|
|
|
|
|
*/
|
|
|
|
|
RemoveSubscriptionRel(InvalidOid, relid);
|
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* Forget any ON COMMIT action for the rel
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
remove_on_commit_action(relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* Flush the relation from the relcache. We want to do this before
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* starting to remove catalog entries, just to be certain that no relcache
|
|
|
|
|
* entry rebuild will happen partway through. (That should not really
|
|
|
|
|
* matter, since we don't do CommandCounterIncrement here, but let's be
|
|
|
|
|
* safe.)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RelationForgetRelation(relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-11-11 23:19:25 +01:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* remove inheritance information
|
2002-11-11 23:19:25 +01:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RelationRemoveInheritance(relid);
|
2002-11-11 23:19:25 +01:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* delete statistics
|
1997-09-07 07:04:48 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RemoveStatistics(relid, 0);
|
2000-07-04 01:10:14 +02:00
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* delete attribute tuples
|
1999-09-18 21:08:25 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
DeleteAttributeTuples(relid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
|
/*
|
2004-08-28 23:05:26 +02:00
|
|
|
|
* delete relation tuple
|
1999-09-05 19:43:47 +02:00
|
|
|
|
*/
|
2004-08-28 23:05:26 +02:00
|
|
|
|
DeleteRelationTuple(relid);
|
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-04-28 20:00:58 +02:00
|
|
|
|
if (OidIsValid(parentOid))
|
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
|
|
|
|
{
|
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 this is not the default partition, the partition constraint of
|
|
|
|
|
* the default partition has changed to include the portion of the key
|
|
|
|
|
* space previously covered by the dropped partition.
|
|
|
|
|
*/
|
|
|
|
|
if (OidIsValid(defaultPartOid) && relid != defaultPartOid)
|
|
|
|
|
CacheInvalidateRelcacheByRelid(defaultPartOid);
|
|
|
|
|
|
2016-12-13 16:54:52 +01:00
|
|
|
|
/*
|
|
|
|
|
* Invalidate the parent's relcache so that the partition is no longer
|
|
|
|
|
* included in its partition descriptor.
|
|
|
|
|
*/
|
2017-04-28 20:00:58 +02:00
|
|
|
|
CacheInvalidateRelcacheByRelid(parentOid);
|
|
|
|
|
/* keep the lock */
|
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
|
|
|
|
}
|
1996-11-06 08:31:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-03-28 02:13:52 +02:00
|
|
|
|
/*
|
|
|
|
|
* RelationClearMissing
|
|
|
|
|
*
|
|
|
|
|
* Set atthasmissing and attmissingval to false/null for all attributes
|
|
|
|
|
* where they are currently set. This can be safely and usefully done if
|
|
|
|
|
* the table is rewritten (e.g. by VACUUM FULL or CLUSTER) where we know there
|
|
|
|
|
* are no rows left with less than a full complement of attributes.
|
|
|
|
|
*
|
|
|
|
|
* The caller must have an AccessExclusive lock on the relation.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RelationClearMissing(Relation rel)
|
|
|
|
|
{
|
|
|
|
|
Relation attr_rel;
|
|
|
|
|
Oid relid = RelationGetRelid(rel);
|
|
|
|
|
int natts = RelationGetNumberOfAttributes(rel);
|
|
|
|
|
int attnum;
|
|
|
|
|
Datum repl_val[Natts_pg_attribute];
|
|
|
|
|
bool repl_null[Natts_pg_attribute];
|
|
|
|
|
bool repl_repl[Natts_pg_attribute];
|
|
|
|
|
Form_pg_attribute attrtuple;
|
|
|
|
|
HeapTuple tuple,
|
|
|
|
|
newtuple;
|
|
|
|
|
|
|
|
|
|
memset(repl_val, 0, sizeof(repl_val));
|
|
|
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
|
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
|
|
|
|
|
|
|
|
repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false);
|
|
|
|
|
repl_null[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
|
|
|
|
|
|
repl_repl[Anum_pg_attribute_atthasmissing - 1] = true;
|
|
|
|
|
repl_repl[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Get a lock on pg_attribute */
|
|
|
|
|
attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* process each non-system attribute, including any dropped columns */
|
|
|
|
|
for (attnum = 1; attnum <= natts; attnum++)
|
|
|
|
|
{
|
|
|
|
|
tuple = SearchSysCache2(ATTNUM,
|
|
|
|
|
ObjectIdGetDatum(relid),
|
|
|
|
|
Int16GetDatum(attnum));
|
|
|
|
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
|
|
|
|
attnum, relid);
|
|
|
|
|
|
|
|
|
|
attrtuple = (Form_pg_attribute) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
|
|
/* ignore any where atthasmissing is not true */
|
|
|
|
|
if (attrtuple->atthasmissing)
|
|
|
|
|
{
|
|
|
|
|
newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
|
|
|
|
|
repl_val, repl_null, repl_repl);
|
|
|
|
|
|
|
|
|
|
CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple);
|
|
|
|
|
|
|
|
|
|
heap_freetuple(newtuple);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Our update of the pg_attribute rows will force a relcache rebuild, so
|
|
|
|
|
* there's nothing else to do here.
|
|
|
|
|
*/
|
|
|
|
|
heap_close(attr_rel, RowExclusiveLock);
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
|
|
|
|
* Store a default expression for column attnum of relation rel.
|
2015-03-25 21:17:56 +01:00
|
|
|
|
*
|
|
|
|
|
* Returns the OID of the new pg_attrdef tuple.
|
2018-03-28 02:13:52 +02:00
|
|
|
|
*
|
|
|
|
|
* add_column_mode must be true if we are storing the default for a new
|
|
|
|
|
* attribute, and false if it's for an already existing attribute. The reason
|
|
|
|
|
* for this is that the missing value must never be updated after it is set,
|
|
|
|
|
* which can only be when a column is added to the table. Otherwise we would
|
|
|
|
|
* in effect be changing existing tuples.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2015-03-25 21:17:56 +01:00
|
|
|
|
Oid
|
2013-03-18 03:55:14 +01:00
|
|
|
|
StoreAttrDefault(Relation rel, AttrNumber attnum,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
Node *expr, bool is_internal, bool add_column_mode)
|
1997-08-22 04:58:51 +02:00
|
|
|
|
{
|
2008-05-10 01:32:05 +02:00
|
|
|
|
char *adbin;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
char *adsrc;
|
1997-09-08 04:41:22 +02:00
|
|
|
|
Relation adrel;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
Datum values[4];
|
2008-11-02 02:45:28 +01:00
|
|
|
|
static bool nulls[4] = {false, false, false, false};
|
1999-10-04 01:55:40 +02:00
|
|
|
|
Relation attrrel;
|
|
|
|
|
HeapTuple atttup;
|
|
|
|
|
Form_pg_attribute attStruct;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
Oid attrdefOid;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
ObjectAddress colobject,
|
2002-07-15 18:33:32 +02:00
|
|
|
|
defobject;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
1999-10-04 04:12:26 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Flatten expression to string form for storage.
|
1999-10-04 04:12:26 +02:00
|
|
|
|
*/
|
2008-05-10 01:32:05 +02:00
|
|
|
|
adbin = nodeToString(expr);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Also deparse it to form the mostly-obsolete adsrc field.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2001-02-14 22:35:07 +01:00
|
|
|
|
adsrc = deparse_expression(expr,
|
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(rel),
|
|
|
|
|
RelationGetRelid(rel)),
|
2002-09-20 00:48:34 +02:00
|
|
|
|
false, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-15 18:33:32 +02:00
|
|
|
|
/*
|
|
|
|
|
* Make the pg_attrdef entry.
|
|
|
|
|
*/
|
1999-11-28 03:03:04 +01:00
|
|
|
|
values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
values[Anum_pg_attrdef_adnum - 1] = attnum;
|
2008-03-25 23:42:46 +01:00
|
|
|
|
values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin);
|
|
|
|
|
values[Anum_pg_attrdef_adsrc - 1] = CStringGetTextDatum(adsrc);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
adrel = heap_open(AttrDefaultRelationId, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
|
tuple = heap_form_tuple(adrel->rd_att, values, nulls);
|
2017-01-31 22:42:24 +01:00
|
|
|
|
attrdefOid = CatalogTupleInsert(adrel, tuple);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
defobject.classId = AttrDefaultRelationId;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
defobject.objectId = attrdefOid;
|
|
|
|
|
defobject.objectSubId = 0;
|
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
|
heap_close(adrel, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-15 18:33:32 +02:00
|
|
|
|
/* now can free some of the stuff allocated above */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
|
|
|
|
|
pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
|
1999-12-16 23:20:03 +01:00
|
|
|
|
heap_freetuple(tuple);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
pfree(adbin);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
pfree(adsrc);
|
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
|
/*
|
|
|
|
|
* Update the pg_attribute entry for the column to show that a default
|
|
|
|
|
* exists.
|
|
|
|
|
*/
|
2005-04-14 22:03:27 +02:00
|
|
|
|
attrrel = heap_open(AttributeRelationId, RowExclusiveLock);
|
2010-02-14 19:42:19 +01:00
|
|
|
|
atttup = SearchSysCacheCopy2(ATTNUM,
|
|
|
|
|
ObjectIdGetDatum(RelationGetRelid(rel)),
|
|
|
|
|
Int16GetDatum(attnum));
|
1999-10-04 01:55:40 +02:00
|
|
|
|
if (!HeapTupleIsValid(atttup))
|
2003-07-20 23:56:35 +02:00
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
|
1999-11-28 03:03:04 +01:00
|
|
|
|
attnum, RelationGetRelid(rel));
|
1999-10-04 01:55:40 +02:00
|
|
|
|
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
if (!attStruct->atthasdef)
|
1999-10-04 01:55:40 +02:00
|
|
|
|
{
|
2018-03-28 02:13:52 +02:00
|
|
|
|
Form_pg_attribute defAttStruct;
|
|
|
|
|
|
|
|
|
|
ExprState *exprState;
|
|
|
|
|
Expr *expr2 = (Expr *) expr;
|
|
|
|
|
EState *estate = NULL;
|
|
|
|
|
ExprContext *econtext;
|
|
|
|
|
Datum valuesAtt[Natts_pg_attribute];
|
|
|
|
|
bool nullsAtt[Natts_pg_attribute];
|
|
|
|
|
bool replacesAtt[Natts_pg_attribute];
|
|
|
|
|
Datum missingval = (Datum) 0;
|
|
|
|
|
bool missingIsNull = true;
|
|
|
|
|
|
|
|
|
|
MemSet(valuesAtt, 0, sizeof(valuesAtt));
|
|
|
|
|
MemSet(nullsAtt, false, sizeof(nullsAtt));
|
|
|
|
|
MemSet(replacesAtt, false, sizeof(replacesAtt));
|
|
|
|
|
valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
|
|
|
|
|
replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
|
|
|
|
|
|
|
|
|
|
if (add_column_mode)
|
|
|
|
|
{
|
|
|
|
|
expr2 = expression_planner(expr2);
|
|
|
|
|
estate = CreateExecutorState();
|
|
|
|
|
exprState = ExecPrepareExpr(expr2, estate);
|
|
|
|
|
econtext = GetPerTupleExprContext(estate);
|
|
|
|
|
|
|
|
|
|
missingval = ExecEvalExpr(exprState, econtext,
|
|
|
|
|
&missingIsNull);
|
|
|
|
|
|
|
|
|
|
FreeExecutorState(estate);
|
|
|
|
|
|
|
|
|
|
defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1);
|
|
|
|
|
|
|
|
|
|
if (missingIsNull)
|
|
|
|
|
{
|
|
|
|
|
/* if the default evaluates to NULL, just store a NULL array */
|
|
|
|
|
missingval = (Datum) 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* otherwise make a one-element array of the value */
|
|
|
|
|
missingval = PointerGetDatum(
|
|
|
|
|
construct_array(&missingval,
|
|
|
|
|
1,
|
|
|
|
|
defAttStruct->atttypid,
|
|
|
|
|
defAttStruct->attlen,
|
|
|
|
|
defAttStruct->attbyval,
|
|
|
|
|
defAttStruct->attalign));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull;
|
|
|
|
|
replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
|
|
|
|
|
valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
|
|
|
|
|
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
|
nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull;
|
|
|
|
|
}
|
|
|
|
|
atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
|
|
|
|
|
valuesAtt, nullsAtt, replacesAtt);
|
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(attrrel, &atttup->t_self, atttup);
|
2018-03-28 02:13:52 +02:00
|
|
|
|
|
|
|
|
|
if (!missingIsNull)
|
|
|
|
|
pfree(DatumGetPointer(missingval));
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
}
|
|
|
|
|
heap_close(attrrel, RowExclusiveLock);
|
1999-12-16 23:20:03 +01:00
|
|
|
|
heap_freetuple(atttup);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Make a dependency so that the pg_attrdef entry goes away if the column
|
|
|
|
|
* (or whole table) is deleted.
|
2002-07-15 18:33:32 +02:00
|
|
|
|
*/
|
2005-04-14 03:38:22 +02:00
|
|
|
|
colobject.classId = RelationRelationId;
|
2002-07-15 18:33:32 +02:00
|
|
|
|
colobject.objectId = RelationGetRelid(rel);
|
|
|
|
|
colobject.objectSubId = attnum;
|
|
|
|
|
|
|
|
|
|
recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Record dependencies on objects used in the expression, too.
|
|
|
|
|
*/
|
|
|
|
|
recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);
|
2013-03-18 03:55:14 +01:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Post creation hook for attribute defaults.
|
|
|
|
|
*
|
2013-05-29 22:58:43 +02:00
|
|
|
|
* XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a
|
|
|
|
|
* couple of deletion/creation of the attribute's default entry, so the
|
|
|
|
|
* callee should check existence of an older version of this entry if it
|
|
|
|
|
* needs to distinguish.
|
2013-03-18 03:55:14 +01:00
|
|
|
|
*/
|
|
|
|
|
InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
|
|
|
|
|
RelationGetRelid(rel), attnum, is_internal);
|
2015-03-25 21:17:56 +01:00
|
|
|
|
|
|
|
|
|
return attrdefOid;
|
1997-08-22 04:58:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
2002-07-16 07:53:34 +02:00
|
|
|
|
* Store a check-constraint expression for the given relation.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
|
|
|
|
* Caller is responsible for updating the count of constraints
|
|
|
|
|
* in the pg_class entry for the relation.
|
2015-03-25 21:17:56 +01:00
|
|
|
|
*
|
|
|
|
|
* The OID of the new constraint is returned.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2015-03-25 21:17:56 +01:00
|
|
|
|
static Oid
|
2017-10-31 15:34:31 +01:00
|
|
|
|
StoreRelCheck(Relation rel, const char *ccname, Node *expr,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
bool is_validated, bool is_local, int inhcount,
|
2013-03-18 03:55:14 +01:00
|
|
|
|
bool is_no_inherit, bool is_internal)
|
1997-08-22 04:58:51 +02:00
|
|
|
|
{
|
2008-05-10 01:32:05 +02:00
|
|
|
|
char *ccbin;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
char *ccsrc;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
List *varList;
|
|
|
|
|
int keycount;
|
|
|
|
|
int16 *attNos;
|
2015-03-25 21:17:56 +01:00
|
|
|
|
Oid constrOid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Flatten expression to string form for storage.
|
1998-11-12 16:39:06 +01:00
|
|
|
|
*/
|
2008-05-10 01:32:05 +02:00
|
|
|
|
ccbin = nodeToString(expr);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Also deparse it to form the mostly-obsolete consrc field.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2001-02-14 22:35:07 +01:00
|
|
|
|
ccsrc = deparse_expression(expr,
|
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(rel),
|
|
|
|
|
RelationGetRelid(rel)),
|
2002-09-20 00:48:34 +02:00
|
|
|
|
false, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Find columns of rel that are used in expr
|
2002-07-16 07:53:34 +02:00
|
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
|
* NB: pull_var_clause is okay here only because we don't allow subselects
|
|
|
|
|
* in check constraints; it would fail to examine the contents of
|
|
|
|
|
* subselects.
|
2002-07-12 20:43:19 +02:00
|
|
|
|
*/
|
2016-03-10 21:52:58 +01:00
|
|
|
|
varList = pull_var_clause(expr, 0);
|
2004-05-26 06:41:50 +02:00
|
|
|
|
keycount = list_length(varList);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
|
|
if (keycount > 0)
|
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
|
ListCell *vl;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
attNos = (int16 *) palloc(keycount * sizeof(int16));
|
|
|
|
|
foreach(vl, varList)
|
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Var *var = (Var *) lfirst(vl);
|
|
|
|
|
int j;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
|
if (attNos[j] == var->varattno)
|
|
|
|
|
break;
|
|
|
|
|
if (j == i)
|
|
|
|
|
attNos[i++] = var->varattno;
|
|
|
|
|
}
|
|
|
|
|
keycount = i;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
attNos = 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
|
|
|
|
/*
|
|
|
|
|
* Partitioned tables do not contain any rows themselves, so a NO INHERIT
|
|
|
|
|
* constraint makes no sense.
|
|
|
|
|
*/
|
|
|
|
|
if (is_no_inherit &&
|
|
|
|
|
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
|
|
|
|
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("cannot add NO INHERIT constraint to partitioned table \"%s\"",
|
|
|
|
|
RelationGetRelationName(rel))));
|
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
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
|
/*
|
|
|
|
|
* Create the Check Constraint
|
|
|
|
|
*/
|
2015-03-25 21:17:56 +01:00
|
|
|
|
constrOid =
|
|
|
|
|
CreateConstraintEntry(ccname, /* Constraint Name */
|
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
|
|
|
|
RelationGetNamespace(rel), /* namespace */
|
2015-03-25 21:17:56 +01:00
|
|
|
|
CONSTRAINT_CHECK, /* Constraint Type */
|
|
|
|
|
false, /* Is Deferrable */
|
|
|
|
|
false, /* Is Deferred */
|
|
|
|
|
is_validated,
|
2018-03-23 14:48:22 +01:00
|
|
|
|
InvalidOid, /* no parent constraint */
|
2015-03-25 21:17:56 +01:00
|
|
|
|
RelationGetRelid(rel), /* relation */
|
|
|
|
|
attNos, /* attrs in the constraint */
|
2016-04-08 20:52:13 +02:00
|
|
|
|
keycount, /* # attrs in the constraint */
|
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
|
|
|
|
InvalidOid, /* not a domain constraint */
|
|
|
|
|
InvalidOid, /* no associated index */
|
|
|
|
|
InvalidOid, /* Foreign key fields */
|
2015-03-25 21:17:56 +01:00
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
' ',
|
|
|
|
|
' ',
|
|
|
|
|
' ',
|
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
|
|
|
|
NULL, /* not an exclusion constraint */
|
|
|
|
|
expr, /* Tree form of check constraint */
|
2015-03-25 21:17:56 +01:00
|
|
|
|
ccbin, /* Binary form of check constraint */
|
|
|
|
|
ccsrc, /* Source form of check constraint */
|
|
|
|
|
is_local, /* conislocal */
|
|
|
|
|
inhcount, /* coninhcount */
|
|
|
|
|
is_no_inherit, /* connoinherit */
|
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
|
|
|
|
is_internal); /* internally constructed? */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
pfree(ccbin);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
pfree(ccsrc);
|
2015-03-25 21:17:56 +01:00
|
|
|
|
|
|
|
|
|
return constrOid;
|
1997-08-22 16:10:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Store defaults and constraints (passed as a list of CookedConstraint).
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
2015-03-25 21:17:56 +01:00
|
|
|
|
* Each CookedConstraint struct is modified to store the new catalog tuple OID.
|
|
|
|
|
*
|
1999-10-04 01:55:40 +02:00
|
|
|
|
* NOTE: only pre-cooked expressions will be passed this way, which is to
|
|
|
|
|
* say expressions inherited from an existing relation. Newly parsed
|
|
|
|
|
* expressions can be added later, by direct calls to StoreAttrDefault
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* and StoreRelCheck (see AddRelationNewConstraints()).
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
|
static void
|
2013-03-18 03:55:14 +01:00
|
|
|
|
StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
|
1997-08-22 16:10:26 +02:00
|
|
|
|
{
|
2008-05-10 01:32:05 +02:00
|
|
|
|
int numchecks = 0;
|
|
|
|
|
ListCell *lc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2015-03-25 21:17:56 +01:00
|
|
|
|
if (cooked_constraints == NIL)
|
2002-03-03 18:47:56 +01:00
|
|
|
|
return; /* nothing to do */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Deparsing of constraint expressions will fail unless the just-created
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* pg_attribute tuples for this relation are made visible. So, bump the
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* command counter. CAUTION: this will cause a relcache entry rebuild.
|
2000-01-16 20:57:00 +01:00
|
|
|
|
*/
|
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
foreach(lc, cooked_constraints)
|
|
|
|
|
{
|
|
|
|
|
CookedConstraint *con = (CookedConstraint *) lfirst(lc);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
switch (con->contype)
|
|
|
|
|
{
|
|
|
|
|
case CONSTR_DEFAULT:
|
2015-03-25 21:17:56 +01:00
|
|
|
|
con->conoid = StoreAttrDefault(rel, con->attnum, con->expr,
|
2018-03-28 02:13:52 +02:00
|
|
|
|
is_internal, false);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
case CONSTR_CHECK:
|
2015-03-25 21:17:56 +01:00
|
|
|
|
con->conoid =
|
|
|
|
|
StoreRelCheck(rel, con->name, con->expr,
|
|
|
|
|
!con->skip_validation, con->is_local,
|
|
|
|
|
con->inhcount, con->is_no_inherit,
|
|
|
|
|
is_internal);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
numchecks++;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
elog(ERROR, "unrecognized constraint type: %d",
|
|
|
|
|
(int) con->contype);
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-03 18:47:56 +01:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
if (numchecks > 0)
|
|
|
|
|
SetRelationNumChecks(rel, numchecks);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* AddRelationNewConstraints
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Add new column default expressions and/or constraint check expressions
|
|
|
|
|
* to an existing relation. This is defined to do both for efficiency in
|
|
|
|
|
* DefineRelation, but of course you can do just one or the other by passing
|
|
|
|
|
* empty lists.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
|
|
|
|
* rel: relation to be modified
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* newColDefaults: list of RawColumnDefault structures
|
|
|
|
|
* newConstraints: list of Constraint nodes
|
2017-08-16 06:22:32 +02:00
|
|
|
|
* allow_merge: true if check constraints may be merged with existing ones
|
|
|
|
|
* is_local: true if definition is local, false if it's inherited
|
|
|
|
|
* is_internal: true if result of some internal process, not a user request
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* All entries in newColDefaults will be processed. Entries in newConstraints
|
|
|
|
|
* will be processed only if they are CONSTR_CHECK type.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*
|
2004-05-05 06:48:48 +02:00
|
|
|
|
* Returns a list of CookedConstraint nodes that shows the cooked form of
|
|
|
|
|
* the default and constraint expressions added to the relation.
|
|
|
|
|
*
|
1999-10-04 01:55:40 +02:00
|
|
|
|
* NB: caller should have opened rel with AccessExclusiveLock, and should
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* hold that lock till end of transaction. Also, we assume the caller has
|
2000-01-16 20:57:00 +01:00
|
|
|
|
* done a CommandCounterIncrement if necessary to make the relation's catalog
|
|
|
|
|
* tuples visible.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2004-05-05 06:48:48 +02:00
|
|
|
|
List *
|
2008-05-10 01:32:05 +02:00
|
|
|
|
AddRelationNewConstraints(Relation rel,
|
|
|
|
|
List *newColDefaults,
|
|
|
|
|
List *newConstraints,
|
|
|
|
|
bool allow_merge,
|
2013-03-18 03:55:14 +01:00
|
|
|
|
bool is_local,
|
|
|
|
|
bool is_internal)
|
1999-10-04 01:55:40 +02:00
|
|
|
|
{
|
2004-05-05 06:48:48 +02:00
|
|
|
|
List *cookedConstraints = NIL;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
TupleDesc tupleDesc;
|
|
|
|
|
TupleConstr *oldconstr;
|
|
|
|
|
int numoldchecks;
|
|
|
|
|
ParseState *pstate;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
RangeTblEntry *rte;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
int numchecks;
|
2004-06-10 19:56:03 +02:00
|
|
|
|
List *checknames;
|
2004-05-26 06:41:50 +02:00
|
|
|
|
ListCell *cell;
|
2002-03-20 20:45:13 +01:00
|
|
|
|
Node *expr;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
CookedConstraint *cooked;
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
|
|
|
|
* Get info about existing constraints.
|
|
|
|
|
*/
|
|
|
|
|
tupleDesc = RelationGetDescr(rel);
|
|
|
|
|
oldconstr = tupleDesc->constr;
|
|
|
|
|
if (oldconstr)
|
|
|
|
|
numoldchecks = oldconstr->num_check;
|
|
|
|
|
else
|
|
|
|
|
numoldchecks = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Create a dummy ParseState and insert the target relation as its sole
|
|
|
|
|
* rangetable entry. We need a ParseState for transformExpr.
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
|
|
|
|
pstate = make_parsestate(NULL);
|
2002-03-22 03:56:37 +01:00
|
|
|
|
rte = addRangeTableEntryForRelation(pstate,
|
2005-04-13 18:50:55 +02:00
|
|
|
|
rel,
|
|
|
|
|
NULL,
|
2002-03-22 03:56:37 +01:00
|
|
|
|
false,
|
|
|
|
|
true);
|
2005-06-05 02:38:11 +02:00
|
|
|
|
addRTEtoQuery(pstate, rte, true, true, true);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Process column default expressions.
|
|
|
|
|
*/
|
2008-05-10 01:32:05 +02:00
|
|
|
|
foreach(cell, newColDefaults)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
|
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell);
|
2017-08-20 20:19:07 +02:00
|
|
|
|
Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1);
|
2015-03-25 21:17:56 +01:00
|
|
|
|
Oid defOid;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
2002-03-20 20:45:13 +01:00
|
|
|
|
expr = cookDefault(pstate, colDef->raw_default,
|
|
|
|
|
atp->atttypid, atp->atttypmod,
|
|
|
|
|
NameStr(atp->attname));
|
2004-05-05 06:48:48 +02:00
|
|
|
|
|
2007-10-29 20:40:40 +01:00
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
|
* If the expression is just a NULL constant, we do not bother to make
|
|
|
|
|
* an explicit pg_attrdef entry, since the default behavior is
|
|
|
|
|
* equivalent.
|
2007-10-29 20:40:40 +01:00
|
|
|
|
*
|
|
|
|
|
* Note a nonobvious property of this test: if the column is of a
|
|
|
|
|
* domain type, what we'll get is not a bare null Const but a
|
|
|
|
|
* CoerceToDomain expr, so we will not discard the default. This is
|
|
|
|
|
* critical because the column default needs to be retained to
|
|
|
|
|
* override any default that the domain might have.
|
|
|
|
|
*/
|
|
|
|
|
if (expr == NULL ||
|
2007-11-15 22:14:46 +01:00
|
|
|
|
(IsA(expr, Const) &&((Const *) expr)->constisnull))
|
2007-10-29 20:40:40 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
2018-03-28 02:13:52 +02:00
|
|
|
|
/* If the DEFAULT is volatile we cannot use a missing value */
|
|
|
|
|
if (colDef->missingMode && contain_volatile_functions((Node *) expr))
|
|
|
|
|
colDef->missingMode = false;
|
|
|
|
|
|
|
|
|
|
defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal,
|
|
|
|
|
colDef->missingMode);
|
2004-05-05 06:48:48 +02:00
|
|
|
|
|
|
|
|
|
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
|
|
|
|
|
cooked->contype = CONSTR_DEFAULT;
|
2015-03-25 21:17:56 +01:00
|
|
|
|
cooked->conoid = defOid;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
cooked->name = NULL;
|
|
|
|
|
cooked->attnum = colDef->attnum;
|
|
|
|
|
cooked->expr = expr;
|
2011-06-02 00:43:50 +02:00
|
|
|
|
cooked->skip_validation = false;
|
2008-05-10 01:32:05 +02:00
|
|
|
|
cooked->is_local = is_local;
|
|
|
|
|
cooked->inhcount = is_local ? 0 : 1;
|
2012-04-21 04:46:20 +02:00
|
|
|
|
cooked->is_no_inherit = false;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
cookedConstraints = lappend(cookedConstraints, cooked);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
|
|
|
|
* Process constraint expressions.
|
|
|
|
|
*/
|
|
|
|
|
numchecks = numoldchecks;
|
2004-06-10 19:56:03 +02:00
|
|
|
|
checknames = NIL;
|
2008-05-10 01:32:05 +02:00
|
|
|
|
foreach(cell, newConstraints)
|
1997-09-07 07:04:48 +02:00
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
|
Constraint *cdef = (Constraint *) lfirst(cell);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
char *ccname;
|
2015-03-25 21:17:56 +01:00
|
|
|
|
Oid constrOid;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
if (cdef->contype != CONSTR_CHECK)
|
1999-10-04 01:55:40 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
if (cdef->raw_expr != NULL)
|
|
|
|
|
{
|
|
|
|
|
Assert(cdef->cooked_expr == NULL);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* Transform raw parsetree to executable expression, and verify
|
|
|
|
|
* it's valid as a CHECK constraint.
|
|
|
|
|
*/
|
|
|
|
|
expr = cookConstraint(pstate, cdef->raw_expr,
|
|
|
|
|
RelationGetRelationName(rel));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Assert(cdef->cooked_expr != NULL);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* Here, we assume the parser will only pass us valid CHECK
|
|
|
|
|
* expressions, so we do no particular checking.
|
|
|
|
|
*/
|
|
|
|
|
expr = stringToNode(cdef->cooked_expr);
|
|
|
|
|
}
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
2004-06-10 19:56:03 +02:00
|
|
|
|
/*
|
|
|
|
|
* Check name uniqueness, or generate a name if none was given.
|
|
|
|
|
*/
|
2009-07-30 04:45:38 +02:00
|
|
|
|
if (cdef->conname != NULL)
|
2004-06-10 19:56:03 +02:00
|
|
|
|
{
|
|
|
|
|
ListCell *cell2;
|
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
|
ccname = cdef->conname;
|
2004-06-10 19:56:03 +02:00
|
|
|
|
/* Check against other new constraints */
|
|
|
|
|
/* Needed because we don't do CommandCounterIncrement in loop */
|
|
|
|
|
foreach(cell2, checknames)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp((char *) lfirst(cell2), ccname) == 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
2005-10-15 04:49:52 +02:00
|
|
|
|
errmsg("check constraint \"%s\" already exists",
|
|
|
|
|
ccname)));
|
2004-06-10 19:56:03 +02:00
|
|
|
|
}
|
2008-05-10 01:32:05 +02:00
|
|
|
|
|
|
|
|
|
/* save name for future checks */
|
|
|
|
|
checknames = lappend(checknames, ccname);
|
|
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* Check against pre-existing constraints. If we are allowed to
|
2009-06-11 16:49:15 +02:00
|
|
|
|
* merge with an existing constraint, there's no more to do here.
|
|
|
|
|
* (We omit the duplicate constraint from the result, which is
|
|
|
|
|
* what ATAddCheckConstraint wants.)
|
2008-05-10 01:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
if (MergeWithExistingConstraint(rel, ccname, expr,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
allow_merge, is_local,
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
cdef->initially_valid,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
cdef->is_no_inherit))
|
2008-05-10 01:32:05 +02:00
|
|
|
|
continue;
|
2004-06-10 19:56:03 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* When generating a name, we want to create "tab_col_check" for a
|
|
|
|
|
* column constraint and "tab_check" for a table constraint. We
|
|
|
|
|
* no longer have any info about the syntactic positioning of the
|
|
|
|
|
* constraint phrase, so we approximate this by seeing whether the
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* expression references more than one column. (If the user
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* played by the rules, the result is the same...)
|
2004-06-10 19:56:03 +02:00
|
|
|
|
*
|
2004-08-29 07:07:03 +02:00
|
|
|
|
* Note: pull_var_clause() doesn't descend into sublinks, but we
|
|
|
|
|
* eliminated those above; and anyway this only needs to be an
|
|
|
|
|
* approximate answer.
|
2004-06-10 19:56:03 +02:00
|
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
|
List *vars;
|
|
|
|
|
char *colname;
|
2004-06-10 19:56:03 +02:00
|
|
|
|
|
2016-03-10 21:52:58 +01:00
|
|
|
|
vars = pull_var_clause(expr, 0);
|
2004-06-10 19:56:03 +02:00
|
|
|
|
|
|
|
|
|
/* eliminate duplicates */
|
|
|
|
|
vars = list_union(NIL, vars);
|
|
|
|
|
|
|
|
|
|
if (list_length(vars) == 1)
|
|
|
|
|
colname = get_attname(RelationGetRelid(rel),
|
2018-02-12 23:30:30 +01:00
|
|
|
|
((Var *) linitial(vars))->varattno,
|
|
|
|
|
true);
|
2004-06-10 19:56:03 +02:00
|
|
|
|
else
|
|
|
|
|
colname = NULL;
|
|
|
|
|
|
|
|
|
|
ccname = ChooseConstraintName(RelationGetRelationName(rel),
|
|
|
|
|
colname,
|
|
|
|
|
"check",
|
|
|
|
|
RelationGetNamespace(rel),
|
|
|
|
|
checknames);
|
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
/* save name for future checks */
|
|
|
|
|
checknames = lappend(checknames, ccname);
|
|
|
|
|
}
|
2004-06-10 19:56:03 +02:00
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
|
|
|
|
* OK, store it.
|
|
|
|
|
*/
|
2015-03-25 21:17:56 +01:00
|
|
|
|
constrOid =
|
2015-12-16 13:43:56 +01:00
|
|
|
|
StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
|
2015-03-25 21:17:56 +01:00
|
|
|
|
is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
|
|
|
|
numchecks++;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
|
|
|
|
|
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
|
|
|
|
|
cooked->contype = CONSTR_CHECK;
|
2015-03-25 21:17:56 +01:00
|
|
|
|
cooked->conoid = constrOid;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
cooked->name = ccname;
|
|
|
|
|
cooked->attnum = 0;
|
|
|
|
|
cooked->expr = expr;
|
2011-06-02 00:43:50 +02:00
|
|
|
|
cooked->skip_validation = cdef->skip_validation;
|
2008-05-10 01:32:05 +02:00
|
|
|
|
cooked->is_local = is_local;
|
|
|
|
|
cooked->inhcount = is_local ? 0 : 1;
|
2012-04-21 04:46:20 +02:00
|
|
|
|
cooked->is_no_inherit = cdef->is_no_inherit;
|
2004-05-05 06:48:48 +02:00
|
|
|
|
cookedConstraints = lappend(cookedConstraints, cooked);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Update the count of constraints in the relation's pg_class tuple. We do
|
|
|
|
|
* this even if there was no change, in order to ensure that an SI update
|
|
|
|
|
* message is sent out for the pg_class tuple, which will force other
|
|
|
|
|
* backends to rebuild their relcache entries for the rel. (This is
|
|
|
|
|
* critical if we added defaults but not constraints.)
|
1999-10-04 01:55:40 +02:00
|
|
|
|
*/
|
2002-03-03 18:47:56 +01:00
|
|
|
|
SetRelationNumChecks(rel, numchecks);
|
2004-05-05 06:48:48 +02:00
|
|
|
|
|
|
|
|
|
return cookedConstraints;
|
2002-03-03 18:47:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* Check for a pre-existing check constraint that conflicts with a proposed
|
|
|
|
|
* new one, and either adjust its conislocal/coninhcount settings or throw
|
|
|
|
|
* error as needed.
|
|
|
|
|
*
|
2017-08-16 06:22:32 +02:00
|
|
|
|
* Returns true if merged (constraint is a duplicate), or false if it's
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* got a so-far-unique name, or throws error if conflict.
|
2012-01-16 23:19:42 +01:00
|
|
|
|
*
|
|
|
|
|
* XXX See MergeConstraintsIntoExisting too if you change this code.
|
2008-05-10 01:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
static bool
|
2017-10-31 15:34:31 +01:00
|
|
|
|
MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
|
2011-12-05 19:10:18 +01:00
|
|
|
|
bool allow_merge, bool is_local,
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
bool is_initially_valid,
|
2012-04-21 04:46:20 +02:00
|
|
|
|
bool is_no_inherit)
|
2008-05-10 01:32:05 +02:00
|
|
|
|
{
|
|
|
|
|
bool found;
|
|
|
|
|
Relation conDesc;
|
|
|
|
|
SysScanDesc conscan;
|
|
|
|
|
ScanKeyData skey[2];
|
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
|
|
/* Search for a pg_constraint entry with same name and relation */
|
|
|
|
|
conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
found = false;
|
|
|
|
|
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_constraint_conname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(ccname));
|
|
|
|
|
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_constraint_connamespace,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(RelationGetNamespace(rel)));
|
|
|
|
|
|
|
|
|
|
conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 2, skey);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
|
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
|
|
|
|
|
{
|
|
|
|
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
|
|
if (con->conrelid == RelationGetRelid(rel))
|
|
|
|
|
{
|
|
|
|
|
/* Found it. Conflicts if not identical check constraint */
|
|
|
|
|
if (con->contype == CONSTRAINT_CHECK)
|
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
|
Datum val;
|
|
|
|
|
bool isnull;
|
2008-05-10 01:32:05 +02:00
|
|
|
|
|
|
|
|
|
val = fastgetattr(tup,
|
|
|
|
|
Anum_pg_constraint_conbin,
|
|
|
|
|
conDesc->rd_att, &isnull);
|
|
|
|
|
if (isnull)
|
|
|
|
|
elog(ERROR, "null conbin for rel %s",
|
|
|
|
|
RelationGetRelationName(rel));
|
|
|
|
|
if (equal(expr, stringToNode(TextDatumGetCString(val))))
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the existing constraint is purely inherited (no local
|
|
|
|
|
* definition) then interpret addition of a local constraint as a
|
|
|
|
|
* legal merge. This allows ALTER ADD CONSTRAINT on parent and
|
|
|
|
|
* child tables to be given in either order with same end state.
|
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
|
|
|
|
* However if the relation is a partition, all inherited
|
|
|
|
|
* constraints are always non-local, including those that were
|
|
|
|
|
* merged.
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02: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 (is_local && !con->conislocal && !rel->rd_rel->relispartition)
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
allow_merge = true;
|
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
if (!found || !allow_merge)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
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("constraint \"%s\" for relation \"%s\" already exists",
|
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
2012-01-16 23:19:42 +01:00
|
|
|
|
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
/* If the child constraint is "no inherit" then cannot merge */
|
2012-04-21 04:46:20 +02:00
|
|
|
|
if (con->connoinherit)
|
2012-01-16 23:19:42 +01:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
|
errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
|
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
|
|
|
|
|
2016-10-13 23:05:14 +02:00
|
|
|
|
/*
|
|
|
|
|
* Must not change an existing inherited constraint to "no
|
|
|
|
|
* inherit" status. That's because inherited constraints should
|
|
|
|
|
* be able to propagate to lower-level children.
|
|
|
|
|
*/
|
|
|
|
|
if (con->coninhcount > 0 && is_no_inherit)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
|
errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"",
|
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
|
|
|
|
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
/*
|
|
|
|
|
* If the child constraint is "not valid" then cannot merge with a
|
|
|
|
|
* valid parent constraint
|
|
|
|
|
*/
|
|
|
|
|
if (is_initially_valid && !con->convalidated)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
|
errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
|
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
|
|
|
|
|
|
|
|
|
/* OK to update the tuple */
|
|
|
|
|
ereport(NOTICE,
|
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("merging constraint \"%s\" with inherited definition",
|
|
|
|
|
ccname)));
|
Fix two bugs in merging of inherited CHECK constraints.
Historically, we've allowed users to add a CHECK constraint to a child
table and then add an identical CHECK constraint to the parent. This
results in "merging" the two constraints so that the pre-existing
child constraint ends up with both conislocal = true and coninhcount > 0.
However, if you tried to do it in the other order, you got a duplicate
constraint error. This is problematic for pg_dump, which needs to issue
separated ADD CONSTRAINT commands in some cases, but has no good way to
ensure that the constraints will be added in the required order.
And it's more than a bit arbitrary, too. The goal of complaining about
duplicated ADD CONSTRAINT commands can be served if we reject the case of
adding a constraint when the existing one already has conislocal = true;
but if it has conislocal = false, let's just make the ADD CONSTRAINT set
conislocal = true. In this way, either order of adding the constraints
has the same end result.
Another problem was that the code allowed creation of a parent constraint
marked convalidated that is merged with a child constraint that is
!convalidated. In this case, an inheritance scan of the parent table could
emit some rows violating the constraint condition, which would be an
unexpected result given the marking of the parent constraint as validated.
Hence, forbid merging of constraints in this case. (Note: valid child and
not-valid parent seems fine, so continue to allow that.)
Per report from Benedikt Grundmann. Back-patch to 9.2 where we introduced
possibly-not-valid check constraints. The second bug obviously doesn't
apply before that, and I think the first doesn't either, because pg_dump
only gets into this situation when dealing with not-valid constraints.
Report: <CADbMkNPT-Jz5PRSQ4RbUASYAjocV_KHUWapR%2Bg8fNvhUAyRpxA%40mail.gmail.com>
Discussion: <22108.1475874586@sss.pgh.pa.us>
2016-10-09 01:29:27 +02:00
|
|
|
|
|
|
|
|
|
tup = heap_copytuple(tup);
|
|
|
|
|
con = (Form_pg_constraint) GETSTRUCT(tup);
|
|
|
|
|
|
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
|
|
|
|
/*
|
|
|
|
|
* In case of partitions, an inherited constraint must be
|
|
|
|
|
* inherited only once since it cannot have multiple parents and
|
|
|
|
|
* it is never considered local.
|
|
|
|
|
*/
|
|
|
|
|
if (rel->rd_rel->relispartition)
|
|
|
|
|
{
|
|
|
|
|
con->coninhcount = 1;
|
|
|
|
|
con->conislocal = false;
|
|
|
|
|
}
|
2008-05-10 01:32:05 +02:00
|
|
|
|
else
|
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 (is_local)
|
|
|
|
|
con->conislocal = true;
|
|
|
|
|
else
|
|
|
|
|
con->coninhcount++;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-21 04:46:20 +02:00
|
|
|
|
if (is_no_inherit)
|
2011-12-05 19:10:18 +01:00
|
|
|
|
{
|
|
|
|
|
Assert(is_local);
|
2012-04-21 04:46:20 +02:00
|
|
|
|
con->connoinherit = true;
|
2011-12-05 19:10:18 +01:00
|
|
|
|
}
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(conDesc, &tup->t_self, tup);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
systable_endscan(conscan);
|
|
|
|
|
heap_close(conDesc, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
|
/*
|
|
|
|
|
* Update the count of constraints in the relation's pg_class tuple.
|
|
|
|
|
*
|
|
|
|
|
* Caller had better hold exclusive lock on the relation.
|
|
|
|
|
*
|
|
|
|
|
* An important side effect is that a SI update message will be sent out for
|
|
|
|
|
* the pg_class tuple, which will force other backends to rebuild their
|
|
|
|
|
* relcache entries for the rel. Also, this backend will rebuild its
|
|
|
|
|
* own relcache entry at the next CommandCounterIncrement.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
SetRelationNumChecks(Relation rel, int numchecks)
|
|
|
|
|
{
|
|
|
|
|
Relation relrel;
|
|
|
|
|
HeapTuple reltup;
|
|
|
|
|
Form_pg_class relStruct;
|
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
relrel = heap_open(RelationRelationId, RowExclusiveLock);
|
2010-02-14 19:42:19 +01:00
|
|
|
|
reltup = SearchSysCacheCopy1(RELOID,
|
|
|
|
|
ObjectIdGetDatum(RelationGetRelid(rel)));
|
1999-10-04 01:55:40 +02:00
|
|
|
|
if (!HeapTupleIsValid(reltup))
|
2003-07-20 23:56:35 +02:00
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u",
|
2000-11-16 23:30:52 +01:00
|
|
|
|
RelationGetRelid(rel));
|
1999-10-04 01:55:40 +02:00
|
|
|
|
relStruct = (Form_pg_class) GETSTRUCT(reltup);
|
|
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
|
if (relStruct->relchecks != numchecks)
|
|
|
|
|
{
|
|
|
|
|
relStruct->relchecks = numchecks;
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
|
2002-03-03 18:47:56 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Skip the disk update, but force relcache inval anyway */
|
2004-02-10 02:55:27 +01:00
|
|
|
|
CacheInvalidateRelcache(rel);
|
2002-03-03 18:47:56 +01:00
|
|
|
|
}
|
1999-10-04 01:55:40 +02:00
|
|
|
|
|
1999-12-16 23:20:03 +01:00
|
|
|
|
heap_freetuple(reltup);
|
2000-11-16 23:30:52 +01:00
|
|
|
|
heap_close(relrel, RowExclusiveLock);
|
1997-08-22 16:10:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-19 03:18:25 +01:00
|
|
|
|
/*
|
|
|
|
|
* Take a raw default and convert it to a cooked format ready for
|
|
|
|
|
* storage.
|
|
|
|
|
*
|
2002-03-20 20:45:13 +01:00
|
|
|
|
* Parse state should be set up to recognize any vars that might appear
|
|
|
|
|
* in the expression. (Even though we plan to reject vars, it's more
|
|
|
|
|
* user-friendly to give the correct error message than "unknown var".)
|
|
|
|
|
*
|
2003-07-29 19:21:27 +02:00
|
|
|
|
* If atttypid is not InvalidOid, coerce the expression to the specified
|
|
|
|
|
* type (and typmod atttypmod). attname is only needed in this case:
|
|
|
|
|
* it is used in the error message, if any.
|
2002-03-19 03:18:25 +01:00
|
|
|
|
*/
|
|
|
|
|
Node *
|
|
|
|
|
cookDefault(ParseState *pstate,
|
|
|
|
|
Node *raw_default,
|
|
|
|
|
Oid atttypid,
|
|
|
|
|
int32 atttypmod,
|
2017-10-31 15:34:31 +01:00
|
|
|
|
const char *attname)
|
2002-03-20 20:45:13 +01:00
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Node *expr;
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
|
|
|
|
Assert(raw_default != NULL);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Transform raw parsetree to executable 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
|
|
|
|
expr = transformExpr(pstate, raw_default, EXPR_KIND_COLUMN_DEFAULT);
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
|
|
|
|
/*
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
|
* Make sure default expr does not refer to any vars (we need this check
|
|
|
|
|
* since the pstate includes the target table).
|
2002-03-19 03:18:25 +01:00
|
|
|
|
*/
|
|
|
|
|
if (contain_var_clause(expr))
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_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
|
|
|
|
errmsg("cannot use column references in default expression")));
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
2002-05-13 01:43:04 +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, aggregates,
|
2016-09-13 19:54:24 +02:00
|
|
|
|
* window functions, and SRFs, based on the EXPR_KIND_ for a default
|
|
|
|
|
* expression.
|
2002-05-13 01:43:04 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2002-03-19 03:18:25 +01:00
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
|
* Coerce the expression to the correct type and typmod, if given. This
|
|
|
|
|
* should match the parser's processing of non-defaulted expressions ---
|
2006-08-02 03:59:48 +02:00
|
|
|
|
* see transformAssignedExpr().
|
2002-03-19 03:18:25 +01:00
|
|
|
|
*/
|
2002-03-20 20:45:13 +01:00
|
|
|
|
if (OidIsValid(atttypid))
|
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Oid type_id = exprType(expr);
|
2002-03-19 03:18:25 +01:00
|
|
|
|
|
2003-07-29 19:21:27 +02:00
|
|
|
|
expr = coerce_to_target_type(pstate, expr, type_id,
|
|
|
|
|
atttypid, atttypmod,
|
|
|
|
|
COERCION_ASSIGNMENT,
|
2008-08-29 01:09:48 +02:00
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
|
-1);
|
2003-07-29 19:21:27 +02:00
|
|
|
|
if (expr == NULL)
|
2003-07-21 03:59:11 +02:00
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
|
errmsg("column \"%s\" is of type %s"
|
|
|
|
|
" but default expression is of type %s",
|
|
|
|
|
attname,
|
|
|
|
|
format_type_be(atttypid),
|
|
|
|
|
format_type_be(type_id)),
|
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
|
|
|
|
errhint("You will need to rewrite or cast the expression.")));
|
2002-03-19 03:18:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
|
/*
|
|
|
|
|
* Finally, take care of collations in the finished expression.
|
|
|
|
|
*/
|
|
|
|
|
assign_expr_collations(pstate, expr);
|
|
|
|
|
|
2003-07-29 19:21:27 +02:00
|
|
|
|
return expr;
|
2002-03-19 03:18:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-05-30 14:57:36 +02:00
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Take a raw CHECK constraint expression and convert it to a cooked format
|
|
|
|
|
* ready for storage.
|
2002-07-12 20:43:19 +02:00
|
|
|
|
*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Parse state must be set up to recognize any vars that might appear
|
|
|
|
|
* in the expression.
|
2001-05-30 14:57:36 +02:00
|
|
|
|
*/
|
2008-05-10 01:32:05 +02:00
|
|
|
|
static Node *
|
|
|
|
|
cookConstraint(ParseState *pstate,
|
|
|
|
|
Node *raw_constraint,
|
|
|
|
|
char *relname)
|
2001-05-30 14:57:36 +02:00
|
|
|
|
{
|
2008-05-10 01:32:05 +02:00
|
|
|
|
Node *expr;
|
2001-10-25 07:50:21 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2008-05-10 01:32:05 +02:00
|
|
|
|
* Transform raw parsetree to executable expression.
|
2001-10-25 07:50:21 +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
|
|
|
|
expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
/*
|
|
|
|
|
* Make sure it yields a boolean result.
|
|
|
|
|
*/
|
|
|
|
|
expr = coerce_to_boolean(pstate, expr, "CHECK");
|
2001-05-30 14:57:36 +02:00
|
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
|
/*
|
|
|
|
|
* Take care of collations.
|
|
|
|
|
*/
|
|
|
|
|
assign_expr_collations(pstate, expr);
|
|
|
|
|
|
2008-05-10 01:32:05 +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
|
|
|
|
* Make sure no outside relations are referred to (this is probably dead
|
|
|
|
|
* code now that add_missing_from is history).
|
2008-05-10 01:32:05 +02:00
|
|
|
|
*/
|
|
|
|
|
if (list_length(pstate->p_rtable) != 1)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_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
|
|
|
|
errmsg("only table \"%s\" can be referenced in check constraint",
|
|
|
|
|
relname)));
|
2001-05-30 14:57:36 +02:00
|
|
|
|
|
2008-05-10 01:32:05 +02:00
|
|
|
|
return expr;
|
1997-08-22 16:10:26 +02:00
|
|
|
|
}
|
1997-08-22 04:58:51 +02:00
|
|
|
|
|
1999-11-28 03:03:04 +01:00
|
|
|
|
|
2003-05-12 02:17:03 +02:00
|
|
|
|
/*
|
|
|
|
|
* RemoveStatistics --- remove entries in pg_statistic for a rel or column
|
|
|
|
|
*
|
2009-12-29 21:11:45 +01:00
|
|
|
|
* If attnum is zero, remove all entries for rel; else remove only the one(s)
|
2003-05-12 02:17:03 +02:00
|
|
|
|
* for that column.
|
|
|
|
|
*/
|
2004-02-15 22:01:39 +01:00
|
|
|
|
void
|
2004-08-28 23:05:26 +02:00
|
|
|
|
RemoveStatistics(Oid relid, AttrNumber attnum)
|
1999-11-28 03:03:04 +01:00
|
|
|
|
{
|
|
|
|
|
Relation pgstatistic;
|
2002-07-20 00:21:17 +02:00
|
|
|
|
SysScanDesc scan;
|
2003-05-12 02:17:03 +02:00
|
|
|
|
ScanKeyData key[2];
|
|
|
|
|
int nkeys;
|
1999-11-28 03:03:04 +01:00
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
|
pgstatistic = heap_open(StatisticRelationId, RowExclusiveLock);
|
1999-11-28 03:03:04 +01:00
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
|
Anum_pg_statistic_starelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
2004-08-28 23:05:26 +02:00
|
|
|
|
ObjectIdGetDatum(relid));
|
1999-11-28 03:03:04 +01:00
|
|
|
|
|
2003-05-12 02:17:03 +02:00
|
|
|
|
if (attnum == 0)
|
|
|
|
|
nkeys = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-11-12 22:15:59 +01:00
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
|
Anum_pg_statistic_staattnum,
|
|
|
|
|
BTEqualStrategyNumber, F_INT2EQ,
|
|
|
|
|
Int16GetDatum(attnum));
|
2003-05-12 02:17:03 +02:00
|
|
|
|
nkeys = 2;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-29 21:11:45 +01:00
|
|
|
|
scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, nkeys, key);
|
2002-07-20 00:21:17 +02:00
|
|
|
|
|
2009-12-29 21:11:45 +01:00
|
|
|
|
/* we must loop even when attnum != 0, in case of inherited stats */
|
2002-07-20 00:21:17 +02:00
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(pgstatistic, &tuple->t_self);
|
1999-11-28 03:03:04 +01:00
|
|
|
|
|
2002-07-20 00:21:17 +02:00
|
|
|
|
systable_endscan(scan);
|
2003-05-12 02:17:03 +02:00
|
|
|
|
|
1999-11-28 03:03:04 +01:00
|
|
|
|
heap_close(pgstatistic, RowExclusiveLock);
|
|
|
|
|
}
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-07-31 22:09:10 +02:00
|
|
|
|
* RelationTruncateIndexes - truncate all indexes associated
|
|
|
|
|
* with the heap relation to zero tuples.
|
2002-07-14 23:08:08 +02:00
|
|
|
|
*
|
2002-08-05 05:29:17 +02:00
|
|
|
|
* The routine will truncate and then reconstruct the indexes on
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* the specified relation. Caller must hold exclusive lock on rel.
|
2002-07-14 23:08:08 +02:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2006-07-31 22:09:10 +02:00
|
|
|
|
RelationTruncateIndexes(Relation heapRelation)
|
2002-07-14 23:08:08 +02:00
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
|
ListCell *indlist;
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2003-05-28 18:04:02 +02:00
|
|
|
|
/* Ask the relcache to produce a list of the indexes of the rel */
|
|
|
|
|
foreach(indlist, RelationGetIndexList(heapRelation))
|
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
|
Oid indexId = lfirst_oid(indlist);
|
2003-05-28 18:04:02 +02:00
|
|
|
|
Relation currentIndex;
|
|
|
|
|
IndexInfo *indexInfo;
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
|
/* Open the index relation; use exclusive lock, just to be sure */
|
|
|
|
|
currentIndex = index_open(indexId, AccessExclusiveLock);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2003-05-28 18:04:02 +02:00
|
|
|
|
/* Fetch info needed for index_build */
|
|
|
|
|
indexInfo = BuildIndexInfo(currentIndex);
|
|
|
|
|
|
2008-09-30 12:52:14 +02:00
|
|
|
|
/*
|
2008-11-27 16:59:28 +01:00
|
|
|
|
* Now truncate the actual file (and discard buffers).
|
2008-09-30 12:52:14 +02:00
|
|
|
|
*/
|
2004-05-08 21:09:25 +02:00
|
|
|
|
RelationTruncate(currentIndex, 0);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
|
|
|
|
/* Initialize the index and rebuild */
|
2006-07-31 03:16:38 +02:00
|
|
|
|
/* Note: we do not need to re-establish pkey setting */
|
Support parallel btree index builds.
To make this work, tuplesort.c and logtape.c must also support
parallelism, so this patch adds that infrastructure and then applies
it to the particular case of parallel btree index builds. Testing
to date shows that this can often be 2-3x faster than a serial
index build.
The model for deciding how many workers to use is fairly primitive
at present, but it's better than not having the feature. We can
refine it as we get more experience.
Peter Geoghegan with some help from Rushabh Lathia. While Heikki
Linnakangas is not an author of this patch, he wrote other patches
without which this feature would not have been possible, and
therefore the release notes should possibly credit him as an author
of this feature. Reviewed by Claudio Freire, Heikki Linnakangas,
Thomas Munro, Tels, Amit Kapila, me.
Discussion: http://postgr.es/m/CAM3SWZQKM=Pzc=CAHzRixKjp2eO5Q0Jg1SoFQqeXFQ647JiwqQ@mail.gmail.com
Discussion: http://postgr.es/m/CAH2-Wz=AxWqDoVvGU7dq856S4r6sJAj6DBn7VMtigkB33N5eyg@mail.gmail.com
2018-02-02 19:25:55 +01:00
|
|
|
|
index_build(heapRelation, currentIndex, indexInfo, false, true, false);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2006-05-11 01:18:39 +02:00
|
|
|
|
/* We're done with this index */
|
2006-07-31 22:09:10 +02:00
|
|
|
|
index_close(currentIndex, NoLock);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* heap_truncate
|
|
|
|
|
*
|
2005-01-27 04:19:37 +01:00
|
|
|
|
* This routine deletes all data within all the specified relations.
|
2003-09-19 23:04:20 +02:00
|
|
|
|
*
|
|
|
|
|
* This is not transaction-safe! There is another, transaction-safe
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* implementation in commands/tablecmds.c. We now use this only for
|
2003-09-19 23:04:20 +02:00
|
|
|
|
* ON COMMIT truncation of temporary tables, where it doesn't matter.
|
2002-07-14 23:08:08 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
2005-01-27 04:19:37 +01:00
|
|
|
|
heap_truncate(List *relids)
|
2002-07-14 23:08:08 +02:00
|
|
|
|
{
|
2005-01-27 04:19:37 +01:00
|
|
|
|
List *relations = NIL;
|
|
|
|
|
ListCell *cell;
|
|
|
|
|
|
|
|
|
|
/* Open relations for processing, and grab exclusive access on each */
|
|
|
|
|
foreach(cell, relids)
|
|
|
|
|
{
|
|
|
|
|
Oid rid = lfirst_oid(cell);
|
|
|
|
|
Relation rel;
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2005-01-27 04:19:37 +01:00
|
|
|
|
rel = heap_open(rid, AccessExclusiveLock);
|
|
|
|
|
relations = lappend(relations, rel);
|
|
|
|
|
}
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2003-09-19 23:04:20 +02:00
|
|
|
|
/* Don't allow truncate on tables that are referenced by foreign keys */
|
2005-01-27 04:19:37 +01:00
|
|
|
|
heap_truncate_check_FKs(relations, true);
|
2003-09-19 23:04:20 +02:00
|
|
|
|
|
2005-01-27 04:19:37 +01:00
|
|
|
|
/* OK to do it */
|
|
|
|
|
foreach(cell, relations)
|
|
|
|
|
{
|
|
|
|
|
Relation rel = lfirst(cell);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2009-08-23 21:23:41 +02:00
|
|
|
|
/* Truncate the relation */
|
|
|
|
|
heap_truncate_one_rel(rel);
|
2002-07-14 23:08:08 +02:00
|
|
|
|
|
2009-08-23 21:23:41 +02:00
|
|
|
|
/* Close the relation, but keep exclusive lock on it until commit */
|
2005-01-27 04:19:37 +01:00
|
|
|
|
heap_close(rel, NoLock);
|
|
|
|
|
}
|
2002-07-14 23:08:08 +02:00
|
|
|
|
}
|
2003-09-19 23:04:20 +02:00
|
|
|
|
|
2009-08-23 21:23:41 +02:00
|
|
|
|
/*
|
|
|
|
|
* heap_truncate_one_rel
|
|
|
|
|
*
|
|
|
|
|
* This routine deletes all data within the specified relation.
|
|
|
|
|
*
|
|
|
|
|
* This is not transaction-safe, because the truncation is done immediately
|
|
|
|
|
* and cannot be rolled back later. Caller is responsible for having
|
|
|
|
|
* checked permissions etc, and must have obtained AccessExclusiveLock.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
heap_truncate_one_rel(Relation rel)
|
|
|
|
|
{
|
|
|
|
|
Oid toastrelid;
|
|
|
|
|
|
|
|
|
|
/* Truncate the actual file (and discard buffers) */
|
|
|
|
|
RelationTruncate(rel, 0);
|
|
|
|
|
|
|
|
|
|
/* If the relation has indexes, truncate the indexes too */
|
|
|
|
|
RelationTruncateIndexes(rel);
|
|
|
|
|
|
|
|
|
|
/* If there is a toast table, truncate that too */
|
|
|
|
|
toastrelid = rel->rd_rel->reltoastrelid;
|
|
|
|
|
if (OidIsValid(toastrelid))
|
|
|
|
|
{
|
|
|
|
|
Relation toastrel = heap_open(toastrelid, AccessExclusiveLock);
|
|
|
|
|
|
|
|
|
|
RelationTruncate(toastrel, 0);
|
|
|
|
|
RelationTruncateIndexes(toastrel);
|
|
|
|
|
/* keep the lock... */
|
|
|
|
|
heap_close(toastrel, NoLock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-19 23:04:20 +02:00
|
|
|
|
/*
|
|
|
|
|
* heap_truncate_check_FKs
|
2005-01-27 04:19:37 +01:00
|
|
|
|
* Check for foreign keys referencing a list of relations that
|
2006-06-29 18:07:29 +02:00
|
|
|
|
* are to be truncated, and raise error if there are any
|
2003-09-19 23:04:20 +02:00
|
|
|
|
*
|
|
|
|
|
* We disallow such FKs (except self-referential ones) since the whole point
|
|
|
|
|
* of TRUNCATE is to not scan the individual rows to be thrown away.
|
|
|
|
|
*
|
|
|
|
|
* This is split out so it can be shared by both implementations of truncate.
|
2005-01-27 04:19:37 +01:00
|
|
|
|
* Caller should already hold a suitable lock on the relations.
|
|
|
|
|
*
|
|
|
|
|
* tempTables is only used to select an appropriate error message.
|
2003-09-19 23:04:20 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
2005-01-27 04:19:37 +01:00
|
|
|
|
heap_truncate_check_FKs(List *relations, bool tempTables)
|
2003-09-19 23:04:20 +02:00
|
|
|
|
{
|
2005-01-27 04:19:37 +01:00
|
|
|
|
List *oids = NIL;
|
2006-06-29 18:07:29 +02:00
|
|
|
|
List *dependents;
|
2005-01-27 04:19:37 +01:00
|
|
|
|
ListCell *cell;
|
2003-09-19 23:04:20 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2005-01-27 04:19:37 +01:00
|
|
|
|
* Build a list of OIDs of the interesting relations.
|
|
|
|
|
*
|
|
|
|
|
* If a relation has no triggers, then it can neither have FKs nor be
|
|
|
|
|
* referenced by a FK from another table, so we can ignore it.
|
2003-09-19 23:04:20 +02:00
|
|
|
|
*/
|
2005-01-27 04:19:37 +01:00
|
|
|
|
foreach(cell, relations)
|
|
|
|
|
{
|
|
|
|
|
Relation rel = lfirst(cell);
|
|
|
|
|
|
2008-11-09 22:24:33 +01:00
|
|
|
|
if (rel->rd_rel->relhastriggers)
|
2005-01-27 04:19:37 +01:00
|
|
|
|
oids = lappend_oid(oids, RelationGetRelid(rel));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Fast path: if no relation has triggers, none has FKs either.
|
|
|
|
|
*/
|
|
|
|
|
if (oids == NIL)
|
2003-09-19 23:04:20 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* Otherwise, must scan pg_constraint. We make one pass with all the
|
2006-06-29 18:07:29 +02:00
|
|
|
|
* relations considered; if this finds nothing, then all is well.
|
2003-09-19 23:04:20 +02:00
|
|
|
|
*/
|
2006-06-29 18:07:29 +02:00
|
|
|
|
dependents = heap_truncate_find_FKs(oids);
|
|
|
|
|
if (dependents == NIL)
|
|
|
|
|
return;
|
2003-09-19 23:04:20 +02:00
|
|
|
|
|
2006-06-29 18:07:29 +02:00
|
|
|
|
/*
|
|
|
|
|
* Otherwise we repeat the scan once per relation to identify a particular
|
|
|
|
|
* pair of relations to complain about. This is pretty slow, but
|
|
|
|
|
* performance shouldn't matter much in a failure path. The reason for
|
|
|
|
|
* doing things this way is to ensure that the message produced is not
|
|
|
|
|
* dependent on chance row locations within pg_constraint.
|
|
|
|
|
*/
|
|
|
|
|
foreach(cell, oids)
|
2003-09-19 23:04:20 +02:00
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
|
Oid relid = lfirst_oid(cell);
|
|
|
|
|
ListCell *cell2;
|
2005-01-27 04:19:37 +01:00
|
|
|
|
|
2006-06-29 18:07:29 +02:00
|
|
|
|
dependents = heap_truncate_find_FKs(list_make1_oid(relid));
|
2005-01-27 04:19:37 +01:00
|
|
|
|
|
2006-06-29 18:07:29 +02:00
|
|
|
|
foreach(cell2, dependents)
|
2005-01-27 04:19:37 +01:00
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
|
Oid relid2 = lfirst_oid(cell2);
|
2006-06-29 18:07:29 +02:00
|
|
|
|
|
|
|
|
|
if (!list_member_oid(oids, relid2))
|
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
|
char *relname = get_rel_name(relid);
|
|
|
|
|
char *relname2 = get_rel_name(relid2);
|
2006-06-29 18:07:29 +02:00
|
|
|
|
|
|
|
|
|
if (tempTables)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("unsupported ON COMMIT and foreign key combination"),
|
|
|
|
|
errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.",
|
|
|
|
|
relname2, relname)));
|
|
|
|
|
else
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
|
errmsg("cannot truncate a table referenced in a foreign key constraint"),
|
|
|
|
|
errdetail("Table \"%s\" references \"%s\".",
|
|
|
|
|
relname2, relname),
|
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
|
|
|
|
errhint("Truncate table \"%s\" at the same time, "
|
|
|
|
|
"or use TRUNCATE ... CASCADE.",
|
|
|
|
|
relname2)));
|
2006-06-29 18:07:29 +02:00
|
|
|
|
}
|
2005-01-27 04:19:37 +01:00
|
|
|
|
}
|
2003-09-19 23:04:20 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-03-03 04:30:54 +01:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* heap_truncate_find_FKs
|
2006-06-29 18:07:29 +02:00
|
|
|
|
* Find relations having foreign keys referencing any of the given rels
|
2006-03-03 04:30:54 +01:00
|
|
|
|
*
|
2006-06-29 18:07:29 +02:00
|
|
|
|
* Input and result are both lists of relation OIDs. The result contains
|
|
|
|
|
* no duplicates, does *not* include any rels that were already in the input
|
|
|
|
|
* list, and is sorted in OID order. (The last property is enforced mainly
|
|
|
|
|
* to guarantee consistent behavior in the regression tests; we don't want
|
|
|
|
|
* behavior to change depending on chance locations of rows in pg_constraint.)
|
2006-03-03 04:30:54 +01:00
|
|
|
|
*
|
2006-06-29 18:07:29 +02:00
|
|
|
|
* Note: caller should already have appropriate lock on all rels mentioned
|
2014-05-06 18:12:18 +02:00
|
|
|
|
* in relationIds. Since adding or dropping an FK requires exclusive lock
|
2006-03-03 04:30:54 +01:00
|
|
|
|
* on both rels, this ensures that the answer will be stable.
|
|
|
|
|
*/
|
|
|
|
|
List *
|
|
|
|
|
heap_truncate_find_FKs(List *relationIds)
|
|
|
|
|
{
|
|
|
|
|
List *result = NIL;
|
|
|
|
|
Relation fkeyRel;
|
|
|
|
|
SysScanDesc fkeyScan;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
|
* Must scan pg_constraint. Right now, it is a seqscan because there is
|
|
|
|
|
* no available index on confrelid.
|
2006-03-03 04:30:54 +01:00
|
|
|
|
*/
|
|
|
|
|
fkeyRel = heap_open(ConstraintRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
|
|
fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
|
NULL, 0, NULL);
|
2006-03-03 04:30:54 +01:00
|
|
|
|
|
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
|
|
|
|
|
{
|
|
|
|
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
|
|
/* Not a foreign key */
|
|
|
|
|
if (con->contype != CONSTRAINT_FOREIGN)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Not referencing one of our list of tables */
|
|
|
|
|
if (!list_member_oid(relationIds, con->confrelid))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Add referencer unless already in input or result list */
|
|
|
|
|
if (!list_member_oid(relationIds, con->conrelid))
|
2006-06-29 18:07:29 +02:00
|
|
|
|
result = insert_ordered_unique_oid(result, con->conrelid);
|
2006-03-03 04:30:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
systable_endscan(fkeyScan);
|
|
|
|
|
heap_close(fkeyRel, AccessShareLock);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2006-06-29 18:07:29 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* insert_ordered_unique_oid
|
|
|
|
|
* Insert a new Oid into a sorted list of Oids, preserving ordering,
|
|
|
|
|
* and eliminating duplicates
|
|
|
|
|
*
|
|
|
|
|
* Building the ordered list this way is O(N^2), but with a pretty small
|
|
|
|
|
* constant, so for the number of entries we expect it will probably be
|
|
|
|
|
* faster than trying to apply qsort(). It seems unlikely someone would be
|
|
|
|
|
* trying to truncate a table with thousands of dependent tables ...
|
|
|
|
|
*/
|
|
|
|
|
static List *
|
|
|
|
|
insert_ordered_unique_oid(List *list, Oid datum)
|
|
|
|
|
{
|
|
|
|
|
ListCell *prev;
|
|
|
|
|
|
|
|
|
|
/* Does the datum belong at the front? */
|
|
|
|
|
if (list == NIL || datum < linitial_oid(list))
|
|
|
|
|
return lcons_oid(datum, list);
|
|
|
|
|
/* Does it match the first entry? */
|
|
|
|
|
if (datum == linitial_oid(list))
|
|
|
|
|
return list; /* duplicate, so don't insert */
|
|
|
|
|
/* No, so find the entry it belongs after */
|
|
|
|
|
prev = list_head(list);
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
ListCell *curr = lnext(prev);
|
|
|
|
|
|
|
|
|
|
if (curr == NULL || datum < lfirst_oid(curr))
|
|
|
|
|
break; /* it belongs after 'prev', before 'curr' */
|
|
|
|
|
|
|
|
|
|
if (datum == lfirst_oid(curr))
|
|
|
|
|
return list; /* duplicate, so don't insert */
|
|
|
|
|
|
|
|
|
|
prev = curr;
|
|
|
|
|
}
|
|
|
|
|
/* Insert datum into list after 'prev' */
|
|
|
|
|
lappend_cell_oid(list, prev, datum);
|
|
|
|
|
return 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
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* StorePartitionKey
|
|
|
|
|
* Store information about the partition key rel into the catalog
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
StorePartitionKey(Relation rel,
|
|
|
|
|
char strategy,
|
|
|
|
|
int16 partnatts,
|
|
|
|
|
AttrNumber *partattrs,
|
|
|
|
|
List *partexprs,
|
|
|
|
|
Oid *partopclass,
|
|
|
|
|
Oid *partcollation)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int2vector *partattrs_vec;
|
|
|
|
|
oidvector *partopclass_vec;
|
|
|
|
|
oidvector *partcollation_vec;
|
|
|
|
|
Datum partexprDatum;
|
|
|
|
|
Relation pg_partitioned_table;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
Datum values[Natts_pg_partitioned_table];
|
|
|
|
|
bool nulls[Natts_pg_partitioned_table];
|
2017-01-24 16:20:02 +01:00
|
|
|
|
ObjectAddress myself;
|
|
|
|
|
ObjectAddress referenced;
|
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
|
|
|
|
|
|
|
|
|
Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
|
|
|
|
|
|
|
|
|
|
/* Copy the partition attribute numbers, opclass OIDs into arrays */
|
|
|
|
|
partattrs_vec = buildint2vector(partattrs, partnatts);
|
|
|
|
|
partopclass_vec = buildoidvector(partopclass, partnatts);
|
|
|
|
|
partcollation_vec = buildoidvector(partcollation, partnatts);
|
|
|
|
|
|
|
|
|
|
/* Convert the expressions (if any) to a text datum */
|
|
|
|
|
if (partexprs)
|
|
|
|
|
{
|
2017-01-24 16:20:02 +01:00
|
|
|
|
char *exprString;
|
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
|
|
|
|
|
|
|
|
|
exprString = nodeToString(partexprs);
|
|
|
|
|
partexprDatum = CStringGetTextDatum(exprString);
|
|
|
|
|
pfree(exprString);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
partexprDatum = (Datum) 0;
|
|
|
|
|
|
|
|
|
|
pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
MemSet(nulls, false, sizeof(nulls));
|
|
|
|
|
|
|
|
|
|
/* Only this can ever be NULL */
|
|
|
|
|
if (!partexprDatum)
|
|
|
|
|
nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
|
|
|
|
|
|
|
|
|
|
values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
|
|
|
|
|
values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy);
|
|
|
|
|
values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts);
|
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
|
|
|
|
values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid);
|
2017-01-24 16:20:02 +01:00
|
|
|
|
values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec);
|
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
|
|
|
|
values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec);
|
|
|
|
|
values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec);
|
|
|
|
|
values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum;
|
|
|
|
|
|
|
|
|
|
tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls);
|
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleInsert(pg_partitioned_table, tuple);
|
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
|
|
|
|
heap_close(pg_partitioned_table, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* Mark this relation as dependent on a few things as follows */
|
|
|
|
|
myself.classId = RelationRelationId;
|
|
|
|
|
myself.objectId = RelationGetRelid(rel);;
|
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
/* Operator class and collation per key column */
|
|
|
|
|
for (i = 0; i < partnatts; i++)
|
|
|
|
|
{
|
|
|
|
|
referenced.classId = OperatorClassRelationId;
|
|
|
|
|
referenced.objectId = partopclass[i];
|
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
|
|
2017-06-06 17:07:20 +02:00
|
|
|
|
/* The default collation is pinned, so don't bother recording it */
|
|
|
|
|
if (OidIsValid(partcollation[i]) &&
|
|
|
|
|
partcollation[i] != DEFAULT_COLLATION_OID)
|
|
|
|
|
{
|
|
|
|
|
referenced.classId = CollationRelationId;
|
|
|
|
|
referenced.objectId = partcollation[i];
|
|
|
|
|
referenced.objectSubId = 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
|
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Anything mentioned in the expressions. We must ignore the column
|
2017-01-24 16:20:02 +01:00
|
|
|
|
* references, which will depend on the table itself; there is no separate
|
|
|
|
|
* partition key object.
|
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 (partexprs)
|
|
|
|
|
recordDependencyOnSingleRelExpr(&myself,
|
|
|
|
|
(Node *) partexprs,
|
|
|
|
|
RelationGetRelid(rel),
|
|
|
|
|
DEPENDENCY_NORMAL,
|
|
|
|
|
DEPENDENCY_AUTO, true);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We must invalidate the relcache so that the next
|
|
|
|
|
* CommandCounterIncrement() will cause the same to be rebuilt using the
|
|
|
|
|
* information in just created catalog entry.
|
|
|
|
|
*/
|
|
|
|
|
CacheInvalidateRelcache(rel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2017-01-24 16:20:02 +01:00
|
|
|
|
* RemovePartitionKeyByRelId
|
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
|
|
|
|
* Remove pg_partitioned_table entry for a relation
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RemovePartitionKeyByRelId(Oid relid)
|
|
|
|
|
{
|
|
|
|
|
Relation rel;
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
|
|
rel = heap_open(PartitionedRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
|
elog(ERROR, "cache lookup failed for partition key of relation %u",
|
|
|
|
|
relid);
|
|
|
|
|
|
2017-02-01 22:13:30 +01:00
|
|
|
|
CatalogTupleDelete(rel, &tuple->t_self);
|
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
|
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* StorePartitionBound
|
|
|
|
|
* Update pg_class tuple of rel to store the partition bound and set
|
|
|
|
|
* relispartition to true
|
2016-12-20 04:53:30 +01:00
|
|
|
|
*
|
2018-03-21 16:03:35 +01:00
|
|
|
|
* If this is the default partition, also update the default partition OID in
|
|
|
|
|
* pg_partitioned_table.
|
|
|
|
|
*
|
2016-12-20 04:53:30 +01:00
|
|
|
|
* Also, invalidate the parent's relcache, so that the next rebuild will load
|
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
|
|
|
|
* the new partition's info into its partition descriptor. If there is a
|
|
|
|
|
* default partition, we must invalidate its relcache entry as well.
|
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
|
|
|
|
*/
|
|
|
|
|
void
|
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
|
|
|
|
StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *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
|
|
|
|
{
|
|
|
|
|
Relation classRel;
|
|
|
|
|
HeapTuple tuple,
|
|
|
|
|
newtuple;
|
2017-01-24 16:20:02 +01:00
|
|
|
|
Datum new_val[Natts_pg_class];
|
|
|
|
|
bool new_null[Natts_pg_class],
|
|
|
|
|
new_repl[Natts_pg_class];
|
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
|
|
|
|
Oid defaultPartOid;
|
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
|
|
|
|
|
|
|
|
|
/* Update pg_class tuple */
|
|
|
|
|
classRel = heap_open(RelationRelationId, RowExclusiveLock);
|
|
|
|
|
tuple = SearchSysCacheCopy1(RELOID,
|
|
|
|
|
ObjectIdGetDatum(RelationGetRelid(rel)));
|
2017-01-04 21:59:00 +01:00
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u",
|
|
|
|
|
RelationGetRelid(rel));
|
|
|
|
|
|
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
|
|
|
|
#ifdef USE_ASSERT_CHECKING
|
|
|
|
|
{
|
2017-01-24 16:20:02 +01:00
|
|
|
|
Form_pg_class classForm;
|
|
|
|
|
bool isnull;
|
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
|
|
|
|
|
|
|
|
|
classForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
|
Assert(!classForm->relispartition);
|
|
|
|
|
(void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound,
|
|
|
|
|
&isnull);
|
|
|
|
|
Assert(isnull);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Fill in relpartbound value */
|
|
|
|
|
memset(new_val, 0, sizeof(new_val));
|
|
|
|
|
memset(new_null, false, sizeof(new_null));
|
|
|
|
|
memset(new_repl, false, sizeof(new_repl));
|
|
|
|
|
new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound));
|
|
|
|
|
new_null[Anum_pg_class_relpartbound - 1] = false;
|
|
|
|
|
new_repl[Anum_pg_class_relpartbound - 1] = true;
|
|
|
|
|
newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
|
|
|
|
|
new_val, new_null, new_repl);
|
|
|
|
|
/* Also set the flag */
|
|
|
|
|
((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true;
|
2017-01-31 22:42:24 +01:00
|
|
|
|
CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple);
|
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
|
|
|
|
heap_freetuple(newtuple);
|
|
|
|
|
heap_close(classRel, RowExclusiveLock);
|
2016-12-20 04:53:30 +01:00
|
|
|
|
|
2018-03-21 16:03:35 +01:00
|
|
|
|
/*
|
|
|
|
|
* If we're storing bounds for the default partition, update
|
|
|
|
|
* pg_partitioned_table too.
|
|
|
|
|
*/
|
|
|
|
|
if (bound->is_default)
|
|
|
|
|
update_default_partition_oid(RelationGetRelid(parent),
|
|
|
|
|
RelationGetRelid(rel));
|
|
|
|
|
|
|
|
|
|
/* Make these updates visible */
|
2018-03-20 15:19:41 +01:00
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
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
|
|
|
|
/*
|
|
|
|
|
* The partition constraint for the default partition depends on the
|
|
|
|
|
* partition bounds of every other partition, so we must invalidate the
|
|
|
|
|
* relcache entry for that partition every time a partition is added or
|
|
|
|
|
* removed.
|
|
|
|
|
*/
|
|
|
|
|
defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
|
|
|
|
|
if (OidIsValid(defaultPartOid))
|
|
|
|
|
CacheInvalidateRelcacheByRelid(defaultPartOid);
|
|
|
|
|
|
2016-12-20 04:53:30 +01:00
|
|
|
|
CacheInvalidateRelcache(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
|
|
|
|
}
|