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
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, 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"
|
|
|
|
|
2019-01-15 02:02:12 +01:00
|
|
|
#include "access/genam.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"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/relation.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "access/sysattr.h"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/table.h"
|
2019-03-29 04:01:14 +01:00
|
|
|
#include "access/tableam.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"
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
#include "catalog/pg_am.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"
|
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-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"
|
2019-01-29 21:48:51 +01:00
|
|
|
#include "optimizer/optimizer.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"
|
2019-03-30 08:13:09 +01:00
|
|
|
#include "parser/parsetree.h"
|
2019-02-21 17:38:54 +01:00
|
|
|
#include "partitioning/partdesc.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"
|
2018-04-15 02:12:14 +02:00
|
|
|
#include "utils/partcache.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"
|
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,
|
2019-05-22 19:04:48 +02:00
|
|
|
Relation new_rel_desc,
|
|
|
|
Oid new_rel_oid,
|
|
|
|
Oid new_type_oid,
|
|
|
|
Oid reloftype,
|
|
|
|
Oid relowner,
|
|
|
|
char relkind,
|
|
|
|
TransactionId relfrozenxid,
|
|
|
|
TransactionId relminmxid,
|
|
|
|
Datum relacl,
|
|
|
|
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,
|
2019-05-22 19:04:48 +02:00
|
|
|
Oid typeNamespace,
|
|
|
|
Oid new_rel_oid,
|
|
|
|
char new_rel_kind,
|
|
|
|
Oid ownerid,
|
|
|
|
Oid new_row_type,
|
|
|
|
Oid new_array_type);
|
2004-08-28 23:05:26 +02:00
|
|
|
static void RelationRemoveInheritance(Oid relid);
|
2019-05-22 19:04:48 +02:00
|
|
|
static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr,
|
|
|
|
bool is_validated, bool is_local, int inhcount,
|
|
|
|
bool is_no_inherit, bool is_internal);
|
2013-03-18 03:55:14 +01:00
|
|
|
static void StoreConstraints(Relation rel, List *cooked_constraints,
|
2019-05-22 19:04:48 +02:00
|
|
|
bool is_internal);
|
2017-10-31 15:34:31 +01:00
|
|
|
static bool MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
|
2019-05-22 19:04:48 +02:00
|
|
|
bool allow_merge, bool is_local,
|
|
|
|
bool is_initially_valid,
|
|
|
|
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,
|
2019-05-22 19:04:48 +02:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2018-10-16 18:44:43 +02:00
|
|
|
static const FormData_pg_attribute a1 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"ctid"},
|
|
|
|
.atttypid = TIDOID,
|
|
|
|
.attlen = sizeof(ItemPointerData),
|
|
|
|
.attnum = SelfItemPointerAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = false,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 's',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
2018-10-16 18:44:43 +02:00
|
|
|
static const FormData_pg_attribute a2 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"xmin"},
|
|
|
|
.atttypid = XIDOID,
|
|
|
|
.attlen = sizeof(TransactionId),
|
|
|
|
.attnum = MinTransactionIdAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = true,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 'i',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
static const FormData_pg_attribute a3 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"cmin"},
|
|
|
|
.atttypid = CIDOID,
|
|
|
|
.attlen = sizeof(CommandId),
|
|
|
|
.attnum = MinCommandIdAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = true,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 'i',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
static const FormData_pg_attribute a4 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"xmax"},
|
|
|
|
.atttypid = XIDOID,
|
|
|
|
.attlen = sizeof(TransactionId),
|
|
|
|
.attnum = MaxTransactionIdAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = true,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 'i',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
static const FormData_pg_attribute a5 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"cmax"},
|
|
|
|
.atttypid = CIDOID,
|
|
|
|
.attlen = sizeof(CommandId),
|
|
|
|
.attnum = MaxCommandIdAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = true,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 'i',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
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.
|
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
static const FormData_pg_attribute a6 = {
|
2018-08-29 08:36:30 +02:00
|
|
|
.attname = {"tableoid"},
|
|
|
|
.atttypid = OIDOID,
|
|
|
|
.attlen = sizeof(Oid),
|
|
|
|
.attnum = TableOidAttributeNumber,
|
|
|
|
.attcacheoff = -1,
|
|
|
|
.atttypmod = -1,
|
|
|
|
.attbyval = true,
|
|
|
|
.attstorage = 'p',
|
|
|
|
.attalign = 'i',
|
|
|
|
.attnotnull = true,
|
|
|
|
.attislocal = true,
|
2000-07-03 00:01:27 +02:00
|
|
|
};
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
static const FormData_pg_attribute *SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6};
|
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
|
|
|
*/
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
SystemAttributeDefinition(AttrNumber attno)
|
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-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
|
|
|
*/
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
SystemAttributeByName(const char *attname)
|
2001-10-23 00:47:57 +02:00
|
|
|
{
|
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++)
|
|
|
|
{
|
2018-10-16 18:44:43 +02:00
|
|
|
const FormData_pg_attribute *att = SysAtt[j];
|
2001-10-23 00:47:57 +02:00
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
if (strcmp(NameStr(att->attname), attname) == 0)
|
|
|
|
return att;
|
2001-10-23 00:47:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
Oid accessmtd,
|
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,
|
2019-03-29 04:01:14 +01:00
|
|
|
bool allow_system_table_mods,
|
|
|
|
TransactionId *relfrozenxid,
|
|
|
|
MultiXactId *relminmxid)
|
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 &&
|
Clean up the behavior and API of catalog.c's is-catalog-relation tests.
The right way for IsCatalogRelation/Class to behave is to return true
for OIDs less than FirstBootstrapObjectId (not FirstNormalObjectId),
without any of the ad-hoc fooling around with schema membership.
The previous code was wrong because (1) it claimed that
information_schema tables were not catalog relations but their toast
tables were, which is silly; and (2) if you dropped and recreated
information_schema, which is a supported operation, the behavior
changed. That's even sillier. With this definition, "catalog
relations" are exactly the ones traceable to the postgres.bki data,
which seems like what we want.
With this simplification, we don't actually need access to the pg_class
tuple to identify a catalog relation; we only need its OID. Hence,
replace IsCatalogClass with "IsCatalogRelationOid(oid)". But keep
IsCatalogRelation as a convenience function.
This allows fixing some arguably-wrong semantics in contrib/sepgsql and
ReindexRelationConcurrently, which were using an IsSystemNamespace test
where what they really should be using is IsCatalogRelationOid. The
previous coding failed to protect toast tables of system catalogs, and
also was not on board with the general principle that user-created tables
do not become catalogs just by virtue of being renamed into pg_catalog.
We can also get rid of a messy hack in ReindexMultipleTables.
While we're at it, also rename IsSystemNamespace to IsCatalogNamespace,
because the previous name invited confusion with the more expansive
semantics used by IsSystemRelation/Class.
Also improve the comments in catalog.c.
There are a few remaining places in replication-related code that are
special-casing OIDs below FirstNormalObjectId. I'm inclined to think
those are wrong too, and if there should be any special case it should
just extend to FirstBootstrapObjectId. But first we need to debate
whether a FOR ALL TABLES publication should include information_schema.
Discussion: https://postgr.es/m/21697.1557092753@sss.pgh.pa.us
Discussion: https://postgr.es/m/15150.1557257111@sss.pgh.pa.us
2019-05-09 05:27:29 +02:00
|
|
|
((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
|
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
|
|
|
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
|
|
|
|
2019-03-29 04:01:14 +01:00
|
|
|
*relfrozenxid = InvalidTransactionId;
|
|
|
|
*relminmxid = InvalidMultiXactId;
|
|
|
|
|
2019-01-04 18:51:17 +01:00
|
|
|
/* Handle reltablespace for specific 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:
|
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.
|
2019-01-04 18:51:17 +01:00
|
|
|
*
|
|
|
|
* Partitioned tables and indexes don't have physical storage
|
|
|
|
* either, but we want to keep their tablespace settings so that
|
|
|
|
* their children can inherit it.
|
2004-08-31 19:10:36 +02:00
|
|
|
*/
|
|
|
|
reltablespace = InvalidOid;
|
|
|
|
break;
|
2018-11-03 17:23:40 +01:00
|
|
|
|
2004-08-31 19:10:36 +02:00
|
|
|
case RELKIND_SEQUENCE:
|
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:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-07-18 17:02:48 +02:00
|
|
|
/*
|
2019-01-04 18:51:17 +01:00
|
|
|
* Decide whether to create storage. If caller passed a valid relfilenode,
|
|
|
|
* storage is already created, so don't do it here. Also don't create it
|
|
|
|
* for relkinds without physical storage.
|
2011-07-18 17:02:48 +02:00
|
|
|
*/
|
2019-01-04 18:51:17 +01:00
|
|
|
if (!RELKIND_HAS_STORAGE(relkind) || OidIsValid(relfilenode))
|
2011-07-18 17:02:48 +02:00
|
|
|
create_storage = false;
|
|
|
|
else
|
2019-01-04 18:51:17 +01:00
|
|
|
{
|
|
|
|
create_storage = true;
|
2011-07-18 17:02:48 +02:00
|
|
|
relfilenode = relid;
|
2019-01-04 18:51:17 +01:00
|
|
|
}
|
2011-07-18 17:02:48 +02:00
|
|
|
|
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,
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
accessmtd,
|
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.
|
|
|
|
*
|
2019-03-29 04:01:14 +01:00
|
|
|
* For relations the callback creates both the main and the init fork, for
|
|
|
|
* indexes only the main fork is created. The 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);
|
2019-03-29 04:01:14 +01:00
|
|
|
|
|
|
|
switch (rel->rd_rel->relkind)
|
|
|
|
{
|
|
|
|
case RELKIND_VIEW:
|
|
|
|
case RELKIND_COMPOSITE_TYPE:
|
|
|
|
case RELKIND_FOREIGN_TABLE:
|
|
|
|
case RELKIND_PARTITIONED_TABLE:
|
|
|
|
case RELKIND_PARTITIONED_INDEX:
|
|
|
|
Assert(false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RELKIND_INDEX:
|
|
|
|
case RELKIND_SEQUENCE:
|
|
|
|
RelationCreateStorage(rel->rd_node, relpersistence);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RELKIND_RELATION:
|
|
|
|
case RELKIND_TOASTVALUE:
|
|
|
|
case RELKIND_MATVIEW:
|
2019-04-30 04:28:05 +02:00
|
|
|
table_relation_set_new_filenode(rel, &rel->rd_node,
|
|
|
|
relpersistence,
|
|
|
|
relfrozenxid, relminmxid);
|
2019-03-29 04:01:14 +01:00
|
|
|
break;
|
|
|
|
}
|
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.
|
2019-01-31 01:25:33 +01:00
|
|
|
*
|
|
|
|
* relkind is the relkind of the relation to be created.
|
|
|
|
* flags controls which datatypes are allowed, cf CheckAttributeType.
|
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,
|
2019-01-31 01:25:33 +01:00
|
|
|
int flags)
|
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);
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
if (SystemAttributeByName(NameStr(attr->attname)) != 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 */
|
2019-01-31 01:25:33 +01:00
|
|
|
flags);
|
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.
|
2019-01-31 01:25:33 +01:00
|
|
|
*
|
|
|
|
* flags is a bitmask controlling which datatypes we allow. For the most
|
|
|
|
* part, pseudo-types are disallowed as attribute types, but there are some
|
|
|
|
* exceptions: ANYARRAYOID, RECORDOID, and RECORDARRAYOID can be allowed
|
|
|
|
* in some cases. (This works because values of those type classes are
|
|
|
|
* self-identifying to some extent. However, RECORDOID and RECORDARRAYOID
|
|
|
|
* are reliably identifiable only within a session, since the identity info
|
|
|
|
* may use a typmod that is only locally assigned. The caller is expected
|
|
|
|
* to know whether these cases are safe.)
|
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,
|
2019-01-31 01:25:33 +01:00
|
|
|
int flags)
|
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
|
|
|
/*
|
2019-01-31 01:25:33 +01:00
|
|
|
* We disallow pseudo-type columns, with the exception of ANYARRAY,
|
|
|
|
* RECORD, and RECORD[] when the caller says that those are OK.
|
|
|
|
*
|
|
|
|
* We don't need to worry about recursive containment for RECORD and
|
|
|
|
* RECORD[] because (a) no named composite type should be allowed to
|
|
|
|
* contain those, and (b) two "anonymous" record types couldn't be
|
|
|
|
* considered to be the same type, so infinite recursion isn't
|
|
|
|
* possible.
|
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
|
|
|
*/
|
2019-01-31 01:25:33 +01:00
|
|
|
if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
|
|
|
|
(atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
|
|
|
|
(atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
|
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,
|
2019-01-31 01:25:33 +01:00
|
|
|
flags);
|
2011-06-03 00:37:57 +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
|
|
|
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,
|
2019-01-31 01:25:33 +01:00
|
|
|
flags);
|
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,
|
2019-01-31 01:25:33 +01:00
|
|
|
flags);
|
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
|
2018-07-17 09:48:29 +02:00
|
|
|
* attribute to insert. attcacheoff is always initialized to -1, attacl and
|
|
|
|
* attoptions 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);
|
2018-07-17 09:48:29 +02:00
|
|
|
values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
|
2008-11-14 02:57:42 +01:00
|
|
|
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);
|
2019-03-30 08:13:09 +01:00
|
|
|
values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(new_attribute->attgenerated);
|
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,
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
char relkind)
|
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
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_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;
|
2018-07-17 09:48:29 +02:00
|
|
|
/* Make sure this is OK, too */
|
2008-11-14 02:57:42 +01:00
|
|
|
attr->attstattarget = -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
|
|
|
|
2019-01-29 01:12:18 +01:00
|
|
|
memcpy(&attStruct, 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
|
|
|
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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
values[Anum_pg_class_oid - 1] = ObjectIdGetDatum(new_rel_oid);
|
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_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
|
|
|
|
|
|
|
/* 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,
|
2019-03-29 04:01:14 +01:00
|
|
|
TransactionId relfrozenxid,
|
|
|
|
TransactionId relminmxid,
|
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
|
|
|
|
2019-03-29 04:01:14 +01:00
|
|
|
new_rel_reltup->relfrozenxid = relfrozenxid;
|
|
|
|
new_rel_reltup->relminmxid = relminmxid;
|
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
|
2009-10-05 21:24:49 +02:00
|
|
|
* 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,
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
Oid accessmtd,
|
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,
|
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;
|
2019-03-29 04:01:14 +01:00
|
|
|
TransactionId relfrozenxid;
|
|
|
|
MultiXactId relminmxid;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
|
2005-08-12 03:36:05 +02:00
|
|
|
|
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
|
|
|
|
2019-01-31 01:25:33 +01:00
|
|
|
/*
|
|
|
|
* Validate proposed tupdesc for the desired relkind. If
|
|
|
|
* allow_system_table_mods is on, allow ANYARRAY to be used; this is a
|
|
|
|
* hack to allow creating pg_statistic and cloning it during VACUUM FULL.
|
|
|
|
*/
|
|
|
|
CheckAttributeNamesTypes(tupdesc, relkind,
|
|
|
|
allow_system_table_mods ? CHKATYPE_ANYARRAY : 0);
|
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
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
|
2010-02-14 19:42:19 +01:00
|
|
|
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,
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
accessmtd,
|
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,
|
2019-03-29 04:01:14 +01:00
|
|
|
allow_system_table_mods,
|
|
|
|
&relfrozenxid,
|
|
|
|
&relminmxid);
|
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,
|
2019-03-29 04:01:14 +01:00
|
|
|
relfrozenxid,
|
|
|
|
relminmxid,
|
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
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind);
|
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;
|
Fix missing role dependencies for some schema and type ACLs.
This patch fixes several related cases in which pg_shdepend entries were
never made, or were lost, for references to roles appearing in the ACLs of
schemas and/or types. While that did no immediate harm, if a referenced
role were later dropped, the drop would be allowed and would leave a
dangling reference in the object's ACL. That still wasn't a big problem
for normal database usage, but it would cause obscure failures in
subsequent dump/reload or pg_upgrade attempts, taking the form of
attempts to grant privileges to all-numeric role names. (I think I've
seen field reports matching that symptom, but can't find any right now.)
Several cases are fixed here:
1. ALTER DOMAIN SET/DROP DEFAULT would lose the dependencies for any
existing ACL entries for the domain. This case is ancient, dating
back as far as we've had pg_shdepend tracking at all.
2. If a default type privilege applies, CREATE TYPE recorded the
ACL properly but forgot to install dependency entries for it.
This dates to the addition of default privileges for types in 9.2.
3. If a default schema privilege applies, CREATE SCHEMA recorded the
ACL properly but forgot to install dependency entries for it.
This dates to the addition of default privileges for schemas in v10
(commit ab89e465c).
Another somewhat-related problem is that when creating a relation
rowtype or implicit array type, TypeCreate would apply any available
default type privileges to that type, which we don't really want
since such an object isn't supposed to have privileges of its own.
(You can't, for example, drop such privileges once they've been added
to an array type.)
ab89e465c is also to blame for a race condition in the regression tests:
privileges.sql transiently installed globally-applicable default
privileges on schemas, which sometimes got absorbed into the ACLs of
schemas created by concurrent test scripts. This should have resulted
in failures when privileges.sql tried to drop the role holding such
privileges; but thanks to the bug fixed here, it instead led to dangling
ACLs in the final state of the regression database. We'd managed not to
notice that, but it became obvious in the wake of commit da906766c, which
allowed the race condition to occur in pg_upgrade tests.
To fix, add a function recordDependencyOnNewAcl to encapsulate what
callers of get_user_default_acl need to do; while the original call
sites got that right via ad-hoc code, none of the later-added ones
have. Also change GenerateTypeDependencies to generate these
dependencies, which requires adding the typacl to its parameter list.
(That might be annoying if there are any extensions calling that
function directly; but if there are, they're most likely buggy in the
same way as the core callers were, so they need work anyway.) While
I was at it, I changed GenerateTypeDependencies to accept most of its
parameters in the form of a Form_pg_type pointer, making its parameter
list a bit less unwieldy and mistake-prone.
The test race condition is fixed just by wrapping the addition and
removal of default privileges into a single transaction, so that that
state is never visible externally. We might eventually prefer to
separate out tests of default privileges into a script that runs by
itself, but that would be a bigger change and would make the tests
run slower overall.
Back-patch relevant parts to all supported branches.
Discussion: https://postgr.es/m/15719.1541725287@sss.pgh.pa.us
2018-11-10 02:42:03 +01:00
|
|
|
|
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
|
|
|
|
Fix missing role dependencies for some schema and type ACLs.
This patch fixes several related cases in which pg_shdepend entries were
never made, or were lost, for references to roles appearing in the ACLs of
schemas and/or types. While that did no immediate harm, if a referenced
role were later dropped, the drop would be allowed and would leave a
dangling reference in the object's ACL. That still wasn't a big problem
for normal database usage, but it would cause obscure failures in
subsequent dump/reload or pg_upgrade attempts, taking the form of
attempts to grant privileges to all-numeric role names. (I think I've
seen field reports matching that symptom, but can't find any right now.)
Several cases are fixed here:
1. ALTER DOMAIN SET/DROP DEFAULT would lose the dependencies for any
existing ACL entries for the domain. This case is ancient, dating
back as far as we've had pg_shdepend tracking at all.
2. If a default type privilege applies, CREATE TYPE recorded the
ACL properly but forgot to install dependency entries for it.
This dates to the addition of default privileges for types in 9.2.
3. If a default schema privilege applies, CREATE SCHEMA recorded the
ACL properly but forgot to install dependency entries for it.
This dates to the addition of default privileges for schemas in v10
(commit ab89e465c).
Another somewhat-related problem is that when creating a relation
rowtype or implicit array type, TypeCreate would apply any available
default type privileges to that type, which we don't really want
since such an object isn't supposed to have privileges of its own.
(You can't, for example, drop such privileges once they've been added
to an array type.)
ab89e465c is also to blame for a race condition in the regression tests:
privileges.sql transiently installed globally-applicable default
privileges on schemas, which sometimes got absorbed into the ACLs of
schemas created by concurrent test scripts. This should have resulted
in failures when privileges.sql tried to drop the role holding such
privileges; but thanks to the bug fixed here, it instead led to dangling
ACLs in the final state of the regression database. We'd managed not to
notice that, but it became obvious in the wake of commit da906766c, which
allowed the race condition to occur in pg_upgrade tests.
To fix, add a function recordDependencyOnNewAcl to encapsulate what
callers of get_user_default_acl need to do; while the original call
sites got that right via ad-hoc code, none of the later-added ones
have. Also change GenerateTypeDependencies to generate these
dependencies, which requires adding the typacl to its parameter list.
(That might be annoying if there are any extensions calling that
function directly; but if there are, they're most likely buggy in the
same way as the core callers were, so they need work anyway.) While
I was at it, I changed GenerateTypeDependencies to accept most of its
parameters in the form of a Form_pg_type pointer, making its parameter
list a bit less unwieldy and mistake-prone.
The test race condition is fixed just by wrapping the addition and
removal of default privileges into a single transaction, so that that
state is never visible externally. We might eventually prefer to
separate out tests of default privileges into a script that runs by
itself, but that would be a bigger change and would make the tests
run slower overall.
Back-patch relevant parts to all supported branches.
Discussion: https://postgr.es/m/15719.1541725287@sss.pgh.pa.us
2018-11-10 02:42:03 +01:00
|
|
|
recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
|
|
|
|
|
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);
|
|
|
|
}
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a dependency link to force the relation to be deleted if its
|
|
|
|
* access method is. Do this only for relation and materialized views.
|
|
|
|
*
|
|
|
|
* No need to add an explicit dependency for the toast table, as the
|
|
|
|
* main table depends on it.
|
|
|
|
*/
|
|
|
|
if (relkind == RELKIND_RELATION ||
|
|
|
|
relkind == RELKIND_MATVIEW)
|
|
|
|
{
|
|
|
|
referenced.classId = AccessMethodRelationId;
|
|
|
|
referenced.objectId = accessmtd;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
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
|
|
|
|
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
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
|
|
|
|
table_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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
catalogRelation = table_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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_class_desc = table_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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
attrel = table_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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
attrel = table_open(AttributeRelationId, RowExclusiveLock);
|
2012-10-24 19:39:37 +02:00
|
|
|
|
|
|
|
/* 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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attrel, RowExclusiveLock);
|
2012-10-24 19:39:37 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
attr_rel = table_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
|
|
|
|
2019-03-30 08:13:09 +01:00
|
|
|
/* Unset this so no one tries to look up the generation expression */
|
|
|
|
attStruct->attgenerated = '\0';
|
|
|
|
|
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);
|
|
|
|
|
2018-06-22 14:42:36 +02:00
|
|
|
/* clear the missing value if any */
|
|
|
|
if (attStruct->atthasmissing)
|
|
|
|
{
|
|
|
|
Datum valuesAtt[Natts_pg_attribute];
|
|
|
|
bool nullsAtt[Natts_pg_attribute];
|
|
|
|
bool replacesAtt[Natts_pg_attribute];
|
|
|
|
|
|
|
|
/* update the tuple - set atthasmissing and attmissingval */
|
|
|
|
MemSet(valuesAtt, 0, sizeof(valuesAtt));
|
|
|
|
MemSet(nullsAtt, false, sizeof(nullsAtt));
|
|
|
|
MemSet(replacesAtt, false, sizeof(replacesAtt));
|
|
|
|
|
|
|
|
valuesAtt[Anum_pg_attribute_atthasmissing - 1] =
|
|
|
|
BoolGetDatum(false);
|
|
|
|
replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
|
|
|
|
valuesAtt[Anum_pg_attribute_attmissingval - 1] = (Datum) 0;
|
|
|
|
nullsAtt[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
|
|
|
|
tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel),
|
|
|
|
valuesAtt, nullsAtt, replacesAtt);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attr_rel, RowExclusiveLock);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
attrdef_rel = table_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;
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
object.classId = AttrDefaultRelationId;
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
object.objectId = attrtuple->oid;
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attrdef_rel, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
attrdef_rel = table_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],
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
Anum_pg_attrdef_oid,
|
2003-11-12 22:15:59 +01:00
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attrdef_rel, RowExclusiveLock);
|
2002-07-15 18:33:32 +02:00
|
|
|
|
|
|
|
/* Fix the pg_attribute row */
|
2019-01-21 19:32:19 +01:00
|
|
|
attr_rel = table_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
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(ForeignTableRelationId, RowExclusiveLock);
|
2011-01-02 05:48:11 +01:00
|
|
|
|
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, RowExclusiveLock);
|
2011-01-02 05:48:11 +01:00
|
|
|
}
|
|
|
|
|
Implement table partitioning.
Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own. The children are called
partitions and contain all of the actual data. Each partition has an
implicit partitioning constraint. Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed. Partitions
can't have extra columns and may not allow nulls unless the parent
does. Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.
Currently, tables can be range-partitioned or list-partitioned. List
partitioning is limited to a single column, but range partitioning can
involve multiple columns. A partitioning "column" can be an
expression.
Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations. The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.
Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others. Minor revisions by me.
2016-12-07 19:17:43 +01:00
|
|
|
/*
|
|
|
|
* If 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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
|
2018-03-28 02:13:52 +02:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attr_rel, RowExclusiveLock);
|
2018-03-28 02:13:52 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 14:42:36 +02:00
|
|
|
/*
|
|
|
|
* SetAttrMissing
|
|
|
|
*
|
|
|
|
* Set the missing value of a single attribute. This should only be used by
|
|
|
|
* binary upgrade. Takes an AccessExclusive lock on the relation owning the
|
|
|
|
* attribute.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SetAttrMissing(Oid relid, char *attname, char *value)
|
|
|
|
{
|
|
|
|
Datum valuesAtt[Natts_pg_attribute];
|
|
|
|
bool nullsAtt[Natts_pg_attribute];
|
|
|
|
bool replacesAtt[Natts_pg_attribute];
|
|
|
|
Datum missingval;
|
|
|
|
Form_pg_attribute attStruct;
|
|
|
|
Relation attrrel,
|
|
|
|
tablerel;
|
|
|
|
HeapTuple atttup,
|
|
|
|
newtup;
|
|
|
|
|
|
|
|
/* lock the table the attribute belongs to */
|
2019-01-21 19:32:19 +01:00
|
|
|
tablerel = table_open(relid, AccessExclusiveLock);
|
2018-06-22 14:42:36 +02:00
|
|
|
|
|
|
|
/* Lock the attribute row and get the data */
|
2019-01-21 19:32:19 +01:00
|
|
|
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
|
2018-06-22 14:42:36 +02:00
|
|
|
atttup = SearchSysCacheAttName(relid, attname);
|
|
|
|
if (!HeapTupleIsValid(atttup))
|
|
|
|
elog(ERROR, "cache lookup failed for attribute %s of relation %u",
|
|
|
|
attname, relid);
|
|
|
|
attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
|
|
|
|
|
|
|
|
/* get an array value from the value string */
|
|
|
|
missingval = OidFunctionCall3(F_ARRAY_IN,
|
|
|
|
CStringGetDatum(value),
|
|
|
|
ObjectIdGetDatum(attStruct->atttypid),
|
|
|
|
Int32GetDatum(attStruct->atttypmod));
|
|
|
|
|
|
|
|
/* update the tuple - set atthasmissing and attmissingval */
|
|
|
|
MemSet(valuesAtt, 0, sizeof(valuesAtt));
|
|
|
|
MemSet(nullsAtt, false, sizeof(nullsAtt));
|
|
|
|
MemSet(replacesAtt, false, sizeof(replacesAtt));
|
|
|
|
|
|
|
|
valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true);
|
|
|
|
replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
|
|
|
|
valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval;
|
|
|
|
replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
|
|
|
|
|
|
|
|
newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel),
|
|
|
|
valuesAtt, nullsAtt, replacesAtt);
|
|
|
|
CatalogTupleUpdate(attrrel, &newtup->t_self, newtup);
|
|
|
|
|
|
|
|
/* clean up */
|
|
|
|
ReleaseSysCache(atttup);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(attrrel, RowExclusiveLock);
|
|
|
|
table_close(tablerel, AccessExclusiveLock);
|
2018-06-22 14:42:36 +02:00
|
|
|
}
|
|
|
|
|
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;
|
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;
|
2019-03-30 08:13:09 +01:00
|
|
|
char attgenerated;
|
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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01: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
|
|
|
|
2002-07-15 18:33:32 +02:00
|
|
|
/*
|
|
|
|
* Make the pg_attrdef entry.
|
|
|
|
*/
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId,
|
|
|
|
Anum_pg_attrdef_oid);
|
|
|
|
values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid);
|
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);
|
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);
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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]));
|
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
|
|
|
|
2002-03-03 18:47:56 +01:00
|
|
|
/*
|
|
|
|
* Update the pg_attribute entry for the column to show that a default
|
|
|
|
* exists.
|
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
attrrel = table_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);
|
2019-03-30 08:13:09 +01:00
|
|
|
attgenerated = attStruct->attgenerated;
|
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;
|
|
|
|
|
2019-03-30 08:13:09 +01:00
|
|
|
if (add_column_mode && !attgenerated)
|
2018-03-28 02:13:52 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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.
|
|
|
|
*/
|
2019-03-30 08:13:09 +01:00
|
|
|
if (attgenerated)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Generated column: Dropping anything that the generation expression
|
|
|
|
* refers to automatically drops the generated column.
|
|
|
|
*/
|
|
|
|
recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel),
|
|
|
|
DEPENDENCY_AUTO,
|
|
|
|
DEPENDENCY_AUTO, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Normal default: Dropping anything that the default refers to
|
|
|
|
* requires CASCADE and drops the default only.
|
|
|
|
*/
|
|
|
|
recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel),
|
|
|
|
DEPENDENCY_NORMAL,
|
|
|
|
DEPENDENCY_NORMAL, false);
|
|
|
|
}
|
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;
|
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
|
|
|
|
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 */
|
2018-04-07 22:00:39 +02:00
|
|
|
keycount, /* # key attrs in the constraint */
|
|
|
|
keycount, /* # total 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 */
|
|
|
|
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);
|
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,
|
2018-08-22 08:42:49 +02:00
|
|
|
bool is_internal,
|
|
|
|
const char *queryString)
|
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);
|
2018-08-22 08:42:49 +02:00
|
|
|
pstate->p_sourcetext = queryString;
|
2002-03-22 03:56:37 +01:00
|
|
|
rte = addRangeTableEntryForRelation(pstate,
|
2005-04-13 18:50:55 +02:00
|
|
|
rel,
|
Create an RTE field to record the query's lock mode for each relation.
Add RangeTblEntry.rellockmode, which records the appropriate lock mode for
each RTE_RELATION rangetable entry (either AccessShareLock, RowShareLock,
or RowExclusiveLock depending on the RTE's role in the query).
This patch creates the field and makes all creators of RTE nodes fill it
in reasonably, but for the moment nothing much is done with it. The plan
is to replace assorted post-parser logic that re-determines the right
lockmode to use with simple uses of rte->rellockmode. For now, just add
Asserts in each of those places that the rellockmode matches what they are
computing today. (In some cases the match isn't perfect, so the Asserts
are weaker than you might expect; but this seems OK, as per discussion.)
This passes check-world for me, but it seems worth pushing in this state
to see if the buildfarm finds any problems in cases I failed to test.
catversion bump due to change of stored rules.
Amit Langote, reviewed by David Rowley and Jesper Pedersen,
and whacked around a bit more by me
Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
2018-09-30 19:55:51 +02:00
|
|
|
AccessShareLock,
|
2005-04-13 18:50:55 +02:00
|
|
|
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,
|
2019-03-30 08:13:09 +01:00
|
|
|
NameStr(atp->attname),
|
|
|
|
atp->attgenerated);
|
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
|
2019-05-22 18:55:34 +02:00
|
|
|
* equivalent. This applies to column defaults, but not for
|
|
|
|
* generation expressions.
|
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 ||
|
2019-03-30 08:13:09 +01:00
|
|
|
(!colDef->generated &&
|
|
|
|
IsA(expr, Const) &&
|
|
|
|
castNode(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;
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
ScanKeyData skey[3];
|
2008-05-10 01:32:05 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
/* Search for a pg_constraint entry with same name and relation */
|
2019-01-21 19:32:19 +01:00
|
|
|
conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
|
|
|
found = false;
|
|
|
|
|
|
|
|
ScanKeyInit(&skey[0],
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
Anum_pg_constraint_conrelid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(RelationGetRelid(rel)));
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
Anum_pg_constraint_contypid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(InvalidOid));
|
|
|
|
ScanKeyInit(&skey[2],
|
2008-05-10 01:32:05 +02:00
|
|
|
Anum_pg_constraint_conname,
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
CStringGetDatum(ccname));
|
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true,
|
|
|
|
NULL, 3, skey);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
/* There can be at most one matching row */
|
|
|
|
if (HeapTupleIsValid(tup = systable_getnext(conscan)))
|
2008-05-10 01:32:05 +02:00
|
|
|
{
|
|
|
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
|
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
/* Found it. Conflicts if not identical check constraint */
|
|
|
|
if (con->contype == CONSTRAINT_CHECK)
|
2008-05-10 01:32:05 +02:00
|
|
|
{
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
Datum val;
|
|
|
|
bool isnull;
|
|
|
|
|
|
|
|
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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +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. However if
|
|
|
|
* the relation is a partition, all inherited constraints are always
|
|
|
|
* non-local, including those that were merged.
|
|
|
|
*/
|
|
|
|
if (is_local && !con->conislocal && !rel->rd_rel->relispartition)
|
|
|
|
allow_merge = 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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
if (!found || !allow_merge)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("constraint \"%s\" for relation \"%s\" already exists",
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
2012-01-16 23:19:42 +01:00
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
/* If the child constraint is "no inherit" then cannot merge */
|
|
|
|
if (con->connoinherit)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
|
|
|
|
ccname, RelationGetRelationName(rel))));
|
2012-01-16 23:19:42 +01:00
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +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))));
|
2016-10-13 23:05:14 +02:00
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +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))));
|
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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
/* OK to update the tuple */
|
|
|
|
ereport(NOTICE,
|
|
|
|
(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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
tup = heap_copytuple(tup);
|
|
|
|
con = (Form_pg_constraint) GETSTRUCT(tup);
|
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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02: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;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (is_local)
|
|
|
|
con->conislocal = true;
|
2008-05-10 01:32:05 +02:00
|
|
|
else
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
con->coninhcount++;
|
|
|
|
}
|
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
|
|
|
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
if (is_no_inherit)
|
|
|
|
{
|
|
|
|
Assert(is_local);
|
|
|
|
con->connoinherit = true;
|
2008-05-10 01:32:05 +02:00
|
|
|
}
|
Fully enforce uniqueness of constraint names.
It's been true for a long time that we expect names of table and domain
constraints to be unique among the constraints of that table or domain.
However, the enforcement of that has been pretty haphazard, and it missed
some corner cases such as creating a CHECK constraint and then an index
constraint of the same name (as per recent report from André Hänsel).
Also, due to the lack of an actual unique index enforcing this, duplicates
could be created through race conditions.
Moreover, the code that searches pg_constraint has been quite inconsistent
about how to handle duplicate names if one did occur: some places checked
and threw errors if there was more than one match, while others just
processed the first match they came to.
To fix, create a unique index on (conrelid, contypid, conname). Since
either conrelid or contypid is zero, this will separately enforce
uniqueness of constraint names among constraints of any one table and any
one domain. (If we ever implement SQL assertions, and put them into this
catalog, more thought might be needed. But it'd be at least as reasonable
to put them into a new catalog; having overloaded this one catalog with
two kinds of constraints was a mistake already IMO.) This index can replace
the existing non-unique index on conrelid, though we need to keep the one
on contypid for query performance reasons.
Having done that, we can simplify the logic in various places that either
coped with duplicates or neglected to, as well as potentially improve
lookup performance when searching for a constraint by name.
Also, as per our usual practice, install a preliminary check so that you
get something more friendly than a unique-index violation report in the
case complained of by André. And teach ChooseIndexName to avoid choosing
autogenerated names that would draw such a failure.
While it's not possible to make such a change in the back branches,
it doesn't seem quite too late to put this into v11, so do so.
Discussion: https://postgr.es/m/0c1001d4428f$0942b430$1bc81c90$@webkr.de
2018-09-04 19:45:35 +02:00
|
|
|
|
|
|
|
CatalogTupleUpdate(conDesc, &tup->t_self, tup);
|
2008-05-10 01:32:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(conscan);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(conDesc, RowExclusiveLock);
|
2008-05-10 01:32:05 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
relrel = table_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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(relrel, RowExclusiveLock);
|
1997-08-22 16:10:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-30 08:13:09 +01:00
|
|
|
/*
|
|
|
|
* Check for references to generated columns
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_nested_generated_walker(Node *node, void *context)
|
|
|
|
{
|
|
|
|
ParseState *pstate = context;
|
|
|
|
|
|
|
|
if (node == NULL)
|
|
|
|
return false;
|
|
|
|
else if (IsA(node, Var))
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
|
|
|
Oid relid;
|
|
|
|
AttrNumber attnum;
|
|
|
|
|
|
|
|
relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
|
|
|
|
attnum = var->varattno;
|
|
|
|
|
|
|
|
if (OidIsValid(relid) && AttributeNumberIsValid(attnum) && get_attgenerated(relid, attnum))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("cannot use generated column \"%s\" in column generation expression",
|
|
|
|
get_attname(relid, attnum, false)),
|
|
|
|
errdetail("A generated column cannot reference another generated column."),
|
|
|
|
parser_errposition(pstate, var->location)));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return expression_tree_walker(node, check_nested_generated_walker,
|
|
|
|
(void *) context);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_nested_generated(ParseState *pstate, Node *node)
|
|
|
|
{
|
|
|
|
check_nested_generated_walker(node, pstate);
|
|
|
|
}
|
|
|
|
|
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,
|
2019-03-30 08:13:09 +01:00
|
|
|
const char *attname,
|
|
|
|
char attgenerated)
|
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.
|
|
|
|
*/
|
2019-03-30 08:13:09 +01:00
|
|
|
expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT);
|
2002-03-19 03:18:25 +01:00
|
|
|
|
2019-03-30 08:13:09 +01:00
|
|
|
if (attgenerated)
|
|
|
|
{
|
|
|
|
check_nested_generated(pstate, expr);
|
|
|
|
|
|
|
|
if (contain_mutable_functions(expr))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("generation expression is not immutable")));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For a default expression, transformExpr() should have rejected
|
|
|
|
* column references.
|
|
|
|
*/
|
|
|
|
Assert(!contain_var_clause(expr));
|
|
|
|
}
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
pgstatistic = table_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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pgstatistic, RowExclusiveLock);
|
1999-11-28 03:03:04 +01:00
|
|
|
}
|
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 */
|
2019-01-23 23:57:09 +01:00
|
|
|
index_build(heapRelation, currentIndex, indexInfo, 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
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(rid, AccessExclusiveLock);
|
2005-01-27 04:19:37 +01:00
|
|
|
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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, NoLock);
|
2005-01-27 04:19:37 +01:00
|
|
|
}
|
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;
|
|
|
|
|
2018-11-05 01:14:33 +01:00
|
|
|
/*
|
|
|
|
* Truncate the relation. Partitioned tables have no storage, so there is
|
|
|
|
* nothing to do for them here.
|
|
|
|
*/
|
|
|
|
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
|
|
|
return;
|
|
|
|
|
2019-03-29 04:01:14 +01:00
|
|
|
/* Truncate the underlying relation */
|
|
|
|
table_relation_nontransactional_truncate(rel);
|
2009-08-23 21:23:41 +02:00
|
|
|
|
|
|
|
/* 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))
|
|
|
|
{
|
2019-01-21 19:32:19 +01:00
|
|
|
Relation toastrel = table_open(toastrelid, AccessExclusiveLock);
|
2009-08-23 21:23:41 +02:00
|
|
|
|
2019-03-29 04:01:14 +01:00
|
|
|
table_relation_nontransactional_truncate(toastrel);
|
2009-08-23 21:23:41 +02:00
|
|
|
RelationTruncateIndexes(toastrel);
|
|
|
|
/* keep the lock... */
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(toastrel, NoLock);
|
2009-08-23 21:23:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2018-07-12 18:09:08 +02:00
|
|
|
* referenced by a FK from another table, so we can ignore it. For
|
|
|
|
* partitioned tables, FKs have no triggers, so we must include them
|
|
|
|
* anyway.
|
2003-09-19 23:04:20 +02:00
|
|
|
*/
|
2005-01-27 04:19:37 +01:00
|
|
|
foreach(cell, relations)
|
|
|
|
{
|
|
|
|
Relation rel = lfirst(cell);
|
|
|
|
|
2018-07-12 18:09:08 +02:00
|
|
|
if (rel->rd_rel->relhastriggers ||
|
|
|
|
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
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
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
fkeyRel = table_open(ConstraintRelationId, AccessShareLock);
|
2006-03-03 04:30:54 +01:00
|
|
|
|
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(fkeyRel, AccessShareLock);
|
2006-03-03 04:30:54 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
pg_partitioned_table = table_open(PartitionedRelationId, 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
|
|
|
|
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pg_partitioned_table, 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
|
|
|
|
|
|
|
/* Mark this relation as dependent on a few things as follows */
|
|
|
|
myself.classId = RelationRelationId;
|
2018-12-13 21:11:09 +01:00
|
|
|
myself.objectId = 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
|
|
|
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
|
|
|
|
2018-12-13 21:11:09 +01:00
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(PartitionedRelationId, 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
|
|
|
|
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2018-06-04 22:17:34 +02:00
|
|
|
* the new partition's info into its partition descriptor. If there is a
|
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
|
|
|
* 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 */
|
2019-01-21 19:32:19 +01:00
|
|
|
classRel = table_open(RelationRelationId, 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
|
|
|
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);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_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
|
|
|
}
|