2002-07-12 20:43:19 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* dependency.c
|
|
|
|
* Routines to support inter-object dependencies.
|
|
|
|
*
|
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
2002-07-12 20:43:19 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/catalog/dependency.c
|
2002-07-12 20:43:19 +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"
|
2019-01-21 19:18:20 +01:00
|
|
|
#include "access/table.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/xact.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
2012-03-09 20:34:56 +01:00
|
|
|
#include "catalog/objectaccess.h"
|
2016-03-24 03:01:35 +01:00
|
|
|
#include "catalog/pg_am.h"
|
2006-12-23 01:43:13 +01:00
|
|
|
#include "catalog/pg_amop.h"
|
|
|
|
#include "catalog/pg_amproc.h"
|
2002-07-15 18:33:32 +02:00
|
|
|
#include "catalog/pg_attrdef.h"
|
2005-07-07 22:40:02 +02:00
|
|
|
#include "catalog/pg_authid.h"
|
2002-07-30 00:14:11 +02:00
|
|
|
#include "catalog/pg_cast.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"
|
2002-07-25 12:07:13 +02:00
|
|
|
#include "catalog/pg_conversion.h"
|
2005-07-07 22:40:02 +02:00
|
|
|
#include "catalog/pg_database.h"
|
2009-10-05 21:24:49 +02:00
|
|
|
#include "catalog/pg_default_acl.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/pg_depend.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "catalog/pg_event_trigger.h"
|
2011-02-08 22:08:41 +01:00
|
|
|
#include "catalog/pg_extension.h"
|
2008-12-19 17:25:19 +01:00
|
|
|
#include "catalog/pg_foreign_data_wrapper.h"
|
|
|
|
#include "catalog/pg_foreign_server.h"
|
2016-04-07 03:45:32 +02:00
|
|
|
#include "catalog/pg_init_privs.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/pg_language.h"
|
2009-12-11 04:34:57 +01:00
|
|
|
#include "catalog/pg_largeobject.h"
|
2005-04-14 22:03:27 +02:00
|
|
|
#include "catalog/pg_namespace.h"
|
2002-07-30 00:14:11 +02:00
|
|
|
#include "catalog/pg_opclass.h"
|
2005-04-14 22:03:27 +02:00
|
|
|
#include "catalog/pg_operator.h"
|
2006-12-23 01:43:13 +01:00
|
|
|
#include "catalog/pg_opfamily.h"
|
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
2014-11-27 07:06:36 +01:00
|
|
|
#include "catalog/pg_policy.h"
|
2005-04-14 03:38:22 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "catalog/pg_publication.h"
|
|
|
|
#include "catalog/pg_publication_rel.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/pg_rewrite.h"
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
#include "catalog/pg_statistic_ext.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "catalog/pg_subscription.h"
|
2005-07-07 22:40:02 +02:00
|
|
|
#include "catalog/pg_tablespace.h"
|
2015-04-26 16:33:14 +02:00
|
|
|
#include "catalog/pg_transform.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "catalog/pg_trigger.h"
|
2007-08-21 03:11:32 +02:00
|
|
|
#include "catalog/pg_ts_config.h"
|
|
|
|
#include "catalog/pg_ts_dict.h"
|
|
|
|
#include "catalog/pg_ts_parser.h"
|
|
|
|
#include "catalog/pg_ts_template.h"
|
2005-04-14 03:38:22 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2008-12-19 17:25:19 +01:00
|
|
|
#include "catalog/pg_user_mapping.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "commands/comment.h"
|
|
|
|
#include "commands/defrem.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "commands/event_trigger.h"
|
2011-02-08 22:08:41 +01:00
|
|
|
#include "commands/extension.h"
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
#include "commands/policy.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "commands/proclang.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "commands/publicationcmds.h"
|
2002-07-18 18:47:26 +02:00
|
|
|
#include "commands/schemacmds.h"
|
2010-09-28 02:55:27 +02:00
|
|
|
#include "commands/seclabel.h"
|
2016-12-20 18:00:00 +01:00
|
|
|
#include "commands/sequence.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "commands/trigger.h"
|
2002-12-06 06:00:34 +01:00
|
|
|
#include "commands/typecmds.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
2002-07-16 07:53:34 +02:00
|
|
|
#include "parser/parsetree.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "rewrite/rewriteRemove.h"
|
2008-06-09 00:41:04 +02:00
|
|
|
#include "storage/lmgr.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "utils/fmgroids.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "utils/guc.h"
|
2002-07-12 20:43:19 +02:00
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* Deletion processing requires additional state for each ObjectAddress that
|
|
|
|
* it's planning to delete. For simplicity and code-sharing we make the
|
|
|
|
* ObjectAddresses code support arrays with or without this extra state.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int flags; /* bitmask, see bit definitions below */
|
|
|
|
ObjectAddress dependee; /* object whose deletion forced this one */
|
|
|
|
} ObjectAddressExtra;
|
|
|
|
|
|
|
|
/* ObjectAddressExtra flag bits */
|
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
|
|
|
#define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */
|
|
|
|
#define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */
|
|
|
|
#define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */
|
|
|
|
#define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
#define DEPFLAG_PARTITION 0x0010 /* reached via partition dependency */
|
|
|
|
#define DEPFLAG_EXTENSION 0x0020 /* reached via extension dependency */
|
|
|
|
#define DEPFLAG_REVERSE 0x0040 /* reverse internal/extension link */
|
|
|
|
#define DEPFLAG_IS_PART 0x0080 /* has a partition dependency */
|
|
|
|
#define DEPFLAG_SUBOBJECT 0x0100 /* subobject of another deletable object */
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/* expansible list of ObjectAddresses */
|
2006-08-20 23:56:16 +02:00
|
|
|
struct ObjectAddresses
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddress *refs; /* => palloc'd array */
|
2009-06-11 16:49:15 +02:00
|
|
|
ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */
|
2002-09-04 22:31:48 +02:00
|
|
|
int numrefs; /* current number of references */
|
2008-06-09 00:41:04 +02:00
|
|
|
int maxrefs; /* current size of palloc'd array(s) */
|
2006-08-20 23:56:16 +02:00
|
|
|
};
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
/* typedef ObjectAddresses appears in dependency.h */
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/* threaded list of ObjectAddresses, for recursion detection */
|
|
|
|
typedef struct ObjectAddressStack
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
const ObjectAddress *object; /* object being visited */
|
2008-06-09 00:41:04 +02:00
|
|
|
int flags; /* its current flag bits */
|
2009-06-11 16:49:15 +02:00
|
|
|
struct ObjectAddressStack *next; /* next outer stack level */
|
2008-06-09 00:41:04 +02:00
|
|
|
} ObjectAddressStack;
|
|
|
|
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
/* temporary storage in findDependentObjects */
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
ObjectAddress obj; /* object to be deleted --- MUST BE FIRST */
|
|
|
|
int subflags; /* flags to pass down when recursing to obj */
|
|
|
|
} ObjectAddressAndFlags;
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/* for find_expr_references_walker */
|
|
|
|
typedef struct
|
|
|
|
{
|
2006-08-20 23:56:16 +02:00
|
|
|
ObjectAddresses *addrs; /* addresses being accumulated */
|
2002-09-04 22:31:48 +02:00
|
|
|
List *rtables; /* list of rangetables to resolve Vars */
|
2002-07-16 07:53:34 +02:00
|
|
|
} find_expr_references_context;
|
|
|
|
|
|
|
|
/*
|
2005-04-14 22:03:27 +02:00
|
|
|
* This constant table maps ObjectClasses to the corresponding catalog OIDs.
|
|
|
|
* See also getObjectClass().
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
2015-07-21 13:20:53 +02:00
|
|
|
static const Oid object_classes[] = {
|
2007-11-15 22:14:46 +01:00
|
|
|
RelationRelationId, /* OCLASS_CLASS */
|
|
|
|
ProcedureRelationId, /* OCLASS_PROC */
|
|
|
|
TypeRelationId, /* OCLASS_TYPE */
|
|
|
|
CastRelationId, /* OCLASS_CAST */
|
2011-02-12 14:54:13 +01:00
|
|
|
CollationRelationId, /* OCLASS_COLLATION */
|
2007-11-15 22:14:46 +01:00
|
|
|
ConstraintRelationId, /* OCLASS_CONSTRAINT */
|
|
|
|
ConversionRelationId, /* OCLASS_CONVERSION */
|
|
|
|
AttrDefaultRelationId, /* OCLASS_DEFAULT */
|
|
|
|
LanguageRelationId, /* OCLASS_LANGUAGE */
|
2009-12-11 04:34:57 +01:00
|
|
|
LargeObjectRelationId, /* OCLASS_LARGEOBJECT */
|
2007-11-15 22:14:46 +01:00
|
|
|
OperatorRelationId, /* OCLASS_OPERATOR */
|
|
|
|
OperatorClassRelationId, /* OCLASS_OPCLASS */
|
|
|
|
OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
|
2016-03-24 03:01:35 +01:00
|
|
|
AccessMethodRelationId, /* OCLASS_AM */
|
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
|
|
|
AccessMethodOperatorRelationId, /* OCLASS_AMOP */
|
2006-12-23 01:43:13 +01:00
|
|
|
AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
|
2007-11-15 22:14:46 +01:00
|
|
|
RewriteRelationId, /* OCLASS_REWRITE */
|
|
|
|
TriggerRelationId, /* OCLASS_TRIGGER */
|
|
|
|
NamespaceRelationId, /* OCLASS_SCHEMA */
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
StatisticExtRelationId, /* OCLASS_STATISTIC_EXT */
|
2007-11-15 22:14:46 +01:00
|
|
|
TSParserRelationId, /* OCLASS_TSPARSER */
|
|
|
|
TSDictionaryRelationId, /* OCLASS_TSDICT */
|
|
|
|
TSTemplateRelationId, /* OCLASS_TSTEMPLATE */
|
|
|
|
TSConfigRelationId, /* OCLASS_TSCONFIG */
|
|
|
|
AuthIdRelationId, /* OCLASS_ROLE */
|
|
|
|
DatabaseRelationId, /* OCLASS_DATABASE */
|
2009-08-07 17:27:56 +02:00
|
|
|
TableSpaceRelationId, /* OCLASS_TBLSPACE */
|
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
|
|
|
ForeignDataWrapperRelationId, /* OCLASS_FDW */
|
2009-08-07 17:27:56 +02:00
|
|
|
ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
|
2009-10-05 21:24:49 +02:00
|
|
|
UserMappingRelationId, /* OCLASS_USER_MAPPING */
|
2011-02-08 22:08:41 +01:00
|
|
|
DefaultAclRelationId, /* OCLASS_DEFACL */
|
2012-07-18 16:16:16 +02:00
|
|
|
ExtensionRelationId, /* OCLASS_EXTENSION */
|
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
2014-11-27 07:06:36 +01:00
|
|
|
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
|
2015-07-21 13:20:53 +02:00
|
|
|
PolicyRelationId, /* OCLASS_POLICY */
|
2017-01-19 18:00:00 +01:00
|
|
|
PublicationRelationId, /* OCLASS_PUBLICATION */
|
|
|
|
PublicationRelRelationId, /* OCLASS_PUBLICATION_REL */
|
|
|
|
SubscriptionRelationId, /* OCLASS_SUBSCRIPTION */
|
2015-07-21 13:20:53 +02:00
|
|
|
TransformRelationId /* OCLASS_TRANSFORM */
|
2005-04-14 22:03:27 +02:00
|
|
|
};
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
static void findDependentObjects(const ObjectAddress *object,
|
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
|
|
|
int objflags,
|
2008-06-09 00:41:04 +02:00
|
|
|
int flags,
|
|
|
|
ObjectAddressStack *stack,
|
|
|
|
ObjectAddresses *targetObjects,
|
|
|
|
const ObjectAddresses *pendingObjects,
|
2012-12-06 05:42:51 +01:00
|
|
|
Relation *depRel);
|
2008-06-09 00:41:04 +02:00
|
|
|
static void reportDependentObjects(const ObjectAddresses *targetObjects,
|
2003-08-04 02:43:34 +02:00
|
|
|
DropBehavior behavior,
|
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
|
|
|
int flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
const ObjectAddress *origObject);
|
2012-01-26 15:24:54 +01:00
|
|
|
static void deleteOneObject(const ObjectAddress *object,
|
2012-12-06 05:42:51 +01:00
|
|
|
Relation *depRel, int32 flags);
|
2012-04-06 11:21:40 +02:00
|
|
|
static void doDeletion(const ObjectAddress *object, int flags);
|
|
|
|
static void AcquireDeletionLock(const ObjectAddress *object, int flags);
|
2008-06-09 00:41:04 +02:00
|
|
|
static void ReleaseDeletionLock(const ObjectAddress *object);
|
2002-07-16 07:53:34 +02:00
|
|
|
static bool find_expr_references_walker(Node *node,
|
2002-09-04 22:31:48 +02:00
|
|
|
find_expr_references_context *context);
|
2002-07-16 07:53:34 +02:00
|
|
|
static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
|
|
|
|
static int object_address_comparator(const void *a, const void *b);
|
2004-05-05 06:48:48 +02:00
|
|
|
static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddresses *addrs);
|
2008-06-09 00:41:04 +02:00
|
|
|
static void add_exact_object_address_extra(const ObjectAddress *object,
|
|
|
|
const ObjectAddressExtra *extra,
|
|
|
|
ObjectAddresses *addrs);
|
|
|
|
static bool object_address_present_add_flags(const ObjectAddress *object,
|
2009-06-11 16:49:15 +02:00
|
|
|
int flags,
|
|
|
|
ObjectAddresses *addrs);
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
static bool stack_address_present_add_flags(const ObjectAddress *object,
|
|
|
|
int flags,
|
|
|
|
ObjectAddressStack *stack);
|
2016-04-07 03:45:32 +02:00
|
|
|
static void DeleteInitPrivs(const ObjectAddress *object);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
|
|
|
* Go through the objects given running the final actions on them, and execute
|
|
|
|
* the actual deletion.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel,
|
|
|
|
int flags)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
int i;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep track of objects for event triggers, if necessary.
|
|
|
|
*/
|
2014-12-19 19:00:45 +01:00
|
|
|
if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL))
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
{
|
|
|
|
for (i = 0; i < targetObjects->numrefs; i++)
|
|
|
|
{
|
2014-12-19 19:00:45 +01:00
|
|
|
const ObjectAddress *thisobj = &targetObjects->refs[i];
|
|
|
|
const ObjectAddressExtra *extra = &targetObjects->extras[i];
|
2015-05-24 03:35:49 +02:00
|
|
|
bool original = false;
|
|
|
|
bool normal = false;
|
2014-12-19 19:00:45 +01:00
|
|
|
|
|
|
|
if (extra->flags & DEPFLAG_ORIGINAL)
|
|
|
|
original = true;
|
|
|
|
if (extra->flags & DEPFLAG_NORMAL)
|
|
|
|
normal = true;
|
|
|
|
if (extra->flags & DEPFLAG_REVERSE)
|
|
|
|
normal = true;
|
|
|
|
|
|
|
|
if (EventTriggerSupportsObjectClass(getObjectClass(thisobj)))
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
{
|
2014-12-19 19:00:45 +01:00
|
|
|
EventTriggerSQLDropAddObject(thisobj, original, normal);
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
* Delete all the objects in the proper order, except that if told to, we
|
|
|
|
* should skip the original object(s).
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
*/
|
|
|
|
for (i = 0; i < targetObjects->numrefs; i++)
|
|
|
|
{
|
|
|
|
ObjectAddress *thisobj = targetObjects->refs + i;
|
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
|
|
|
ObjectAddressExtra *thisextra = targetObjects->extras + i;
|
|
|
|
|
|
|
|
if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) &&
|
|
|
|
(thisextra->flags & DEPFLAG_ORIGINAL))
|
|
|
|
continue;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
deleteOneObject(thisobj, depRel, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
|
|
|
* performDeletion: attempt to drop the specified object. If CASCADE
|
|
|
|
* behavior is specified, also drop any dependent objects (recursively).
|
|
|
|
* If RESTRICT behavior is specified, error out if there are any dependent
|
|
|
|
* objects, except for those that should be implicitly dropped anyway
|
|
|
|
* according to the dependency type.
|
|
|
|
*
|
|
|
|
* This is the outer control routine for all forms of DROP that drop objects
|
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
|
|
|
* that can participate in dependencies. Note that performMultipleDeletions
|
|
|
|
* is a variant on the same theme; if you change anything here you'll likely
|
|
|
|
* need to fix that too.
|
|
|
|
*
|
|
|
|
* Bits in the flags argument can include:
|
|
|
|
*
|
|
|
|
* PERFORM_DELETION_INTERNAL: indicates that the drop operation is not the
|
|
|
|
* direct result of a user-initiated action. For example, when a temporary
|
|
|
|
* schema is cleaned out so that a new backend can use it, or when a column
|
|
|
|
* default is dropped as an intermediate step while adding a new one, that's
|
|
|
|
* an internal operation. On the other hand, when we drop something because
|
|
|
|
* the user issued a DROP statement against it, that's not internal. Currently
|
|
|
|
* this suppresses calling event triggers and making some permissions checks.
|
2012-01-26 15:24:54 +01:00
|
|
|
*
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
* PERFORM_DELETION_CONCURRENTLY: perform the drop concurrently. This does
|
|
|
|
* not currently work for anything except dropping indexes; don't set it for
|
|
|
|
* other object types or you may get strange results.
|
|
|
|
*
|
|
|
|
* PERFORM_DELETION_QUIETLY: reduce message level from NOTICE to DEBUG2.
|
|
|
|
*
|
|
|
|
* PERFORM_DELETION_SKIP_ORIGINAL: do not delete the specified object(s),
|
|
|
|
* but only what depends on it/them.
|
|
|
|
*
|
|
|
|
* PERFORM_DELETION_SKIP_EXTENSIONS: do not delete extensions, even when
|
|
|
|
* deleting objects that are part of an extension. This should generally
|
|
|
|
* be used only when dropping temporary objects.
|
2019-03-29 08:25:20 +01:00
|
|
|
*
|
|
|
|
* PERFORM_DELETION_CONCURRENT_LOCK: perform the drop normally but with a lock
|
|
|
|
* as if it were concurrent. This is used by REINDEX CONCURRENTLY.
|
|
|
|
*
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
performDeletion(const ObjectAddress *object,
|
2012-01-26 15:24:54 +01:00
|
|
|
DropBehavior behavior, int flags)
|
2002-07-12 20:43:19 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Relation depRel;
|
2008-06-09 00:41:04 +02:00
|
|
|
ObjectAddresses *targetObjects;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We save some cycles by opening pg_depend just once and passing the
|
|
|
|
* Relation pointer down to all the recursive deletion steps.
|
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
depRel = table_open(DependRelationId, RowExclusiveLock);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2002-09-22 02:37:09 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Acquire deletion lock on the target object. (Ideally the caller has
|
2008-06-09 00:41:04 +02:00
|
|
|
* done this already, but many places are sloppy about it.)
|
2002-09-22 02:37:09 +02:00
|
|
|
*/
|
2012-04-06 11:21:40 +02:00
|
|
|
AcquireDeletionLock(object, 0);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* Construct a list of objects to delete (ie, the given object plus
|
|
|
|
* everything directly or indirectly dependent on it).
|
2006-08-20 23:56:16 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
targetObjects = new_object_addresses();
|
|
|
|
|
|
|
|
findDependentObjects(object,
|
|
|
|
DEPFLAG_ORIGINAL,
|
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
|
|
|
flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
NULL, /* empty stack */
|
|
|
|
targetObjects,
|
|
|
|
NULL, /* no pendingObjects */
|
2012-12-06 05:42:51 +01:00
|
|
|
&depRel);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* Check if deletion is allowed, and report about cascaded deletes.
|
2006-08-20 23:56:16 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
reportDependentObjects(targetObjects,
|
|
|
|
behavior,
|
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
|
|
|
flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
object);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* do the deed */
|
|
|
|
deleteObjectsInList(targetObjects, &depRel, flags);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/* And clean up */
|
|
|
|
free_object_addresses(targetObjects);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(depRel, RowExclusiveLock);
|
2006-08-20 23:56:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* performMultipleDeletions: Similar to performDeletion, but act on multiple
|
2006-08-20 23:56:16 +02:00
|
|
|
* objects at once.
|
|
|
|
*
|
|
|
|
* The main difference from issuing multiple performDeletion calls is that the
|
|
|
|
* list of objects that would be implicitly dropped, for each object to be
|
|
|
|
* dropped, is the union of the implicit-object list for all objects. This
|
|
|
|
* makes each check be more relaxed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
performMultipleDeletions(const ObjectAddresses *objects,
|
2012-01-26 15:24:54 +01:00
|
|
|
DropBehavior behavior, int flags)
|
2006-08-20 23:56:16 +02:00
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
Relation depRel;
|
2008-06-09 00:41:04 +02:00
|
|
|
ObjectAddresses *targetObjects;
|
2006-10-04 02:30:14 +02:00
|
|
|
int i;
|
2006-08-20 23:56:16 +02:00
|
|
|
|
2008-06-14 20:04:34 +02:00
|
|
|
/* No work if no objects... */
|
|
|
|
if (objects->numrefs <= 0)
|
|
|
|
return;
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* We save some cycles by opening pg_depend just once and passing the
|
|
|
|
* Relation pointer down to all the recursive deletion steps.
|
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
depRel = table_open(DependRelationId, RowExclusiveLock);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* Construct a list of objects to delete (ie, the given objects plus
|
|
|
|
* everything directly or indirectly dependent on them). Note that
|
2009-06-11 16:49:15 +02:00
|
|
|
* because we pass the whole objects list as pendingObjects context, we
|
|
|
|
* won't get a failure from trying to delete an object that is internally
|
|
|
|
* dependent on another one in the list; we'll just skip that object and
|
|
|
|
* delete it when we reach its owner.
|
2006-08-20 23:56:16 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
targetObjects = new_object_addresses();
|
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
for (i = 0; i < objects->numrefs; i++)
|
|
|
|
{
|
2008-06-09 00:41:04 +02:00
|
|
|
const ObjectAddress *thisobj = objects->refs + i;
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* Acquire deletion lock on each target object. (Ideally the caller
|
|
|
|
* has done this already, but many places are sloppy about it.)
|
2006-08-20 23:56:16 +02:00
|
|
|
*/
|
2012-04-06 11:21:40 +02:00
|
|
|
AcquireDeletionLock(thisobj, flags);
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
findDependentObjects(thisobj,
|
|
|
|
DEPFLAG_ORIGINAL,
|
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
|
|
|
flags,
|
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, /* empty stack */
|
2008-06-09 00:41:04 +02:00
|
|
|
targetObjects,
|
|
|
|
objects,
|
2012-12-06 05:42:51 +01:00
|
|
|
&depRel);
|
2006-08-20 23:56:16 +02:00
|
|
|
}
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* Check if deletion is allowed, and report about cascaded deletes.
|
2008-06-14 20:04:34 +02:00
|
|
|
*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If there's exactly one object being deleted, report it the same way as
|
|
|
|
* in performDeletion(), else we have to be vaguer.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
reportDependentObjects(targetObjects,
|
|
|
|
behavior,
|
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
|
|
|
flags,
|
2008-06-14 20:04:34 +02:00
|
|
|
(objects->numrefs == 1 ? objects->refs : NULL));
|
2006-08-20 23:56:16 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* do the deed */
|
|
|
|
deleteObjectsInList(targetObjects, &depRel, flags);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/* And clean up */
|
|
|
|
free_object_addresses(targetObjects);
|
2006-08-20 23:56:16 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(depRel, RowExclusiveLock);
|
2006-08-20 23:56:16 +02:00
|
|
|
}
|
|
|
|
|
2002-09-22 02:37:09 +02:00
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* findDependentObjects - find all objects that depend on 'object'
|
2002-07-16 07:53:34 +02:00
|
|
|
*
|
2008-06-09 00:41:04 +02:00
|
|
|
* For every object that depends on the starting object, acquire a deletion
|
|
|
|
* lock on the object, add it to targetObjects (if not already there),
|
2014-05-06 18:12:18 +02:00
|
|
|
* and recursively find objects that depend on it. An object's dependencies
|
2008-06-09 00:41:04 +02:00
|
|
|
* will be placed into targetObjects before the object itself; this means
|
|
|
|
* that the finished list's order represents a safe deletion order.
|
2002-09-22 02:37:09 +02:00
|
|
|
*
|
2008-06-09 00:41:04 +02:00
|
|
|
* The caller must already have a deletion lock on 'object' itself,
|
|
|
|
* but must not have added it to targetObjects. (Note: there are corner
|
|
|
|
* cases where we won't add the object either, and will also release the
|
|
|
|
* caller-taken lock. This is a bit ugly, but the API is set up this way
|
|
|
|
* to allow easy rechecking of an object's liveness after we lock it. See
|
|
|
|
* notes within the function.)
|
2002-07-12 20:43:19 +02:00
|
|
|
*
|
2008-06-09 00:41:04 +02:00
|
|
|
* When dropping a whole object (subId = 0), we find dependencies for
|
|
|
|
* its sub-objects too.
|
2002-09-22 02:37:09 +02:00
|
|
|
*
|
2008-06-09 00:41:04 +02:00
|
|
|
* object: the object to add to targetObjects and find dependencies on
|
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
|
|
|
* objflags: flags to be ORed into the object's targetObjects entry
|
|
|
|
* flags: PERFORM_DELETION_xxx flags for the deletion operation as a whole
|
2008-06-09 00:41:04 +02:00
|
|
|
* stack: list of objects being visited in current recursion; topmost item
|
|
|
|
* is the object that we recursed from (NULL for external callers)
|
|
|
|
* targetObjects: list of objects that are scheduled to be deleted
|
|
|
|
* pendingObjects: list of other objects slated for destruction, but
|
|
|
|
* not necessarily in targetObjects yet (can be NULL if none)
|
2012-12-06 05:42:51 +01:00
|
|
|
* *depRel: already opened pg_depend relation
|
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
|
|
|
*
|
|
|
|
* Note: objflags describes the reason for visiting this particular object
|
|
|
|
* at this time, and is not passed down when recursing. The flags argument
|
|
|
|
* is passed down, since it describes what we're doing overall.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
static void
|
|
|
|
findDependentObjects(const ObjectAddress *object,
|
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
|
|
|
int objflags,
|
2008-06-09 00:41:04 +02:00
|
|
|
int flags,
|
|
|
|
ObjectAddressStack *stack,
|
|
|
|
ObjectAddresses *targetObjects,
|
|
|
|
const ObjectAddresses *pendingObjects,
|
2012-12-06 05:42:51 +01:00
|
|
|
Relation *depRel)
|
2002-07-12 20:43:19 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ScanKeyData key[3];
|
|
|
|
int nkeys;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
ObjectAddress otherObject;
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
ObjectAddress owningObject;
|
|
|
|
ObjectAddress partitionObject;
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
ObjectAddressAndFlags *dependentObjects;
|
|
|
|
int numDependentObjects;
|
|
|
|
int maxDependentObjects;
|
2008-06-09 00:41:04 +02:00
|
|
|
ObjectAddressStack mystack;
|
|
|
|
ObjectAddressExtra extra;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* If the target object is already being visited in an outer recursion
|
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
|
|
|
* level, just report the current objflags back to that level and exit.
|
|
|
|
* This is needed to avoid infinite recursion in the face of circular
|
2008-06-09 00:41:04 +02:00
|
|
|
* dependencies.
|
|
|
|
*
|
|
|
|
* The stack check alone would result in dependency loops being broken at
|
|
|
|
* an arbitrary point, ie, the first member object of the loop to be
|
|
|
|
* visited is the last one to be deleted. This is obviously unworkable.
|
|
|
|
* However, the check for internal dependency below guarantees that we
|
|
|
|
* will not break a loop at an internal dependency: if we enter the loop
|
|
|
|
* at an "owned" object we will switch and start at the "owning" object
|
|
|
|
* instead. We could probably hack something up to avoid breaking at an
|
2014-05-06 18:12:18 +02:00
|
|
|
* auto dependency, too, if we had to. However there are no known cases
|
2008-06-09 00:41:04 +02:00
|
|
|
* where that would be necessary.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
if (stack_address_present_add_flags(object, objflags, stack))
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
return;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
/*
|
2008-06-09 00:41:04 +02:00
|
|
|
* It's also possible that the target object has already been completely
|
|
|
|
* processed and put into targetObjects. If so, again we just add the
|
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
|
|
|
* specified objflags to its entry and return.
|
2002-07-12 20:43:19 +02:00
|
|
|
*
|
2008-06-09 00:41:04 +02:00
|
|
|
* (Note: in these early-exit cases we could release the caller-taken
|
2009-06-11 16:49:15 +02:00
|
|
|
* lock, since the object is presumably now locked multiple times; but it
|
|
|
|
* seems not worth the cycles.)
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
if (object_address_present_add_flags(object, objflags, targetObjects))
|
2008-06-09 00:41:04 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The target object might be internally dependent on some other object
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* (its "owner"), and/or be a member of an extension (also considered its
|
2014-05-06 18:12:18 +02:00
|
|
|
* owner). If so, and if we aren't recursing from the owning object, we
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* have to transform this deletion request into a deletion request of the
|
|
|
|
* owning object. (We'll eventually recurse back to this object, but the
|
2012-06-10 21:20:04 +02:00
|
|
|
* owning object has to be visited first so it will be deleted after.) The
|
|
|
|
* way to find out about this is to scan the pg_depend entries that show
|
|
|
|
* what this object depends on.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_depend_classid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->classId));
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
Anum_pg_depend_objid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->objectId));
|
2002-07-12 20:43:19 +02:00
|
|
|
if (object->objectSubId != 0)
|
|
|
|
{
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[2],
|
|
|
|
Anum_pg_depend_objsubid,
|
|
|
|
BTEqualStrategyNumber, F_INT4EQ,
|
|
|
|
Int32GetDatum(object->objectSubId));
|
2002-07-12 20:43:19 +02:00
|
|
|
nkeys = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nkeys = 2;
|
|
|
|
|
2012-12-06 05:42:51 +01:00
|
|
|
scan = systable_beginscan(*depRel, DependDependerIndexId, 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-12 20:43:19 +02:00
|
|
|
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
/* initialize variables that loop may fill */
|
|
|
|
memset(&owningObject, 0, sizeof(owningObject));
|
|
|
|
memset(&partitionObject, 0, sizeof(partitionObject));
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
otherObject.classId = foundDep->refclassid;
|
|
|
|
otherObject.objectId = foundDep->refobjid;
|
|
|
|
otherObject.objectSubId = foundDep->refobjsubid;
|
|
|
|
|
|
|
|
switch (foundDep->deptype)
|
|
|
|
{
|
|
|
|
case DEPENDENCY_NORMAL:
|
|
|
|
case DEPENDENCY_AUTO:
|
2016-04-05 23:38:54 +02:00
|
|
|
case DEPENDENCY_AUTO_EXTENSION:
|
2002-07-12 20:43:19 +02:00
|
|
|
/* no problem */
|
|
|
|
break;
|
Fix test about ignoring extension dependencies during extension scripts.
Commit 08dd23cec introduced an exception to the rule that extension member
objects can only be dropped as part of dropping the whole extension,
intending to allow such drops while running the extension's own creation or
update scripts. However, the exception was only applied at the outermost
recursion level, because it was modeled on a pre-existing check to ignore
dependencies on objects listed in pendingObjects. Bug #14434 from Philippe
Beaudoin shows that this is inadequate: in some cases we can reach an
extension member object by recursion from another one. (The bug concerns
the serial-sequence case; I'm not sure if there are other cases, but there
might well be.)
To fix, revert 08dd23cec's changes to findDependentObjects() and instead
apply the creating_extension exception regardless of stack level.
Having seen this example, I'm a bit suspicious that the pendingObjects
logic is also wrong and such cases should likewise be allowed at any
recursion level. However, changing that would interact in subtle ways
with the recursion logic (at least it would need to be moved to after the
recursing-from check). Given that the code's been like that a long time,
I'll refrain from touching it without a clear example showing it's wrong.
Back-patch to all active branches. In HEAD and 9.6, where suitable
test infrastructure exists, add a regression test case based on the
bug report.
Report: <20161125151448.6529.33039@wrigleys.postgresql.org>
Discussion: <13224.1480177514@sss.pgh.pa.us>
2016-11-26 19:31:35 +01:00
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
case DEPENDENCY_EXTENSION:
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
/*
|
|
|
|
* If told to, ignore EXTENSION dependencies altogether. This
|
|
|
|
* flag is normally used to prevent dropping extensions during
|
|
|
|
* temporary-object cleanup, even if a temp object was created
|
|
|
|
* during an extension script.
|
|
|
|
*/
|
|
|
|
if (flags & PERFORM_DELETION_SKIP_EXTENSIONS)
|
|
|
|
break;
|
|
|
|
|
Fix test about ignoring extension dependencies during extension scripts.
Commit 08dd23cec introduced an exception to the rule that extension member
objects can only be dropped as part of dropping the whole extension,
intending to allow such drops while running the extension's own creation or
update scripts. However, the exception was only applied at the outermost
recursion level, because it was modeled on a pre-existing check to ignore
dependencies on objects listed in pendingObjects. Bug #14434 from Philippe
Beaudoin shows that this is inadequate: in some cases we can reach an
extension member object by recursion from another one. (The bug concerns
the serial-sequence case; I'm not sure if there are other cases, but there
might well be.)
To fix, revert 08dd23cec's changes to findDependentObjects() and instead
apply the creating_extension exception regardless of stack level.
Having seen this example, I'm a bit suspicious that the pendingObjects
logic is also wrong and such cases should likewise be allowed at any
recursion level. However, changing that would interact in subtle ways
with the recursion logic (at least it would need to be moved to after the
recursing-from check). Given that the code's been like that a long time,
I'll refrain from touching it without a clear example showing it's wrong.
Back-patch to all active branches. In HEAD and 9.6, where suitable
test infrastructure exists, add a regression test case based on the
bug report.
Report: <20161125151448.6529.33039@wrigleys.postgresql.org>
Discussion: <13224.1480177514@sss.pgh.pa.us>
2016-11-26 19:31:35 +01:00
|
|
|
/*
|
|
|
|
* If the other object is the extension currently being
|
|
|
|
* created/altered, ignore this dependency and continue with
|
|
|
|
* the deletion. This allows dropping of an extension's
|
|
|
|
* objects within the extension's scripts, as well as corner
|
|
|
|
* cases such as dropping a transient object created within
|
|
|
|
* such a script.
|
|
|
|
*/
|
|
|
|
if (creating_extension &&
|
|
|
|
otherObject.classId == ExtensionRelationId &&
|
|
|
|
otherObject.objectId == CurrentExtensionObject)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Otherwise, treat this like an internal dependency */
|
|
|
|
/* FALL THRU */
|
|
|
|
|
|
|
|
case DEPENDENCY_INTERNAL:
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* This object is part of the internal implementation of
|
2011-02-08 22:08:41 +01:00
|
|
|
* another object, or is part of the extension that is the
|
|
|
|
* other object. We have three cases:
|
2002-07-16 07:53:34 +02:00
|
|
|
*
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
* 1. At the outermost recursion level, we must disallow the
|
|
|
|
* DROP. However, if the owning object is listed in
|
|
|
|
* pendingObjects, just release the caller's lock and return;
|
|
|
|
* we'll eventually complete the DROP when we reach that entry
|
|
|
|
* in the pending list.
|
|
|
|
*
|
|
|
|
* Note: the above statement is true only if this pg_depend
|
|
|
|
* entry still exists by then; in principle, therefore, we
|
|
|
|
* could miss deleting an item the user told us to delete.
|
|
|
|
* However, no inconsistency can result: since we're at outer
|
|
|
|
* level, there is no object depending on this one.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
if (stack == NULL)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2009-09-22 17:46:35 +02:00
|
|
|
if (pendingObjects &&
|
|
|
|
object_address_present(&otherObject, pendingObjects))
|
2008-06-09 00:41:04 +02:00
|
|
|
{
|
|
|
|
systable_endscan(scan);
|
|
|
|
/* need to release caller's lock; see notes below */
|
|
|
|
ReleaseDeletionLock(object);
|
|
|
|
return;
|
|
|
|
}
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We postpone actually issuing the error message until
|
|
|
|
* after this loop, so that we can make the behavior
|
|
|
|
* independent of the ordering of pg_depend entries, at
|
|
|
|
* least if there's not more than one INTERNAL and one
|
|
|
|
* EXTENSION dependency. (If there's more, we'll complain
|
|
|
|
* about a random one of them.) Prefer to complain about
|
|
|
|
* EXTENSION, since that's generally a more important
|
|
|
|
* dependency.
|
|
|
|
*/
|
|
|
|
if (!OidIsValid(owningObject.classId) ||
|
|
|
|
foundDep->deptype == DEPENDENCY_EXTENSION)
|
|
|
|
owningObject = otherObject;
|
|
|
|
break;
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* 2. When recursing from the other end of this dependency,
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* it's okay to continue with the deletion. This holds when
|
2005-10-15 04:49:52 +02:00
|
|
|
* recursing from a whole object that includes the nominal
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* other end as a component, too. Since there can be more
|
2012-06-10 21:20:04 +02:00
|
|
|
* than one "owning" object, we have to allow matches that are
|
|
|
|
* more than one level down in the stack.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
if (stack_address_present_add_flags(&otherObject, 0, stack))
|
2002-07-16 07:53:34 +02:00
|
|
|
break;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* 3. Not all the owning objects have been visited, so
|
|
|
|
* transform this deletion request into a delete of this
|
|
|
|
* owning object.
|
2008-06-09 00:41:04 +02:00
|
|
|
*
|
|
|
|
* First, release caller's lock on this object and get
|
2014-05-06 18:12:18 +02:00
|
|
|
* deletion lock on the owning object. (We must release
|
2008-06-09 00:41:04 +02:00
|
|
|
* caller's lock to avoid deadlock against a concurrent
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* deletion of the owning object.)
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
ReleaseDeletionLock(object);
|
2012-04-06 11:21:40 +02:00
|
|
|
AcquireDeletionLock(&otherObject, 0);
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
/*
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* The owning object might have been deleted while we waited
|
|
|
|
* to lock it; if so, neither it nor the current object are
|
2008-06-09 00:41:04 +02:00
|
|
|
* interesting anymore. We test this by checking the
|
|
|
|
* pg_depend entry (see notes below).
|
|
|
|
*/
|
|
|
|
if (!systable_recheck_tuple(scan, tup))
|
|
|
|
{
|
|
|
|
systable_endscan(scan);
|
|
|
|
ReleaseDeletionLock(&otherObject);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
/*
|
|
|
|
* One way or the other, we're done with the scan; might as
|
|
|
|
* well close it down before recursing, to reduce peak
|
|
|
|
* resource consumption.
|
|
|
|
*/
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
* Okay, recurse to the owning object instead of proceeding.
|
|
|
|
*
|
|
|
|
* We do not need to stack the current object; we want the
|
|
|
|
* traversal order to be as if the original reference had
|
|
|
|
* linked to the owning object instead of this one.
|
|
|
|
*
|
|
|
|
* The dependency type is a "reverse" dependency: we need to
|
|
|
|
* delete the owning object if this one is to be deleted, but
|
|
|
|
* this linkage is never a reason for an automatic deletion.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
findDependentObjects(&otherObject,
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
DEPFLAG_REVERSE,
|
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
|
|
|
flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
stack,
|
|
|
|
targetObjects,
|
|
|
|
pendingObjects,
|
|
|
|
depRel);
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The current target object should have been added to
|
|
|
|
* targetObjects while processing the owning object; but it
|
|
|
|
* probably got only the flag bits associated with the
|
|
|
|
* dependency we're looking at. We need to add the objflags
|
|
|
|
* that were passed to this recursion level, too, else we may
|
|
|
|
* get a bogus failure in reportDependentObjects (if, for
|
|
|
|
* example, we were called due to a partition dependency).
|
|
|
|
*
|
|
|
|
* If somehow the current object didn't get scheduled for
|
|
|
|
* deletion, bleat. (That would imply that somebody deleted
|
|
|
|
* this dependency record before the recursion got to it.)
|
|
|
|
* Another idea would be to reacquire lock on the current
|
|
|
|
* object and resume trying to delete it, but it seems not
|
|
|
|
* worth dealing with the race conditions inherent in that.
|
|
|
|
*/
|
|
|
|
if (!object_address_present_add_flags(object, objflags,
|
|
|
|
targetObjects))
|
|
|
|
elog(ERROR, "deletion of owning object %s failed to delete %s",
|
|
|
|
getObjectDescription(&otherObject),
|
|
|
|
getObjectDescription(object));
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/* And we're done here. */
|
|
|
|
return;
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
case DEPENDENCY_PARTITION_PRI:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remember that this object has a partition-type dependency.
|
|
|
|
* After the dependency scan, we'll complain if we didn't find
|
|
|
|
* a reason to delete one of its partition dependencies.
|
|
|
|
*/
|
|
|
|
objflags |= DEPFLAG_IS_PART;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Also remember the primary partition owner, for error
|
|
|
|
* messages. If there are multiple primary owners (which
|
|
|
|
* there should not be), we'll report a random one of them.
|
|
|
|
*/
|
|
|
|
partitionObject = otherObject;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DEPENDENCY_PARTITION_SEC:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only use secondary partition owners in error messages if we
|
|
|
|
* find no primary owner (which probably shouldn't happen).
|
|
|
|
*/
|
|
|
|
if (!(objflags & DEPFLAG_IS_PART))
|
|
|
|
partitionObject = otherObject;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remember that this object has a partition-type dependency.
|
|
|
|
* After the dependency scan, we'll complain if we didn't find
|
|
|
|
* a reason to delete one of its partition dependencies.
|
|
|
|
*/
|
|
|
|
objflags |= DEPFLAG_IS_PART;
|
|
|
|
break;
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
case DEPENDENCY_PIN:
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Should not happen; PIN dependencies should have zeroes in
|
|
|
|
* the depender fields...
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "incorrect use of PIN dependency with %s",
|
2008-06-09 00:41:04 +02:00
|
|
|
getObjectDescription(object));
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "unrecognized dependency type '%c' for %s",
|
2008-06-09 00:41:04 +02:00
|
|
|
foundDep->deptype, getObjectDescription(object));
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
/*
|
|
|
|
* If we found an INTERNAL or EXTENSION dependency when we're at outer
|
|
|
|
* level, complain about it now. If we also found a PARTITION dependency,
|
|
|
|
* we prefer to report the PARTITION dependency. This is arbitrary but
|
|
|
|
* seems to be more useful in practice.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(owningObject.classId))
|
|
|
|
{
|
|
|
|
char *otherObjDesc;
|
|
|
|
|
|
|
|
if (OidIsValid(partitionObject.classId))
|
|
|
|
otherObjDesc = getObjectDescription(&partitionObject);
|
|
|
|
else
|
|
|
|
otherObjDesc = getObjectDescription(&owningObject);
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("cannot drop %s because %s requires it",
|
|
|
|
getObjectDescription(object), otherObjDesc),
|
|
|
|
errhint("You can drop %s instead.", otherObjDesc)));
|
|
|
|
}
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
* Next, identify all objects that directly depend on the current object.
|
|
|
|
* To ensure predictable deletion order, we collect them up in
|
|
|
|
* dependentObjects and sort the list before actually recursing. (The
|
|
|
|
* deletion order would be valid in any case, but doing this ensures
|
|
|
|
* consistent output from DROP CASCADE commands, which is helpful for
|
|
|
|
* regression testing.)
|
2003-02-07 02:33:06 +01:00
|
|
|
*/
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
maxDependentObjects = 128; /* arbitrary initial allocation */
|
|
|
|
dependentObjects = (ObjectAddressAndFlags *)
|
|
|
|
palloc(maxDependentObjects * sizeof(ObjectAddressAndFlags));
|
|
|
|
numDependentObjects = 0;
|
2003-02-07 02:33:06 +01:00
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_depend_refclassid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->classId));
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
Anum_pg_depend_refobjid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->objectId));
|
2002-07-12 20:43:19 +02:00
|
|
|
if (object->objectSubId != 0)
|
|
|
|
{
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[2],
|
|
|
|
Anum_pg_depend_refobjsubid,
|
|
|
|
BTEqualStrategyNumber, F_INT4EQ,
|
|
|
|
Int32GetDatum(object->objectSubId));
|
2002-07-12 20:43:19 +02:00
|
|
|
nkeys = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nkeys = 2;
|
|
|
|
|
2012-12-06 05:42:51 +01:00
|
|
|
scan = systable_beginscan(*depRel, DependReferenceIndexId, 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-12 20:43:19 +02:00
|
|
|
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
|
2009-06-11 16:49:15 +02:00
|
|
|
int subflags;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
otherObject.classId = foundDep->classid;
|
|
|
|
otherObject.objectId = foundDep->objid;
|
|
|
|
otherObject.objectSubId = foundDep->objsubid;
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* Must lock the dependent object before recursing to it.
|
|
|
|
*/
|
2012-04-06 11:21:40 +02:00
|
|
|
AcquireDeletionLock(&otherObject, 0);
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* The dependent object might have been deleted while we waited to
|
|
|
|
* lock it; if so, we don't need to do anything more with it. We can
|
|
|
|
* test this cheaply and independently of the object's type by seeing
|
|
|
|
* if the pg_depend tuple we are looking at is still live. (If the
|
|
|
|
* object got deleted, the tuple would have been deleted too.)
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
if (!systable_recheck_tuple(scan, tup))
|
|
|
|
{
|
|
|
|
/* release the now-useless lock */
|
|
|
|
ReleaseDeletionLock(&otherObject);
|
|
|
|
/* and continue scanning for dependencies */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
/*
|
|
|
|
* We do need to delete it, so identify objflags to be passed down,
|
|
|
|
* which depend on the dependency type.
|
|
|
|
*/
|
2002-07-12 20:43:19 +02:00
|
|
|
switch (foundDep->deptype)
|
|
|
|
{
|
|
|
|
case DEPENDENCY_NORMAL:
|
2008-06-09 00:41:04 +02:00
|
|
|
subflags = DEPFLAG_NORMAL;
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
|
|
|
case DEPENDENCY_AUTO:
|
2016-04-05 23:38:54 +02:00
|
|
|
case DEPENDENCY_AUTO_EXTENSION:
|
2008-06-09 00:41:04 +02:00
|
|
|
subflags = DEPFLAG_AUTO;
|
|
|
|
break;
|
2002-07-12 20:43:19 +02:00
|
|
|
case DEPENDENCY_INTERNAL:
|
2008-06-09 00:41:04 +02:00
|
|
|
subflags = DEPFLAG_INTERNAL;
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
case DEPENDENCY_PARTITION_PRI:
|
|
|
|
case DEPENDENCY_PARTITION_SEC:
|
|
|
|
subflags = DEPFLAG_PARTITION;
|
|
|
|
break;
|
2011-02-08 22:08:41 +01:00
|
|
|
case DEPENDENCY_EXTENSION:
|
|
|
|
subflags = DEPFLAG_EXTENSION;
|
|
|
|
break;
|
2002-07-12 20:43:19 +02:00
|
|
|
case DEPENDENCY_PIN:
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
2003-07-21 03:59:11 +02:00
|
|
|
* For a PIN dependency we just ereport immediately; there
|
2002-07-12 20:43:19 +02:00
|
|
|
* won't be any others to report.
|
|
|
|
*/
|
2003-07-21 03:59:11 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("cannot drop %s because it is required by the database system",
|
2008-06-09 00:41:04 +02:00
|
|
|
getObjectDescription(object))));
|
|
|
|
subflags = 0; /* keep compiler quiet */
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "unrecognized dependency type '%c' for %s",
|
2008-06-09 00:41:04 +02:00
|
|
|
foundDep->deptype, getObjectDescription(object));
|
|
|
|
subflags = 0; /* keep compiler quiet */
|
2002-07-12 20:43:19 +02:00
|
|
|
break;
|
|
|
|
}
|
2008-06-09 00:41:04 +02:00
|
|
|
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
/* And add it to the pending-objects list */
|
|
|
|
if (numDependentObjects >= maxDependentObjects)
|
|
|
|
{
|
|
|
|
/* enlarge array if needed */
|
|
|
|
maxDependentObjects *= 2;
|
|
|
|
dependentObjects = (ObjectAddressAndFlags *)
|
|
|
|
repalloc(dependentObjects,
|
|
|
|
maxDependentObjects * sizeof(ObjectAddressAndFlags));
|
|
|
|
}
|
|
|
|
|
|
|
|
dependentObjects[numDependentObjects].obj = otherObject;
|
|
|
|
dependentObjects[numDependentObjects].subflags = subflags;
|
|
|
|
numDependentObjects++;
|
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we can sort the dependent objects into a stable visitation order.
|
|
|
|
* It's safe to use object_address_comparator here since the obj field is
|
|
|
|
* first within ObjectAddressAndFlags.
|
|
|
|
*/
|
|
|
|
if (numDependentObjects > 1)
|
|
|
|
qsort((void *) dependentObjects, numDependentObjects,
|
|
|
|
sizeof(ObjectAddressAndFlags),
|
|
|
|
object_address_comparator);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now recurse to the dependent objects. We must visit them first since
|
|
|
|
* they have to be deleted before the current object.
|
|
|
|
*/
|
|
|
|
mystack.object = object; /* set up a new stack level */
|
|
|
|
mystack.flags = objflags;
|
|
|
|
mystack.next = stack;
|
|
|
|
|
|
|
|
for (int i = 0; i < numDependentObjects; i++)
|
|
|
|
{
|
|
|
|
ObjectAddressAndFlags *depObj = dependentObjects + i;
|
|
|
|
|
|
|
|
findDependentObjects(&depObj->obj,
|
|
|
|
depObj->subflags,
|
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
|
|
|
flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
&mystack,
|
|
|
|
targetObjects,
|
|
|
|
pendingObjects,
|
|
|
|
depRel);
|
2002-07-12 20:43:19 +02:00
|
|
|
}
|
|
|
|
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
pfree(dependentObjects);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Finally, we can add the target object to targetObjects. Be careful to
|
2009-06-11 16:49:15 +02:00
|
|
|
* include any flags that were passed back down to us from inner recursion
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
* levels. Record the "dependee" as being either the most important
|
|
|
|
* partition owner if there is one, else the object we recursed from, if
|
|
|
|
* any. (The logic in reportDependentObjects() is such that it can only
|
|
|
|
* need one of those objects.)
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
extra.flags = mystack.flags;
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
if (extra.flags & DEPFLAG_IS_PART)
|
|
|
|
extra.dependee = partitionObject;
|
|
|
|
else if (stack)
|
2008-06-09 00:41:04 +02:00
|
|
|
extra.dependee = *stack->object;
|
|
|
|
else
|
|
|
|
memset(&extra.dependee, 0, sizeof(extra.dependee));
|
|
|
|
add_exact_object_address_extra(object, &extra, targetObjects);
|
2002-07-12 20:43:19 +02:00
|
|
|
}
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* reportDependentObjects - report about dependencies, and fail if RESTRICT
|
|
|
|
*
|
|
|
|
* Tell the user about dependent objects that we are going to delete
|
|
|
|
* (or would need to delete, but are prevented by RESTRICT mode);
|
|
|
|
* then error out if there are any and it's not CASCADE mode.
|
|
|
|
*
|
|
|
|
* targetObjects: list of objects that are scheduled to be deleted
|
|
|
|
* behavior: RESTRICT or CASCADE
|
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
|
|
|
* flags: other flags for the deletion operation
|
2008-06-09 00:41:04 +02:00
|
|
|
* origObject: base object of deletion, or NULL if not available
|
|
|
|
* (the latter case occurs in DROP OWNED)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
reportDependentObjects(const ObjectAddresses *targetObjects,
|
|
|
|
DropBehavior behavior,
|
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
|
|
|
int flags,
|
2008-06-09 00:41:04 +02:00
|
|
|
const ObjectAddress *origObject)
|
|
|
|
{
|
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
|
|
|
int msglevel = (flags & PERFORM_DELETION_QUIETLY) ? DEBUG2 : NOTICE;
|
2008-06-09 00:41:04 +02:00
|
|
|
bool ok = true;
|
2008-06-11 23:53:49 +02:00
|
|
|
StringInfoData clientdetail;
|
|
|
|
StringInfoData logdetail;
|
|
|
|
int numReportedClient = 0;
|
|
|
|
int numNotReportedClient = 0;
|
2008-06-09 00:41:04 +02:00
|
|
|
int i;
|
|
|
|
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
/*
|
|
|
|
* If we need to delete any partition-dependent objects, make sure that
|
|
|
|
* we're deleting at least one of their partition dependencies, too. That
|
|
|
|
* can be detected by checking that we reached them by a PARTITION
|
|
|
|
* dependency at some point.
|
|
|
|
*
|
|
|
|
* We just report the first such object, as in most cases the only way to
|
|
|
|
* trigger this complaint is to explicitly try to delete one partition of
|
|
|
|
* a partitioned object.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < targetObjects->numrefs; i++)
|
|
|
|
{
|
|
|
|
const ObjectAddressExtra *extra = &targetObjects->extras[i];
|
|
|
|
|
|
|
|
if ((extra->flags & DEPFLAG_IS_PART) &&
|
|
|
|
!(extra->flags & DEPFLAG_PARTITION))
|
|
|
|
{
|
|
|
|
const ObjectAddress *object = &targetObjects->refs[i];
|
|
|
|
char *otherObjDesc = getObjectDescription(&extra->dependee);
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("cannot drop %s because %s requires it",
|
|
|
|
getObjectDescription(object), otherObjDesc),
|
|
|
|
errhint("You can drop %s instead.", otherObjDesc)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-11 23:53:49 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If no error is to be thrown, and the msglevel is too low to be shown to
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
* either client or server log, there's no need to do any of the rest of
|
|
|
|
* the work.
|
2008-06-11 23:53:49 +02:00
|
|
|
*
|
|
|
|
* Note: this code doesn't know all there is to be known about elog
|
|
|
|
* levels, but it works for NOTICE and DEBUG2, which are the only values
|
|
|
|
* msglevel can currently have. We also assume we are running in a normal
|
|
|
|
* operating environment.
|
|
|
|
*/
|
|
|
|
if (behavior == DROP_CASCADE &&
|
|
|
|
msglevel < client_min_messages &&
|
|
|
|
(msglevel < log_min_messages || log_min_messages == LOG))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We limit the number of dependencies reported to the client to
|
|
|
|
* MAX_REPORTED_DEPS, since client software may not deal well with
|
2014-05-06 18:12:18 +02:00
|
|
|
* enormous error strings. The server log always gets a full report.
|
2008-06-11 23:53:49 +02:00
|
|
|
*/
|
|
|
|
#define MAX_REPORTED_DEPS 100
|
|
|
|
|
|
|
|
initStringInfo(&clientdetail);
|
|
|
|
initStringInfo(&logdetail);
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* We process the list back to front (ie, in dependency order not deletion
|
|
|
|
* order), since this makes for a more understandable display.
|
|
|
|
*/
|
|
|
|
for (i = targetObjects->numrefs - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
const ObjectAddress *obj = &targetObjects->refs[i];
|
|
|
|
const ObjectAddressExtra *extra = &targetObjects->extras[i];
|
2008-06-11 23:53:49 +02:00
|
|
|
char *objDesc;
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
/* Ignore the original deletion target(s) */
|
|
|
|
if (extra->flags & DEPFLAG_ORIGINAL)
|
|
|
|
continue;
|
|
|
|
|
2019-01-18 17:05:11 +01:00
|
|
|
/* Also ignore sub-objects; we'll report the whole object elsewhere */
|
|
|
|
if (extra->flags & DEPFLAG_SUBOBJECT)
|
|
|
|
continue;
|
|
|
|
|
2008-06-11 23:53:49 +02:00
|
|
|
objDesc = getObjectDescription(obj);
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If, at any stage of the recursive search, we reached the object via
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
* an AUTO, INTERNAL, PARTITION, or EXTENSION dependency, then it's
|
|
|
|
* okay to delete it even in RESTRICT mode.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
2011-02-08 22:08:41 +01:00
|
|
|
if (extra->flags & (DEPFLAG_AUTO |
|
|
|
|
DEPFLAG_INTERNAL |
|
Redesign the partition dependency mechanism.
The original setup for dependencies of partitioned objects had
serious problems:
1. It did not verify that a drop cascading to a partition-child object
also cascaded to at least one of the object's partition parents. Now,
normally a child object would share all its dependencies with one or
another parent (e.g. a child index's opclass dependencies would be shared
with the parent index), so that this oversight is usually harmless.
But if some dependency failed to fit this pattern, the child could be
dropped while all its parents remain, creating a logically broken
situation. (It's easy to construct artificial cases that break it,
such as attaching an unrelated extension dependency to the child object
and then dropping the extension. I'm not sure if any less-artificial
cases exist.)
2. Management of partition dependencies during ATTACH/DETACH PARTITION
was complicated and buggy; for example, after detaching a partition
table it was possible to create cases where a formerly-child index
should be dropped and was not, because the correct set of dependencies
had not been reconstructed.
Less seriously, because multiple partition relationships were
represented identically in pg_depend, there was an order-of-traversal
dependency on which partition parent was cited in error messages.
We also had some pre-existing order-of-traversal hazards for error
messages related to internal and extension dependencies. This is
cosmetic to users but causes testing problems.
To fix #1, add a check at the end of the partition tree traversal
to ensure that at least one partition parent got deleted. To fix #2,
establish a new policy that partition dependencies are in addition to,
not instead of, a child object's usual dependencies; in this way
ATTACH/DETACH PARTITION need not cope with adding or removing the
usual dependencies.
To fix the cosmetic problem, distinguish between primary and secondary
partition dependency entries in pg_depend, by giving them different
deptypes. (They behave identically except for having different
priorities for being cited in error messages.) This means that the
former 'I' dependency type is replaced with new 'P' and 'S' types.
This also fixes a longstanding bug that after handling an internal
dependency by recursing to the owning object, findDependentObjects
did not verify that the current target was now scheduled for deletion,
and did not apply the current recursion level's objflags to it.
Perhaps that should be back-patched; but in the back branches it
would only matter if some concurrent transaction had removed the
internal-linkage pg_depend entry before the recursive call found it,
or the recursive call somehow failed to find it, both of which seem
unlikely.
Catversion bump because the contents of pg_depend change for
partitioning relationships.
Patch HEAD only. It's annoying that we're not fixing #2 in v11,
but there seems no practical way to do so given that the problem
is exactly a poor choice of what entries to put in pg_depend.
We can't really fix that while staying compatible with what's
in pg_depend in existing v11 installations.
Discussion: https://postgr.es/m/CAH2-Wzkypv1R+teZrr71U23J578NnTBt2X8+Y=Odr4pOdW1rXg@mail.gmail.com
2019-02-11 20:41:13 +01:00
|
|
|
DEPFLAG_PARTITION |
|
2011-02-08 22:08:41 +01:00
|
|
|
DEPFLAG_EXTENSION))
|
2008-06-11 23:53:49 +02:00
|
|
|
{
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* auto-cascades are reported at DEBUG2, not msglevel. We don't
|
2009-06-11 16:49:15 +02:00
|
|
|
* try to combine them with the regular message because the
|
|
|
|
* results are too confusing when client_min_messages and
|
2008-06-11 23:53:49 +02:00
|
|
|
* log_min_messages are different.
|
|
|
|
*/
|
2008-06-09 00:41:04 +02:00
|
|
|
ereport(DEBUG2,
|
|
|
|
(errmsg("drop auto-cascades to %s",
|
2008-06-11 23:53:49 +02:00
|
|
|
objDesc)));
|
|
|
|
}
|
2008-06-09 00:41:04 +02:00
|
|
|
else if (behavior == DROP_RESTRICT)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
char *otherDesc = getObjectDescription(&extra->dependee);
|
2008-06-11 23:53:49 +02:00
|
|
|
|
|
|
|
if (numReportedClient < MAX_REPORTED_DEPS)
|
|
|
|
{
|
|
|
|
/* separate entries with a newline */
|
|
|
|
if (clientdetail.len != 0)
|
|
|
|
appendStringInfoChar(&clientdetail, '\n');
|
|
|
|
appendStringInfo(&clientdetail, _("%s depends on %s"),
|
|
|
|
objDesc, otherDesc);
|
|
|
|
numReportedClient++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
numNotReportedClient++;
|
|
|
|
/* separate entries with a newline */
|
|
|
|
if (logdetail.len != 0)
|
|
|
|
appendStringInfoChar(&logdetail, '\n');
|
|
|
|
appendStringInfo(&logdetail, _("%s depends on %s"),
|
|
|
|
objDesc, otherDesc);
|
|
|
|
pfree(otherDesc);
|
2008-06-09 00:41:04 +02:00
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
else
|
2008-06-11 23:53:49 +02:00
|
|
|
{
|
|
|
|
if (numReportedClient < MAX_REPORTED_DEPS)
|
|
|
|
{
|
|
|
|
/* separate entries with a newline */
|
|
|
|
if (clientdetail.len != 0)
|
|
|
|
appendStringInfoChar(&clientdetail, '\n');
|
|
|
|
appendStringInfo(&clientdetail, _("drop cascades to %s"),
|
|
|
|
objDesc);
|
|
|
|
numReportedClient++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
numNotReportedClient++;
|
|
|
|
/* separate entries with a newline */
|
|
|
|
if (logdetail.len != 0)
|
|
|
|
appendStringInfoChar(&logdetail, '\n');
|
|
|
|
appendStringInfo(&logdetail, _("drop cascades to %s"),
|
|
|
|
objDesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(objDesc);
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
|
2008-06-11 23:53:49 +02:00
|
|
|
if (numNotReportedClient > 0)
|
2009-03-26 23:26:08 +01:00
|
|
|
appendStringInfo(&clientdetail, ngettext("\nand %d other object "
|
|
|
|
"(see server log for list)",
|
|
|
|
"\nand %d other objects "
|
|
|
|
"(see server log for list)",
|
|
|
|
numNotReportedClient),
|
2008-06-11 23:53:49 +02:00
|
|
|
numNotReportedClient);
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
if (origObject)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
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 drop %s because other objects depend on it",
|
|
|
|
getObjectDescription(origObject)),
|
2008-06-11 23:53:49 +02:00
|
|
|
errdetail("%s", clientdetail.data),
|
|
|
|
errdetail_log("%s", logdetail.data),
|
2008-06-09 00:41:04 +02:00
|
|
|
errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
|
|
|
errmsg("cannot drop desired object(s) because other objects depend on them"),
|
2008-06-11 23:53:49 +02:00
|
|
|
errdetail("%s", clientdetail.data),
|
|
|
|
errdetail_log("%s", logdetail.data),
|
2008-06-09 00:41:04 +02:00
|
|
|
errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
|
|
|
|
}
|
2008-06-11 23:53:49 +02:00
|
|
|
else if (numReportedClient > 1)
|
|
|
|
{
|
|
|
|
ereport(msglevel,
|
2009-06-11 16:49:15 +02:00
|
|
|
/* translator: %d always has a value larger than 1 */
|
2009-06-04 20:33:08 +02:00
|
|
|
(errmsg_plural("drop cascades to %d other object",
|
|
|
|
"drop cascades to %d other objects",
|
|
|
|
numReportedClient + numNotReportedClient,
|
|
|
|
numReportedClient + numNotReportedClient),
|
2008-06-11 23:53:49 +02:00
|
|
|
errdetail("%s", clientdetail.data),
|
|
|
|
errdetail_log("%s", logdetail.data)));
|
|
|
|
}
|
|
|
|
else if (numReportedClient == 1)
|
|
|
|
{
|
|
|
|
/* we just use the single item as-is */
|
|
|
|
ereport(msglevel,
|
|
|
|
(errmsg_internal("%s", clientdetail.data)));
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(clientdetail.data);
|
|
|
|
pfree(logdetail.data);
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deleteOneObject: delete a single object for performDeletion.
|
|
|
|
*
|
2012-12-06 05:42:51 +01:00
|
|
|
* *depRel is the already-open pg_depend relation.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
static void
|
2012-12-06 05:42:51 +01:00
|
|
|
deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
|
2008-06-09 00:41:04 +02:00
|
|
|
{
|
|
|
|
ScanKeyData key[3];
|
|
|
|
int nkeys;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
2012-03-09 20:34:56 +01:00
|
|
|
/* DROP hook of the objects being removed */
|
2013-03-07 02:52:06 +01:00
|
|
|
InvokeObjectDropHookArg(object->classId, object->objectId,
|
|
|
|
object->objectSubId, flags);
|
2012-03-09 20:34:56 +01:00
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
* Close depRel if we are doing a drop concurrently. The object deletion
|
|
|
|
* subroutine will commit the current transaction, so we can't keep the
|
|
|
|
* relation open across doDeletion().
|
2012-10-19 10:56:29 +02:00
|
|
|
*/
|
|
|
|
if (flags & PERFORM_DELETION_CONCURRENTLY)
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(*depRel, RowExclusiveLock);
|
2012-10-19 10:56:29 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete the object itself, in an object-type-dependent way.
|
|
|
|
*
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
* We used to do this after removing the outgoing dependency links, but it
|
|
|
|
* seems just as reasonable to do it beforehand. In the concurrent case
|
|
|
|
* we *must* do it in this order, because we can't make any transactional
|
|
|
|
* updates before calling doDeletion() --- they'd get committed right
|
|
|
|
* away, which is not cool if the deletion then fails.
|
2012-10-19 10:56:29 +02:00
|
|
|
*/
|
|
|
|
doDeletion(object, flags);
|
|
|
|
|
|
|
|
/*
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
* Reopen depRel if we closed it above
|
2012-10-19 10:56:29 +02:00
|
|
|
*/
|
|
|
|
if (flags & PERFORM_DELETION_CONCURRENTLY)
|
2019-01-21 19:32:19 +01:00
|
|
|
*depRel = table_open(DependRelationId, RowExclusiveLock);
|
2012-10-19 10:56:29 +02:00
|
|
|
|
|
|
|
/*
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
* Now remove any pg_depend records that link from this object to others.
|
|
|
|
* (Any records linking to this object should be gone already.)
|
2008-06-09 00:41:04 +02:00
|
|
|
*
|
|
|
|
* When dropping a whole object (subId = 0), remove all pg_depend records
|
|
|
|
* for its sub-objects too.
|
|
|
|
*/
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_depend_classid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->classId));
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
Anum_pg_depend_objid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->objectId));
|
|
|
|
if (object->objectSubId != 0)
|
|
|
|
{
|
|
|
|
ScanKeyInit(&key[2],
|
|
|
|
Anum_pg_depend_objsubid,
|
|
|
|
BTEqualStrategyNumber, F_INT4EQ,
|
|
|
|
Int32GetDatum(object->objectSubId));
|
|
|
|
nkeys = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nkeys = 2;
|
|
|
|
|
2012-12-06 05:42:51 +01:00
|
|
|
scan = systable_beginscan(*depRel, DependDependerIndexId, 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);
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
|
|
|
{
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(*depRel, &tup->t_self);
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
2009-01-22 21:16:10 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Delete shared dependency references related to this object. Again, if
|
2009-06-11 16:49:15 +02:00
|
|
|
* subId = 0, remove records for sub-objects too.
|
2009-01-22 21:16:10 +01:00
|
|
|
*/
|
|
|
|
deleteSharedDependencyRecordsFor(object->classId, object->objectId,
|
|
|
|
object->objectSubId);
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
/*
|
2016-04-07 03:45:32 +02:00
|
|
|
* Delete any comments, security labels, or initial privileges associated
|
|
|
|
* with this object. (This is a convenient place to do these things,
|
|
|
|
* rather than having every object type know to do it.)
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
DeleteComments(object->objectId, object->classId, object->objectSubId);
|
2010-09-28 02:55:27 +02:00
|
|
|
DeleteSecurityLabel(object);
|
2016-04-07 03:45:32 +02:00
|
|
|
DeleteInitPrivs(object);
|
2008-06-09 00:41:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CommandCounterIncrement here to ensure that preceding changes are all
|
|
|
|
* visible to the next deletion step.
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* And we're done!
|
|
|
|
*/
|
|
|
|
}
|
2002-07-12 20:43:19 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* doDeletion: actually delete a single object
|
|
|
|
*/
|
|
|
|
static void
|
2012-04-06 11:21:40 +02:00
|
|
|
doDeletion(const ObjectAddress *object, int flags)
|
2002-07-12 20:43:19 +02:00
|
|
|
{
|
|
|
|
switch (getObjectClass(object))
|
|
|
|
{
|
|
|
|
case OCLASS_CLASS:
|
|
|
|
{
|
2002-09-20 01:40:56 +02:00
|
|
|
char relKind = get_rel_relkind(object->objectId);
|
2002-09-04 22:31:48 +02:00
|
|
|
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
if (relKind == RELKIND_INDEX ||
|
|
|
|
relKind == RELKIND_PARTITIONED_INDEX)
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
Delete deleteWhatDependsOn() in favor of more performDeletion() flag bits.
deleteWhatDependsOn() had grown an uncomfortably large number of
assumptions about what it's used for. There are actually only two minor
differences between what it does and what a regular performDeletion() call
can do, so let's invent additional bits in performDeletion's existing flags
argument that specify those behaviors, and get rid of deleteWhatDependsOn()
as such. (We'd probably have done it this way from the start, except that
performDeletion didn't originally have a flags argument, IIRC.)
Also, add a SKIP_EXTENSIONS flag bit that prevents ever recursing to an
extension, and use that when dropping temporary objects at session end.
This provides a more general solution to the problem addressed in a hacky
way in commit 08dd23cec: if an extension script creates temp objects and
forgets to remove them again, the whole extension went away when its
contained temp objects were deleted. The previous solution only covered
temp relations, but this solves it for all object types.
These changes require minor additions in dependency.c to pass the flags
to subroutines that previously didn't get them, but it's still a net
savings of code, and it seems cleaner than before.
Having done this, revert the special-case code added in 08dd23cec that
prevented addition of pg_depend records for temp table extension
membership, because that caused its own oddities: dropping an extension
that had created such a table didn't automatically remove the table,
leading to a failure if the table had another dependency on the extension
(such as use of an extension data type), or to a duplicate-name failure if
you then tried to recreate the extension. But we keep the part that
prevents the pg_temp_nnn schema from becoming an extension member; we never
want that to happen. Add a regression test case covering these behaviors.
Although this fixes some arguable bugs, we've heard few field complaints,
and any such problems are easily worked around by explicitly dropping temp
objects at the end of extension scripts (which seems like good practice
anyway). So I won't risk a back-patch.
Discussion: https://postgr.es/m/e51f4311-f483-4dd0-1ccc-abec3c405110@BlueTreble.com
2016-12-02 20:57:35 +01:00
|
|
|
bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
|
2019-03-29 08:25:20 +01:00
|
|
|
bool concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
|
2012-04-06 11:21:40 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
Assert(object->objectSubId == 0);
|
2019-03-29 08:25:20 +01:00
|
|
|
index_drop(object->objectId, concurrent, concurrent_lock_mode);
|
2002-09-04 22:31:48 +02:00
|
|
|
}
|
2002-07-12 20:43:19 +02:00
|
|
|
else
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
if (object->objectSubId != 0)
|
|
|
|
RemoveAttributeById(object->objectId,
|
|
|
|
object->objectSubId);
|
|
|
|
else
|
|
|
|
heap_drop_with_catalog(object->objectId);
|
|
|
|
}
|
2016-12-20 18:00:00 +01:00
|
|
|
|
2017-05-17 22:31:56 +02:00
|
|
|
/*
|
|
|
|
* for a sequence, in addition to dropping the heap, also
|
|
|
|
* delete pg_sequence tuple
|
|
|
|
*/
|
2016-12-20 18:00:00 +01:00
|
|
|
if (relKind == RELKIND_SEQUENCE)
|
|
|
|
DeleteSequenceTuple(object->objectId);
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
2002-07-12 20:43:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case OCLASS_PROC:
|
|
|
|
RemoveFunctionById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TYPE:
|
|
|
|
RemoveTypeById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
case OCLASS_CAST:
|
|
|
|
DropCastById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OCLASS_COLLATION:
|
|
|
|
RemoveCollationById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
case OCLASS_CONSTRAINT:
|
|
|
|
RemoveConstraintById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-25 12:07:13 +02:00
|
|
|
case OCLASS_CONVERSION:
|
|
|
|
RemoveConversionById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-15 18:33:32 +02:00
|
|
|
case OCLASS_DEFAULT:
|
|
|
|
RemoveAttrDefaultById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
case OCLASS_LANGUAGE:
|
|
|
|
DropProceduralLanguageById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2009-12-11 04:34:57 +01:00
|
|
|
case OCLASS_LARGEOBJECT:
|
|
|
|
LargeObjectDrop(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
case OCLASS_OPERATOR:
|
|
|
|
RemoveOperatorById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
case OCLASS_OPCLASS:
|
|
|
|
RemoveOpClassById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
case OCLASS_OPFAMILY:
|
|
|
|
RemoveOpFamilyById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2016-03-24 03:01:35 +01:00
|
|
|
case OCLASS_AM:
|
|
|
|
RemoveAccessMethodById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
case OCLASS_AMOP:
|
|
|
|
RemoveAmOpEntryById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_AMPROC:
|
|
|
|
RemoveAmProcEntryById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
case OCLASS_REWRITE:
|
|
|
|
RemoveRewriteRuleById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TRIGGER:
|
|
|
|
RemoveTriggerById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2002-07-18 18:47:26 +02:00
|
|
|
case OCLASS_SCHEMA:
|
|
|
|
RemoveSchemaById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2017-05-14 19:32:59 +02:00
|
|
|
case OCLASS_STATISTIC_EXT:
|
|
|
|
RemoveStatisticsById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
case OCLASS_TSPARSER:
|
|
|
|
RemoveTSParserById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSDICT:
|
|
|
|
RemoveTSDictionaryById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSTEMPLATE:
|
|
|
|
RemoveTSTemplateById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSCONFIG:
|
|
|
|
RemoveTSConfigurationById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2009-08-07 17:27:56 +02:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE intentionally not
|
|
|
|
* handled here
|
2009-08-07 17:27:56 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
case OCLASS_FDW:
|
|
|
|
RemoveForeignDataWrapperById(object->objectId);
|
2008-12-19 17:25:19 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_FOREIGN_SERVER:
|
|
|
|
RemoveForeignServerById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2009-08-07 17:27:56 +02:00
|
|
|
case OCLASS_USER_MAPPING:
|
|
|
|
RemoveUserMappingById(object->objectId);
|
2008-12-19 17:25:19 +01:00
|
|
|
break;
|
|
|
|
|
2009-10-05 21:24:49 +02:00
|
|
|
case OCLASS_DEFACL:
|
|
|
|
RemoveDefaultACLById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
case OCLASS_EXTENSION:
|
|
|
|
RemoveExtensionById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2012-12-06 05:42:51 +01:00
|
|
|
case OCLASS_EVENT_TRIGGER:
|
|
|
|
RemoveEventTriggerById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
2014-11-27 07:06:36 +01:00
|
|
|
case OCLASS_POLICY:
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
RemovePolicyById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
case OCLASS_PUBLICATION:
|
|
|
|
RemovePublicationById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_PUBLICATION_REL:
|
|
|
|
RemovePublicationRelById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2015-04-26 16:33:14 +02:00
|
|
|
case OCLASS_TRANSFORM:
|
|
|
|
DropTransformById(object->objectId);
|
|
|
|
break;
|
|
|
|
|
2017-05-14 19:32:59 +02:00
|
|
|
/*
|
|
|
|
* These global object types are not supported here.
|
|
|
|
*/
|
|
|
|
case OCLASS_ROLE:
|
|
|
|
case OCLASS_DATABASE:
|
|
|
|
case OCLASS_TBLSPACE:
|
|
|
|
case OCLASS_SUBSCRIPTION:
|
|
|
|
elog(ERROR, "global objects cannot be deleted by doDeletion");
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
break;
|
|
|
|
|
2017-05-14 19:32:59 +02:00
|
|
|
/*
|
|
|
|
* There's intentionally no default: case here; we want the
|
|
|
|
* compiler to warn if a new OCLASS hasn't been handled above.
|
|
|
|
*/
|
2002-07-12 20:43:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* AcquireDeletionLock - acquire a suitable lock for deleting an object
|
|
|
|
*
|
|
|
|
* We use LockRelation for relations, LockDatabaseObject for everything
|
|
|
|
* else. Note that dependency.c is not concerned with deleting any kind of
|
|
|
|
* shared-across-databases object, so we have no need for LockSharedObject.
|
|
|
|
*/
|
|
|
|
static void
|
2012-04-06 11:21:40 +02:00
|
|
|
AcquireDeletionLock(const ObjectAddress *object, int flags)
|
2008-06-09 00:41:04 +02:00
|
|
|
{
|
|
|
|
if (object->classId == RelationRelationId)
|
2012-04-06 11:21:40 +02:00
|
|
|
{
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
/*
|
|
|
|
* In DROP INDEX CONCURRENTLY, take only ShareUpdateExclusiveLock on
|
|
|
|
* the index for the moment. index_drop() will promote the lock once
|
|
|
|
* it's safe to do so. In all other cases we need full exclusive
|
|
|
|
* lock.
|
|
|
|
*/
|
2012-10-19 10:56:29 +02:00
|
|
|
if (flags & PERFORM_DELETION_CONCURRENTLY)
|
2012-04-06 11:21:40 +02:00
|
|
|
LockRelationOid(object->objectId, ShareUpdateExclusiveLock);
|
|
|
|
else
|
|
|
|
LockRelationOid(object->objectId, AccessExclusiveLock);
|
|
|
|
}
|
2008-06-09 00:41:04 +02:00
|
|
|
else
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
{
|
2008-06-09 00:41:04 +02:00
|
|
|
/* assume we should lock the whole object not a sub-object */
|
|
|
|
LockDatabaseObject(object->classId, object->objectId, 0,
|
|
|
|
AccessExclusiveLock);
|
Fix assorted bugs in CREATE/DROP INDEX CONCURRENTLY.
Commit 8cb53654dbdb4c386369eb988062d0bbb6de725e, which introduced DROP
INDEX CONCURRENTLY, managed to break CREATE INDEX CONCURRENTLY via a poor
choice of catalog state representation. The pg_index state for an index
that's reached the final pre-drop stage was the same as the state for an
index just created by CREATE INDEX CONCURRENTLY. This meant that the
(necessary) change to make RelationGetIndexList ignore about-to-die indexes
also made it ignore freshly-created indexes; which is catastrophic because
the latter do need to be considered in HOT-safety decisions. Failure to
do so leads to incorrect index entries and subsequently wrong results from
queries depending on the concurrently-created index.
To fix, add an additional boolean column "indislive" to pg_index, so that
the freshly-created and about-to-die states can be distinguished. (This
change obviously is only possible in HEAD. This patch will need to be
back-patched, but in 9.2 we'll use a kluge consisting of overloading the
formerly-impossible state of indisvalid = true and indisready = false.)
In addition, change CREATE/DROP INDEX CONCURRENTLY so that the pg_index
flag changes they make without exclusive lock on the index are made via
heap_inplace_update() rather than a normal transactional update. The
latter is not very safe because moving the pg_index tuple could result in
concurrent SnapshotNow scans finding it twice or not at all, thus possibly
resulting in index corruption. This is a pre-existing bug in CREATE INDEX
CONCURRENTLY, which was copied into the DROP code.
In addition, fix various places in the code that ought to check to make
sure that the indexes they are manipulating are valid and/or ready as
appropriate. These represent bugs that have existed since 8.2, since
a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid
index behind, and we ought not try to do anything that might fail with
such an index.
Also fix RelationReloadIndexInfo to ensure it copies all the pg_index
columns that are allowed to change after initial creation. Previously we
could have been left with stale values of some fields in an index relcache
entry. It's not clear whether this actually had any user-visible
consequences, but it's at least a bug waiting to happen.
In addition, do some code and docs review for DROP INDEX CONCURRENTLY;
some cosmetic code cleanup but mostly addition and revision of comments.
This will need to be back-patched, but in a noticeably different form,
so I'm committing it to HEAD before working on the back-patch.
Problem reported by Amit Kapila, diagnosis by Pavan Deolassee,
fix by Tom Lane and Andres Freund.
2012-11-29 03:25:27 +01:00
|
|
|
}
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ReleaseDeletionLock - release an object deletion lock
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ReleaseDeletionLock(const ObjectAddress *object)
|
|
|
|
{
|
|
|
|
if (object->classId == RelationRelationId)
|
|
|
|
UnlockRelationOid(object->objectId, AccessExclusiveLock);
|
|
|
|
else
|
|
|
|
/* assume we should lock the whole object not a sub-object */
|
|
|
|
UnlockDatabaseObject(object->classId, object->objectId, 0,
|
|
|
|
AccessExclusiveLock);
|
|
|
|
}
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
|
|
|
* recordDependencyOnExpr - find expression dependencies
|
|
|
|
*
|
|
|
|
* This is used to find the dependencies of rules, constraint expressions,
|
|
|
|
* etc.
|
|
|
|
*
|
|
|
|
* Given an expression or query in node-tree form, find all the objects
|
|
|
|
* it refers to (tables, columns, operators, functions, etc). Record
|
|
|
|
* a dependency of the specified type from the given depender object
|
|
|
|
* to each object mentioned in the expression.
|
|
|
|
*
|
|
|
|
* rtable is the rangetable to be used to interpret Vars with varlevelsup=0.
|
|
|
|
* It can be NIL if no such variables are expected.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
recordDependencyOnExpr(const ObjectAddress *depender,
|
|
|
|
Node *expr, List *rtable,
|
|
|
|
DependencyType behavior)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
find_expr_references_context context;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
context.addrs = new_object_addresses();
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
/* Set up interpretation for Vars at varlevelsup = 0 */
|
2004-05-26 06:41:50 +02:00
|
|
|
context.rtables = list_make1(rtable);
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
/* Scan the expression tree for referenceable objects */
|
|
|
|
find_expr_references_walker(expr, &context);
|
|
|
|
|
|
|
|
/* Remove any duplicates */
|
2006-08-20 23:56:16 +02:00
|
|
|
eliminate_duplicate_dependencies(context.addrs);
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
/* And record 'em */
|
2003-05-28 18:04:02 +02:00
|
|
|
recordMultipleDependencies(depender,
|
2006-08-20 23:56:16 +02:00
|
|
|
context.addrs->refs, context.addrs->numrefs,
|
2003-05-28 18:04:02 +02:00
|
|
|
behavior);
|
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
free_object_addresses(context.addrs);
|
2003-05-28 18:04:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* recordDependencyOnSingleRelExpr - find expression dependencies
|
|
|
|
*
|
|
|
|
* As above, but only one relation is expected to be referenced (with
|
2014-05-06 18:12:18 +02:00
|
|
|
* varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
|
2003-05-28 18:04:02 +02:00
|
|
|
* range table. An additional frammish is that dependencies on that
|
|
|
|
* relation (or its component columns) will be marked with 'self_behavior',
|
|
|
|
* whereas 'behavior' is used for everything else.
|
2010-11-02 22:15:07 +01:00
|
|
|
*
|
|
|
|
* NOTE: the caller should ensure that a whole-table dependency on the
|
2014-05-06 18:12:18 +02:00
|
|
|
* specified relation is created separately, if one is needed. In particular,
|
2010-11-02 22:15:07 +01:00
|
|
|
* a whole-row Var "relation.*" will not cause this routine to emit any
|
|
|
|
* dependency item. This is appropriate behavior for subexpressions of an
|
|
|
|
* ordinary query, so other cases need to cope as necessary.
|
2003-05-28 18:04:02 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
|
|
|
|
Node *expr, Oid relId,
|
|
|
|
DependencyType behavior,
|
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
|
|
|
DependencyType self_behavior,
|
|
|
|
bool ignore_self)
|
2003-05-28 18:04:02 +02:00
|
|
|
{
|
|
|
|
find_expr_references_context context;
|
|
|
|
RangeTblEntry rte;
|
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
context.addrs = new_object_addresses();
|
2003-05-28 18:04:02 +02:00
|
|
|
|
|
|
|
/* We gin up a rather bogus rangetable list to handle Vars */
|
|
|
|
MemSet(&rte, 0, sizeof(rte));
|
|
|
|
rte.type = T_RangeTblEntry;
|
|
|
|
rte.rtekind = RTE_RELATION;
|
|
|
|
rte.relid = relId;
|
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
|
|
|
rte.relkind = RELKIND_RELATION; /* no need for exactness here */
|
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
|
|
|
rte.rellockmode = AccessShareLock;
|
2003-05-28 18:04:02 +02:00
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
context.rtables = list_make1(list_make1(&rte));
|
2003-05-28 18:04:02 +02:00
|
|
|
|
|
|
|
/* Scan the expression tree for referenceable objects */
|
|
|
|
find_expr_references_walker(expr, &context);
|
|
|
|
|
|
|
|
/* Remove any duplicates */
|
2006-08-20 23:56:16 +02:00
|
|
|
eliminate_duplicate_dependencies(context.addrs);
|
2003-05-28 18:04:02 +02:00
|
|
|
|
|
|
|
/* Separate self-dependencies if necessary */
|
2006-08-20 23:56:16 +02:00
|
|
|
if (behavior != self_behavior && context.addrs->numrefs > 0)
|
2003-05-28 18:04:02 +02:00
|
|
|
{
|
2006-08-20 23:56:16 +02:00
|
|
|
ObjectAddresses *self_addrs;
|
2003-05-28 18:04:02 +02:00
|
|
|
ObjectAddress *outobj;
|
|
|
|
int oldref,
|
|
|
|
outrefs;
|
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
self_addrs = new_object_addresses();
|
2003-05-28 18:04:02 +02:00
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
outobj = context.addrs->refs;
|
2003-05-28 18:04:02 +02:00
|
|
|
outrefs = 0;
|
2006-08-20 23:56:16 +02:00
|
|
|
for (oldref = 0; oldref < context.addrs->numrefs; oldref++)
|
2003-05-28 18:04:02 +02:00
|
|
|
{
|
2006-08-20 23:56:16 +02:00
|
|
|
ObjectAddress *thisobj = context.addrs->refs + oldref;
|
2003-05-28 18:04:02 +02:00
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
if (thisobj->classId == RelationRelationId &&
|
2003-05-28 18:04:02 +02:00
|
|
|
thisobj->objectId == relId)
|
|
|
|
{
|
|
|
|
/* Move this ref into self_addrs */
|
2008-06-09 00:41:04 +02:00
|
|
|
add_exact_object_address(thisobj, self_addrs);
|
2003-05-28 18:04:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Keep it in context.addrs */
|
2008-06-09 00:41:04 +02:00
|
|
|
*outobj = *thisobj;
|
2003-05-28 18:04:02 +02:00
|
|
|
outobj++;
|
|
|
|
outrefs++;
|
|
|
|
}
|
|
|
|
}
|
2006-08-20 23:56:16 +02:00
|
|
|
context.addrs->numrefs = outrefs;
|
2003-05-28 18:04:02 +02:00
|
|
|
|
|
|
|
/* Record the self-dependencies */
|
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 (!ignore_self)
|
|
|
|
recordMultipleDependencies(depender,
|
|
|
|
self_addrs->refs, self_addrs->numrefs,
|
|
|
|
self_behavior);
|
2003-05-28 18:04:02 +02:00
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
free_object_addresses(self_addrs);
|
2003-05-28 18:04:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Record the external dependencies */
|
2002-07-16 07:53:34 +02:00
|
|
|
recordMultipleDependencies(depender,
|
2006-08-20 23:56:16 +02:00
|
|
|
context.addrs->refs, context.addrs->numrefs,
|
2002-07-16 07:53:34 +02:00
|
|
|
behavior);
|
|
|
|
|
2006-08-20 23:56:16 +02:00
|
|
|
free_object_addresses(context.addrs);
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recursively search an expression tree for object references.
|
2002-09-11 16:48:55 +02:00
|
|
|
*
|
|
|
|
* Note: we avoid creating references to columns of tables that participate
|
|
|
|
* in an SQL JOIN construct, but are not actually used anywhere in the query.
|
|
|
|
* To do so, we do not scan the joinaliasvars list of a join RTE while
|
|
|
|
* scanning the query rangetable, but instead scan each individual entry
|
|
|
|
* of the alias list when we find a reference to it.
|
2006-03-16 01:31:55 +01:00
|
|
|
*
|
|
|
|
* Note: in many cases we do not need to create dependencies on the datatypes
|
|
|
|
* involved in an expression, because we'll have an indirect dependency via
|
|
|
|
* some other object. For instance Var nodes depend on a column which depends
|
|
|
|
* on the datatype, and OpExpr nodes depend on the operator which depends on
|
|
|
|
* the datatype. However we do need a type dependency if there is no such
|
|
|
|
* indirect dependency, as for example in Const and CoerceToDomain nodes.
|
2011-03-11 22:27:51 +01:00
|
|
|
*
|
|
|
|
* Similarly, we don't need to create dependencies on collations except where
|
|
|
|
* the collation is being freshly introduced to the expression.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
find_expr_references_walker(Node *node,
|
|
|
|
find_expr_references_context *context)
|
|
|
|
{
|
|
|
|
if (node == NULL)
|
|
|
|
return false;
|
|
|
|
if (IsA(node, Var))
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
2004-05-26 06:41:50 +02:00
|
|
|
List *rtable;
|
2002-07-16 07:53:34 +02:00
|
|
|
RangeTblEntry *rte;
|
|
|
|
|
|
|
|
/* Find matching rtable entry, or complain if not found */
|
2004-05-26 06:41:50 +02:00
|
|
|
if (var->varlevelsup >= list_length(context->rtables))
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
|
2004-05-26 06:41:50 +02:00
|
|
|
rtable = (List *) list_nth(context->rtables, var->varlevelsup);
|
|
|
|
if (var->varno <= 0 || var->varno > list_length(rtable))
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "invalid varno %d", var->varno);
|
2002-07-16 07:53:34 +02:00
|
|
|
rte = rt_fetch(var->varno, rtable);
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-08-19 22:57:41 +02:00
|
|
|
/*
|
|
|
|
* A whole-row Var references no specific columns, so adds no new
|
2014-05-06 18:12:18 +02:00
|
|
|
* dependency. (We assume that there is a whole-table dependency
|
2010-11-02 22:15:07 +01:00
|
|
|
* arising from each underlying rangetable entry. While we could
|
|
|
|
* record such a dependency when finding a whole-row Var that
|
|
|
|
* references a relation directly, it's quite unclear how to extend
|
|
|
|
* that to whole-row Vars for JOINs, so it seems better to leave the
|
|
|
|
* responsibility with the range table. Note that this poses some
|
|
|
|
* risks for identifying dependencies of stand-alone expressions:
|
|
|
|
* whole-table references may need to be created separately.)
|
2004-08-19 22:57:41 +02:00
|
|
|
*/
|
|
|
|
if (var->varattno == InvalidAttrNumber)
|
|
|
|
return false;
|
2002-07-16 07:53:34 +02:00
|
|
|
if (rte->rtekind == RTE_RELATION)
|
2002-09-11 16:48:55 +02:00
|
|
|
{
|
|
|
|
/* If it's a plain relation, reference this column */
|
2002-07-16 07:53:34 +02:00
|
|
|
add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2002-09-11 16:48:55 +02:00
|
|
|
}
|
|
|
|
else if (rte->rtekind == RTE_JOIN)
|
|
|
|
{
|
|
|
|
/* Scan join output column to add references to join inputs */
|
2003-08-04 02:43:34 +02:00
|
|
|
List *save_rtables;
|
2002-12-04 21:00:37 +01:00
|
|
|
|
|
|
|
/* We must make the context appropriate for join's level */
|
|
|
|
save_rtables = context->rtables;
|
2004-05-26 06:41:50 +02:00
|
|
|
context->rtables = list_copy_tail(context->rtables,
|
|
|
|
var->varlevelsup);
|
2002-09-11 16:48:55 +02:00
|
|
|
if (var->varattno <= 0 ||
|
2004-05-26 06:41:50 +02:00
|
|
|
var->varattno > list_length(rte->joinaliasvars))
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "invalid varattno %d", var->varattno);
|
2004-05-26 06:41:50 +02:00
|
|
|
find_expr_references_walker((Node *) list_nth(rte->joinaliasvars,
|
2005-10-15 04:49:52 +02:00
|
|
|
var->varattno - 1),
|
2002-09-11 16:48:55 +02:00
|
|
|
context);
|
2004-05-26 06:41:50 +02:00
|
|
|
list_free(context->rtables);
|
2002-12-04 21:00:37 +01:00
|
|
|
context->rtables = save_rtables;
|
2002-09-11 16:48:55 +02:00
|
|
|
}
|
2002-07-16 07:53:34 +02:00
|
|
|
return false;
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, Const))
|
2005-10-03 01:50:16 +02:00
|
|
|
{
|
|
|
|
Const *con = (Const *) node;
|
|
|
|
Oid objoid;
|
|
|
|
|
2006-03-16 01:31:55 +01:00
|
|
|
/* A constant must depend on the constant's datatype */
|
|
|
|
add_object_address(OCLASS_TYPE, con->consttype, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2011-03-11 22:27:51 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We must also depend on the constant's collation: it could be
|
2011-04-10 17:42:00 +02:00
|
|
|
* different from the datatype's, if a CollateExpr was const-folded to
|
|
|
|
* a simple constant. However we can save work in the most common
|
2011-03-11 22:27:51 +01:00
|
|
|
* case where the collation is "default", since we know that's pinned.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(con->constcollid) &&
|
|
|
|
con->constcollid != DEFAULT_COLLATION_OID)
|
2011-02-12 14:54:13 +01:00
|
|
|
add_object_address(OCLASS_COLLATION, con->constcollid, 0,
|
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
|
2005-10-03 01:50:16 +02:00
|
|
|
/*
|
|
|
|
* If it's a regclass or similar literal referring to an existing
|
2014-05-06 18:12:18 +02:00
|
|
|
* object, add a reference to that object. (Currently, only the
|
2007-08-21 03:11:32 +02:00
|
|
|
* regclass and regconfig cases have any likely use, but we may as
|
|
|
|
* well handle all the OID-alias datatypes consistently.)
|
2005-10-03 01:50:16 +02:00
|
|
|
*/
|
|
|
|
if (!con->constisnull)
|
|
|
|
{
|
|
|
|
switch (con->consttype)
|
|
|
|
{
|
|
|
|
case REGPROCOID:
|
|
|
|
case REGPROCEDUREOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(PROCOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2005-10-03 01:50:16 +02:00
|
|
|
add_object_address(OCLASS_PROC, objoid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2005-10-03 01:50:16 +02:00
|
|
|
break;
|
|
|
|
case REGOPEROID:
|
|
|
|
case REGOPERATOROID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(OPEROID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2005-10-03 01:50:16 +02:00
|
|
|
add_object_address(OCLASS_OPERATOR, objoid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2005-10-03 01:50:16 +02:00
|
|
|
break;
|
|
|
|
case REGCLASSOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(RELOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2005-10-03 01:50:16 +02:00
|
|
|
add_object_address(OCLASS_CLASS, objoid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2005-10-03 01:50:16 +02:00
|
|
|
break;
|
|
|
|
case REGTYPEOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(TYPEOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2005-10-03 01:50:16 +02:00
|
|
|
add_object_address(OCLASS_TYPE, objoid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2005-10-03 01:50:16 +02:00
|
|
|
break;
|
2007-08-21 03:11:32 +02:00
|
|
|
case REGCONFIGOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(TSCONFIGOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2007-08-21 03:11:32 +02:00
|
|
|
add_object_address(OCLASS_TSCONFIG, objoid, 0,
|
|
|
|
context->addrs);
|
|
|
|
break;
|
|
|
|
case REGDICTIONARYOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
2010-02-14 19:42:19 +01:00
|
|
|
if (SearchSysCacheExists1(TSDICTOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
2007-08-21 03:11:32 +02:00
|
|
|
add_object_address(OCLASS_TSDICT, objoid, 0,
|
|
|
|
context->addrs);
|
|
|
|
break;
|
2015-05-09 19:06:49 +02:00
|
|
|
|
2015-05-09 19:36:52 +02:00
|
|
|
case REGNAMESPACEOID:
|
|
|
|
objoid = DatumGetObjectId(con->constvalue);
|
|
|
|
if (SearchSysCacheExists1(NAMESPACEOID,
|
|
|
|
ObjectIdGetDatum(objoid)))
|
|
|
|
add_object_address(OCLASS_SCHEMA, objoid, 0,
|
|
|
|
context->addrs);
|
|
|
|
break;
|
|
|
|
|
2015-05-24 03:35:49 +02:00
|
|
|
/*
|
|
|
|
* Dependencies for regrole should be shared among all
|
|
|
|
* databases, so explicitly inhibit to have dependencies.
|
|
|
|
*/
|
2015-05-09 19:06:49 +02:00
|
|
|
case REGROLEOID:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("constant of the type %s cannot be used here",
|
|
|
|
"regrole")));
|
2015-05-09 19:06:49 +02:00
|
|
|
break;
|
2005-10-03 01:50:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, Param))
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
|
|
|
Param *param = (Param *) node;
|
|
|
|
|
|
|
|
/* A parameter must depend on the parameter's datatype */
|
|
|
|
add_object_address(OCLASS_TYPE, param->paramtype, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2011-03-11 22:27:51 +01:00
|
|
|
/* and its collation, just as for Consts */
|
2011-03-20 01:29:08 +01:00
|
|
|
if (OidIsValid(param->paramcollid) &&
|
|
|
|
param->paramcollid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, param->paramcollid, 0,
|
2011-02-12 14:54:13 +01:00
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, FuncExpr))
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
FuncExpr *funcexpr = (FuncExpr *) node;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2002-12-12 16:49:42 +01:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, OpExpr))
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
OpExpr *opexpr = (OpExpr *) node;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2002-12-12 16:49:42 +01:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, DistinctExpr))
|
2002-12-12 16:49:42 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
DistinctExpr *distinctexpr = (DistinctExpr *) node;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2002-07-16 07:53:34 +02:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2011-03-20 01:29:08 +01:00
|
|
|
else if (IsA(node, NullIfExpr))
|
2003-06-29 02:33:44 +02:00
|
|
|
{
|
2011-03-20 01:29:08 +01:00
|
|
|
NullIfExpr *nullifexpr = (NullIfExpr *) node;
|
2003-06-29 02:33:44 +02:00
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2003-06-29 02:33:44 +02:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2011-03-20 01:29:08 +01:00
|
|
|
else if (IsA(node, ScalarArrayOpExpr))
|
2003-02-16 03:30:39 +01:00
|
|
|
{
|
2011-03-20 01:29:08 +01:00
|
|
|
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
|
2003-02-16 03:30:39 +01:00
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2003-02-16 03:30:39 +01:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, Aggref))
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
|
|
|
Aggref *aggref = (Aggref *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2002-07-16 07:53:34 +02:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-12-28 19:54:01 +01:00
|
|
|
else if (IsA(node, WindowFunc))
|
|
|
|
{
|
|
|
|
WindowFunc *wfunc = (WindowFunc *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_PROC, wfunc->winfnoid, 0,
|
|
|
|
context->addrs);
|
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-22 02:16:04 +02:00
|
|
|
else if (IsA(node, SubPlan))
|
2003-01-10 22:08:15 +01:00
|
|
|
{
|
2005-12-28 02:30:02 +01:00
|
|
|
/* Extra work needed here if we ever need this case */
|
|
|
|
elog(ERROR, "already-planned subqueries not supported");
|
|
|
|
}
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
else if (IsA(node, FieldSelect))
|
|
|
|
{
|
|
|
|
FieldSelect *fselect = (FieldSelect *) node;
|
2017-10-27 18:18:56 +02:00
|
|
|
Oid argtype = getBaseType(exprType((Node *) fselect->arg));
|
|
|
|
Oid reltype = get_typ_typrelid(argtype);
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
|
2017-10-27 18:18:56 +02:00
|
|
|
/*
|
|
|
|
* We need a dependency on the specific column named in FieldSelect,
|
|
|
|
* assuming we can identify the pg_class OID for it. (Probably we
|
|
|
|
* always can at the moment, but in future it might be possible for
|
|
|
|
* argtype to be RECORDOID.) If we can make a column dependency then
|
|
|
|
* we shouldn't need a dependency on the column's type; but if we
|
|
|
|
* can't, make a dependency on the type, as it might not appear
|
|
|
|
* anywhere else in the expression.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(reltype))
|
|
|
|
add_object_address(OCLASS_CLASS, reltype, fselect->fieldnum,
|
|
|
|
context->addrs);
|
|
|
|
else
|
|
|
|
add_object_address(OCLASS_TYPE, fselect->resulttype, 0,
|
|
|
|
context->addrs);
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
/* the collation might not be referenced anywhere else, either */
|
|
|
|
if (OidIsValid(fselect->resultcollid) &&
|
|
|
|
fselect->resultcollid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, fselect->resultcollid, 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
else if (IsA(node, FieldStore))
|
|
|
|
{
|
|
|
|
FieldStore *fstore = (FieldStore *) node;
|
2017-10-27 18:18:56 +02:00
|
|
|
Oid reltype = get_typ_typrelid(fstore->resulttype);
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
|
2017-10-27 18:18:56 +02:00
|
|
|
/* similar considerations to FieldSelect, but multiple column(s) */
|
|
|
|
if (OidIsValid(reltype))
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, fstore->fieldnums)
|
|
|
|
add_object_address(OCLASS_CLASS, reltype, lfirst_int(l),
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
add_object_address(OCLASS_TYPE, fstore->resulttype, 0,
|
|
|
|
context->addrs);
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, RelabelType))
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
RelabelType *relab = (RelabelType *) node;
|
2006-03-16 01:31:55 +01:00
|
|
|
|
|
|
|
/* since there is no function dependency, need to depend on type */
|
|
|
|
add_object_address(OCLASS_TYPE, relab->resulttype, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2011-03-20 01:29:08 +01:00
|
|
|
/* the collation might not be referenced anywhere else, either */
|
|
|
|
if (OidIsValid(relab->resultcollid) &&
|
|
|
|
relab->resultcollid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, relab->resultcollid, 0,
|
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, CoerceViaIO))
|
2007-06-05 23:31:09 +02:00
|
|
|
{
|
|
|
|
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
|
|
|
|
|
|
|
|
/* since there is no exposed function, need to depend on type */
|
|
|
|
add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
|
|
|
|
context->addrs);
|
Fix some oversights in expression dependency recording.
find_expr_references() neglected to record a dependency on the result type
of a FieldSelect node, allowing a DROP TYPE to break a view or rule that
contains such an expression. I think we'd omitted this case intentionally,
reasoning that there would always be a related dependency ensuring that the
DROP would cascade to the view. But at least with nested field selection
expressions, that's not true, as shown in bug #14867 from Mansur Galiev.
Add the dependency, and for good measure a dependency on the node's exposed
collation.
Likewise add a dependency on the result type of a FieldStore. I think here
the reasoning was that it'd only appear within an assignment to a field,
and the dependency on the field's column would be enough ... but having
seen this example, I think that's wrong for nested-composites cases.
Looking at nearby code, I notice we're not recording a dependency on the
exposed collation of CoerceViaIO, which seems inconsistent with our choices
for related node types. Maybe that's OK but I'm feeling suspicious of this
code today, so let's add that; it certainly can't hurt.
This patch does not do anything to protect already-existing views, only
views created after it's installed. But seeing that the issue has been
there a very long time and nobody noticed till now, that's probably good
enough.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/20171023150118.1477.19174@wrigleys.postgresql.org
2017-10-23 19:57:45 +02:00
|
|
|
/* the collation might not be referenced anywhere else, either */
|
|
|
|
if (OidIsValid(iocoerce->resultcollid) &&
|
|
|
|
iocoerce->resultcollid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, iocoerce->resultcollid, 0,
|
|
|
|
context->addrs);
|
2007-06-05 23:31:09 +02:00
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, ArrayCoerceExpr))
|
2007-03-28 01:21:12 +02:00
|
|
|
{
|
|
|
|
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
|
|
|
|
|
Support arrays over domains.
Allowing arrays with a domain type as their element type was left un-done
in the original domain patch, but not for any very good reason. This
omission leads to such surprising results as array_agg() not working on
a domain column, because the parser can't identify a suitable output type
for the polymorphic aggregate.
In order to fix this, first clean up the APIs of coerce_to_domain() and
some internal functions in parse_coerce.c so that we consistently pass
around a CoercionContext along with CoercionForm. Previously, we sometimes
passed an "isExplicit" boolean flag instead, which is strictly less
information; and coerce_to_domain() didn't even get that, but instead had
to reverse-engineer isExplicit from CoercionForm. That's contrary to the
documentation in primnodes.h that says that CoercionForm only affects
display and not semantics. I don't think this change fixes any live bugs,
but it makes things more consistent. The main reason for doing it though
is that now build_coercion_expression() receives ccontext, which it needs
in order to be able to recursively invoke coerce_to_target_type().
Next, reimplement ArrayCoerceExpr so that the node does not directly know
any details of what has to be done to the individual array elements while
performing the array coercion. Instead, the per-element processing is
represented by a sub-expression whose input is a source array element and
whose output is a target array element. This simplifies life in
parse_coerce.c, because it can build that sub-expression by a recursive
invocation of coerce_to_target_type(). The executor now handles the
per-element processing as a compiled expression instead of hard-wired code.
The main advantage of this is that we can use a single ArrayCoerceExpr to
handle as many as three successive steps per element: base type conversion,
typmod coercion, and domain constraint checking. The old code used two
stacked ArrayCoerceExprs to handle type + typmod coercion, which was pretty
inefficient, and adding yet another array deconstruction to do domain
constraint checking seemed very unappetizing.
In the case where we just need a single, very simple coercion function,
doing this straightforwardly leads to a noticeable increase in the
per-array-element runtime cost. Hence, add an additional shortcut evalfunc
in execExprInterp.c that skips unnecessary overhead for that specific form
of expression. The runtime speed of simple cases is within 1% or so of
where it was before, while cases that previously required two levels of
array processing are significantly faster.
Finally, create an implicit array type for every domain type, as we do for
base types, enums, etc. Everything except the array-coercion case seems
to just work without further effort.
Tom Lane, reviewed by Andrew Dunstan
Discussion: https://postgr.es/m/9852.1499791473@sss.pgh.pa.us
2017-09-30 19:40:56 +02:00
|
|
|
/* as above, depend on type */
|
2007-03-28 01:21:12 +02:00
|
|
|
add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
|
|
|
|
context->addrs);
|
Support arrays over domains.
Allowing arrays with a domain type as their element type was left un-done
in the original domain patch, but not for any very good reason. This
omission leads to such surprising results as array_agg() not working on
a domain column, because the parser can't identify a suitable output type
for the polymorphic aggregate.
In order to fix this, first clean up the APIs of coerce_to_domain() and
some internal functions in parse_coerce.c so that we consistently pass
around a CoercionContext along with CoercionForm. Previously, we sometimes
passed an "isExplicit" boolean flag instead, which is strictly less
information; and coerce_to_domain() didn't even get that, but instead had
to reverse-engineer isExplicit from CoercionForm. That's contrary to the
documentation in primnodes.h that says that CoercionForm only affects
display and not semantics. I don't think this change fixes any live bugs,
but it makes things more consistent. The main reason for doing it though
is that now build_coercion_expression() receives ccontext, which it needs
in order to be able to recursively invoke coerce_to_target_type().
Next, reimplement ArrayCoerceExpr so that the node does not directly know
any details of what has to be done to the individual array elements while
performing the array coercion. Instead, the per-element processing is
represented by a sub-expression whose input is a source array element and
whose output is a target array element. This simplifies life in
parse_coerce.c, because it can build that sub-expression by a recursive
invocation of coerce_to_target_type(). The executor now handles the
per-element processing as a compiled expression instead of hard-wired code.
The main advantage of this is that we can use a single ArrayCoerceExpr to
handle as many as three successive steps per element: base type conversion,
typmod coercion, and domain constraint checking. The old code used two
stacked ArrayCoerceExprs to handle type + typmod coercion, which was pretty
inefficient, and adding yet another array deconstruction to do domain
constraint checking seemed very unappetizing.
In the case where we just need a single, very simple coercion function,
doing this straightforwardly leads to a noticeable increase in the
per-array-element runtime cost. Hence, add an additional shortcut evalfunc
in execExprInterp.c that skips unnecessary overhead for that specific form
of expression. The runtime speed of simple cases is within 1% or so of
where it was before, while cases that previously required two levels of
array processing are significantly faster.
Finally, create an implicit array type for every domain type, as we do for
base types, enums, etc. Everything except the array-coercion case seems
to just work without further effort.
Tom Lane, reviewed by Andrew Dunstan
Discussion: https://postgr.es/m/9852.1499791473@sss.pgh.pa.us
2017-09-30 19:40:56 +02:00
|
|
|
/* the collation might not be referenced anywhere else, either */
|
|
|
|
if (OidIsValid(acoerce->resultcollid) &&
|
|
|
|
acoerce->resultcollid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, acoerce->resultcollid, 0,
|
|
|
|
context->addrs);
|
2007-03-28 01:21:12 +02:00
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, ConvertRowtypeExpr))
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
|
|
|
ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
|
|
|
|
|
|
|
|
/* since there is no function dependency, need to depend on type */
|
|
|
|
add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
2011-03-11 22:27:51 +01:00
|
|
|
else if (IsA(node, CollateExpr))
|
|
|
|
{
|
|
|
|
CollateExpr *coll = (CollateExpr *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_COLLATION, coll->collOid, 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, RowExpr))
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
RowExpr *rowexpr = (RowExpr *) node;
|
2006-03-16 01:31:55 +01:00
|
|
|
|
|
|
|
add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, RowCompareExpr))
|
2005-12-28 02:30:02 +01:00
|
|
|
{
|
|
|
|
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
|
|
|
|
ListCell *l;
|
2003-01-10 22:08:15 +01:00
|
|
|
|
2005-12-28 02:30:02 +01:00
|
|
|
foreach(l, rcexpr->opnos)
|
2003-01-10 22:08:15 +01:00
|
|
|
{
|
2005-12-28 02:30:02 +01:00
|
|
|
add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2005-12-28 02:30:02 +01:00
|
|
|
}
|
2006-12-23 01:43:13 +01:00
|
|
|
foreach(l, rcexpr->opfamilies)
|
2005-12-28 02:30:02 +01:00
|
|
|
{
|
2006-12-23 01:43:13 +01:00
|
|
|
add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2003-01-10 22:08:15 +01:00
|
|
|
}
|
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, CoerceToDomain))
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
|
|
|
CoerceToDomain *cd = (CoerceToDomain *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_TYPE, cd->resulttype, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
Code review for NextValueExpr expression node type.
Add missing infrastructure for this node type, notably in ruleutils.c where
its lack could demonstrably cause EXPLAIN to fail. Add outfuncs/readfuncs
support. (outfuncs support is useful today for debugging purposes. The
readfuncs support may never be needed, since at present it would only
matter for parallel query and NextValueExpr should never appear in a
parallelizable query; but it seems like a bad idea to have a primnode type
that isn't fully supported here.) Teach planner infrastructure that
NextValueExpr is a volatile, parallel-unsafe, non-leaky expression node
with cost cpu_operator_cost. Given its limited scope of usage, there
*might* be no live bug today from the lack of that knowledge, but it's
certainly going to bite us on the rear someday. Teach pg_stat_statements
about the new node type, too.
While at it, also teach cost_qual_eval() that MinMaxExpr, SQLValueFunction,
XmlExpr, and CoerceToDomain should be charged as cpu_operator_cost.
Failing to do this for SQLValueFunction was an oversight in my commit
0bb51aa96. The others are longer-standing oversights, but no time like the
present to fix them. (In principle, CoerceToDomain could have cost much
higher than this, but it doesn't presently seem worth trying to examine the
domain's constraints here.)
Modify execExprInterp.c to execute NextValueExpr as an out-of-line
function; it seems quite unlikely to me that it's worth insisting that
it be inlined in all expression eval methods. Besides, providing the
out-of-line function doesn't stop anyone from inlining if they want to.
Adjust some places where NextValueExpr support had been inserted with the
aid of a dartboard rather than keeping it in the same order as elsewhere.
Discussion: https://postgr.es/m/23862.1499981661@sss.pgh.pa.us
2017-07-14 21:25:43 +02:00
|
|
|
else if (IsA(node, NextValueExpr))
|
|
|
|
{
|
|
|
|
NextValueExpr *nve = (NextValueExpr *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_CLASS, nve->seqid, 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
2016-05-11 22:20:03 +02:00
|
|
|
else if (IsA(node, OnConflictExpr))
|
|
|
|
{
|
|
|
|
OnConflictExpr *onconflict = (OnConflictExpr *) node;
|
|
|
|
|
|
|
|
if (OidIsValid(onconflict->constraint))
|
|
|
|
add_object_address(OCLASS_CONSTRAINT, onconflict->constraint, 0,
|
|
|
|
context->addrs);
|
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, SortGroupClause))
|
|
|
|
{
|
|
|
|
SortGroupClause *sgc = (SortGroupClause *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_OPERATOR, sgc->eqop, 0,
|
|
|
|
context->addrs);
|
|
|
|
if (OidIsValid(sgc->sortop))
|
|
|
|
add_object_address(OCLASS_OPERATOR, sgc->sortop, 0,
|
|
|
|
context->addrs);
|
|
|
|
return false;
|
|
|
|
}
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
2018-02-07 06:06:50 +01:00
|
|
|
else if (IsA(node, WindowClause))
|
|
|
|
{
|
|
|
|
WindowClause *wc = (WindowClause *) node;
|
|
|
|
|
|
|
|
if (OidIsValid(wc->startInRangeFunc))
|
|
|
|
add_object_address(OCLASS_PROC, wc->startInRangeFunc, 0,
|
|
|
|
context->addrs);
|
|
|
|
if (OidIsValid(wc->endInRangeFunc))
|
|
|
|
add_object_address(OCLASS_PROC, wc->endInRangeFunc, 0,
|
|
|
|
context->addrs);
|
|
|
|
if (OidIsValid(wc->inRangeColl) &&
|
|
|
|
wc->inRangeColl != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, wc->inRangeColl, 0,
|
|
|
|
context->addrs);
|
|
|
|
/* fall through to examine substructure */
|
|
|
|
}
|
2008-08-02 23:32:01 +02:00
|
|
|
else if (IsA(node, Query))
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
|
|
|
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
|
|
|
Query *query = (Query *) node;
|
2010-08-07 04:44:09 +02:00
|
|
|
ListCell *lc;
|
2002-07-16 07:53:34 +02:00
|
|
|
bool result;
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Add whole-relation refs for each plain relation mentioned in the
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
* subquery's rtable.
|
2011-04-18 21:31:52 +02:00
|
|
|
*
|
|
|
|
* Note: query_tree_walker takes care of recursing into RTE_FUNCTION
|
|
|
|
* RTEs, subqueries, etc, so no need to do that here. But keep it
|
|
|
|
* from looking at join alias lists.
|
|
|
|
*
|
|
|
|
* Note: we don't need to worry about collations mentioned in
|
|
|
|
* RTE_VALUES or RTE_CTE RTEs, because those must just duplicate
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
* collations referenced in other parts of the Query. We do have to
|
|
|
|
* worry about collations mentioned in RTE_FUNCTION, but we take care
|
|
|
|
* of those when we recurse to the RangeTblFunction node(s).
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
2010-08-07 04:44:09 +02:00
|
|
|
foreach(lc, query->rtable)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2010-08-07 04:44:09 +02:00
|
|
|
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2006-03-16 01:31:55 +01:00
|
|
|
switch (rte->rtekind)
|
|
|
|
{
|
|
|
|
case RTE_RELATION:
|
|
|
|
add_object_address(OCLASS_CLASS, rte->relid, 0,
|
2006-08-20 23:56:16 +02:00
|
|
|
context->addrs);
|
2006-03-16 01:31:55 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
|
2012-03-11 23:14:23 +01:00
|
|
|
/*
|
|
|
|
* If the query is an INSERT or UPDATE, we should create a dependency
|
|
|
|
* on each target column, to prevent the specific target column from
|
|
|
|
* being dropped. Although we will visit the TargetEntry nodes again
|
|
|
|
* during query_tree_walker, we won't have enough context to do this
|
|
|
|
* conveniently, so do it here.
|
|
|
|
*/
|
|
|
|
if (query->commandType == CMD_INSERT ||
|
|
|
|
query->commandType == CMD_UPDATE)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
|
|
|
|
if (query->resultRelation <= 0 ||
|
|
|
|
query->resultRelation > list_length(query->rtable))
|
|
|
|
elog(ERROR, "invalid resultRelation %d",
|
|
|
|
query->resultRelation);
|
|
|
|
rte = rt_fetch(query->resultRelation, query->rtable);
|
|
|
|
if (rte->rtekind == RTE_RELATION)
|
|
|
|
{
|
|
|
|
foreach(lc, query->targetList)
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
|
|
|
|
|
|
|
if (tle->resjunk)
|
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
|
|
|
continue; /* ignore junk tlist items */
|
2012-03-11 23:14:23 +01:00
|
|
|
add_object_address(OCLASS_CLASS, rte->relid, tle->resno,
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-07 04:44:09 +02:00
|
|
|
/*
|
|
|
|
* Add dependencies on constraints listed in query's constraintDeps
|
|
|
|
*/
|
|
|
|
foreach(lc, query->constraintDeps)
|
|
|
|
{
|
|
|
|
add_object_address(OCLASS_CONSTRAINT, lfirst_oid(lc), 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
|
2008-08-02 23:32:01 +02:00
|
|
|
/* query_tree_walker ignores ORDER BY etc, but we need those opers */
|
|
|
|
find_expr_references_walker((Node *) query->sortClause, context);
|
|
|
|
find_expr_references_walker((Node *) query->groupClause, context);
|
2008-12-28 19:54:01 +01:00
|
|
|
find_expr_references_walker((Node *) query->windowClause, context);
|
2008-08-02 23:32:01 +02:00
|
|
|
find_expr_references_walker((Node *) query->distinctClause, context);
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/* Examine substructure of query */
|
|
|
|
context->rtables = lcons(query->rtable, context->rtables);
|
|
|
|
result = query_tree_walker(query,
|
|
|
|
find_expr_references_walker,
|
2002-09-11 16:48:55 +02:00
|
|
|
(void *) context,
|
|
|
|
QTW_IGNORE_JOINALIASES);
|
2004-05-26 06:41:50 +02:00
|
|
|
context->rtables = list_delete_first(context->rtables);
|
2002-07-16 07:53:34 +02:00
|
|
|
return result;
|
|
|
|
}
|
2008-08-07 03:11:52 +02:00
|
|
|
else if (IsA(node, SetOperationStmt))
|
|
|
|
{
|
|
|
|
SetOperationStmt *setop = (SetOperationStmt *) node;
|
|
|
|
|
|
|
|
/* we need to look at the groupClauses for operator references */
|
|
|
|
find_expr_references_walker((Node *) setop->groupClauses, context);
|
|
|
|
/* fall through to examine child nodes */
|
|
|
|
}
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
else if (IsA(node, RangeTblFunction))
|
|
|
|
{
|
|
|
|
RangeTblFunction *rtfunc = (RangeTblFunction *) node;
|
|
|
|
ListCell *ct;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add refs for any datatypes and collations used in a column
|
|
|
|
* definition list for a RECORD function. (For other cases, it should
|
|
|
|
* be enough to depend on the function itself.)
|
|
|
|
*/
|
|
|
|
foreach(ct, rtfunc->funccoltypes)
|
|
|
|
{
|
|
|
|
add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
foreach(ct, rtfunc->funccolcollations)
|
|
|
|
{
|
|
|
|
Oid collid = lfirst_oid(ct);
|
|
|
|
|
|
|
|
if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
|
|
|
|
add_object_address(OCLASS_COLLATION, collid, 0,
|
|
|
|
context->addrs);
|
|
|
|
}
|
|
|
|
}
|
Redesign tablesample method API, and do extensive code review.
The original implementation of TABLESAMPLE modeled the tablesample method
API on index access methods, which wasn't a good choice because, without
specialized DDL commands, there's no way to build an extension that can
implement a TSM. (Raw inserts into system catalogs are not an acceptable
thing to do, because we can't undo them during DROP EXTENSION, nor will
pg_upgrade behave sanely.) Instead adopt an API more like procedural
language handlers or foreign data wrappers, wherein the only SQL-level
support object needed is a single handler function identified by having
a special return type. This lets us get rid of the supporting catalog
altogether, so that no custom DDL support is needed for the feature.
Adjust the API so that it can support non-constant tablesample arguments
(the original coding assumed we could evaluate the argument expressions at
ExecInitSampleScan time, which is undesirable even if it weren't outright
unsafe), and discourage sampling methods from looking at invisible tuples.
Make sure that the BERNOULLI and SYSTEM methods are genuinely repeatable
within and across queries, as required by the SQL standard, and deal more
honestly with methods that can't support that requirement.
Make a full code-review pass over the tablesample additions, and fix
assorted bugs, omissions, infelicities, and cosmetic issues (such as
failure to put the added code stanzas in a consistent ordering).
Improve EXPLAIN's output of tablesample plans, too.
Back-patch to 9.5 so that we don't have to support the original API
in production.
2015-07-25 20:39:00 +02:00
|
|
|
else if (IsA(node, TableSampleClause))
|
|
|
|
{
|
|
|
|
TableSampleClause *tsc = (TableSampleClause *) node;
|
|
|
|
|
|
|
|
add_object_address(OCLASS_PROC, tsc->tsmhandler, 0,
|
|
|
|
context->addrs);
|
|
|
|
/* fall through to examine arguments */
|
|
|
|
}
|
2008-08-07 03:11:52 +02:00
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
return expression_tree_walker(node, find_expr_references_walker,
|
|
|
|
(void *) context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given an array of dependency references, eliminate any duplicates.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
eliminate_duplicate_dependencies(ObjectAddresses *addrs)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddress *priorobj;
|
2002-07-16 07:53:34 +02:00
|
|
|
int oldref,
|
|
|
|
newrefs;
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* We can't sort if the array has "extra" data, because there's no way to
|
|
|
|
* keep it in sync. Fortunately that combination of features is not
|
|
|
|
* needed.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
|
|
|
Assert(!addrs->extras);
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
if (addrs->numrefs <= 1)
|
|
|
|
return; /* nothing to do */
|
|
|
|
|
|
|
|
/* Sort the refs so that duplicates are adjacent */
|
|
|
|
qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress),
|
|
|
|
object_address_comparator);
|
|
|
|
|
|
|
|
/* Remove dups */
|
|
|
|
priorobj = addrs->refs;
|
|
|
|
newrefs = 1;
|
|
|
|
for (oldref = 1; oldref < addrs->numrefs; oldref++)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddress *thisobj = addrs->refs + oldref;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
if (priorobj->classId == thisobj->classId &&
|
|
|
|
priorobj->objectId == thisobj->objectId)
|
|
|
|
{
|
|
|
|
if (priorobj->objectSubId == thisobj->objectSubId)
|
|
|
|
continue; /* identical, so drop thisobj */
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we have a whole-object reference and a reference to a part
|
|
|
|
* of the same object, we don't need the whole-object reference
|
|
|
|
* (for example, we don't need to reference both table foo and
|
|
|
|
* column foo.bar). The whole-object reference will always appear
|
|
|
|
* first in the sorted list.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
|
|
|
if (priorobj->objectSubId == 0)
|
|
|
|
{
|
|
|
|
/* replace whole ref with partial */
|
|
|
|
priorobj->objectSubId = thisobj->objectSubId;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Not identical, so add thisobj to output set */
|
|
|
|
priorobj++;
|
2008-06-09 00:41:04 +02:00
|
|
|
*priorobj = *thisobj;
|
2002-07-16 07:53:34 +02:00
|
|
|
newrefs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
addrs->numrefs = newrefs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qsort comparator for ObjectAddress items
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
object_address_comparator(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const ObjectAddress *obja = (const ObjectAddress *) a;
|
|
|
|
const ObjectAddress *objb = (const ObjectAddress *) b;
|
|
|
|
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
/*
|
|
|
|
* Primary sort key is OID descending. Most of the time, this will result
|
|
|
|
* in putting newer objects before older ones, which is likely to be the
|
|
|
|
* right order to delete in.
|
|
|
|
*/
|
|
|
|
if (obja->objectId > objb->objectId)
|
2002-07-16 07:53:34 +02:00
|
|
|
return -1;
|
|
|
|
if (obja->objectId < objb->objectId)
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Next sort on catalog ID, in case identical OIDs appear in different
|
|
|
|
* catalogs. Sort direction is pretty arbitrary here.
|
|
|
|
*/
|
|
|
|
if (obja->classId < objb->classId)
|
2002-07-16 07:53:34 +02:00
|
|
|
return -1;
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
if (obja->classId > objb->classId)
|
2002-07-16 07:53:34 +02:00
|
|
|
return 1;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
Sort the dependent objects before recursing in findDependentObjects().
Historically, the notices output by DROP CASCADE tended to come out
in uncertain order, and in some cases you might get different claims
about which object depends on which other one. This is because we
just traversed the dependency tree in the order in which pg_depend
entries are seen, and nbtree has never promised anything about the
order of equal-keyed index entries. We've put up with that for years,
hacking regression tests when necessary to prevent them from emitting
unstable output. However, it's a problem for pending work that will
change nbtree's behavior for equal keys, as that causes unexpected
changes in the regression test results.
Hence, adjust findDependentObjects to sort the results of each
indexscan before processing them. The sort is on descending OID of
the dependent objects, hence more or less reverse creation order.
While this rule could still result in bogus regression test failures
if an OID wraparound occurred mid-test, that seems unlikely to happen
in any plausible development or packaging-test scenario.
This is enough to ensure output stability for ordinary DROP CASCADE
commands, but not for DROP OWNED BY, because that has a different
code path with the same problem. We might later choose to sort in
the DROP OWNED BY code as well, but this patch doesn't do so.
I've also not done anything about reverting the existing hacks to
suppress unstable DROP CASCADE output in specific regression tests.
It might be worth undoing those, but it seems like a distinct question.
The first indexscan loop in findDependentObjects is not touched,
meaning there is a hazard of unstable error reports from that too.
However, said hazard is not the fault of that code: it was designed
on the assumption that there could be at most one "owning" object
to complain about, and that assumption does not seem unreasonable.
The recent patch that added the possibility of multiple
DEPENDENCY_INTERNAL_AUTO links broke that assumption, but we should
fix that situation not band-aid around it. That's a matter for
another patch, though.
Discussion: https://postgr.es/m/12244.1547854440@sss.pgh.pa.us
2019-01-21 19:48:07 +01:00
|
|
|
* Last, sort on object subId.
|
|
|
|
*
|
|
|
|
* We sort the subId as an unsigned int so that 0 (the whole object) will
|
|
|
|
* come first. This is essential for eliminate_duplicate_dependencies,
|
|
|
|
* and is also the best order for findDependentObjects.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
|
|
|
if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId)
|
|
|
|
return -1;
|
|
|
|
if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routines for handling an expansible array of ObjectAddress items.
|
|
|
|
*
|
2006-08-20 23:56:16 +02:00
|
|
|
* new_object_addresses: create a new ObjectAddresses array.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
2006-08-20 23:56:16 +02:00
|
|
|
ObjectAddresses *
|
|
|
|
new_object_addresses(void)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
ObjectAddresses *addrs;
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
addrs = palloc(sizeof(ObjectAddresses));
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
addrs->numrefs = 0;
|
2006-08-20 23:56:16 +02:00
|
|
|
addrs->maxrefs = 32;
|
2002-07-16 07:53:34 +02:00
|
|
|
addrs->refs = (ObjectAddress *)
|
|
|
|
palloc(addrs->maxrefs * sizeof(ObjectAddress));
|
2008-06-09 00:41:04 +02:00
|
|
|
addrs->extras = NULL; /* until/unless needed */
|
2006-08-20 23:56:16 +02:00
|
|
|
|
|
|
|
return addrs;
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an entry to an ObjectAddresses array.
|
|
|
|
*
|
|
|
|
* It is convenient to specify the class by ObjectClass rather than directly
|
|
|
|
* by catalog OID.
|
|
|
|
*/
|
|
|
|
static void
|
2004-05-05 06:48:48 +02:00
|
|
|
add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
|
2002-07-16 07:53:34 +02:00
|
|
|
ObjectAddresses *addrs)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddress *item;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2015-07-21 13:20:53 +02:00
|
|
|
/*
|
|
|
|
* Make sure object_classes is kept up to date with the ObjectClass enum.
|
|
|
|
*/
|
|
|
|
StaticAssertStmt(lengthof(object_classes) == LAST_OCLASS + 1,
|
|
|
|
"object_classes[] must cover all ObjectClasses");
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/* enlarge array if needed */
|
|
|
|
if (addrs->numrefs >= addrs->maxrefs)
|
|
|
|
{
|
|
|
|
addrs->maxrefs *= 2;
|
|
|
|
addrs->refs = (ObjectAddress *)
|
|
|
|
repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
|
2008-06-09 00:41:04 +02:00
|
|
|
Assert(!addrs->extras);
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
/* record this item */
|
|
|
|
item = addrs->refs + addrs->numrefs;
|
|
|
|
item->classId = object_classes[oclass];
|
|
|
|
item->objectId = objectId;
|
|
|
|
item->objectSubId = subId;
|
|
|
|
addrs->numrefs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an entry to an ObjectAddresses array.
|
|
|
|
*
|
|
|
|
* As above, but specify entry exactly.
|
|
|
|
*/
|
2006-08-20 23:56:16 +02:00
|
|
|
void
|
2002-07-16 07:53:34 +02:00
|
|
|
add_exact_object_address(const ObjectAddress *object,
|
|
|
|
ObjectAddresses *addrs)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
ObjectAddress *item;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
|
|
|
/* enlarge array if needed */
|
|
|
|
if (addrs->numrefs >= addrs->maxrefs)
|
|
|
|
{
|
|
|
|
addrs->maxrefs *= 2;
|
|
|
|
addrs->refs = (ObjectAddress *)
|
|
|
|
repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
|
2008-06-09 00:41:04 +02:00
|
|
|
Assert(!addrs->extras);
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
/* record this item */
|
|
|
|
item = addrs->refs + addrs->numrefs;
|
|
|
|
*item = *object;
|
|
|
|
addrs->numrefs++;
|
|
|
|
}
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* Add an entry to an ObjectAddresses array.
|
|
|
|
*
|
|
|
|
* As above, but specify entry exactly and provide some "extra" data too.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
add_exact_object_address_extra(const ObjectAddress *object,
|
|
|
|
const ObjectAddressExtra *extra,
|
|
|
|
ObjectAddresses *addrs)
|
|
|
|
{
|
|
|
|
ObjectAddress *item;
|
|
|
|
ObjectAddressExtra *itemextra;
|
|
|
|
|
|
|
|
/* allocate extra space if first time */
|
|
|
|
if (!addrs->extras)
|
|
|
|
addrs->extras = (ObjectAddressExtra *)
|
|
|
|
palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
|
|
|
|
|
|
|
|
/* enlarge array if needed */
|
|
|
|
if (addrs->numrefs >= addrs->maxrefs)
|
|
|
|
{
|
|
|
|
addrs->maxrefs *= 2;
|
|
|
|
addrs->refs = (ObjectAddress *)
|
|
|
|
repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress));
|
|
|
|
addrs->extras = (ObjectAddressExtra *)
|
2009-06-11 16:49:15 +02:00
|
|
|
repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra));
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
/* record this item */
|
|
|
|
item = addrs->refs + addrs->numrefs;
|
|
|
|
*item = *object;
|
|
|
|
itemextra = addrs->extras + addrs->numrefs;
|
|
|
|
*itemextra = *extra;
|
|
|
|
addrs->numrefs++;
|
|
|
|
}
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
2002-09-22 02:37:09 +02:00
|
|
|
* Test whether an object is present in an ObjectAddresses array.
|
|
|
|
*
|
|
|
|
* We return "true" if object is a subobject of something in the array, too.
|
2002-07-16 07:53:34 +02:00
|
|
|
*/
|
2006-08-20 23:56:16 +02:00
|
|
|
bool
|
2002-09-22 02:37:09 +02:00
|
|
|
object_address_present(const ObjectAddress *object,
|
2008-06-09 00:41:04 +02:00
|
|
|
const ObjectAddresses *addrs)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2002-09-22 02:37:09 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = addrs->numrefs - 1; i >= 0; i--)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2008-06-09 00:41:04 +02:00
|
|
|
const ObjectAddress *thisobj = addrs->refs + i;
|
2002-07-16 07:53:34 +02:00
|
|
|
|
2002-09-22 02:37:09 +02:00
|
|
|
if (object->classId == thisobj->classId &&
|
|
|
|
object->objectId == thisobj->objectId)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
2002-09-22 02:37:09 +02:00
|
|
|
if (object->objectSubId == thisobj->objectSubId ||
|
|
|
|
thisobj->objectSubId == 0)
|
|
|
|
return true;
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-22 02:37:09 +02:00
|
|
|
return false;
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
|
2008-06-09 00:41:04 +02:00
|
|
|
/*
|
|
|
|
* As above, except that if the object is present then also OR the given
|
|
|
|
* flags into its associated extra data (which must exist).
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
object_address_present_add_flags(const ObjectAddress *object,
|
|
|
|
int flags,
|
|
|
|
ObjectAddresses *addrs)
|
|
|
|
{
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
bool result = false;
|
2008-06-09 00:41:04 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = addrs->numrefs - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
ObjectAddress *thisobj = addrs->refs + i;
|
|
|
|
|
|
|
|
if (object->classId == thisobj->classId &&
|
|
|
|
object->objectId == thisobj->objectId)
|
|
|
|
{
|
|
|
|
if (object->objectSubId == thisobj->objectSubId)
|
|
|
|
{
|
|
|
|
ObjectAddressExtra *thisextra = addrs->extras + i;
|
|
|
|
|
|
|
|
thisextra->flags |= flags;
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
result = true;
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
else if (thisobj->objectSubId == 0)
|
2008-06-09 00:41:04 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We get here if we find a need to delete a column after
|
2014-05-06 18:12:18 +02:00
|
|
|
* having already decided to drop its whole table. Obviously
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
* we no longer need to drop the subobject, so report that we
|
|
|
|
* found the subobject in the array. But don't plaster its
|
|
|
|
* flags on the whole object.
|
2008-06-09 00:41:04 +02:00
|
|
|
*/
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
else if (object->objectSubId == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We get here if we find a need to delete a whole table after
|
|
|
|
* having already decided to drop one of its columns. We
|
|
|
|
* can't report that the whole object is in the array, but we
|
|
|
|
* should mark the subobject with the whole object's flags.
|
|
|
|
*
|
|
|
|
* It might seem attractive to physically delete the column's
|
|
|
|
* array entry, or at least mark it as no longer needing
|
|
|
|
* separate deletion. But that could lead to, e.g., dropping
|
|
|
|
* the column's datatype before we drop the table, which does
|
|
|
|
* not seem like a good idea. This is a very rare situation
|
|
|
|
* in practice, so we just take the hit of doing a separate
|
|
|
|
* DROP COLUMN action even though we know we're gonna delete
|
|
|
|
* the table later.
|
|
|
|
*
|
2019-01-18 17:05:11 +01:00
|
|
|
* What we can do, though, is mark this as a subobject so that
|
|
|
|
* we don't report it separately, which is confusing because
|
|
|
|
* it's unpredictable whether it happens or not. But do so
|
|
|
|
* only if flags != 0 (flags == 0 is a read-only probe).
|
|
|
|
*
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
* Because there could be other subobjects of this object in
|
|
|
|
* the array, this case means we always have to loop through
|
|
|
|
* the whole array; we cannot exit early on a match.
|
|
|
|
*/
|
|
|
|
ObjectAddressExtra *thisextra = addrs->extras + i;
|
|
|
|
|
2019-01-18 17:05:11 +01:00
|
|
|
if (flags)
|
|
|
|
thisextra->flags |= (flags | DEPFLAG_SUBOBJECT);
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
return result;
|
2008-06-09 00:41:04 +02:00
|
|
|
}
|
|
|
|
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
/*
|
|
|
|
* Similar to above, except we search an ObjectAddressStack.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
stack_address_present_add_flags(const ObjectAddress *object,
|
|
|
|
int flags,
|
|
|
|
ObjectAddressStack *stack)
|
|
|
|
{
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
bool result = false;
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
ObjectAddressStack *stackptr;
|
|
|
|
|
|
|
|
for (stackptr = stack; stackptr; stackptr = stackptr->next)
|
|
|
|
{
|
|
|
|
const ObjectAddress *thisobj = stackptr->object;
|
|
|
|
|
|
|
|
if (object->classId == thisobj->classId &&
|
|
|
|
object->objectId == thisobj->objectId)
|
|
|
|
{
|
|
|
|
if (object->objectSubId == thisobj->objectSubId)
|
|
|
|
{
|
|
|
|
stackptr->flags |= flags;
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
else if (thisobj->objectSubId == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We're visiting a column with whole table already on stack.
|
|
|
|
* As in object_address_present_add_flags(), we can skip
|
|
|
|
* further processing of the subobject, but we don't want to
|
|
|
|
* propagate flags for the subobject to the whole object.
|
|
|
|
*/
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
else if (object->objectSubId == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We're visiting a table with column already on stack. As in
|
|
|
|
* object_address_present_add_flags(), we should propagate
|
|
|
|
* flags for the whole object to each of its subobjects.
|
|
|
|
*/
|
2019-01-18 17:05:11 +01:00
|
|
|
if (flags)
|
|
|
|
stackptr->flags |= (flags | DEPFLAG_SUBOBJECT);
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix dependency searching for case where column is visited before table.
When the recursive search in dependency.c visits a column and then later
visits the whole table containing the column, it needs to propagate the
drop-context flags for the table to the existing target-object entry for
the column. Otherwise we might refuse the DROP (if not CASCADE) on the
incorrect grounds that there was no automatic drop pathway to the column.
Remarkably, this has not been reported before, though it's possible at
least when an extension creates both a datatype and a table using that
datatype.
Rather than just marking the column as allowed to be dropped, it might
seem good to skip the DROP COLUMN step altogether, since the later DROP
of the table will surely get the job done. The problem with that is that
the datatype would then be dropped before the table (since the whole
situation occurred because we visited the datatype, and then recursed to
the dependent column, before visiting the table). That seems pretty risky,
and the case is rare enough that it doesn't seem worth expending a lot of
effort or risk to make the drops happen in a safe order. So we just play
dumb and delete the column separately according to the existing drop
ordering rules.
Per report from Petr Jelinek, though this is different from his proposed
patch.
Back-patch to 9.1, where extensions were introduced. There's currently
no evidence that such cases can arise before 9.1, and in any case we would
also need to back-patch cb5c2ba2d82688d29b5902d86b993a54355cad4d to 9.0
if we wanted to back-patch this.
2014-11-11 23:00:11 +01:00
|
|
|
return result;
|
Fix multiple bugs in extension dropping.
When we implemented extensions, we made findDependentObjects() treat
EXTENSION dependency links similarly to INTERNAL links. However, that
logic contained an implicit assumption that an object could have at most
one INTERNAL dependency, so it did not work correctly for objects having
both INTERNAL and DEPENDENCY links. This led to failure to drop some
extension member objects when dropping the extension. Furthermore, we'd
never actually exercised the case of recursing to an internally-referenced
(owning) object from anything other than a NORMAL dependency, and it turns
out that passing the incoming dependency's flags to the owning object is
the Wrong Thing. This led to sometimes dropping a whole extension silently
when we should have rejected the drop command for lack of CASCADE.
Since we obviously were under-testing extension drop scenarios, add some
regression test cases. Unfortunately, such test cases require some
extensions (duh), so we can't test for problems in the core regression
tests. I chose to add them to the earthdistance contrib module, which is
a good test case because it has a dependency on the cube contrib module.
Back-patch to 9.1. Arguably these are pre-existing bugs in INTERNAL
dependency handling, but since it appears that the cases can never arise
pre-9.1, I'll refrain from back-patching the logic changes further than
that.
2011-08-24 19:09:06 +02:00
|
|
|
}
|
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
/*
|
|
|
|
* Record multiple dependencies from an ObjectAddresses array, after first
|
|
|
|
* removing any duplicates.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
record_object_address_dependencies(const ObjectAddress *depender,
|
|
|
|
ObjectAddresses *referenced,
|
|
|
|
DependencyType behavior)
|
|
|
|
{
|
|
|
|
eliminate_duplicate_dependencies(referenced);
|
|
|
|
recordMultipleDependencies(depender,
|
|
|
|
referenced->refs, referenced->numrefs,
|
|
|
|
behavior);
|
|
|
|
}
|
|
|
|
|
2019-03-20 23:06:29 +01:00
|
|
|
/*
|
|
|
|
* Sort the items in an ObjectAddresses array.
|
|
|
|
*
|
|
|
|
* The major sort key is OID-descending, so that newer objects will be listed
|
|
|
|
* first in most cases. This is primarily useful for ensuring stable outputs
|
|
|
|
* from regression tests; it's not recommended if the order of the objects is
|
|
|
|
* determined by user input, such as the order of targets in a DROP command.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sort_object_addresses(ObjectAddresses *addrs)
|
|
|
|
{
|
|
|
|
if (addrs->numrefs > 1)
|
|
|
|
qsort((void *) addrs->refs, addrs->numrefs,
|
|
|
|
sizeof(ObjectAddress),
|
|
|
|
object_address_comparator);
|
|
|
|
}
|
|
|
|
|
2002-07-16 07:53:34 +02:00
|
|
|
/*
|
|
|
|
* Clean up when done with an ObjectAddresses array.
|
|
|
|
*/
|
2006-08-20 23:56:16 +02:00
|
|
|
void
|
|
|
|
free_object_addresses(ObjectAddresses *addrs)
|
2002-07-16 07:53:34 +02:00
|
|
|
{
|
|
|
|
pfree(addrs->refs);
|
2008-06-09 00:41:04 +02:00
|
|
|
if (addrs->extras)
|
|
|
|
pfree(addrs->extras);
|
2006-08-20 23:56:16 +02:00
|
|
|
pfree(addrs);
|
2002-07-16 07:53:34 +02:00
|
|
|
}
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
|
|
|
* Determine the class of a given object identified by objectAddress.
|
|
|
|
*
|
2005-04-14 22:03:27 +02:00
|
|
|
* This function is essentially the reverse mapping for the object_classes[]
|
|
|
|
* table. We implement it as a function because the OIDs aren't consecutive.
|
2002-07-12 20:43:19 +02:00
|
|
|
*/
|
2004-05-05 06:48:48 +02:00
|
|
|
ObjectClass
|
2002-07-12 20:43:19 +02:00
|
|
|
getObjectClass(const ObjectAddress *object)
|
|
|
|
{
|
2010-11-18 20:33:48 +01:00
|
|
|
/* only pg_class entries can have nonzero objectSubId */
|
|
|
|
if (object->classId != RelationRelationId &&
|
|
|
|
object->objectSubId != 0)
|
2013-03-20 22:19:19 +01:00
|
|
|
elog(ERROR, "invalid non-zero objectSubId for object class %u",
|
2010-11-18 20:33:48 +01:00
|
|
|
object->classId);
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
switch (object->classId)
|
|
|
|
{
|
2005-04-14 03:38:22 +02:00
|
|
|
case RelationRelationId:
|
2002-07-12 20:43:19 +02:00
|
|
|
/* caller must check objectSubId */
|
|
|
|
return OCLASS_CLASS;
|
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
case ProcedureRelationId:
|
2002-07-12 20:43:19 +02:00
|
|
|
return OCLASS_PROC;
|
|
|
|
|
2005-04-14 03:38:22 +02:00
|
|
|
case TypeRelationId:
|
2002-07-12 20:43:19 +02:00
|
|
|
return OCLASS_TYPE;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
case CastRelationId:
|
|
|
|
return OCLASS_CAST;
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case CollationRelationId:
|
|
|
|
return OCLASS_COLLATION;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
case ConstraintRelationId:
|
|
|
|
return OCLASS_CONSTRAINT;
|
|
|
|
|
|
|
|
case ConversionRelationId:
|
|
|
|
return OCLASS_CONVERSION;
|
|
|
|
|
|
|
|
case AttrDefaultRelationId:
|
|
|
|
return OCLASS_DEFAULT;
|
|
|
|
|
|
|
|
case LanguageRelationId:
|
|
|
|
return OCLASS_LANGUAGE;
|
|
|
|
|
2009-12-11 04:34:57 +01:00
|
|
|
case LargeObjectRelationId:
|
|
|
|
return OCLASS_LARGEOBJECT;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
case OperatorRelationId:
|
|
|
|
return OCLASS_OPERATOR;
|
|
|
|
|
|
|
|
case OperatorClassRelationId:
|
|
|
|
return OCLASS_OPCLASS;
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
case OperatorFamilyRelationId:
|
|
|
|
return OCLASS_OPFAMILY;
|
|
|
|
|
2016-03-24 03:01:35 +01:00
|
|
|
case AccessMethodRelationId:
|
|
|
|
return OCLASS_AM;
|
|
|
|
|
2006-12-23 01:43:13 +01:00
|
|
|
case AccessMethodOperatorRelationId:
|
|
|
|
return OCLASS_AMOP;
|
|
|
|
|
|
|
|
case AccessMethodProcedureRelationId:
|
|
|
|
return OCLASS_AMPROC;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
case RewriteRelationId:
|
|
|
|
return OCLASS_REWRITE;
|
|
|
|
|
|
|
|
case TriggerRelationId:
|
|
|
|
return OCLASS_TRIGGER;
|
|
|
|
|
|
|
|
case NamespaceRelationId:
|
|
|
|
return OCLASS_SCHEMA;
|
2005-07-07 22:40:02 +02:00
|
|
|
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
case StatisticExtRelationId:
|
|
|
|
return OCLASS_STATISTIC_EXT;
|
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
case TSParserRelationId:
|
|
|
|
return OCLASS_TSPARSER;
|
|
|
|
|
|
|
|
case TSDictionaryRelationId:
|
|
|
|
return OCLASS_TSDICT;
|
|
|
|
|
|
|
|
case TSTemplateRelationId:
|
|
|
|
return OCLASS_TSTEMPLATE;
|
|
|
|
|
|
|
|
case TSConfigRelationId:
|
|
|
|
return OCLASS_TSCONFIG;
|
|
|
|
|
2005-07-07 22:40:02 +02:00
|
|
|
case AuthIdRelationId:
|
|
|
|
return OCLASS_ROLE;
|
|
|
|
|
|
|
|
case DatabaseRelationId:
|
|
|
|
return OCLASS_DATABASE;
|
|
|
|
|
|
|
|
case TableSpaceRelationId:
|
|
|
|
return OCLASS_TBLSPACE;
|
2008-12-19 17:25:19 +01:00
|
|
|
|
|
|
|
case ForeignDataWrapperRelationId:
|
|
|
|
return OCLASS_FDW;
|
|
|
|
|
|
|
|
case ForeignServerRelationId:
|
|
|
|
return OCLASS_FOREIGN_SERVER;
|
|
|
|
|
|
|
|
case UserMappingRelationId:
|
|
|
|
return OCLASS_USER_MAPPING;
|
2009-10-05 21:24:49 +02:00
|
|
|
|
|
|
|
case DefaultAclRelationId:
|
|
|
|
return OCLASS_DEFACL;
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
case ExtensionRelationId:
|
|
|
|
return OCLASS_EXTENSION;
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
case EventTriggerRelationId:
|
|
|
|
return OCLASS_EVENT_TRIGGER;
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
|
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
2014-11-27 07:06:36 +01:00
|
|
|
case PolicyRelationId:
|
|
|
|
return OCLASS_POLICY;
|
2015-04-26 16:33:14 +02:00
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
case PublicationRelationId:
|
|
|
|
return OCLASS_PUBLICATION;
|
|
|
|
|
|
|
|
case PublicationRelRelationId:
|
|
|
|
return OCLASS_PUBLICATION_REL;
|
|
|
|
|
|
|
|
case SubscriptionRelationId:
|
|
|
|
return OCLASS_SUBSCRIPTION;
|
|
|
|
|
2015-04-26 16:33:14 +02:00
|
|
|
case TransformRelationId:
|
|
|
|
return OCLASS_TRANSFORM;
|
2002-07-18 18:47:26 +02:00
|
|
|
}
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
/* shouldn't get here */
|
2003-07-21 03:59:11 +02:00
|
|
|
elog(ERROR, "unrecognized object class: %u", object->classId);
|
2002-07-12 20:43:19 +02:00
|
|
|
return OCLASS_CLASS; /* keep compiler quiet */
|
|
|
|
}
|
2016-04-07 03:45:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* delete initial ACL for extension objects
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
DeleteInitPrivs(const ObjectAddress *object)
|
|
|
|
{
|
|
|
|
Relation relation;
|
|
|
|
ScanKeyData key[3];
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple oldtuple;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
relation = table_open(InitPrivsRelationId, RowExclusiveLock);
|
2016-04-07 03:45:32 +02:00
|
|
|
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_init_privs_objoid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->objectId));
|
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
Anum_pg_init_privs_classoid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(object->classId));
|
|
|
|
ScanKeyInit(&key[2],
|
|
|
|
Anum_pg_init_privs_objsubid,
|
|
|
|
BTEqualStrategyNumber, F_INT4EQ,
|
|
|
|
Int32GetDatum(object->objectSubId));
|
|
|
|
|
|
|
|
scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
|
|
|
|
NULL, 3, key);
|
|
|
|
|
|
|
|
while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(relation, &oldtuple->t_self);
|
2016-04-07 03:45:32 +02:00
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(relation, RowExclusiveLock);
|
2016-04-07 03:45:32 +02:00
|
|
|
}
|