2002-04-15 07:22:04 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* typecmds.c
|
|
|
|
* Routines for SQL commands that manipulate types (and domains).
|
|
|
|
*
|
2016-01-02 19:33:40 +01:00
|
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
2002-04-15 07:22:04 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/commands/typecmds.c
|
2002-04-15 07:22:04 +02:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The "DefineFoo" routines take the parse tree and pick out the
|
|
|
|
* appropriate arguments/flags, passing the results to the
|
|
|
|
* corresponding "FooDefine" routines (in src/catalog) that do
|
|
|
|
* the actual catalog-munging. These routines also verify permission
|
|
|
|
* of the user to execute the command.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* These things must be defined and committed in the following order:
|
|
|
|
* "create function":
|
2003-05-09 00:19:58 +02:00
|
|
|
* input/output, recv/send functions
|
2002-04-15 07:22:04 +02:00
|
|
|
* "create type":
|
|
|
|
* type
|
|
|
|
* "create operator":
|
|
|
|
* operators
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/xact.h"
|
2013-12-19 22:10:01 +01:00
|
|
|
#include "catalog/binary_upgrade.h"
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
#include "catalog/catalog.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "catalog/heap.h"
|
2013-03-18 03:55:14 +01:00
|
|
|
#include "catalog/objectaccess.h"
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
#include "catalog/pg_am.h"
|
2012-05-31 05:47:57 +02:00
|
|
|
#include "catalog/pg_authid.h"
|
2011-02-08 22:04:18 +01:00
|
|
|
#include "catalog/pg_collation.h"
|
2002-11-15 03:50:21 +01:00
|
|
|
#include "catalog/pg_constraint.h"
|
2016-02-11 21:51:28 +01:00
|
|
|
#include "catalog/pg_constraint_fn.h"
|
2003-01-04 01:46:08 +01:00
|
|
|
#include "catalog/pg_depend.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
#include "catalog/pg_enum.h"
|
2011-11-03 12:16:28 +01:00
|
|
|
#include "catalog/pg_language.h"
|
2005-08-01 06:03:59 +02:00
|
|
|
#include "catalog/pg_namespace.h"
|
2011-11-03 12:16:28 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_proc_fn.h"
|
|
|
|
#include "catalog/pg_range.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2008-03-27 04:57:34 +01:00
|
|
|
#include "catalog/pg_type_fn.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "commands/defrem.h"
|
2002-08-15 18:36:08 +02:00
|
|
|
#include "commands/tablecmds.h"
|
2002-12-06 06:00:34 +01:00
|
|
|
#include "commands/typecmds.h"
|
|
|
|
#include "executor/executor.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "miscadmin.h"
|
2006-03-14 23:48:25 +01:00
|
|
|
#include "nodes/makefuncs.h"
|
2002-11-15 03:50:21 +01:00
|
|
|
#include "optimizer/var.h"
|
|
|
|
#include "parser/parse_coerce.h"
|
2011-03-20 01:29:08 +01:00
|
|
|
#include "parser/parse_collate.h"
|
2002-11-15 03:50:21 +01:00
|
|
|
#include "parser/parse_expr.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "parser/parse_func.h"
|
|
|
|
#include "parser/parse_type.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/fmgroids.h"
|
2002-04-27 05:45:03 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2005-05-06 19:24:55 +02:00
|
|
|
#include "utils/memutils.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2014-10-08 23:10:47 +02:00
|
|
|
#include "utils/ruleutils.h"
|
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
|
|
|
#include "utils/snapmgr.h"
|
2002-04-15 07:22:04 +02:00
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
|
|
|
|
/* result structure for get_rels_with_domain() */
|
|
|
|
typedef struct
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
Relation rel; /* opened and locked relation */
|
|
|
|
int natts; /* number of attributes of interest */
|
|
|
|
int *atts; /* attribute numbers */
|
2003-01-04 01:46:08 +01:00
|
|
|
/* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
|
2003-08-08 23:42:59 +02:00
|
|
|
} RelToCheck;
|
2003-01-04 01:46:08 +01:00
|
|
|
|
2015-03-11 03:33:25 +01:00
|
|
|
/* Potentially set by pg_upgrade_support functions */
|
2011-01-08 03:25:34 +01:00
|
|
|
Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
|
2003-01-04 01:46:08 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
static void makeRangeConstructors(const char *name, Oid namespace,
|
|
|
|
Oid rangeOid, Oid subtype);
|
2003-05-09 00:19:58 +02:00
|
|
|
static Oid findTypeInputFunction(List *procname, Oid typeOid);
|
|
|
|
static Oid findTypeOutputFunction(List *procname, Oid typeOid);
|
|
|
|
static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
|
|
|
|
static Oid findTypeSendFunction(List *procname, Oid typeOid);
|
2006-12-30 22:21:56 +01:00
|
|
|
static Oid findTypeTypmodinFunction(List *procname);
|
|
|
|
static Oid findTypeTypmodoutFunction(List *procname);
|
2004-02-13 00:41:04 +01:00
|
|
|
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
|
2011-11-21 22:19:53 +01:00
|
|
|
static Oid findRangeSubOpclass(List *opcname, Oid subtype);
|
2011-11-14 18:08:48 +01:00
|
|
|
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
|
2011-11-21 22:19:53 +01:00
|
|
|
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
|
2011-11-14 18:08:48 +01:00
|
|
|
static void validateDomainConstraint(Oid domainoid, char *ccbin);
|
2003-01-04 01:46:08 +01:00
|
|
|
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
|
2010-10-25 05:04:37 +02:00
|
|
|
static void checkEnumOwner(HeapTuple tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
|
2003-08-04 02:43:34 +02:00
|
|
|
Oid baseTypeOid,
|
|
|
|
int typMod, Constraint *constr,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
char *domainName, ObjectAddress *constrAddr);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* DefineType
|
2008-07-31 18:27:16 +02:00
|
|
|
* Registers a new base type.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2016-09-06 18:00:00 +02:00
|
|
|
DefineType(ParseState *pstate, List *names, List *parameters)
|
2002-04-15 07:22:04 +02:00
|
|
|
{
|
|
|
|
char *typeName;
|
|
|
|
Oid typeNamespace;
|
2003-05-09 00:19:58 +02:00
|
|
|
int16 internalLength = -1; /* default: variable-length */
|
2002-04-15 07:22:04 +02:00
|
|
|
List *inputName = NIL;
|
|
|
|
List *outputName = NIL;
|
2003-05-09 00:19:58 +02:00
|
|
|
List *receiveName = NIL;
|
|
|
|
List *sendName = NIL;
|
2006-12-30 22:21:56 +01:00
|
|
|
List *typmodinName = NIL;
|
|
|
|
List *typmodoutName = NIL;
|
2004-02-13 00:41:04 +01:00
|
|
|
List *analyzeName = NIL;
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
char category = TYPCATEGORY_USER;
|
2008-07-30 21:35:13 +02:00
|
|
|
bool preferred = false;
|
2002-04-15 07:22:04 +02:00
|
|
|
char delimiter = DEFAULT_TYPDELIM;
|
2008-11-30 20:01:29 +01:00
|
|
|
Oid elemType = InvalidOid;
|
|
|
|
char *defaultValue = NULL;
|
|
|
|
bool byValue = false;
|
2002-04-15 07:22:04 +02:00
|
|
|
char alignment = 'i'; /* default alignment */
|
2003-08-04 02:43:34 +02:00
|
|
|
char storage = 'p'; /* default TOAST storage method */
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid collation = InvalidOid;
|
2009-06-11 16:49:15 +02:00
|
|
|
DefElem *likeTypeEl = NULL;
|
|
|
|
DefElem *internalLengthEl = NULL;
|
|
|
|
DefElem *inputNameEl = NULL;
|
|
|
|
DefElem *outputNameEl = NULL;
|
|
|
|
DefElem *receiveNameEl = NULL;
|
|
|
|
DefElem *sendNameEl = NULL;
|
|
|
|
DefElem *typmodinNameEl = NULL;
|
|
|
|
DefElem *typmodoutNameEl = NULL;
|
|
|
|
DefElem *analyzeNameEl = NULL;
|
|
|
|
DefElem *categoryEl = NULL;
|
|
|
|
DefElem *preferredEl = NULL;
|
|
|
|
DefElem *delimiterEl = NULL;
|
|
|
|
DefElem *elemTypeEl = NULL;
|
|
|
|
DefElem *defaultValueEl = NULL;
|
|
|
|
DefElem *byValueEl = NULL;
|
|
|
|
DefElem *alignmentEl = NULL;
|
|
|
|
DefElem *storageEl = NULL;
|
2011-04-10 17:42:00 +02:00
|
|
|
DefElem *collatableEl = NULL;
|
2002-04-15 07:22:04 +02:00
|
|
|
Oid inputOid;
|
|
|
|
Oid outputOid;
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid receiveOid = InvalidOid;
|
|
|
|
Oid sendOid = InvalidOid;
|
2006-12-30 22:21:56 +01:00
|
|
|
Oid typmodinOid = InvalidOid;
|
|
|
|
Oid typmodoutOid = InvalidOid;
|
2004-02-13 00:41:04 +01:00
|
|
|
Oid analyzeOid = InvalidOid;
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
char *array_type;
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid array_oid;
|
2002-04-15 07:22:04 +02:00
|
|
|
Oid typoid;
|
2002-08-22 02:01:51 +02:00
|
|
|
Oid resulttype;
|
2008-11-30 20:01:29 +01:00
|
|
|
ListCell *pl;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2008-07-31 18:27:16 +02:00
|
|
|
/*
|
|
|
|
* As of Postgres 8.4, we require superuser privilege to create a base
|
|
|
|
* type. This is simple paranoia: there are too many ways to mess up the
|
|
|
|
* system with an incorrect type definition (for instance, representation
|
2009-06-11 16:49:15 +02:00
|
|
|
* parameters that don't match what the C code expects). In practice it
|
|
|
|
* takes superuser privilege to create the I/O functions, and so the
|
2008-07-31 18:27:16 +02:00
|
|
|
* former requirement that you own the I/O functions pretty much forced
|
|
|
|
* superuserness anyway. We're just making doubly sure here.
|
|
|
|
*
|
|
|
|
* XXX re-enable NOT_USED code sections below if you remove this test.
|
|
|
|
*/
|
|
|
|
if (!superuser())
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("must be superuser to create a base type")));
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/* Convert list of names to a name and namespace */
|
|
|
|
typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
|
|
|
|
|
2008-07-31 18:27:16 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
/* XXX this is unnecessary given the superuser check above */
|
2002-04-27 05:45:03 +02:00
|
|
|
/* Check we have creation rights in target namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
2003-08-01 02:15:26 +02:00
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(typeNamespace));
|
2008-07-31 18:27:16 +02:00
|
|
|
#endif
|
2002-04-27 05:45:03 +02:00
|
|
|
|
2006-02-28 23:37:27 +01:00
|
|
|
/*
|
|
|
|
* Look to see if type already exists (presumably as a shell; if not,
|
2007-05-12 02:55:00 +02:00
|
|
|
* TypeCreate will complain).
|
2006-02-28 23:37:27 +01:00
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
typoid = GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
CStringGetDatum(typeName),
|
|
|
|
ObjectIdGetDatum(typeNamespace));
|
2007-05-12 02:55:00 +02:00
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If it's not a shell, see if it's an autogenerated array type, and if so
|
|
|
|
* rename it out of the way.
|
2007-05-12 02:55:00 +02:00
|
|
|
*/
|
|
|
|
if (OidIsValid(typoid) && get_typisdefined(typoid))
|
|
|
|
{
|
|
|
|
if (moveArrayTypeName(typoid, typeName, typeNamespace))
|
|
|
|
typoid = InvalidOid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If it doesn't exist, create it as a shell, so that the OID is known for
|
|
|
|
* use in the I/O function definitions.
|
2007-05-12 02:55:00 +02:00
|
|
|
*/
|
2006-02-28 23:37:27 +01:00
|
|
|
if (!OidIsValid(typoid))
|
|
|
|
{
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
address = TypeShellMake(typeName, typeNamespace, GetUserId());
|
2015-04-22 21:23:02 +02:00
|
|
|
typoid = address.objectId;
|
2006-02-28 23:37:27 +01:00
|
|
|
/* Make new shell type visible for modification below */
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the command was a parameterless CREATE TYPE, we're done ---
|
|
|
|
* creating the shell type was all we're supposed to do.
|
|
|
|
*/
|
|
|
|
if (parameters == NIL)
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2006-02-28 23:37:27 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Complain if dummy CREATE TYPE and entry already exists */
|
|
|
|
if (parameters == NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", typeName)));
|
|
|
|
}
|
|
|
|
|
2008-11-30 20:01:29 +01:00
|
|
|
/* Extract the parameters from the parameter list */
|
2002-04-15 07:22:04 +02:00
|
|
|
foreach(pl, parameters)
|
|
|
|
{
|
|
|
|
DefElem *defel = (DefElem *) lfirst(pl);
|
2008-11-30 20:01:29 +01:00
|
|
|
DefElem **defelp;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2008-11-30 20:01:29 +01:00
|
|
|
if (pg_strcasecmp(defel->defname, "like") == 0)
|
|
|
|
defelp = &likeTypeEl;
|
|
|
|
else if (pg_strcasecmp(defel->defname, "internallength") == 0)
|
|
|
|
defelp = &internalLengthEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "input") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &inputNameEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "output") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &outputNameEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "receive") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &receiveNameEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "send") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &sendNameEl;
|
2006-12-30 22:21:56 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &typmodinNameEl;
|
2006-12-30 22:21:56 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &typmodoutNameEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
|
|
|
|
pg_strcasecmp(defel->defname, "analyse") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &analyzeNameEl;
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "category") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &categoryEl;
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "preferred") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &preferredEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &delimiterEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "element") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &elemTypeEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "default") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &defaultValueEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &byValueEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "alignment") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &alignmentEl;
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strcasecmp(defel->defname, "storage") == 0)
|
2008-11-30 20:01:29 +01:00
|
|
|
defelp = &storageEl;
|
2011-02-08 22:04:18 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "collatable") == 0)
|
|
|
|
defelp = &collatableEl;
|
2002-04-15 07:22:04 +02:00
|
|
|
else
|
2008-11-30 20:01:29 +01:00
|
|
|
{
|
|
|
|
/* WARNING, not ERROR, for historical backwards-compatibility */
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("type attribute \"%s\" not recognized",
|
2016-09-06 18:00:00 +02:00
|
|
|
defel->defname),
|
|
|
|
parser_errposition(pstate, defel->location)));
|
2008-11-30 20:01:29 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*defelp != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2016-09-06 18:00:00 +02:00
|
|
|
errmsg("conflicting or redundant options"),
|
|
|
|
parser_errposition(pstate, defel->location)));
|
2008-11-30 20:01:29 +01:00
|
|
|
*defelp = defel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Now interpret the options; we do this separately so that LIKE can be
|
|
|
|
* overridden by other options regardless of the ordering in the parameter
|
|
|
|
* list.
|
2008-11-30 20:01:29 +01:00
|
|
|
*/
|
|
|
|
if (likeTypeEl)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Type likeType;
|
2008-11-30 20:01:29 +01:00
|
|
|
Form_pg_type likeForm;
|
|
|
|
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
|
2008-11-30 20:01:29 +01:00
|
|
|
likeForm = (Form_pg_type) GETSTRUCT(likeType);
|
|
|
|
internalLength = likeForm->typlen;
|
|
|
|
byValue = likeForm->typbyval;
|
|
|
|
alignment = likeForm->typalign;
|
|
|
|
storage = likeForm->typstorage;
|
|
|
|
ReleaseSysCache(likeType);
|
|
|
|
}
|
|
|
|
if (internalLengthEl)
|
|
|
|
internalLength = defGetTypeLength(internalLengthEl);
|
|
|
|
if (inputNameEl)
|
|
|
|
inputName = defGetQualifiedName(inputNameEl);
|
|
|
|
if (outputNameEl)
|
|
|
|
outputName = defGetQualifiedName(outputNameEl);
|
|
|
|
if (receiveNameEl)
|
|
|
|
receiveName = defGetQualifiedName(receiveNameEl);
|
|
|
|
if (sendNameEl)
|
|
|
|
sendName = defGetQualifiedName(sendNameEl);
|
|
|
|
if (typmodinNameEl)
|
|
|
|
typmodinName = defGetQualifiedName(typmodinNameEl);
|
|
|
|
if (typmodoutNameEl)
|
|
|
|
typmodoutName = defGetQualifiedName(typmodoutNameEl);
|
|
|
|
if (analyzeNameEl)
|
|
|
|
analyzeName = defGetQualifiedName(analyzeNameEl);
|
|
|
|
if (categoryEl)
|
|
|
|
{
|
|
|
|
char *p = defGetString(categoryEl);
|
|
|
|
|
|
|
|
category = p[0];
|
|
|
|
/* restrict to non-control ASCII */
|
|
|
|
if (category < 32 || category > 126)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2009-06-11 16:49:15 +02:00
|
|
|
errmsg("invalid type category \"%s\": must be simple ASCII",
|
|
|
|
p)));
|
2008-11-30 20:01:29 +01:00
|
|
|
}
|
|
|
|
if (preferredEl)
|
|
|
|
preferred = defGetBoolean(preferredEl);
|
|
|
|
if (delimiterEl)
|
|
|
|
{
|
|
|
|
char *p = defGetString(delimiterEl);
|
|
|
|
|
|
|
|
delimiter = p[0];
|
|
|
|
/* XXX shouldn't we restrict the delimiter? */
|
|
|
|
}
|
|
|
|
if (elemTypeEl)
|
|
|
|
{
|
2010-10-25 20:40:46 +02:00
|
|
|
elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
|
2008-11-30 20:01:29 +01:00
|
|
|
/* disallow arrays of pseudotypes */
|
|
|
|
if (get_typtype(elemType) == TYPTYPE_PSEUDO)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("array element type cannot be %s",
|
|
|
|
format_type_be(elemType))));
|
|
|
|
}
|
|
|
|
if (defaultValueEl)
|
|
|
|
defaultValue = defGetString(defaultValueEl);
|
|
|
|
if (byValueEl)
|
|
|
|
byValue = defGetBoolean(byValueEl);
|
|
|
|
if (alignmentEl)
|
|
|
|
{
|
|
|
|
char *a = defGetString(alignmentEl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: if argument was an unquoted identifier, parser will have
|
2009-06-11 16:49:15 +02:00
|
|
|
* applied translations to it, so be prepared to recognize translated
|
|
|
|
* type names as well as the nominal form.
|
2008-11-30 20:01:29 +01:00
|
|
|
*/
|
|
|
|
if (pg_strcasecmp(a, "double") == 0 ||
|
|
|
|
pg_strcasecmp(a, "float8") == 0 ||
|
|
|
|
pg_strcasecmp(a, "pg_catalog.float8") == 0)
|
|
|
|
alignment = 'd';
|
|
|
|
else if (pg_strcasecmp(a, "int4") == 0 ||
|
|
|
|
pg_strcasecmp(a, "pg_catalog.int4") == 0)
|
|
|
|
alignment = 'i';
|
|
|
|
else if (pg_strcasecmp(a, "int2") == 0 ||
|
|
|
|
pg_strcasecmp(a, "pg_catalog.int2") == 0)
|
|
|
|
alignment = 's';
|
|
|
|
else if (pg_strcasecmp(a, "char") == 0 ||
|
|
|
|
pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
|
|
|
|
alignment = 'c';
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("alignment \"%s\" not recognized", a)));
|
|
|
|
}
|
|
|
|
if (storageEl)
|
|
|
|
{
|
|
|
|
char *a = defGetString(storageEl);
|
|
|
|
|
|
|
|
if (pg_strcasecmp(a, "plain") == 0)
|
|
|
|
storage = 'p';
|
|
|
|
else if (pg_strcasecmp(a, "external") == 0)
|
|
|
|
storage = 'e';
|
|
|
|
else if (pg_strcasecmp(a, "extended") == 0)
|
|
|
|
storage = 'x';
|
|
|
|
else if (pg_strcasecmp(a, "main") == 0)
|
|
|
|
storage = 'm';
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("storage \"%s\" not recognized", a)));
|
2002-04-15 07:22:04 +02:00
|
|
|
}
|
2011-02-08 22:04:18 +01:00
|
|
|
if (collatableEl)
|
|
|
|
collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* make sure we have our required definitions
|
|
|
|
*/
|
|
|
|
if (inputName == NIL)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type input function must be specified")));
|
2002-04-15 07:22:04 +02:00
|
|
|
if (outputName == NIL)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type output function must be specified")));
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
if (typmodinName == NIL && typmodoutName != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type modifier output function is useless without a type modifier input function")));
|
|
|
|
|
2002-08-22 02:01:51 +02:00
|
|
|
/*
|
|
|
|
* Convert I/O proc names to OIDs
|
|
|
|
*/
|
2003-05-09 00:19:58 +02:00
|
|
|
inputOid = findTypeInputFunction(inputName, typoid);
|
|
|
|
outputOid = findTypeOutputFunction(outputName, typoid);
|
|
|
|
if (receiveName)
|
|
|
|
receiveOid = findTypeReceiveFunction(receiveName, typoid);
|
|
|
|
if (sendName)
|
|
|
|
sendOid = findTypeSendFunction(sendName, typoid);
|
2002-08-22 02:01:51 +02:00
|
|
|
|
|
|
|
/*
|
2002-09-21 20:39:26 +02:00
|
|
|
* Verify that I/O procs return the expected thing. If we see OPAQUE,
|
|
|
|
* complain and change it to the correct type-safe choice.
|
2002-08-22 02:01:51 +02:00
|
|
|
*/
|
|
|
|
resulttype = get_func_rettype(inputOid);
|
2002-09-21 20:39:26 +02:00
|
|
|
if (resulttype != typoid)
|
2002-08-23 18:41:38 +02:00
|
|
|
{
|
|
|
|
if (resulttype == OPAQUEOID)
|
2002-09-21 20:39:26 +02:00
|
|
|
{
|
2003-07-20 23:56:35 +02:00
|
|
|
/* backwards-compatibility hack */
|
2003-10-02 08:34:04 +02:00
|
|
|
ereport(WARNING,
|
2016-06-10 00:02:36 +02:00
|
|
|
(errmsg("changing return type of function %s from %s to %s",
|
|
|
|
NameListToString(inputName), "opaque", typeName)));
|
2002-09-21 20:39:26 +02:00
|
|
|
SetFunctionReturnType(inputOid, typoid);
|
|
|
|
}
|
2002-08-23 18:41:38 +02:00
|
|
|
else
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("type input function %s must return type %s",
|
2003-07-20 23:56:35 +02:00
|
|
|
NameListToString(inputName), typeName)));
|
2002-08-23 18:41:38 +02:00
|
|
|
}
|
2002-08-22 02:01:51 +02:00
|
|
|
resulttype = get_func_rettype(outputOid);
|
2002-08-23 18:41:38 +02:00
|
|
|
if (resulttype != CSTRINGOID)
|
|
|
|
{
|
|
|
|
if (resulttype == OPAQUEOID)
|
2002-09-21 20:39:26 +02:00
|
|
|
{
|
2003-07-20 23:56:35 +02:00
|
|
|
/* backwards-compatibility hack */
|
2003-10-02 08:34:04 +02:00
|
|
|
ereport(WARNING,
|
2016-06-10 00:02:36 +02:00
|
|
|
(errmsg("changing return type of function %s from %s to %s",
|
|
|
|
NameListToString(outputName), "opaque", "cstring")));
|
2002-09-21 20:39:26 +02:00
|
|
|
SetFunctionReturnType(outputOid, CSTRINGOID);
|
|
|
|
}
|
2002-08-23 18:41:38 +02:00
|
|
|
else
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-06-10 00:02:36 +02:00
|
|
|
errmsg("type output function %s must return type %s",
|
|
|
|
NameListToString(outputName), "cstring")));
|
2002-08-23 18:41:38 +02:00
|
|
|
}
|
2003-05-09 00:19:58 +02:00
|
|
|
if (receiveOid)
|
|
|
|
{
|
|
|
|
resulttype = get_func_rettype(receiveOid);
|
|
|
|
if (resulttype != typoid)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("type receive function %s must return type %s",
|
2005-10-15 04:49:52 +02:00
|
|
|
NameListToString(receiveName), typeName)));
|
2003-05-09 00:19:58 +02:00
|
|
|
}
|
|
|
|
if (sendOid)
|
|
|
|
{
|
|
|
|
resulttype = get_func_rettype(sendOid);
|
|
|
|
if (resulttype != BYTEAOID)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-06-10 00:02:36 +02:00
|
|
|
errmsg("type send function %s must return type %s",
|
|
|
|
NameListToString(sendName), "bytea")));
|
2003-05-09 00:19:58 +02:00
|
|
|
}
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
/*
|
|
|
|
* Convert typmodin/out function proc names to OIDs.
|
|
|
|
*/
|
|
|
|
if (typmodinName)
|
|
|
|
typmodinOid = findTypeTypmodinFunction(typmodinName);
|
|
|
|
if (typmodoutName)
|
|
|
|
typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
|
|
|
|
|
2004-02-13 00:41:04 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Convert analysis function proc name to an OID. If no analysis function
|
|
|
|
* is specified, we'll use zero to select the built-in default algorithm.
|
2004-02-13 00:41:04 +01:00
|
|
|
*/
|
|
|
|
if (analyzeName)
|
|
|
|
analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
|
|
|
|
|
2006-01-13 19:06:45 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Check permissions on functions. We choose to require the creator/owner
|
|
|
|
* of a type to also own the underlying functions. Since creating a type
|
2006-01-13 19:06:45 +01:00
|
|
|
* is tantamount to granting public execute access on the functions, the
|
2006-10-04 02:30:14 +02:00
|
|
|
* minimum sane check would be for execute-with-grant-option. But we
|
|
|
|
* don't have a way to make the type go away if the grant option is
|
|
|
|
* revoked, so ownership seems better.
|
2006-01-13 19:06:45 +01:00
|
|
|
*/
|
2008-07-31 18:27:16 +02:00
|
|
|
#ifdef NOT_USED
|
|
|
|
/* XXX this is unnecessary given the superuser check above */
|
2006-01-13 19:06:45 +01:00
|
|
|
if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(inputName));
|
|
|
|
if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(outputName));
|
|
|
|
if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(receiveName));
|
|
|
|
if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(sendName));
|
2006-12-30 22:21:56 +01:00
|
|
|
if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(typmodinName));
|
|
|
|
if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(typmodoutName));
|
2006-01-13 19:06:45 +01:00
|
|
|
if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
|
|
|
NameListToString(analyzeName));
|
2008-07-31 18:27:16 +02:00
|
|
|
#endif
|
2006-01-13 19:06:45 +01:00
|
|
|
|
2014-11-05 17:44:06 +01:00
|
|
|
/*
|
|
|
|
* Print warnings if any of the type's I/O functions are marked volatile.
|
|
|
|
* There is a general assumption that I/O functions are stable or
|
|
|
|
* immutable; this allows us for example to mark record_in/record_out
|
|
|
|
* stable rather than volatile. Ideally we would throw errors not just
|
|
|
|
* warnings here; but since this check is new as of 9.5, and since the
|
|
|
|
* volatility marking might be just an error-of-omission and not a true
|
|
|
|
* indication of how the function behaves, we'll let it pass as a warning
|
|
|
|
* for now.
|
|
|
|
*/
|
|
|
|
if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type input function %s should not be volatile",
|
|
|
|
NameListToString(inputName))));
|
|
|
|
if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type output function %s should not be volatile",
|
|
|
|
NameListToString(outputName))));
|
|
|
|
if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type receive function %s should not be volatile",
|
|
|
|
NameListToString(receiveName))));
|
|
|
|
if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
|
|
|
errmsg("type send function %s should not be volatile",
|
|
|
|
NameListToString(sendName))));
|
|
|
|
if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("type modifier input function %s should not be volatile",
|
|
|
|
NameListToString(typmodinName))));
|
2014-11-05 17:44:06 +01:00
|
|
|
if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
|
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("type modifier output function %s should not be volatile",
|
|
|
|
NameListToString(typmodoutName))));
|
2014-11-05 17:44:06 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* OK, we're done checking, time to make the type. We must assign the
|
|
|
|
* array type OID ahead of calling TypeCreate, since the base type and
|
|
|
|
* array type each refer to the other.
|
|
|
|
*/
|
2009-12-24 23:09:24 +01:00
|
|
|
array_oid = AssignTypeArrayOid();
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/*
|
|
|
|
* now have TypeCreate do all the real work.
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
*
|
|
|
|
* Note: the pg_type.oid is stored in user tables as array elements (base
|
2014-05-06 18:12:18 +02:00
|
|
|
* types) in ArrayType and in composite types in DatumTupleFields. This
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
* oid must be preserved by binary upgrades.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
address =
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
TypeCreate(InvalidOid, /* no predetermined type OID */
|
|
|
|
typeName, /* type name */
|
2002-09-04 22:31:48 +02:00
|
|
|
typeNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
2009-06-11 16:49:15 +02:00
|
|
|
GetUserId(), /* owner's ID */
|
2002-09-04 22:31:48 +02:00
|
|
|
internalLength, /* internal size */
|
2007-11-15 22:14:46 +01:00
|
|
|
TYPTYPE_BASE, /* type-type (base type) */
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
category, /* type-category */
|
|
|
|
preferred, /* is it a preferred type? */
|
2002-09-04 22:31:48 +02:00
|
|
|
delimiter, /* array element delimiter */
|
|
|
|
inputOid, /* input procedure */
|
|
|
|
outputOid, /* output procedure */
|
2003-05-09 00:19:58 +02:00
|
|
|
receiveOid, /* receive procedure */
|
|
|
|
sendOid, /* send procedure */
|
2006-12-30 22:21:56 +01:00
|
|
|
typmodinOid, /* typmodin procedure */
|
2007-11-15 22:14:46 +01:00
|
|
|
typmodoutOid, /* typmodout procedure */
|
2004-02-13 00:41:04 +01:00
|
|
|
analyzeOid, /* analyze procedure */
|
2002-09-04 22:31:48 +02:00
|
|
|
elemType, /* element type ID */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
false, /* this is not an array type */
|
|
|
|
array_oid, /* array type we are about to create */
|
2002-09-04 22:31:48 +02:00
|
|
|
InvalidOid, /* base type ID (only for domains) */
|
2002-04-15 07:22:04 +02:00
|
|
|
defaultValue, /* default type value */
|
2002-09-04 22:31:48 +02:00
|
|
|
NULL, /* no binary form available */
|
|
|
|
byValue, /* passed by value */
|
|
|
|
alignment, /* required alignment */
|
|
|
|
storage, /* TOAST strategy */
|
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array Dimensions of typbasetype */
|
2011-02-08 22:04:18 +01:00
|
|
|
false, /* Type NOT NULL */
|
2011-04-22 23:43:18 +02:00
|
|
|
collation); /* type's collation */
|
2015-04-22 21:23:02 +02:00
|
|
|
Assert(typoid == address.objectId);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/*
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
* Create the array type that goes with it.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
array_type = makeArrayTypeName(typeName, typeNamespace);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* alignment must be 'i' or 'd' for arrays */
|
|
|
|
alignment = (alignment == 'd') ? 'd' : 'i';
|
|
|
|
|
2014-08-25 21:32:26 +02:00
|
|
|
TypeCreate(array_oid, /* force assignment of this type OID */
|
|
|
|
array_type, /* type name */
|
|
|
|
typeNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
2015-05-24 03:35:49 +02:00
|
|
|
0, /* relation kind (ditto) */
|
|
|
|
GetUserId(), /* owner's ID */
|
|
|
|
-1, /* internal size (always varlena) */
|
2014-08-25 21:32:26 +02:00
|
|
|
TYPTYPE_BASE, /* type-type (base type) */
|
|
|
|
TYPCATEGORY_ARRAY, /* type-category (array) */
|
2015-05-24 03:35:49 +02:00
|
|
|
false, /* array types are never preferred */
|
2014-08-25 21:32:26 +02:00
|
|
|
delimiter, /* array element delimiter */
|
|
|
|
F_ARRAY_IN, /* input procedure */
|
2015-05-24 03:35:49 +02:00
|
|
|
F_ARRAY_OUT, /* output procedure */
|
2014-08-25 21:32:26 +02:00
|
|
|
F_ARRAY_RECV, /* receive procedure */
|
|
|
|
F_ARRAY_SEND, /* send procedure */
|
2015-05-24 03:35:49 +02:00
|
|
|
typmodinOid, /* typmodin procedure */
|
2014-08-25 21:32:26 +02:00
|
|
|
typmodoutOid, /* typmodout procedure */
|
|
|
|
F_ARRAY_TYPANALYZE, /* analyze procedure */
|
2015-05-24 03:35:49 +02:00
|
|
|
typoid, /* element type ID */
|
|
|
|
true, /* yes this is an array type */
|
2014-08-25 21:32:26 +02:00
|
|
|
InvalidOid, /* no further array type */
|
|
|
|
InvalidOid, /* base type ID */
|
2015-05-24 03:35:49 +02:00
|
|
|
NULL, /* never a default type value */
|
|
|
|
NULL, /* binary default isn't sent either */
|
|
|
|
false, /* never passed by value */
|
2014-08-25 21:32:26 +02:00
|
|
|
alignment, /* see above */
|
2015-05-24 03:35:49 +02:00
|
|
|
'x', /* ARRAY is always toastable */
|
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array dimensions of typbasetype */
|
|
|
|
false, /* Type NOT NULL */
|
2014-08-25 21:32:26 +02:00
|
|
|
collation); /* type's collation */
|
2002-04-15 07:22:04 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
pfree(array_type);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2002-04-15 07:22:04 +02:00
|
|
|
}
|
|
|
|
|
2002-07-12 20:43:19 +02:00
|
|
|
/*
|
|
|
|
* Guts of type deletion.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
RemoveTypeById(Oid typeOid)
|
|
|
|
{
|
|
|
|
Relation relation;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
relation = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
|
2002-04-15 07:22:04 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
simple_heap_delete(relation, &tup->t_self);
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If it is an enum, delete the pg_enum entries too; we don't bother with
|
|
|
|
* making dependency entries for those, so it has to be done "by hand"
|
|
|
|
* here.
|
2007-04-02 05:49:42 +02:00
|
|
|
*/
|
|
|
|
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
|
|
|
|
EnumValuesDelete(typeOid);
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
/*
|
2011-11-21 05:50:27 +01:00
|
|
|
* If it is a range type, delete the pg_range entry too; we don't bother
|
|
|
|
* with making a dependency entry for that, so it has to be done "by hand"
|
|
|
|
* here.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
|
|
|
|
RangeDelete(typeOid);
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
heap_close(relation, RowExclusiveLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DefineDomain
|
|
|
|
* Registers a new domain.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2002-04-15 07:22:04 +02:00
|
|
|
DefineDomain(CreateDomainStmt *stmt)
|
|
|
|
{
|
|
|
|
char *domainName;
|
|
|
|
Oid domainNamespace;
|
2002-04-27 05:45:03 +02:00
|
|
|
AclResult aclresult;
|
2002-04-15 07:22:04 +02:00
|
|
|
int16 internalLength;
|
|
|
|
Oid inputProcedure;
|
|
|
|
Oid outputProcedure;
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid receiveProcedure;
|
|
|
|
Oid sendProcedure;
|
2004-02-13 00:41:04 +01:00
|
|
|
Oid analyzeProcedure;
|
2002-04-15 07:22:04 +02:00
|
|
|
bool byValue;
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
char category;
|
2002-04-15 07:22:04 +02:00
|
|
|
char delimiter;
|
|
|
|
char alignment;
|
|
|
|
char storage;
|
|
|
|
char typtype;
|
|
|
|
Datum datum;
|
|
|
|
bool isnull;
|
|
|
|
char *defaultValue = NULL;
|
|
|
|
char *defaultValueBin = NULL;
|
2007-06-20 20:15:49 +02:00
|
|
|
bool saw_default = false;
|
2002-04-15 07:22:04 +02:00
|
|
|
bool typNotNull = false;
|
2002-07-17 00:12:20 +02:00
|
|
|
bool nullDefined = false;
|
2009-07-16 08:33:46 +02:00
|
|
|
int32 typNDims = list_length(stmt->typeName->arrayBounds);
|
2002-04-15 07:22:04 +02:00
|
|
|
HeapTuple typeTup;
|
|
|
|
List *schema = stmt->constraints;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *listptr;
|
2002-07-12 20:43:19 +02:00
|
|
|
Oid basetypeoid;
|
2007-05-12 02:55:00 +02:00
|
|
|
Oid old_type_oid;
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
Oid domaincoll;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type baseType;
|
2006-12-30 22:21:56 +01:00
|
|
|
int32 basetypeMod;
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid baseColl;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* Convert list of names to a name and namespace */
|
|
|
|
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
|
|
|
|
&domainName);
|
|
|
|
|
2002-04-27 05:45:03 +02:00
|
|
|
/* Check we have creation rights in target namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
|
|
|
|
ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
2003-08-01 02:15:26 +02:00
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(domainNamespace));
|
2002-04-27 05:45:03 +02:00
|
|
|
|
2007-05-12 02:55:00 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Check for collision with an existing type name. If there is one and
|
2007-05-12 02:55:00 +02:00
|
|
|
* it's an autogenerated array, we can rename it out of the way.
|
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
old_type_oid = GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
CStringGetDatum(domainName),
|
|
|
|
ObjectIdGetDatum(domainNamespace));
|
2007-05-12 02:55:00 +02:00
|
|
|
if (OidIsValid(old_type_oid))
|
|
|
|
{
|
|
|
|
if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", domainName)));
|
|
|
|
}
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/*
|
|
|
|
* Look up the base type.
|
|
|
|
*/
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
|
2002-07-12 20:43:19 +02:00
|
|
|
baseType = (Form_pg_type) GETSTRUCT(typeTup);
|
2002-07-20 07:16:59 +02:00
|
|
|
basetypeoid = HeapTupleGetOid(typeTup);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/*
|
2011-11-03 12:16:28 +01:00
|
|
|
* Base type must be a plain base type, another domain, an enum or a range
|
|
|
|
* type. Domains over pseudotypes would create a security hole. Domains
|
2011-11-14 18:08:48 +01:00
|
|
|
* over composite types might be made to work in the future, but not
|
|
|
|
* today.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
2002-07-12 20:43:19 +02:00
|
|
|
typtype = baseType->typtype;
|
2007-04-02 05:49:42 +02:00
|
|
|
if (typtype != TYPTYPE_BASE &&
|
|
|
|
typtype != TYPTYPE_DOMAIN &&
|
2011-11-03 12:16:28 +01:00
|
|
|
typtype != TYPTYPE_ENUM &&
|
|
|
|
typtype != TYPTYPE_RANGE)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("\"%s\" is not a valid base type for a domain",
|
2009-07-16 08:33:46 +02:00
|
|
|
TypeNameToString(stmt->typeName))));
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2011-12-19 23:05:19 +01:00
|
|
|
aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(aclresult, basetypeoid);
|
2011-12-19 23:05:19 +01:00
|
|
|
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
/*
|
|
|
|
* Identify the collation if any
|
|
|
|
*/
|
|
|
|
baseColl = baseType->typcollation;
|
|
|
|
if (stmt->collClause)
|
2011-03-11 22:27:51 +01:00
|
|
|
domaincoll = get_collation_oid(stmt->collClause->collname, false);
|
Remove collation information from TypeName, where it does not belong.
The initial collations patch treated a COLLATE spec as part of a TypeName,
following what can only be described as brain fade on the part of the SQL
committee. It's a lot more reasonable to treat COLLATE as a syntactically
separate object, so that it can be added in only the productions where it
actually belongs, rather than needing to reject it in a boatload of places
where it doesn't belong (something the original patch mostly failed to do).
In addition this change lets us meet the spec's requirement to allow
COLLATE anywhere in the clauses of a ColumnDef, and it avoids unfriendly
behavior for constructs such as "foo::type COLLATE collation".
To do this, pull collation information out of TypeName and put it in
ColumnDef instead, thus reverting most of the collation-related changes in
parse_type.c's API. I made one additional structural change, which was to
use a ColumnDef as an intermediate node in AT_AlterColumnType AlterTableCmd
nodes. This provides enough room to get rid of the "transform" wart in
AlterTableCmd too, since the ColumnDef can carry the USING expression
easily enough.
Also fix some other minor bugs that have crept in in the same areas,
like failure to copy recently-added fields of ColumnDef in copyfuncs.c.
While at it, document the formerly secret ability to specify a collation
in ALTER TABLE ALTER COLUMN TYPE, ALTER TYPE ADD ATTRIBUTE, and
ALTER TYPE ALTER ATTRIBUTE TYPE; and correct some misstatements about
what the default collation selection will be when COLLATE is omitted.
BTW, the three-parameter form of format_type() should go away too,
since it just contributes to the confusion in this area; but I'll do
that in a separate patch.
2011-03-10 04:38:52 +01:00
|
|
|
else
|
|
|
|
domaincoll = baseColl;
|
|
|
|
|
|
|
|
/* Complain if COLLATE is applied to an uncollatable type */
|
|
|
|
if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("collations are not supported by type %s",
|
|
|
|
format_type_be(basetypeoid))));
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/* passed by value */
|
2002-07-12 20:43:19 +02:00
|
|
|
byValue = baseType->typbyval;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* Required Alignment */
|
2002-07-12 20:43:19 +02:00
|
|
|
alignment = baseType->typalign;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* TOAST Strategy */
|
2002-07-12 20:43:19 +02:00
|
|
|
storage = baseType->typstorage;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* Storage Length */
|
2002-07-12 20:43:19 +02:00
|
|
|
internalLength = baseType->typlen;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
/* Type Category */
|
|
|
|
category = baseType->typcategory;
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/* Array element Delimiter */
|
2002-07-12 20:43:19 +02:00
|
|
|
delimiter = baseType->typdelim;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* I/O Functions */
|
2006-04-06 00:11:58 +02:00
|
|
|
inputProcedure = F_DOMAIN_IN;
|
2002-07-12 20:43:19 +02:00
|
|
|
outputProcedure = baseType->typoutput;
|
2006-04-06 00:11:58 +02:00
|
|
|
receiveProcedure = F_DOMAIN_RECV;
|
2003-05-09 00:19:58 +02:00
|
|
|
sendProcedure = baseType->typsend;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
/* Domains never accept typmods, so no typmodin/typmodout needed */
|
|
|
|
|
2004-02-13 00:41:04 +01:00
|
|
|
/* Analysis function */
|
|
|
|
analyzeProcedure = baseType->typanalyze;
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/* Inherited default value */
|
2002-09-04 22:31:48 +02:00
|
|
|
datum = SysCacheGetAttr(TYPEOID, typeTup,
|
2002-04-15 07:22:04 +02:00
|
|
|
Anum_pg_type_typdefault, &isnull);
|
|
|
|
if (!isnull)
|
2008-03-25 23:42:46 +01:00
|
|
|
defaultValue = TextDatumGetCString(datum);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/* Inherited default binary value */
|
2002-09-04 22:31:48 +02:00
|
|
|
datum = SysCacheGetAttr(TYPEOID, typeTup,
|
2002-04-15 07:22:04 +02:00
|
|
|
Anum_pg_type_typdefaultbin, &isnull);
|
|
|
|
if (!isnull)
|
2008-03-25 23:42:46 +01:00
|
|
|
defaultValueBin = TextDatumGetCString(datum);
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Run through constraints manually to avoid the additional processing
|
|
|
|
* conducted by DefineRelation() and friends.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
|
|
|
foreach(listptr, schema)
|
|
|
|
{
|
2009-07-30 04:45:38 +02:00
|
|
|
Constraint *constr = lfirst(listptr);
|
2002-12-09 21:31:05 +01:00
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
if (!IsA(constr, Constraint))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
2009-07-30 04:45:38 +02:00
|
|
|
(int) nodeTag(constr));
|
2003-07-20 23:56:35 +02:00
|
|
|
switch (constr->contype)
|
2002-04-15 07:22:04 +02:00
|
|
|
{
|
2002-12-09 21:31:05 +01:00
|
|
|
case CONSTR_DEFAULT:
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The inherited default value may be overridden by the user
|
2007-06-20 20:15:49 +02:00
|
|
|
* with the DEFAULT <expr> clause ... but only once.
|
2002-09-04 22:31:48 +02:00
|
|
|
*/
|
2007-06-20 20:15:49 +02:00
|
|
|
if (saw_default)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("multiple default expressions")));
|
2007-06-20 20:15:49 +02:00
|
|
|
saw_default = true;
|
|
|
|
|
|
|
|
if (constr->raw_expr)
|
|
|
|
{
|
|
|
|
ParseState *pstate;
|
|
|
|
Node *defaultExpr;
|
|
|
|
|
|
|
|
/* Create a dummy ParseState for transformExpr */
|
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Cook the constr->raw_expr into an expression. Note:
|
|
|
|
* name is strictly for error message
|
2007-06-20 20:15:49 +02:00
|
|
|
*/
|
|
|
|
defaultExpr = cookDefault(pstate, constr->raw_expr,
|
|
|
|
basetypeoid,
|
|
|
|
basetypeMod,
|
|
|
|
domainName);
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If the expression is just a NULL constant, we treat it
|
|
|
|
* like not having a default.
|
2007-10-29 20:40:40 +01:00
|
|
|
*
|
|
|
|
* Note that if the basetype is another domain, we'll see
|
|
|
|
* a CoerceToDomain expr here and not discard the default.
|
|
|
|
* This is critical because the domain default needs to be
|
|
|
|
* retained to override any default that the base domain
|
|
|
|
* might have.
|
2007-06-20 20:15:49 +02:00
|
|
|
*/
|
2007-10-29 20:40:40 +01:00
|
|
|
if (defaultExpr == NULL ||
|
|
|
|
(IsA(defaultExpr, Const) &&
|
|
|
|
((Const *) defaultExpr)->constisnull))
|
|
|
|
{
|
|
|
|
defaultValue = NULL;
|
|
|
|
defaultValueBin = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Expression must be stored as a nodeToString result,
|
|
|
|
* but we also require a valid textual representation
|
|
|
|
* (mainly to make life easier for pg_dump).
|
|
|
|
*/
|
|
|
|
defaultValue =
|
|
|
|
deparse_expression(defaultExpr,
|
2012-12-31 21:13:26 +01:00
|
|
|
NIL, false, false);
|
2007-10-29 20:40:40 +01:00
|
|
|
defaultValueBin = nodeToString(defaultExpr);
|
|
|
|
}
|
2007-06-20 20:15:49 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-10-29 20:40:40 +01:00
|
|
|
/* No default (can this still happen?) */
|
2007-06-20 20:15:49 +02:00
|
|
|
defaultValue = NULL;
|
|
|
|
defaultValueBin = NULL;
|
|
|
|
}
|
2002-04-15 07:22:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_NOTNULL:
|
2002-12-12 21:35:16 +01:00
|
|
|
if (nullDefined && !typNotNull)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("conflicting NULL/NOT NULL constraints")));
|
2002-07-17 00:12:20 +02:00
|
|
|
typNotNull = true;
|
|
|
|
nullDefined = true;
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
case CONSTR_NULL:
|
2002-12-12 21:35:16 +01:00
|
|
|
if (nullDefined && typNotNull)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("conflicting NULL/NOT NULL constraints")));
|
2002-07-17 00:12:20 +02:00
|
|
|
typNotNull = false;
|
|
|
|
nullDefined = true;
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_CHECK:
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2002-12-09 21:31:05 +01:00
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Check constraints are handled after domain creation, as
|
2012-07-24 21:49:54 +02:00
|
|
|
* they require the Oid of the domain; at this point we can
|
2013-05-29 22:58:43 +02:00
|
|
|
* only check that they're not marked NO INHERIT, because that
|
|
|
|
* would be bogus.
|
2002-12-09 21:31:05 +01:00
|
|
|
*/
|
2012-07-24 21:49:54 +02:00
|
|
|
if (constr->is_no_inherit)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2013-01-05 14:25:21 +01:00
|
|
|
errmsg("check constraints for domains cannot be marked NO INHERIT")));
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-12-09 21:31:05 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* All else are error cases
|
|
|
|
*/
|
2003-08-04 02:43:34 +02:00
|
|
|
case CONSTR_UNIQUE:
|
|
|
|
ereport(ERROR,
|
2003-09-10 01:22:21 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("unique constraints not possible for domains")));
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-12-09 21:31:05 +01:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
case CONSTR_PRIMARY:
|
|
|
|
ereport(ERROR,
|
2003-09-10 01:22:21 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("primary key constraints not possible for domains")));
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-12-09 21:31:05 +01:00
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
case CONSTR_EXCLUSION:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2010-02-26 03:01:40 +01:00
|
|
|
errmsg("exclusion constraints not possible for domains")));
|
2009-12-07 06:22:23 +01:00
|
|
|
break;
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_FOREIGN:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("foreign key constraints not possible for domains")));
|
|
|
|
break;
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
case CONSTR_ATTR_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_NOT_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_DEFERRED:
|
|
|
|
case CONSTR_ATTR_IMMEDIATE:
|
|
|
|
ereport(ERROR,
|
2003-07-20 23:56:35 +02:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2003-09-10 01:22:21 +02:00
|
|
|
errmsg("specifying constraint deferrability not supported for domains")));
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
default:
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized constraint subtype: %d",
|
|
|
|
(int) constr->contype);
|
2002-09-04 22:31:48 +02:00
|
|
|
break;
|
2002-04-15 07:22:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Have TypeCreate do all the real work.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
address =
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
TypeCreate(InvalidOid, /* no predetermined type OID */
|
|
|
|
domainName, /* type name */
|
2002-07-17 00:12:20 +02:00
|
|
|
domainNamespace, /* namespace */
|
2002-09-04 22:31:48 +02:00
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
2009-06-11 16:49:15 +02:00
|
|
|
GetUserId(), /* owner's ID */
|
2002-07-17 00:12:20 +02:00
|
|
|
internalLength, /* internal size */
|
2007-04-02 05:49:42 +02:00
|
|
|
TYPTYPE_DOMAIN, /* type-type (domain type) */
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
category, /* type-category */
|
2008-07-30 21:35:13 +02:00
|
|
|
false, /* domain types are never preferred */
|
2002-09-04 22:31:48 +02:00
|
|
|
delimiter, /* array element delimiter */
|
2002-07-17 00:12:20 +02:00
|
|
|
inputProcedure, /* input procedure */
|
|
|
|
outputProcedure, /* output procedure */
|
2003-05-09 00:19:58 +02:00
|
|
|
receiveProcedure, /* receive procedure */
|
|
|
|
sendProcedure, /* send procedure */
|
2007-11-15 22:14:46 +01:00
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2004-02-13 00:41:04 +01:00
|
|
|
analyzeProcedure, /* analyze procedure */
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
InvalidOid, /* no array element type */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
false, /* this isn't an array */
|
|
|
|
InvalidOid, /* no arrays for domains (yet) */
|
2002-09-04 22:31:48 +02:00
|
|
|
basetypeoid, /* base type ID */
|
|
|
|
defaultValue, /* default type value (text) */
|
2002-07-17 00:12:20 +02:00
|
|
|
defaultValueBin, /* default type value (binary) */
|
2003-08-04 02:43:34 +02:00
|
|
|
byValue, /* passed by value */
|
|
|
|
alignment, /* required alignment */
|
|
|
|
storage, /* TOAST strategy */
|
2006-12-30 22:21:56 +01:00
|
|
|
basetypeMod, /* typeMod value */
|
2003-08-04 02:43:34 +02:00
|
|
|
typNDims, /* Array dimensions for base type */
|
2011-02-08 22:04:18 +01:00
|
|
|
typNotNull, /* Type NOT NULL */
|
2011-06-09 20:32:50 +02:00
|
|
|
domaincoll); /* type's collation */
|
2002-11-15 03:50:21 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Process constraints which refer to the domain ID returned by TypeCreate
|
2002-11-15 03:50:21 +01:00
|
|
|
*/
|
|
|
|
foreach(listptr, schema)
|
|
|
|
{
|
|
|
|
Constraint *constr = lfirst(listptr);
|
|
|
|
|
2002-12-09 21:31:05 +01:00
|
|
|
/* it must be a Constraint, per check above */
|
|
|
|
|
2002-11-15 03:50:21 +01:00
|
|
|
switch (constr->contype)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
case CONSTR_CHECK:
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
domainAddConstraint(address.objectId, domainNamespace,
|
2006-12-30 22:21:56 +01:00
|
|
|
basetypeoid, basetypeMod,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
constr, domainName, NULL);
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
/* Other constraint types were fully processed above */
|
2002-12-09 21:31:05 +01:00
|
|
|
|
2002-11-15 03:50:21 +01:00
|
|
|
default:
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-11-15 03:50:21 +01:00
|
|
|
}
|
2004-06-10 19:56:03 +02:00
|
|
|
|
|
|
|
/* CCI so we can detect duplicate constraint names */
|
|
|
|
CommandCounterIncrement();
|
2002-11-15 03:50:21 +01:00
|
|
|
}
|
2002-07-17 00:12:20 +02:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/*
|
|
|
|
* Now we can clean up.
|
|
|
|
*/
|
|
|
|
ReleaseSysCache(typeTup);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2002-04-15 07:22:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
/*
|
|
|
|
* DefineEnum
|
|
|
|
* Registers a new enum.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2007-11-15 23:25:18 +01:00
|
|
|
DefineEnum(CreateEnumStmt *stmt)
|
2007-04-02 05:49:42 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *enumName;
|
|
|
|
char *enumArrayName;
|
|
|
|
Oid enumNamespace;
|
2007-04-02 05:49:42 +02:00
|
|
|
AclResult aclresult;
|
2007-11-15 22:14:46 +01:00
|
|
|
Oid old_type_oid;
|
|
|
|
Oid enumArrayOid;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress enumTypeAddr;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/* Convert list of names to a name and namespace */
|
2009-07-16 08:33:46 +02:00
|
|
|
enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
|
2007-04-02 05:49:42 +02:00
|
|
|
&enumName);
|
|
|
|
|
|
|
|
/* Check we have creation rights in target namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(enumNamespace));
|
|
|
|
|
2007-05-12 02:55:00 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Check for collision with an existing type name. If there is one and
|
2007-05-12 02:55:00 +02:00
|
|
|
* it's an autogenerated array, we can rename it out of the way.
|
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
old_type_oid = GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
CStringGetDatum(enumName),
|
|
|
|
ObjectIdGetDatum(enumNamespace));
|
2007-05-12 02:55:00 +02:00
|
|
|
if (OidIsValid(old_type_oid))
|
|
|
|
{
|
|
|
|
if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", enumName)));
|
|
|
|
}
|
|
|
|
|
2009-12-24 23:09:24 +01:00
|
|
|
enumArrayOid = AssignTypeArrayOid();
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/* Create the pg_type entry */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
enumTypeAddr =
|
2007-11-15 22:14:46 +01:00
|
|
|
TypeCreate(InvalidOid, /* no predetermined type OID */
|
|
|
|
enumName, /* type name */
|
|
|
|
enumNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
2009-06-11 16:49:15 +02:00
|
|
|
GetUserId(), /* owner's ID */
|
2007-11-15 22:14:46 +01:00
|
|
|
sizeof(Oid), /* internal size */
|
2007-04-02 05:49:42 +02:00
|
|
|
TYPTYPE_ENUM, /* type-type (enum type) */
|
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
2008-07-30 19:05:05 +02:00
|
|
|
TYPCATEGORY_ENUM, /* type-category (enum type) */
|
2008-07-30 21:35:13 +02:00
|
|
|
false, /* enum types are never preferred */
|
2007-04-02 05:49:42 +02:00
|
|
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
2007-11-15 22:14:46 +01:00
|
|
|
F_ENUM_IN, /* input procedure */
|
|
|
|
F_ENUM_OUT, /* output procedure */
|
|
|
|
F_ENUM_RECV, /* receive procedure */
|
|
|
|
F_ENUM_SEND, /* send procedure */
|
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
|
|
|
InvalidOid, /* analyze procedure - default */
|
|
|
|
InvalidOid, /* element type ID */
|
|
|
|
false, /* this is not an array type */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
enumArrayOid, /* array type we are about to create */
|
2007-11-15 22:14:46 +01:00
|
|
|
InvalidOid, /* base type ID (only for domains) */
|
|
|
|
NULL, /* never a default type value */
|
|
|
|
NULL, /* binary default isn't sent either */
|
|
|
|
true, /* always passed by value */
|
|
|
|
'i', /* int alignment */
|
|
|
|
'p', /* TOAST strategy always plain */
|
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array dimensions of typbasetype */
|
2011-02-08 22:04:18 +01:00
|
|
|
false, /* Type NOT NULL */
|
2011-04-22 23:43:18 +02:00
|
|
|
InvalidOid); /* type's collation */
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/* Enter the enum's values into pg_enum */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/*
|
|
|
|
* Create the array type that goes with it.
|
|
|
|
*/
|
|
|
|
enumArrayName = makeArrayTypeName(enumName, enumNamespace);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
TypeCreate(enumArrayOid, /* force assignment of this type OID */
|
2007-11-15 22:14:46 +01:00
|
|
|
enumArrayName, /* type name */
|
|
|
|
enumNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER
TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row. However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes). Problem identified by Cott Lang.
Back-patch to 8.1. The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1. Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
2009-02-24 02:38:10 +01:00
|
|
|
GetUserId(), /* owner's ID */
|
2007-11-15 22:14:46 +01:00
|
|
|
-1, /* internal size (always varlena) */
|
2007-04-02 05:49:42 +02:00
|
|
|
TYPTYPE_BASE, /* type-type (base type) */
|
2009-06-11 16:49:15 +02:00
|
|
|
TYPCATEGORY_ARRAY, /* type-category (array) */
|
2008-07-30 21:35:13 +02:00
|
|
|
false, /* array types are never preferred */
|
2007-11-15 22:14:46 +01:00
|
|
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
|
|
|
F_ARRAY_IN, /* input procedure */
|
|
|
|
F_ARRAY_OUT, /* output procedure */
|
|
|
|
F_ARRAY_RECV, /* receive procedure */
|
|
|
|
F_ARRAY_SEND, /* send procedure */
|
2007-04-02 05:49:42 +02:00
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2012-06-10 21:20:04 +02:00
|
|
|
F_ARRAY_TYPANALYZE, /* analyze procedure */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
enumTypeAddr.objectId, /* element type ID */
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
true, /* yes this is an array type */
|
|
|
|
InvalidOid, /* no further array type */
|
2007-11-15 22:14:46 +01:00
|
|
|
InvalidOid, /* base type ID */
|
|
|
|
NULL, /* never a default type value */
|
|
|
|
NULL, /* binary default isn't sent either */
|
|
|
|
false, /* never passed by value */
|
|
|
|
'i', /* enums have align i, so do their arrays */
|
|
|
|
'x', /* ARRAY is always toastable */
|
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array dimensions of typbasetype */
|
2011-02-08 22:04:18 +01:00
|
|
|
false, /* Type NOT NULL */
|
2011-04-22 23:43:18 +02:00
|
|
|
InvalidOid); /* type's collation */
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
pfree(enumArrayName);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return enumTypeAddr;
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/*
|
|
|
|
* AlterEnum
|
|
|
|
* Adds a new label to an existing enum.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2016-09-05 18:59:55 +02:00
|
|
|
AlterEnum(AlterEnumStmt *stmt)
|
2011-11-21 22:19:53 +01:00
|
|
|
{
|
|
|
|
Oid enum_type_oid;
|
|
|
|
TypeName *typename;
|
|
|
|
HeapTuple tup;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2011-11-21 22:19:53 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
|
|
|
typename = makeTypeNameFromNameList(stmt->typeName);
|
|
|
|
enum_type_oid = typenameTypeId(NULL, typename);
|
|
|
|
|
|
|
|
tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
|
|
|
|
|
|
|
|
/* Check it's an enum and check user has permission to ALTER the enum */
|
|
|
|
checkEnumOwner(tup);
|
|
|
|
|
2016-09-07 22:11:56 +02:00
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
if (stmt->oldVal)
|
|
|
|
{
|
|
|
|
/* Rename an existing label */
|
|
|
|
RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add a new label */
|
|
|
|
AddEnumLabel(enum_type_oid, stmt->newVal,
|
|
|
|
stmt->newValNeighbor, stmt->newValIsAfter,
|
|
|
|
stmt->skipIfNewValExists);
|
|
|
|
}
|
2011-11-21 22:19:53 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, enum_type_oid);
|
|
|
|
|
|
|
|
return address;
|
2011-11-21 22:19:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* checkEnumOwner
|
|
|
|
*
|
|
|
|
* Check that the type is actually an enum and that the current user
|
|
|
|
* has permission to do ALTER TYPE on it. Throw an error if not.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
checkEnumOwner(HeapTuple tup)
|
|
|
|
{
|
|
|
|
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/* Check that this is actually an enum */
|
|
|
|
if (typTup->typtype != TYPTYPE_ENUM)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("%s is not an enum",
|
|
|
|
format_type_be(HeapTupleGetOid(tup)))));
|
|
|
|
|
|
|
|
/* Permission check: must own type */
|
|
|
|
if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
|
2011-11-21 22:19:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
/*
|
|
|
|
* DefineRange
|
|
|
|
* Registers a new range type.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2011-11-14 18:12:23 +01:00
|
|
|
DefineRange(CreateRangeStmt *stmt)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-14 18:08:48 +01:00
|
|
|
char *typeName;
|
|
|
|
Oid typeNamespace;
|
|
|
|
Oid typoid;
|
2011-11-21 22:19:53 +01:00
|
|
|
char *rangeArrayName;
|
2011-11-14 18:08:48 +01:00
|
|
|
Oid rangeArrayOid;
|
2011-11-21 22:19:53 +01:00
|
|
|
Oid rangeSubtype = InvalidOid;
|
2011-11-14 18:08:48 +01:00
|
|
|
List *rangeSubOpclassName = NIL;
|
|
|
|
List *rangeCollationName = NIL;
|
2011-11-21 22:19:53 +01:00
|
|
|
List *rangeCanonicalName = NIL;
|
|
|
|
List *rangeSubtypeDiffName = NIL;
|
|
|
|
Oid rangeSubOpclass;
|
|
|
|
Oid rangeCollation;
|
|
|
|
regproc rangeCanonical;
|
|
|
|
regproc rangeSubtypeDiff;
|
2011-11-15 03:42:04 +01:00
|
|
|
int16 subtyplen;
|
|
|
|
bool subtypbyval;
|
|
|
|
char subtypalign;
|
|
|
|
char alignment;
|
2011-11-14 18:08:48 +01:00
|
|
|
AclResult aclresult;
|
2011-11-15 03:42:04 +01:00
|
|
|
ListCell *lc;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
/* Convert list of names to a name and namespace */
|
|
|
|
typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
|
|
|
|
&typeName);
|
|
|
|
|
|
|
|
/* Check we have creation rights in target namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(typeNamespace));
|
|
|
|
|
|
|
|
/*
|
2011-11-21 22:19:53 +01:00
|
|
|
* Look to see if type already exists.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
typoid = GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
CStringGetDatum(typeName),
|
|
|
|
ObjectIdGetDatum(typeNamespace));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's not a shell, see if it's an autogenerated array type, and if so
|
|
|
|
* rename it out of the way.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(typoid) && get_typisdefined(typoid))
|
|
|
|
{
|
|
|
|
if (moveArrayTypeName(typoid, typeName, typeNamespace))
|
|
|
|
typoid = InvalidOid;
|
2011-11-21 22:19:53 +01:00
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", typeName)));
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it doesn't exist, create it as a shell, so that the OID is known for
|
2011-11-21 22:19:53 +01:00
|
|
|
* use in the range function definitions.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
if (!OidIsValid(typoid))
|
|
|
|
{
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
address = TypeShellMake(typeName, typeNamespace, GetUserId());
|
|
|
|
typoid = address.objectId;
|
2011-11-03 12:16:28 +01:00
|
|
|
/* Make new shell type visible for modification below */
|
|
|
|
CommandCounterIncrement();
|
|
|
|
}
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/* Extract the parameters from the parameter list */
|
2011-11-03 12:16:28 +01:00
|
|
|
foreach(lc, stmt->params)
|
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
DefElem *defel = (DefElem *) lfirst(lc);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (pg_strcasecmp(defel->defname, "subtype") == 0)
|
|
|
|
{
|
|
|
|
if (OidIsValid(rangeSubtype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
2011-11-21 22:19:53 +01:00
|
|
|
/* we can look up the subtype name immediately */
|
2011-11-03 12:16:28 +01:00
|
|
|
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
|
|
|
|
}
|
2011-11-21 22:19:53 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
if (rangeSubOpclassName != NIL)
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
2011-11-21 22:19:53 +01:00
|
|
|
rangeSubOpclassName = defGetQualifiedName(defel);
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
else if (pg_strcasecmp(defel->defname, "collation") == 0)
|
|
|
|
{
|
|
|
|
if (rangeCollationName != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
|
|
|
rangeCollationName = defGetQualifiedName(defel);
|
|
|
|
}
|
2011-11-21 22:19:53 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "canonical") == 0)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
if (rangeCanonicalName != NIL)
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
2011-11-21 22:19:53 +01:00
|
|
|
rangeCanonicalName = defGetQualifiedName(defel);
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
2011-11-21 22:19:53 +01:00
|
|
|
else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
if (rangeSubtypeDiffName != NIL)
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("conflicting or redundant options")));
|
2011-11-21 22:19:53 +01:00
|
|
|
rangeSubtypeDiffName = defGetQualifiedName(defel);
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("type attribute \"%s\" not recognized",
|
|
|
|
defel->defname)));
|
|
|
|
}
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/* Must have a subtype */
|
2011-11-03 12:16:28 +01:00
|
|
|
if (!OidIsValid(rangeSubtype))
|
2011-11-14 18:08:48 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("type attribute \"subtype\" is required")));
|
2011-11-21 22:19:53 +01:00
|
|
|
/* disallow ranges of pseudotypes */
|
|
|
|
if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("range subtype cannot be %s",
|
|
|
|
format_type_be(rangeSubtype))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/* Identify subopclass */
|
|
|
|
rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
|
|
|
|
|
|
|
|
/* Identify collation to use, if any */
|
2011-11-03 12:16:28 +01:00
|
|
|
if (type_is_collatable(rangeSubtype))
|
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
if (rangeCollationName != NIL)
|
2011-11-03 12:16:28 +01:00
|
|
|
rangeCollation = get_collation_oid(rangeCollationName, false);
|
2011-11-21 22:19:53 +01:00
|
|
|
else
|
|
|
|
rangeCollation = get_typcollation(rangeSubtype);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rangeCollationName != NIL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("range collation specified but subtype does not support collation")));
|
|
|
|
rangeCollation = InvalidOid;
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/* Identify support functions, if provided */
|
|
|
|
if (rangeCanonicalName != NIL)
|
|
|
|
rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
|
|
|
|
typoid);
|
|
|
|
else
|
|
|
|
rangeCanonical = InvalidOid;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (rangeSubtypeDiffName != NIL)
|
2011-11-15 03:42:04 +01:00
|
|
|
rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
|
|
|
|
rangeSubtype);
|
2011-11-21 22:19:53 +01:00
|
|
|
else
|
|
|
|
rangeSubtypeDiff = InvalidOid;
|
|
|
|
|
2011-11-15 03:42:04 +01:00
|
|
|
get_typlenbyvalalign(rangeSubtype,
|
|
|
|
&subtyplen, &subtypbyval, &subtypalign);
|
|
|
|
|
|
|
|
/* alignment must be 'i' or 'd' for ranges */
|
|
|
|
alignment = (subtypalign == 'd') ? 'd' : 'i';
|
|
|
|
|
|
|
|
/* Allocate OID for array type */
|
2011-11-03 12:16:28 +01:00
|
|
|
rangeArrayOid = AssignTypeArrayOid();
|
|
|
|
|
|
|
|
/* Create the pg_type entry */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
address =
|
2011-11-03 12:16:28 +01:00
|
|
|
TypeCreate(InvalidOid, /* no predetermined type OID */
|
|
|
|
typeName, /* type name */
|
|
|
|
typeNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
|
|
|
GetUserId(), /* owner's ID */
|
2011-11-15 03:42:04 +01:00
|
|
|
-1, /* internal size (always varlena) */
|
2011-11-14 18:08:48 +01:00
|
|
|
TYPTYPE_RANGE, /* type-type (range type) */
|
2011-11-03 12:16:28 +01:00
|
|
|
TYPCATEGORY_RANGE, /* type-category (range type) */
|
|
|
|
false, /* range types are never preferred */
|
|
|
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
|
|
|
F_RANGE_IN, /* input procedure */
|
2011-11-14 18:08:48 +01:00
|
|
|
F_RANGE_OUT, /* output procedure */
|
|
|
|
F_RANGE_RECV, /* receive procedure */
|
|
|
|
F_RANGE_SEND, /* send procedure */
|
2011-11-03 12:16:28 +01:00
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2011-11-23 06:03:22 +01:00
|
|
|
F_RANGE_TYPANALYZE, /* analyze procedure */
|
2011-11-15 03:42:04 +01:00
|
|
|
InvalidOid, /* element type ID - none */
|
2011-11-03 12:16:28 +01:00
|
|
|
false, /* this is not an array type */
|
2011-11-14 18:08:48 +01:00
|
|
|
rangeArrayOid, /* array type we are about to create */
|
2011-11-03 12:16:28 +01:00
|
|
|
InvalidOid, /* base type ID (only for domains) */
|
|
|
|
NULL, /* never a default type value */
|
2011-11-21 22:19:53 +01:00
|
|
|
NULL, /* no binary form available either */
|
2011-11-03 12:16:28 +01:00
|
|
|
false, /* never passed by value */
|
2011-11-15 03:42:04 +01:00
|
|
|
alignment, /* alignment */
|
|
|
|
'x', /* TOAST strategy (always extended) */
|
2011-11-03 12:16:28 +01:00
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array dimensions of typbasetype */
|
|
|
|
false, /* Type NOT NULL */
|
2011-11-21 22:19:53 +01:00
|
|
|
InvalidOid); /* type's collation (ranges never have one) */
|
2015-04-22 21:23:02 +02:00
|
|
|
Assert(typoid == address.objectId);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/* Create the entry in pg_range */
|
2011-11-03 12:16:28 +01:00
|
|
|
RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
|
|
|
|
rangeCanonical, rangeSubtypeDiff);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the array type that goes with it.
|
|
|
|
*/
|
|
|
|
rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
|
|
|
|
|
|
|
|
TypeCreate(rangeArrayOid, /* force assignment of this type OID */
|
|
|
|
rangeArrayName, /* type name */
|
|
|
|
typeNamespace, /* namespace */
|
|
|
|
InvalidOid, /* relation oid (n/a here) */
|
|
|
|
0, /* relation kind (ditto) */
|
|
|
|
GetUserId(), /* owner's ID */
|
|
|
|
-1, /* internal size (always varlena) */
|
|
|
|
TYPTYPE_BASE, /* type-type (base type) */
|
|
|
|
TYPCATEGORY_ARRAY, /* type-category (array) */
|
|
|
|
false, /* array types are never preferred */
|
|
|
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
|
|
|
F_ARRAY_IN, /* input procedure */
|
|
|
|
F_ARRAY_OUT, /* output procedure */
|
|
|
|
F_ARRAY_RECV, /* receive procedure */
|
|
|
|
F_ARRAY_SEND, /* send procedure */
|
|
|
|
InvalidOid, /* typmodin procedure - none */
|
|
|
|
InvalidOid, /* typmodout procedure - none */
|
2012-06-10 21:20:04 +02:00
|
|
|
F_ARRAY_TYPANALYZE, /* analyze procedure */
|
2011-11-14 18:08:48 +01:00
|
|
|
typoid, /* element type ID */
|
2011-11-03 12:16:28 +01:00
|
|
|
true, /* yes this is an array type */
|
|
|
|
InvalidOid, /* no further array type */
|
|
|
|
InvalidOid, /* base type ID */
|
|
|
|
NULL, /* never a default type value */
|
|
|
|
NULL, /* binary default isn't sent either */
|
|
|
|
false, /* never passed by value */
|
2011-11-15 03:42:04 +01:00
|
|
|
alignment, /* alignment - same as range's */
|
2011-11-03 12:16:28 +01:00
|
|
|
'x', /* ARRAY is always toastable */
|
|
|
|
-1, /* typMod (Domains only) */
|
|
|
|
0, /* Array dimensions of typbasetype */
|
|
|
|
false, /* Type NOT NULL */
|
|
|
|
InvalidOid); /* typcollation */
|
|
|
|
|
|
|
|
pfree(rangeArrayName);
|
|
|
|
|
2011-11-15 03:42:04 +01:00
|
|
|
/* And create the constructor functions for this range type */
|
2011-11-21 22:19:53 +01:00
|
|
|
makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-11-21 22:19:53 +01:00
|
|
|
* Because there may exist several range types over the same subtype, the
|
|
|
|
* range type can't be uniquely determined from the subtype. So it's
|
|
|
|
* impossible to define a polymorphic constructor; we have to generate new
|
|
|
|
* constructor functions explicitly for each range type.
|
2011-11-03 12:16:28 +01:00
|
|
|
*
|
2014-05-06 18:12:18 +02:00
|
|
|
* We actually define 4 functions, with 0 through 3 arguments. This is just
|
2011-11-21 22:19:53 +01:00
|
|
|
* to offer more convenience for the user.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
static void
|
2011-11-21 22:19:53 +01:00
|
|
|
makeRangeConstructors(const char *name, Oid namespace,
|
|
|
|
Oid rangeOid, Oid subtype)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
static const char *const prosrc[2] = {"range_constructor2",
|
|
|
|
"range_constructor3"};
|
2011-11-23 02:45:05 +01:00
|
|
|
static const int pronargs[2] = {2, 3};
|
2011-11-21 22:19:53 +01:00
|
|
|
|
2011-11-14 18:08:48 +01:00
|
|
|
Oid constructorArgTypes[3];
|
2011-11-21 22:19:53 +01:00
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
2011-11-14 18:08:48 +01:00
|
|
|
int i;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
constructorArgTypes[0] = subtype;
|
|
|
|
constructorArgTypes[1] = subtype;
|
|
|
|
constructorArgTypes[2] = TEXTOID;
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
referenced.classId = TypeRelationId;
|
|
|
|
referenced.objectId = rangeOid;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < lengthof(prosrc); i++)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-14 18:08:48 +01:00
|
|
|
oidvector *constructorArgTypesVector;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
constructorArgTypesVector = buildoidvector(constructorArgTypes,
|
|
|
|
pronargs[i]);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
myself = ProcedureCreate(name, /* name: same as range type */
|
|
|
|
namespace, /* namespace */
|
|
|
|
false, /* replace */
|
|
|
|
false, /* returns set */
|
|
|
|
rangeOid, /* return type */
|
|
|
|
BOOTSTRAP_SUPERUSERID, /* proowner */
|
|
|
|
INTERNALlanguageId, /* language */
|
|
|
|
F_FMGR_INTERNAL_VALIDATOR, /* language validator */
|
|
|
|
prosrc[i], /* prosrc */
|
|
|
|
NULL, /* probin */
|
|
|
|
false, /* isAgg */
|
|
|
|
false, /* isWindowFunc */
|
|
|
|
false, /* security_definer */
|
|
|
|
false, /* leakproof */
|
|
|
|
false, /* isStrict */
|
|
|
|
PROVOLATILE_IMMUTABLE, /* volatility */
|
2015-09-16 21:38:47 +02:00
|
|
|
PROPARALLEL_SAFE, /* parallel safety */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
constructorArgTypesVector, /* parameterTypes */
|
|
|
|
PointerGetDatum(NULL), /* allParameterTypes */
|
|
|
|
PointerGetDatum(NULL), /* parameterModes */
|
|
|
|
PointerGetDatum(NULL), /* parameterNames */
|
|
|
|
NIL, /* parameterDefaults */
|
2015-05-24 03:35:49 +02:00
|
|
|
PointerGetDatum(NULL), /* trftypes */
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
PointerGetDatum(NULL), /* proconfig */
|
|
|
|
1.0, /* procost */
|
|
|
|
0.0); /* prorows */
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
/*
|
2011-11-21 05:50:27 +01:00
|
|
|
* Make the constructors internally-dependent on the range type so
|
|
|
|
* that they go away silently when the type is dropped. Note that
|
|
|
|
* pg_dump depends on this choice to avoid dumping the constructors.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
|
|
|
|
/*
|
2003-05-09 00:19:58 +02:00
|
|
|
* Find suitable I/O functions for a type.
|
2002-08-22 02:01:51 +02:00
|
|
|
*
|
2002-09-21 20:39:26 +02:00
|
|
|
* typeOid is the type's OID (which will already exist, if only as a shell
|
|
|
|
* type).
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
2003-05-09 00:19:58 +02:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
static Oid
|
2003-05-09 00:19:58 +02:00
|
|
|
findTypeInputFunction(List *procname, Oid typeOid)
|
2002-04-15 07:22:04 +02:00
|
|
|
{
|
2005-03-29 05:01:32 +02:00
|
|
|
Oid argList[3];
|
2002-04-15 07:22:04 +02:00
|
|
|
Oid procOid;
|
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Input functions can take a single argument of type CSTRING, or three
|
|
|
|
* arguments (string, typioparam OID, typmod).
|
2003-05-09 00:19:58 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* For backwards compatibility we allow OPAQUE in place of CSTRING; if we
|
|
|
|
* see this, we issue a warning and fix up the pg_proc entry.
|
2003-05-09 00:19:58 +02:00
|
|
|
*/
|
|
|
|
argList[0] = CSTRINGOID;
|
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
|
|
|
|
|
|
|
argList[1] = OIDOID;
|
|
|
|
argList[2] = INT4OID;
|
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 3, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
|
|
|
|
|
|
|
/* No luck, try it with OPAQUE */
|
|
|
|
argList[0] = OPAQUEOID;
|
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
|
|
|
|
if (!OidIsValid(procOid))
|
2002-04-15 07:22:04 +02:00
|
|
|
{
|
2003-05-09 00:19:58 +02:00
|
|
|
argList[1] = OIDOID;
|
|
|
|
argList[2] = INT4OID;
|
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 3, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (OidIsValid(procOid))
|
|
|
|
{
|
|
|
|
/* Found, but must complain and fix the pg_proc entry */
|
2003-10-02 08:34:04 +02:00
|
|
|
ereport(WARNING,
|
2003-09-25 08:58:07 +02:00
|
|
|
(errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
|
2003-07-20 23:56:35 +02:00
|
|
|
NameListToString(procname))));
|
2003-05-09 00:19:58 +02:00
|
|
|
SetFunctionArgType(procOid, 0, CSTRINGOID);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-04-15 07:22:04 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Need CommandCounterIncrement since DefineType will likely try to
|
|
|
|
* alter the pg_proc tuple again.
|
2002-04-15 07:22:04 +02:00
|
|
|
*/
|
2003-05-09 00:19:58 +02:00
|
|
|
CommandCounterIncrement();
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
return procOid;
|
|
|
|
}
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/* Use CSTRING (preferred) in the error message */
|
|
|
|
argList[0] = CSTRINGOID;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
return InvalidOid; /* keep compiler quiet */
|
|
|
|
}
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
static Oid
|
|
|
|
findTypeOutputFunction(List *procname, Oid typeOid)
|
|
|
|
{
|
2005-05-01 20:56:19 +02:00
|
|
|
Oid argList[1];
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid procOid;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/*
|
2005-05-01 20:56:19 +02:00
|
|
|
* Output functions can take a single argument of the type.
|
2003-05-09 00:19:58 +02:00
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
* For backwards compatibility we allow OPAQUE in place of the actual type
|
|
|
|
* name; if we see this, we issue a warning and fix up the pg_proc entry.
|
2003-05-09 00:19:58 +02:00
|
|
|
*/
|
|
|
|
argList[0] = typeOid;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
2002-09-21 20:39:26 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/* No luck, try it with OPAQUE */
|
|
|
|
argList[0] = OPAQUEOID;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
2002-08-22 02:01:51 +02:00
|
|
|
{
|
2003-05-09 00:19:58 +02:00
|
|
|
/* Found, but must complain and fix the pg_proc entry */
|
2003-10-02 08:34:04 +02:00
|
|
|
ereport(WARNING,
|
2005-10-15 04:49:52 +02:00
|
|
|
(errmsg("changing argument type of function %s from \"opaque\" to %s",
|
|
|
|
NameListToString(procname), format_type_be(typeOid))));
|
2003-05-09 00:19:58 +02:00
|
|
|
SetFunctionArgType(procOid, 0, typeOid);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-08-22 02:01:51 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Need CommandCounterIncrement since DefineType will likely try to
|
|
|
|
* alter the pg_proc tuple again.
|
2002-08-22 02:01:51 +02:00
|
|
|
*/
|
2003-05-09 00:19:58 +02:00
|
|
|
CommandCounterIncrement();
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
return procOid;
|
|
|
|
}
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/* Use type name, not OPAQUE, in the failure message. */
|
|
|
|
argList[0] = typeOid;
|
2002-04-15 07:22:04 +02:00
|
|
|
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
return InvalidOid; /* keep compiler quiet */
|
|
|
|
}
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
static Oid
|
|
|
|
findTypeReceiveFunction(List *procname, Oid typeOid)
|
|
|
|
{
|
2005-07-10 23:14:00 +02:00
|
|
|
Oid argList[3];
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid procOid;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Receive functions can take a single argument of type INTERNAL, or three
|
|
|
|
* arguments (internal, typioparam OID, typmod).
|
2003-05-09 00:19:58 +02:00
|
|
|
*/
|
|
|
|
argList[0] = INTERNALOID;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
2002-09-21 20:39:26 +02:00
|
|
|
|
2003-05-10 01:01:45 +02:00
|
|
|
argList[1] = OIDOID;
|
2005-07-10 23:14:00 +02:00
|
|
|
argList[2] = INT4OID;
|
2003-05-10 01:01:45 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
procOid = LookupFuncName(procname, 3, argList, true);
|
2003-05-10 01:01:45 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
|
|
|
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
return InvalidOid; /* keep compiler quiet */
|
|
|
|
}
|
2002-09-21 20:39:26 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
static Oid
|
|
|
|
findTypeSendFunction(List *procname, Oid typeOid)
|
|
|
|
{
|
2005-05-01 20:56:19 +02:00
|
|
|
Oid argList[1];
|
2003-05-09 00:19:58 +02:00
|
|
|
Oid procOid;
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
/*
|
2005-05-01 20:56:19 +02:00
|
|
|
* Send functions can take a single argument of the type.
|
2003-05-09 00:19:58 +02:00
|
|
|
*/
|
|
|
|
argList[0] = typeOid;
|
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2003-05-09 00:19:58 +02:00
|
|
|
if (OidIsValid(procOid))
|
|
|
|
return procOid;
|
|
|
|
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2002-08-22 02:01:51 +02:00
|
|
|
|
|
|
|
return InvalidOid; /* keep compiler quiet */
|
2002-04-15 07:22:04 +02:00
|
|
|
}
|
2002-08-15 18:36:08 +02:00
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
static Oid
|
|
|
|
findTypeTypmodinFunction(List *procname)
|
|
|
|
{
|
|
|
|
Oid argList[1];
|
|
|
|
Oid procOid;
|
|
|
|
|
|
|
|
/*
|
2007-06-15 22:56:52 +02:00
|
|
|
* typmodin functions always take one cstring[] argument and return int4.
|
2006-12-30 22:21:56 +01:00
|
|
|
*/
|
2007-06-15 22:56:52 +02:00
|
|
|
argList[0] = CSTRINGARRAYOID;
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
|
|
|
if (!OidIsValid(procOid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
if (get_func_rettype(procOid) != INT4OID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("typmod_in function %s must return type %s",
|
2016-03-28 19:12:00 +02:00
|
|
|
NameListToString(procname), "integer")));
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
return procOid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Oid
|
|
|
|
findTypeTypmodoutFunction(List *procname)
|
|
|
|
{
|
|
|
|
Oid argList[1];
|
|
|
|
Oid procOid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* typmodout functions always take one int4 argument and return cstring.
|
|
|
|
*/
|
|
|
|
argList[0] = INT4OID;
|
|
|
|
|
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
|
|
|
if (!OidIsValid(procOid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
if (get_func_rettype(procOid) != CSTRINGOID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("typmod_out function %s must return type %s",
|
2016-03-28 19:12:00 +02:00
|
|
|
NameListToString(procname), "cstring")));
|
2006-12-30 22:21:56 +01:00
|
|
|
|
|
|
|
return procOid;
|
|
|
|
}
|
|
|
|
|
2004-02-13 00:41:04 +01:00
|
|
|
static Oid
|
|
|
|
findTypeAnalyzeFunction(List *procname, Oid typeOid)
|
|
|
|
{
|
2005-03-29 05:01:32 +02:00
|
|
|
Oid argList[1];
|
2004-02-13 00:41:04 +01:00
|
|
|
Oid procOid;
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Analyze functions always take one INTERNAL argument and return bool.
|
2004-02-13 00:41:04 +01:00
|
|
|
*/
|
|
|
|
argList[0] = INTERNALOID;
|
|
|
|
|
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
|
|
|
if (!OidIsValid(procOid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2009-10-08 04:39:25 +02:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2004-02-13 00:41:04 +01:00
|
|
|
|
|
|
|
if (get_func_rettype(procOid) != BOOLOID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-06-10 00:02:36 +02:00
|
|
|
errmsg("type analyze function %s must return type %s",
|
|
|
|
NameListToString(procname), "boolean")));
|
2004-02-13 00:41:04 +01:00
|
|
|
|
|
|
|
return procOid;
|
|
|
|
}
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/*
|
|
|
|
* Find suitable support functions and opclasses for a range type.
|
|
|
|
*/
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
/*
|
|
|
|
* Find named btree opclass for subtype, or default btree opclass if
|
2011-11-21 22:19:53 +01:00
|
|
|
* opcname is NIL.
|
2011-11-03 12:16:28 +01:00
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
findRangeSubOpclass(List *opcname, Oid subtype)
|
|
|
|
{
|
|
|
|
Oid opcid;
|
2011-11-21 22:19:53 +01:00
|
|
|
Oid opInputType;
|
|
|
|
|
|
|
|
if (opcname != NIL)
|
|
|
|
{
|
|
|
|
opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/*
|
|
|
|
* Verify that the operator class accepts this datatype. Note we will
|
|
|
|
* accept binary compatibility.
|
|
|
|
*/
|
|
|
|
opInputType = get_opclass_input_type(opcid);
|
|
|
|
if (!IsBinaryCoercible(subtype, opInputType))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
2012-06-10 21:20:04 +02:00
|
|
|
errmsg("operator class \"%s\" does not accept data type %s",
|
|
|
|
NameListToString(opcname),
|
|
|
|
format_type_be(subtype))));
|
2011-11-21 22:19:53 +01:00
|
|
|
}
|
|
|
|
else
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
|
|
|
opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
|
|
|
|
if (!OidIsValid(opcid))
|
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
/* We spell the error message identically to GetIndexOpClass */
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
2011-11-21 22:19:53 +01:00
|
|
|
errmsg("data type %s has no default operator class for access method \"%s\"",
|
|
|
|
format_type_be(subtype), "btree"),
|
|
|
|
errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
|
2011-11-03 12:16:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return opcid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Oid
|
2011-11-21 22:19:53 +01:00
|
|
|
findRangeCanonicalFunction(List *procname, Oid typeOid)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
Oid argList[1];
|
2011-11-03 12:16:28 +01:00
|
|
|
Oid procOid;
|
2011-11-23 18:45:49 +01:00
|
|
|
AclResult aclresult;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/*
|
|
|
|
* Range canonical functions must take and return the range type, and must
|
|
|
|
* be immutable.
|
|
|
|
*/
|
2011-11-03 12:16:28 +01:00
|
|
|
argList[0] = typeOid;
|
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
procOid = LookupFuncName(procname, 1, argList, true);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (!OidIsValid(procOid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2011-11-21 22:19:53 +01:00
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
if (get_func_rettype(procOid) != typeOid)
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2011-11-21 22:19:53 +01:00
|
|
|
errmsg("range canonical function %s must return range type",
|
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2011-11-21 22:19:53 +01:00
|
|
|
errmsg("range canonical function %s must be immutable",
|
|
|
|
func_signature_string(procname, 1, NIL, argList))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-23 18:45:49 +01:00
|
|
|
/* Also, range type's creator must have permission to call function */
|
|
|
|
aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
return procOid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Oid
|
2011-11-21 22:19:53 +01:00
|
|
|
findRangeSubtypeDiffFunction(List *procname, Oid subtype)
|
2011-11-03 12:16:28 +01:00
|
|
|
{
|
2011-11-21 22:19:53 +01:00
|
|
|
Oid argList[2];
|
2011-11-03 12:16:28 +01:00
|
|
|
Oid procOid;
|
2011-11-23 18:45:49 +01:00
|
|
|
AclResult aclresult;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
/*
|
|
|
|
* Range subtype diff functions must take two arguments of the subtype,
|
|
|
|
* must return float8, and must be immutable.
|
|
|
|
*/
|
|
|
|
argList[0] = subtype;
|
|
|
|
argList[1] = subtype;
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
procOid = LookupFuncName(procname, 2, argList, true);
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (!OidIsValid(procOid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("function %s does not exist",
|
2011-11-21 22:19:53 +01:00
|
|
|
func_signature_string(procname, 2, NIL, argList))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-21 22:19:53 +01:00
|
|
|
if (get_func_rettype(procOid) != FLOAT8OID)
|
2011-11-03 12:16:28 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("range subtype diff function %s must return type %s",
|
2016-03-28 19:12:00 +02:00
|
|
|
func_signature_string(procname, 2, NIL, argList),
|
|
|
|
"double precision")));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
|
|
|
if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2011-11-21 22:19:53 +01:00
|
|
|
errmsg("range subtype diff function %s must be immutable",
|
|
|
|
func_signature_string(procname, 2, NIL, argList))));
|
2011-11-03 12:16:28 +01:00
|
|
|
|
2011-11-23 18:45:49 +01:00
|
|
|
/* Also, range type's creator must have permission to call function */
|
|
|
|
aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
|
|
|
|
|
2011-11-03 12:16:28 +01:00
|
|
|
return procOid;
|
|
|
|
}
|
|
|
|
|
2009-12-24 23:09:24 +01:00
|
|
|
/*
|
|
|
|
* AssignTypeArrayOid
|
|
|
|
*
|
|
|
|
* Pre-assign the type's array OID for use in pg_type.typarray
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
AssignTypeArrayOid(void)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
Oid type_array_oid;
|
2009-12-24 23:09:24 +01:00
|
|
|
|
2014-08-26 04:19:05 +02:00
|
|
|
/* Use binary-upgrade override for pg_type.typarray? */
|
|
|
|
if (IsBinaryUpgrade)
|
2009-12-24 23:09:24 +01:00
|
|
|
{
|
2014-08-26 04:19:05 +02:00
|
|
|
if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("pg_type array OID value not set when in binary upgrade mode")));
|
|
|
|
|
2011-01-08 03:25:34 +01:00
|
|
|
type_array_oid = binary_upgrade_next_array_pg_type_oid;
|
|
|
|
binary_upgrade_next_array_pg_type_oid = InvalidOid;
|
2009-12-24 23:09:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
type_array_oid = GetNewOid(pg_type);
|
|
|
|
heap_close(pg_type, AccessShareLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
return type_array_oid;
|
|
|
|
}
|
|
|
|
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2002-08-15 18:36:08 +02:00
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
* DefineCompositeType
|
|
|
|
*
|
|
|
|
* Create a Composite Type relation.
|
|
|
|
* `DefineRelation' does all the work, we just provide the correct
|
|
|
|
* arguments!
|
|
|
|
*
|
|
|
|
* If the relation already exists, then 'DefineRelation' will abort
|
|
|
|
* the xact...
|
|
|
|
*
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
* Return type is the new type's object address.
|
2002-08-15 18:36:08 +02:00
|
|
|
*-------------------------------------------------------------------
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2012-02-26 14:22:27 +01:00
|
|
|
DefineCompositeType(RangeVar *typevar, List *coldeflist)
|
2002-08-15 18:36:08 +02:00
|
|
|
{
|
|
|
|
CreateStmt *createStmt = makeNode(CreateStmt);
|
2010-01-20 06:47:09 +01:00
|
|
|
Oid old_type_oid;
|
|
|
|
Oid typeNamespace;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2002-08-15 18:36:08 +02:00
|
|
|
|
|
|
|
/*
|
2004-08-29 07:07:03 +02:00
|
|
|
* now set the parameters for keys/inheritance etc. All of these are
|
|
|
|
* uninteresting for composite types...
|
2002-08-15 18:36:08 +02:00
|
|
|
*/
|
2012-02-26 14:22:27 +01:00
|
|
|
createStmt->relation = typevar;
|
2002-08-15 18:36:08 +02:00
|
|
|
createStmt->tableElts = coldeflist;
|
|
|
|
createStmt->inhRelations = NIL;
|
|
|
|
createStmt->constraints = NIL;
|
Clean up the mess around EXPLAIN and materialized views.
Revert the matview-related changes in explain.c's API, as per recent
complaint from Robert Haas. The reason for these appears to have been
principally some ill-considered choices around having intorel_startup do
what ought to be parse-time checking, plus a poor arrangement for passing
it the view parsetree it needs to store into pg_rewrite when creating a
materialized view. Do the latter by having parse analysis stick a copy
into the IntoClause, instead of doing it at runtime. (On the whole,
I seriously question the choice to represent CREATE MATERIALIZED VIEW as a
variant of SELECT INTO/CREATE TABLE AS, because that means injecting even
more complexity into what was already a horrid legacy kluge. However,
I didn't go so far as to rethink that choice ... yet.)
I also moved several error checks into matview parse analysis, and
made the check for external Params in a matview more accurate.
In passing, clean things up a bit more around interpretOidsOption(),
and fix things so that we can use that to force no-oids for views,
sequences, etc, thereby eliminating the need to cons up "oids = false"
options when creating them.
catversion bump due to change in IntoClause. (I wonder though if we
really need readfuncs/outfuncs support for IntoClause anymore.)
2013-04-13 01:25:20 +02:00
|
|
|
createStmt->options = NIL;
|
2002-11-11 23:19:25 +01:00
|
|
|
createStmt->oncommit = ONCOMMIT_NOOP;
|
2004-06-18 08:14:31 +02:00
|
|
|
createStmt->tablespacename = NULL;
|
2010-07-26 01:21:22 +02:00
|
|
|
createStmt->if_not_exists = false;
|
2002-08-15 18:36:08 +02:00
|
|
|
|
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Check for collision with an existing type name. If there is one and
|
|
|
|
* it's an autogenerated array, we can rename it out of the way. This
|
|
|
|
* check is here mainly to get a better error message about a "type"
|
|
|
|
* instead of below about a "relation".
|
2010-01-20 06:47:09 +01:00
|
|
|
*/
|
Prevent adding relations to a concurrently dropped schema.
In the previous coding, it was possible for a relation to be created
via CREATE TABLE, CREATE VIEW, CREATE SEQUENCE, CREATE FOREIGN TABLE,
etc. in a schema while that schema was meanwhile being concurrently
dropped. This led to a pg_class entry with an invalid relnamespace
value. The same problem could occur if a relation was moved using
ALTER .. SET SCHEMA while the target schema was being concurrently
dropped. This patch prevents both of those scenarios by locking the
schema to which the relation is being added using AccessShareLock,
which conflicts with the AccessExclusiveLock taken by DROP.
As a desirable side effect, this also prevents the use of CREATE OR
REPLACE VIEW to queue for an AccessExclusiveLock on a relation on which
you have no rights: that will now fail immediately with a permissions
error, before trying to obtain a lock.
We need similar protection for all other object types, but as everything
other than relations uses a slightly different set of code paths, I'm
leaving that for a separate commit.
Original complaint (as far as I could find) about CREATE by Nikhil
Sontakke; risk for ALTER .. SET SCHEMA pointed out by Tom Lane;
further details by Dan Farina; patch by me; review by Hitoshi Harada.
2012-01-16 15:34:21 +01:00
|
|
|
typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
|
|
|
|
NoLock, NULL);
|
Fix bugs in relpersistence handling during table creation.
Unlike the relistemp field which it replaced, relpersistence must be
set correctly quite early during the table creation process, as we
rely on it quite early on for a number of purposes, including security
checks. Normally, this is set based on whether the user enters CREATE
TABLE, CREATE UNLOGGED TABLE, or CREATE TEMPORARY TABLE, but a
relation may also be made implicitly temporary by creating it in
pg_temp. This patch fixes the handling of that case, and also
disables creation of unlogged tables in temporary tablespace (such
table indeed skip WAL-logging, but we reject an explicit
specification) and creation of relations in the temporary schemas of
other sessions (which is not very sensible, and didn't work right
anyway).
Report by Amit Khandekar.
2011-07-03 23:34:47 +02:00
|
|
|
RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
|
2010-02-14 19:42:19 +01:00
|
|
|
old_type_oid =
|
|
|
|
GetSysCacheOid2(TYPENAMENSP,
|
|
|
|
CStringGetDatum(createStmt->relation->relname),
|
|
|
|
ObjectIdGetDatum(typeNamespace));
|
2010-01-20 06:47:09 +01:00
|
|
|
if (OidIsValid(old_type_oid))
|
|
|
|
{
|
|
|
|
if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists", createStmt->relation->relname)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally create the relation. This also creates the type.
|
2002-08-15 18:36:08 +02:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
|
|
|
|
|
|
|
|
return address;
|
2002-08-15 18:36:08 +02:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterDomainDefault
|
|
|
|
*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
*
|
|
|
|
* Returns ObjectAddress of the modified domain.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2002-12-06 06:00:34 +01:00
|
|
|
AlterDomainDefault(List *names, Node *defaultRaw)
|
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid domainoid;
|
|
|
|
HeapTuple tup;
|
|
|
|
ParseState *pstate;
|
|
|
|
Relation rel;
|
|
|
|
char *defaultValue;
|
2003-08-04 02:43:34 +02:00
|
|
|
Node *defaultExpr = NULL; /* NULL if no default specified */
|
2002-12-06 06:00:34 +01:00
|
|
|
Datum new_record[Natts_pg_type];
|
2008-11-02 02:45:28 +01:00
|
|
|
bool new_record_nulls[Natts_pg_type];
|
|
|
|
bool new_record_repl[Natts_pg_type];
|
2002-12-06 06:00:34 +01:00
|
|
|
HeapTuple newtuple;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type typTup;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
2006-03-14 23:48:25 +01:00
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
domainoid = typenameTypeId(NULL, typename);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Look up the domain in the type table */
|
2005-04-14 22:03:27 +02:00
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
|
2002-12-06 06:00:34 +01:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", domainoid);
|
2006-03-14 23:48:25 +01:00
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Check it's a domain and check user has permission for ALTER DOMAIN */
|
2010-10-25 05:04:37 +02:00
|
|
|
checkDomainOwner(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Setup new tuple */
|
|
|
|
MemSet(new_record, (Datum) 0, sizeof(new_record));
|
2008-11-02 02:45:28 +01:00
|
|
|
MemSet(new_record_nulls, false, sizeof(new_record_nulls));
|
|
|
|
MemSet(new_record_repl, false, sizeof(new_record_repl));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2007-10-29 20:40:40 +01:00
|
|
|
/* Store the new default into the tuple */
|
2002-12-06 06:00:34 +01:00
|
|
|
if (defaultRaw)
|
|
|
|
{
|
|
|
|
/* Create a dummy ParseState for transformExpr */
|
|
|
|
pstate = make_parsestate(NULL);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Cook the colDef->raw_expr into an expression. Note: Name is
|
|
|
|
* strictly for error message
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
defaultExpr = cookDefault(pstate, defaultRaw,
|
|
|
|
typTup->typbasetype,
|
|
|
|
typTup->typtypmod,
|
|
|
|
NameStr(typTup->typname));
|
|
|
|
|
|
|
|
/*
|
2007-10-29 20:40:40 +01:00
|
|
|
* If the expression is just a NULL constant, we treat the command
|
|
|
|
* like ALTER ... DROP DEFAULT. (But see note for same test in
|
|
|
|
* DefineDomain.)
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2007-10-29 20:40:40 +01:00
|
|
|
if (defaultExpr == NULL ||
|
2007-11-15 22:14:46 +01:00
|
|
|
(IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
|
2007-10-29 20:40:40 +01:00
|
|
|
{
|
|
|
|
/* Default is NULL, drop it */
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
|
|
|
|
new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
|
|
|
|
new_record_nulls[Anum_pg_type_typdefault - 1] = true;
|
|
|
|
new_record_repl[Anum_pg_type_typdefault - 1] = true;
|
2007-10-29 20:40:40 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Expression must be stored as a nodeToString result, but we also
|
|
|
|
* require a valid textual representation (mainly to make life
|
|
|
|
* easier for pg_dump).
|
|
|
|
*/
|
|
|
|
defaultValue = deparse_expression(defaultExpr,
|
2012-12-31 21:13:26 +01:00
|
|
|
NIL, false, false);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2007-10-29 20:40:40 +01:00
|
|
|
/*
|
|
|
|
* Form an updated tuple with the new default and write it back.
|
|
|
|
*/
|
2008-03-25 23:42:46 +01:00
|
|
|
new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
|
2008-03-25 23:42:46 +01:00
|
|
|
new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_repl[Anum_pg_type_typdefault - 1] = true;
|
2007-10-29 20:40:40 +01:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
else
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2007-10-29 20:40:40 +01:00
|
|
|
/* ALTER ... DROP DEFAULT */
|
2008-11-02 02:45:28 +01:00
|
|
|
new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
|
|
|
|
new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
|
|
|
|
new_record_nulls[Anum_pg_type_typdefault - 1] = true;
|
|
|
|
new_record_repl[Anum_pg_type_typdefault - 1] = true;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
|
2009-06-11 16:49:15 +02:00
|
|
|
new_record, new_record_nulls,
|
|
|
|
new_record_repl);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
simple_heap_update(rel, &tup->t_self, newtuple);
|
|
|
|
|
|
|
|
CatalogUpdateIndexes(rel, newtuple);
|
|
|
|
|
|
|
|
/* Rebuild dependencies */
|
|
|
|
GenerateTypeDependencies(typTup->typnamespace,
|
|
|
|
domainoid,
|
2007-11-15 22:14:46 +01:00
|
|
|
InvalidOid, /* typrelid is n/a */
|
2003-08-04 02:43:34 +02:00
|
|
|
0, /* relation kind is n/a */
|
2005-07-07 22:40:02 +02:00
|
|
|
typTup->typowner,
|
2002-12-06 06:00:34 +01:00
|
|
|
typTup->typinput,
|
|
|
|
typTup->typoutput,
|
2003-05-09 00:19:58 +02:00
|
|
|
typTup->typreceive,
|
|
|
|
typTup->typsend,
|
2006-12-30 22:21:56 +01:00
|
|
|
typTup->typmodin,
|
|
|
|
typTup->typmodout,
|
2004-02-13 00:41:04 +01:00
|
|
|
typTup->typanalyze,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
InvalidOid,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
false, /* a domain isn't an implicit array */
|
2002-12-06 06:00:34 +01:00
|
|
|
typTup->typbasetype,
|
2011-02-12 14:54:13 +01:00
|
|
|
typTup->typcollation,
|
2003-01-08 22:40:39 +01:00
|
|
|
defaultExpr,
|
2003-08-04 02:43:34 +02:00
|
|
|
true); /* Rebuild is true */
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, domainoid);
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/* Clean up */
|
|
|
|
heap_close(rel, NoLock);
|
|
|
|
heap_freetuple(newtuple);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2003-04-08 18:57:45 +02:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterDomainNotNull
|
|
|
|
*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
*
|
|
|
|
* Returns ObjectAddress of the modified domain.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2002-12-06 06:00:34 +01:00
|
|
|
AlterDomainNotNull(List *names, bool notNull)
|
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid domainoid;
|
2003-01-04 01:46:08 +01:00
|
|
|
Relation typrel;
|
2002-12-06 06:00:34 +01:00
|
|
|
HeapTuple tup;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type typTup;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address = InvalidObjectAddress;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
2006-03-14 23:48:25 +01:00
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
domainoid = typenameTypeId(NULL, typename);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Look up the domain in the type table */
|
2005-04-14 22:03:27 +02:00
|
|
|
typrel = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
|
2002-12-06 06:00:34 +01:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", domainoid);
|
2003-01-04 01:46:08 +01:00
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Check it's a domain and check user has permission for ALTER DOMAIN */
|
2010-10-25 05:04:37 +02:00
|
|
|
checkDomainOwner(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Is the domain already set to the desired constraint? */
|
2002-12-06 06:00:34 +01:00
|
|
|
if (typTup->typnotnull == notNull)
|
2003-01-04 01:46:08 +01:00
|
|
|
{
|
|
|
|
heap_close(typrel, RowExclusiveLock);
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2003-01-04 01:46:08 +01:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Adding a NOT NULL constraint requires checking existing columns */
|
2002-12-06 06:00:34 +01:00
|
|
|
if (notNull)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
List *rels;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *rt;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Fetch relation list with attributes based on this domain */
|
2003-01-04 01:46:08 +01:00
|
|
|
/* ShareLock is sufficient to prevent concurrent data changes */
|
|
|
|
|
|
|
|
rels = get_rels_with_domain(domainoid, ShareLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
foreach(rt, rels)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-01-04 01:46:08 +01:00
|
|
|
RelToCheck *rtc = (RelToCheck *) lfirst(rt);
|
|
|
|
Relation testrel = rtc->rel;
|
|
|
|
TupleDesc tupdesc = RelationGetDescr(testrel);
|
2002-12-06 06:00:34 +01:00
|
|
|
HeapScanDesc scan;
|
2003-01-04 01:46:08 +01:00
|
|
|
HeapTuple tuple;
|
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
|
|
|
Snapshot snapshot;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Scan all tuples in this relation */
|
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
|
|
|
snapshot = RegisterSnapshot(GetLatestSnapshot());
|
|
|
|
scan = heap_beginscan(testrel, snapshot, 0, NULL);
|
2002-12-06 06:00:34 +01:00
|
|
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int i;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Test attributes that are of the domain */
|
2002-12-06 06:00:34 +01:00
|
|
|
for (i = 0; i < rtc->natts; i++)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int attnum = rtc->atts[i];
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2004-06-04 22:35:21 +02:00
|
|
|
if (heap_attisnull(tuple, attnum))
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In principle the auxiliary information for this
|
|
|
|
* error should be errdatatype(), but errtablecol()
|
2014-05-06 18:12:18 +02:00
|
|
|
* seems considerably more useful in practice. Since
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
* this code only executes in an ALTER DOMAIN command,
|
|
|
|
* the client should already know which domain is in
|
|
|
|
* question.
|
|
|
|
*/
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NOT_NULL_VIOLATION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("column \"%s\" of table \"%s\" contains null values",
|
2005-10-15 04:49:52 +02:00
|
|
|
NameStr(tupdesc->attrs[attnum - 1]->attname),
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
RelationGetRelationName(testrel)),
|
|
|
|
errtablecol(testrel, attnum)));
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
heap_endscan(scan);
|
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
|
|
|
UnregisterSnapshot(snapshot);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Close each rel after processing, but keep lock */
|
|
|
|
heap_close(testrel, NoLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Okay to update pg_type row. We can scribble on typTup because it's a
|
2005-10-15 04:49:52 +02:00
|
|
|
* copy.
|
2003-01-04 01:46:08 +01:00
|
|
|
*/
|
|
|
|
typTup->typnotnull = notNull;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
simple_heap_update(typrel, &tup->t_self, tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
CatalogUpdateIndexes(typrel, tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, domainoid);
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/* Clean up */
|
2003-01-04 01:46:08 +01:00
|
|
|
heap_freetuple(tup);
|
|
|
|
heap_close(typrel, RowExclusiveLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterDomainDropConstraint
|
|
|
|
*
|
|
|
|
* Implements the ALTER DOMAIN DROP CONSTRAINT statement
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2006-03-14 23:48:25 +01:00
|
|
|
AlterDomainDropConstraint(List *names, const char *constrName,
|
2012-01-05 18:48:55 +01:00
|
|
|
DropBehavior behavior, bool missing_ok)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid domainoid;
|
|
|
|
HeapTuple tup;
|
|
|
|
Relation rel;
|
|
|
|
Relation conrel;
|
|
|
|
SysScanDesc conscan;
|
|
|
|
ScanKeyData key[1];
|
|
|
|
HeapTuple contup;
|
2012-01-05 18:48:55 +01:00
|
|
|
bool found = false;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address = InvalidObjectAddress;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
2006-03-14 23:48:25 +01:00
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
domainoid = typenameTypeId(NULL, typename);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Look up the domain in the type table */
|
2005-04-14 22:03:27 +02:00
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
|
2002-12-06 06:00:34 +01:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", domainoid);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Check it's a domain and check user has permission for ALTER DOMAIN */
|
2010-10-25 05:04:37 +02:00
|
|
|
checkDomainOwner(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Grab an appropriate lock on the pg_constraint relation */
|
2005-04-14 22:03:27 +02:00
|
|
|
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Use the index to scan only constraints of the target relation */
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_constraint_contypid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(HeapTupleGetOid(tup)));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
NULL, 1, key);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan over the result set, removing any matching entries.
|
|
|
|
*/
|
|
|
|
while ((contup = systable_getnext(conscan)) != NULL)
|
|
|
|
{
|
|
|
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
|
|
|
|
|
|
|
|
if (strcmp(NameStr(con->conname), constrName) == 0)
|
|
|
|
{
|
|
|
|
ObjectAddress conobj;
|
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
conobj.classId = ConstraintRelationId;
|
2002-12-06 06:00:34 +01:00
|
|
|
conobj.objectId = HeapTupleGetOid(contup);
|
|
|
|
conobj.objectSubId = 0;
|
|
|
|
|
2012-01-26 15:24:54 +01:00
|
|
|
performDeletion(&conobj, behavior, 0);
|
2012-01-05 18:48:55 +01:00
|
|
|
found = true;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
}
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
|
|
|
|
ObjectAddressSet(address, TypeRelationId, domainoid);
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/* Clean up after the scan */
|
|
|
|
systable_endscan(conscan);
|
|
|
|
heap_close(conrel, RowExclusiveLock);
|
|
|
|
|
|
|
|
heap_close(rel, NoLock);
|
2012-01-05 18:48:55 +01:00
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
if (!missing_ok)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
2012-06-10 21:20:04 +02:00
|
|
|
errmsg("constraint \"%s\" of domain \"%s\" does not exist",
|
|
|
|
constrName, TypeNameToString(typename))));
|
2012-01-05 18:48:55 +01:00
|
|
|
else
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
|
|
|
|
constrName, TypeNameToString(typename))));
|
|
|
|
}
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2003-04-08 18:57:45 +02:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterDomainAddConstraint
|
|
|
|
*
|
|
|
|
* Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
|
|
|
AlterDomainAddConstraint(List *names, Node *newConstraint,
|
|
|
|
ObjectAddress *constrAddr)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid domainoid;
|
2003-01-04 01:46:08 +01:00
|
|
|
Relation typrel;
|
2002-12-06 06:00:34 +01:00
|
|
|
HeapTuple tup;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type typTup;
|
2002-12-06 06:00:34 +01:00
|
|
|
Constraint *constr;
|
2011-06-02 00:43:50 +02:00
|
|
|
char *ccbin;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
2006-03-14 23:48:25 +01:00
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
domainoid = typenameTypeId(NULL, typename);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Look up the domain in the type table */
|
2005-04-14 22:03:27 +02:00
|
|
|
typrel = heap_open(TypeRelationId, RowExclusiveLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
|
2002-12-06 06:00:34 +01:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", domainoid);
|
2002-12-09 21:31:05 +01:00
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Check it's a domain and check user has permission for ALTER DOMAIN */
|
2010-10-25 05:04:37 +02:00
|
|
|
checkDomainOwner(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-09 21:31:05 +01:00
|
|
|
if (!IsA(newConstraint, Constraint))
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(newConstraint));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
constr = (Constraint *) newConstraint;
|
2002-12-09 21:31:05 +01:00
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
switch (constr->contype)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
case CONSTR_CHECK:
|
2002-12-09 21:31:05 +01:00
|
|
|
/* processed below */
|
2003-08-04 02:43:34 +02:00
|
|
|
break;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-09 21:31:05 +01:00
|
|
|
case CONSTR_UNIQUE:
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
2003-09-10 01:22:21 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("unique constraints not possible for domains")));
|
2002-12-09 21:31:05 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTR_PRIMARY:
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
2003-09-10 01:22:21 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("primary key constraints not possible for domains")));
|
2002-12-09 21:31:05 +01:00
|
|
|
break;
|
|
|
|
|
2009-12-07 06:22:23 +01:00
|
|
|
case CONSTR_EXCLUSION:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2010-02-26 03:01:40 +01:00
|
|
|
errmsg("exclusion constraints not possible for domains")));
|
2009-12-07 06:22:23 +01:00
|
|
|
break;
|
|
|
|
|
2009-07-30 04:45:38 +02:00
|
|
|
case CONSTR_FOREIGN:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("foreign key constraints not possible for domains")));
|
|
|
|
break;
|
|
|
|
|
2002-12-09 21:31:05 +01:00
|
|
|
case CONSTR_ATTR_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_NOT_DEFERRABLE:
|
|
|
|
case CONSTR_ATTR_DEFERRED:
|
|
|
|
case CONSTR_ATTR_IMMEDIATE:
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2003-09-10 01:22:21 +02:00
|
|
|
errmsg("specifying constraint deferrability not supported for domains")));
|
2002-12-09 21:31:05 +01:00
|
|
|
break;
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
default:
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized constraint subtype: %d",
|
|
|
|
(int) constr->contype);
|
2002-12-06 06:00:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-08-04 02:43:34 +02:00
|
|
|
* Since all other constraint types throw errors, this must be a check
|
2014-05-06 18:12:18 +02:00
|
|
|
* constraint. First, process the constraint expression and add an entry
|
2005-10-15 04:49:52 +02:00
|
|
|
* to pg_constraint.
|
2002-12-09 21:31:05 +01:00
|
|
|
*/
|
|
|
|
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
|
2002-12-09 21:31:05 +01:00
|
|
|
typTup->typbasetype, typTup->typtypmod,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
constr, NameStr(typTup->typname), constrAddr);
|
2002-12-09 21:31:05 +01:00
|
|
|
|
|
|
|
/*
|
2011-06-02 00:43:50 +02:00
|
|
|
* If requested to validate the constraint, test all values stored in the
|
|
|
|
* attributes based on the domain the constraint is being added to.
|
|
|
|
*/
|
|
|
|
if (!constr->skip_validation)
|
|
|
|
validateDomainConstraint(domainoid, ccbin);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, domainoid);
|
|
|
|
|
2011-06-02 00:43:50 +02:00
|
|
|
/* Clean up */
|
|
|
|
heap_close(typrel, RowExclusiveLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2011-06-02 00:43:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterDomainValidateConstraint
|
|
|
|
*
|
|
|
|
* Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2011-06-02 00:43:50 +02:00
|
|
|
AlterDomainValidateConstraint(List *names, char *constrName)
|
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid domainoid;
|
|
|
|
Relation typrel;
|
|
|
|
Relation conrel;
|
|
|
|
HeapTuple tup;
|
2011-07-02 02:57:34 +02:00
|
|
|
Form_pg_constraint con = NULL;
|
2011-06-02 00:43:50 +02:00
|
|
|
Form_pg_constraint copy_con;
|
|
|
|
char *conbin;
|
2011-11-14 18:08:48 +01:00
|
|
|
SysScanDesc scan;
|
2011-06-02 00:43:50 +02:00
|
|
|
Datum val;
|
|
|
|
bool found = false;
|
|
|
|
bool isnull;
|
|
|
|
HeapTuple tuple;
|
|
|
|
HeapTuple copyTuple;
|
2011-11-14 18:08:48 +01:00
|
|
|
ScanKeyData key;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2011-06-02 00:43:50 +02:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
|
|
|
typename = makeTypeNameFromNameList(names);
|
|
|
|
domainoid = typenameTypeId(NULL, typename);
|
|
|
|
|
|
|
|
/* Look up the domain in the type table */
|
|
|
|
typrel = heap_open(TypeRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", domainoid);
|
|
|
|
|
|
|
|
/* Check it's a domain and check user has permission for ALTER DOMAIN */
|
|
|
|
checkDomainOwner(tup);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find and check the target constraint
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2011-06-02 00:43:50 +02:00
|
|
|
conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
|
|
|
|
ScanKeyInit(&key,
|
|
|
|
Anum_pg_constraint_contypid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(domainoid));
|
|
|
|
scan = systable_beginscan(conrel, ConstraintTypidIndexId,
|
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
|
|
|
true, NULL, 1, &key);
|
2011-06-02 00:43:50 +02:00
|
|
|
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
|
|
|
{
|
|
|
|
con = (Form_pg_constraint) GETSTRUCT(tuple);
|
|
|
|
if (strcmp(NameStr(con->conname), constrName) == 0)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("constraint \"%s\" of domain \"%s\" does not exist",
|
2011-07-04 20:28:05 +02:00
|
|
|
constrName, TypeNameToString(typename))));
|
2011-06-02 00:43:50 +02:00
|
|
|
|
|
|
|
if (con->contype != CONSTRAINT_CHECK)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2011-11-14 18:08:48 +01:00
|
|
|
errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
|
|
|
|
constrName, TypeNameToString(typename))));
|
2011-06-02 00:43:50 +02:00
|
|
|
|
|
|
|
val = SysCacheGetAttr(CONSTROID, tuple,
|
|
|
|
Anum_pg_constraint_conbin,
|
|
|
|
&isnull);
|
|
|
|
if (isnull)
|
|
|
|
elog(ERROR, "null conbin for constraint %u",
|
|
|
|
HeapTupleGetOid(tuple));
|
|
|
|
conbin = TextDatumGetCString(val);
|
|
|
|
|
|
|
|
validateDomainConstraint(domainoid, conbin);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now update the catalog, while we have the door open.
|
|
|
|
*/
|
|
|
|
copyTuple = heap_copytuple(tuple);
|
|
|
|
copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
|
|
|
|
copy_con->convalidated = true;
|
|
|
|
simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
|
|
|
|
CatalogUpdateIndexes(conrel, copyTuple);
|
2013-03-18 03:55:14 +01:00
|
|
|
|
|
|
|
InvokeObjectPostAlterHook(ConstraintRelationId,
|
|
|
|
HeapTupleGetOid(copyTuple), 0);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, domainoid);
|
|
|
|
|
2011-06-02 00:43:50 +02:00
|
|
|
heap_freetuple(copyTuple);
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
|
|
|
|
heap_close(typrel, AccessShareLock);
|
|
|
|
heap_close(conrel, RowExclusiveLock);
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2011-06-02 00:43:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
validateDomainConstraint(Oid domainoid, char *ccbin)
|
|
|
|
{
|
|
|
|
Expr *expr = (Expr *) stringToNode(ccbin);
|
|
|
|
List *rels;
|
|
|
|
ListCell *rt;
|
|
|
|
EState *estate;
|
|
|
|
ExprContext *econtext;
|
|
|
|
ExprState *exprstate;
|
2002-12-12 21:35:16 +01:00
|
|
|
|
2002-12-15 17:17:59 +01:00
|
|
|
/* Need an EState to run ExecEvalExpr */
|
|
|
|
estate = CreateExecutorState();
|
|
|
|
econtext = GetPerTupleExprContext(estate);
|
|
|
|
|
|
|
|
/* build execution state for expr */
|
|
|
|
exprstate = ExecPrepareExpr(expr, estate);
|
2002-12-12 21:35:16 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Fetch relation list with attributes based on this domain */
|
|
|
|
/* ShareLock is sufficient to prevent concurrent data changes */
|
|
|
|
|
|
|
|
rels = get_rels_with_domain(domainoid, ShareLock);
|
2002-12-12 16:49:42 +01:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
foreach(rt, rels)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-01-04 01:46:08 +01:00
|
|
|
RelToCheck *rtc = (RelToCheck *) lfirst(rt);
|
|
|
|
Relation testrel = rtc->rel;
|
|
|
|
TupleDesc tupdesc = RelationGetDescr(testrel);
|
2002-12-06 06:00:34 +01:00
|
|
|
HeapScanDesc scan;
|
2003-01-04 01:46:08 +01:00
|
|
|
HeapTuple tuple;
|
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
|
|
|
Snapshot snapshot;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Scan all tuples in this relation */
|
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
|
|
|
snapshot = RegisterSnapshot(GetLatestSnapshot());
|
|
|
|
scan = heap_beginscan(testrel, snapshot, 0, NULL);
|
2002-12-06 06:00:34 +01:00
|
|
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int i;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Test attributes that are of the domain */
|
2002-12-06 06:00:34 +01:00
|
|
|
for (i = 0; i < rtc->natts; i++)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
int attnum = rtc->atts[i];
|
|
|
|
Datum d;
|
|
|
|
bool isNull;
|
|
|
|
Datum conResult;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
d = heap_getattr(tuple, attnum, tupdesc, &isNull);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
econtext->domainValue_datum = d;
|
|
|
|
econtext->domainValue_isNull = isNull;
|
|
|
|
|
2002-12-15 17:17:59 +01:00
|
|
|
conResult = ExecEvalExprSwitchContext(exprstate,
|
|
|
|
econtext,
|
|
|
|
&isNull, NULL);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-12 21:35:16 +01:00
|
|
|
if (!isNull && !DatumGetBool(conResult))
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In principle the auxiliary information for this error
|
|
|
|
* should be errdomainconstraint(), but errtablecol()
|
2014-05-06 18:12:18 +02:00
|
|
|
* seems considerably more useful in practice. Since this
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
* code only executes in an ALTER DOMAIN command, the
|
|
|
|
* client should already know which domain is in question,
|
|
|
|
* and which constraint too.
|
|
|
|
*/
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_CHECK_VIOLATION),
|
2003-09-29 02:05:25 +02:00
|
|
|
errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
|
2005-10-15 04:49:52 +02:00
|
|
|
NameStr(tupdesc->attrs[attnum - 1]->attname),
|
Provide database object names as separate fields in error messages.
This patch addresses the problem that applications currently have to
extract object names from possibly-localized textual error messages,
if they want to know for example which index caused a UNIQUE_VIOLATION
failure. It adds new error message fields to the wire protocol, which
can carry the name of a table, table column, data type, or constraint
associated with the error. (Since the protocol spec has always instructed
clients to ignore unrecognized field types, this should not create any
compatibility problem.)
Support for providing these new fields has been added to just a limited set
of error reports (mainly, those in the "integrity constraint violation"
SQLSTATE class), but we will doubtless add them to more calls in future.
Pavel Stehule, reviewed and extensively revised by Peter Geoghegan, with
additional hacking by Tom Lane.
2013-01-29 23:06:26 +01:00
|
|
|
RelationGetRelationName(testrel)),
|
|
|
|
errtablecol(testrel, attnum)));
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ResetExprContext(econtext);
|
|
|
|
}
|
|
|
|
heap_endscan(scan);
|
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
|
|
|
UnregisterSnapshot(snapshot);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-12 21:35:16 +01:00
|
|
|
/* Hold relation lock till commit (XXX bad for concurrency) */
|
|
|
|
heap_close(testrel, NoLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
2002-12-15 17:17:59 +01:00
|
|
|
FreeExecutorState(estate);
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
2011-11-14 18:08:48 +01:00
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/*
|
|
|
|
* get_rels_with_domain
|
|
|
|
*
|
|
|
|
* Fetch all relations / attributes which are using the domain
|
2003-01-04 01:46:08 +01:00
|
|
|
*
|
|
|
|
* The result is a list of RelToCheck structs, one for each distinct
|
|
|
|
* relation, each containing one or more attribute numbers that are of
|
|
|
|
* the domain type. We have opened each rel and acquired the specified lock
|
|
|
|
* type on it.
|
|
|
|
*
|
2007-05-11 22:17:15 +02:00
|
|
|
* We support nested domains by including attributes that are of derived
|
|
|
|
* domain types. Current callers do not need to distinguish between attributes
|
|
|
|
* that are of exactly the given domain and those that are of derived domains.
|
|
|
|
*
|
2003-01-04 01:46:08 +01:00
|
|
|
* XXX this is completely broken because there is no way to lock the domain
|
|
|
|
* to prevent columns from being added or dropped while our command runs.
|
|
|
|
* We can partially protect against column drops by locking relations as we
|
|
|
|
* come across them, but there is still a race condition (the window between
|
|
|
|
* seeing a pg_depend entry and acquiring lock on the relation it references).
|
|
|
|
* Also, holding locks on all these relations simultaneously creates a non-
|
|
|
|
* trivial risk of deadlock. We can minimize but not eliminate the deadlock
|
|
|
|
* risk by using the weakest suitable lock (ShareLock for most callers).
|
|
|
|
*
|
2007-05-11 22:17:15 +02:00
|
|
|
* XXX the API for this is not sufficient to support checking domain values
|
|
|
|
* that are inside composite types or arrays. Currently we just error out
|
|
|
|
* if a composite type containing the target domain is stored anywhere.
|
|
|
|
* There are not currently arrays of domains; if there were, we could take
|
|
|
|
* the same approach, but it'd be nicer to fix it properly.
|
2002-12-06 06:00:34 +01:00
|
|
|
*
|
|
|
|
* Generally used for retrieving a list of tests when adding
|
|
|
|
* new constraints to a domain.
|
|
|
|
*/
|
2003-01-04 01:46:08 +01:00
|
|
|
static List *
|
|
|
|
get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
List *result = NIL;
|
2003-01-04 01:46:08 +01:00
|
|
|
Relation depRel;
|
|
|
|
ScanKeyData key[2];
|
|
|
|
SysScanDesc depScan;
|
|
|
|
HeapTuple depTup;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
Assert(lockmode != NoLock);
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We scan pg_depend to find those things that depend on the domain. (We
|
|
|
|
* assume we can ignore refobjsubid for a domain.)
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2005-04-14 22:03:27 +02:00
|
|
|
depRel = heap_open(DependRelationId, AccessShareLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_depend_refclassid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
2005-04-14 03:38:22 +02:00
|
|
|
ObjectIdGetDatum(TypeRelationId));
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&key[1],
|
|
|
|
Anum_pg_depend_refobjid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(domainOid));
|
2003-01-04 01:46:08 +01:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
depScan = 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, 2, key);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
|
2003-01-04 01:46:08 +01:00
|
|
|
RelToCheck *rtc = NULL;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *rellist;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_attribute pg_att;
|
2003-01-04 01:46:08 +01:00
|
|
|
int ptr;
|
|
|
|
|
2007-05-11 22:17:15 +02:00
|
|
|
/* Check for directly dependent types --- must be domains */
|
|
|
|
if (pg_depend->classid == TypeRelationId)
|
|
|
|
{
|
|
|
|
Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2007-05-11 22:17:15 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Recursively add dependent columns to the output list. This is
|
|
|
|
* a bit inefficient since we may fail to combine RelToCheck
|
2007-05-11 22:17:15 +02:00
|
|
|
* entries when attributes of the same rel have different derived
|
|
|
|
* domain types, but it's probably not worth improving.
|
|
|
|
*/
|
|
|
|
result = list_concat(result,
|
|
|
|
get_rels_with_domain(pg_depend->objid,
|
|
|
|
lockmode));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Else, ignore dependees that aren't user columns of relations */
|
2003-01-04 01:46:08 +01:00
|
|
|
/* (we assume system columns are never of domain types) */
|
2005-04-14 03:38:22 +02:00
|
|
|
if (pg_depend->classid != RelationRelationId ||
|
2003-01-04 01:46:08 +01:00
|
|
|
pg_depend->objsubid <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* See if we already have an entry for this relation */
|
|
|
|
foreach(rellist, result)
|
|
|
|
{
|
|
|
|
RelToCheck *rt = (RelToCheck *) lfirst(rellist);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
if (RelationGetRelid(rt->rel) == pg_depend->objid)
|
|
|
|
{
|
|
|
|
rtc = rt;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
if (rtc == NULL)
|
|
|
|
{
|
|
|
|
/* First attribute found for this relation */
|
|
|
|
Relation rel;
|
|
|
|
|
|
|
|
/* Acquire requested lock on relation */
|
2004-05-05 19:06:56 +02:00
|
|
|
rel = relation_open(pg_depend->objid, lockmode);
|
|
|
|
|
2007-05-11 22:17:15 +02:00
|
|
|
/*
|
|
|
|
* Check to see if rowtype is stored anyplace as a composite-type
|
|
|
|
* column; if so we have to fail, for now anyway.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(rel->rd_rel->reltype))
|
|
|
|
find_composite_type_dependencies(rel->rd_rel->reltype,
|
2011-02-11 14:47:38 +01:00
|
|
|
NULL,
|
2007-05-11 22:17:15 +02:00
|
|
|
format_type_be(domainOid));
|
|
|
|
|
2013-07-05 21:25:51 +02:00
|
|
|
/*
|
|
|
|
* Otherwise, we can ignore relations except those with both
|
|
|
|
* storage and user-chosen column types.
|
|
|
|
*
|
|
|
|
* XXX If an index-only scan could satisfy "col::some_domain" from
|
|
|
|
* a suitable expression index, this should also check expression
|
|
|
|
* index columns.
|
|
|
|
*/
|
2013-03-04 01:23:31 +01:00
|
|
|
if (rel->rd_rel->relkind != RELKIND_RELATION &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_MATVIEW)
|
2004-05-05 19:06:56 +02:00
|
|
|
{
|
|
|
|
relation_close(rel, lockmode);
|
|
|
|
continue;
|
|
|
|
}
|
2003-01-04 01:46:08 +01:00
|
|
|
|
|
|
|
/* Build the RelToCheck entry with enough space for all atts */
|
|
|
|
rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
|
|
|
|
rtc->rel = rel;
|
|
|
|
rtc->natts = 0;
|
|
|
|
rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
|
|
|
|
result = lcons(rtc, result);
|
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Confirm column has not been dropped, and is of the expected type.
|
2012-04-24 04:43:09 +02:00
|
|
|
* This defends against an ALTER DROP COLUMN occurring just before we
|
2005-10-15 04:49:52 +02:00
|
|
|
* acquired lock ... but if the whole table were dropped, we'd still
|
|
|
|
* have a problem.
|
2003-01-04 01:46:08 +01:00
|
|
|
*/
|
|
|
|
if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
|
|
|
|
continue;
|
|
|
|
pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
|
|
|
|
if (pg_att->attisdropped || pg_att->atttypid != domainOid)
|
|
|
|
continue;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Okay, add column to result. We store the columns in column-number
|
2005-10-15 04:49:52 +02:00
|
|
|
* order; this is just a hack to improve predictability of regression
|
|
|
|
* test output ...
|
2003-01-04 01:46:08 +01:00
|
|
|
*/
|
|
|
|
Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
ptr = rtc->natts++;
|
2003-08-04 02:43:34 +02:00
|
|
|
while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
rtc->atts[ptr] = rtc->atts[ptr - 1];
|
2003-01-04 01:46:08 +01:00
|
|
|
ptr--;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
2003-01-04 01:46:08 +01:00
|
|
|
rtc->atts[ptr] = pg_depend->objsubid;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
systable_endscan(depScan);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
relation_close(depRel, AccessShareLock);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
return result;
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-14 23:48:25 +01:00
|
|
|
* checkDomainOwner
|
2002-12-06 06:00:34 +01:00
|
|
|
*
|
2006-03-14 23:48:25 +01:00
|
|
|
* Check that the type is actually a domain and that the current user
|
|
|
|
* has permission to do ALTER DOMAIN on it. Throw an error if not.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2012-04-03 07:11:51 +02:00
|
|
|
void
|
2010-10-25 05:04:37 +02:00
|
|
|
checkDomainOwner(HeapTuple tup)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/* Check that this is actually a domain */
|
2007-04-02 05:49:42 +02:00
|
|
|
if (typTup->typtype != TYPTYPE_DOMAIN)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2010-10-25 05:04:37 +02:00
|
|
|
errmsg("%s is not a domain",
|
|
|
|
format_type_be(HeapTupleGetOid(tup)))));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2003-01-04 01:46:08 +01:00
|
|
|
/* Permission check: must own type */
|
|
|
|
if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
|
2003-01-04 01:46:08 +01:00
|
|
|
}
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
2002-12-12 21:35:16 +01:00
|
|
|
* domainAddConstraint - code shared between CREATE and ALTER DOMAIN
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2002-12-12 21:35:16 +01:00
|
|
|
static char *
|
2002-12-06 06:00:34 +01:00
|
|
|
domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
|
2002-12-12 21:35:16 +01:00
|
|
|
int typMod, Constraint *constr,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
char *domainName, ObjectAddress *constrAddr)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
|
|
|
Node *expr;
|
|
|
|
char *ccsrc;
|
|
|
|
char *ccbin;
|
|
|
|
ParseState *pstate;
|
2003-08-04 02:43:34 +02:00
|
|
|
CoerceToDomainValue *domVal;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
Oid ccoid;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign or validate constraint name
|
|
|
|
*/
|
2009-07-30 04:45:38 +02:00
|
|
|
if (constr->conname)
|
2002-12-06 06:00:34 +01:00
|
|
|
{
|
|
|
|
if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
|
|
|
|
domainOid,
|
|
|
|
domainNamespace,
|
2009-07-30 04:45:38 +02:00
|
|
|
constr->conname))
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("constraint \"%s\" for domain \"%s\" already exists",
|
2009-07-30 04:45:38 +02:00
|
|
|
constr->conname, domainName)));
|
2002-12-06 06:00:34 +01:00
|
|
|
}
|
|
|
|
else
|
2009-07-30 04:45:38 +02:00
|
|
|
constr->conname = ChooseConstraintName(domainName,
|
|
|
|
NULL,
|
|
|
|
"check",
|
|
|
|
domainNamespace,
|
|
|
|
NIL);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
2002-12-12 21:35:16 +01:00
|
|
|
* Convert the A_EXPR in raw_expr into an EXPR
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
pstate = make_parsestate(NULL);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Set up a CoerceToDomainValue to represent the occurrence of VALUE in
|
2014-05-06 18:12:18 +02:00
|
|
|
* the expression. Note that it will appear to have the type of the base
|
2005-10-15 04:49:52 +02:00
|
|
|
* type, not the domain. This seems correct since within the check
|
|
|
|
* expression, we should not assume the input value can be considered a
|
|
|
|
* member of the domain.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
2003-02-03 22:15:45 +01:00
|
|
|
domVal = makeNode(CoerceToDomainValue);
|
2002-12-06 06:00:34 +01:00
|
|
|
domVal->typeId = baseTypeOid;
|
|
|
|
domVal->typeMod = typMod;
|
2011-03-20 01:29:08 +01:00
|
|
|
domVal->collation = get_typcollation(baseTypeOid);
|
2008-08-29 01:09:48 +02:00
|
|
|
domVal->location = -1; /* will be set when/if used */
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-12 21:35:16 +01:00
|
|
|
pstate->p_value_substitute = (Node *) domVal;
|
2002-12-06 06:00:34 +01:00
|
|
|
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure it yields a boolean result.
|
|
|
|
*/
|
2003-04-30 00:13:11 +02:00
|
|
|
expr = coerce_to_boolean(pstate, expr, "CHECK");
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2011-03-20 01:29:08 +01:00
|
|
|
/*
|
|
|
|
* Fix up collation information.
|
|
|
|
*/
|
|
|
|
assign_expr_collations(pstate, expr);
|
|
|
|
|
2002-12-06 06:00:34 +01:00
|
|
|
/*
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
* Domains don't allow variables (this is probably dead code now that
|
|
|
|
* add_missing_from is history, but let's be sure).
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
Centralize the logic for detecting misplaced aggregates, window funcs, etc.
Formerly we relied on checking after-the-fact to see if an expression
contained aggregates, window functions, or sub-selects when it shouldn't.
This is grotty, easily forgotten (indeed, we had forgotten to teach
DefineIndex about rejecting window functions), and none too efficient
since it requires extra traversals of the parse tree. To improve matters,
define an enum type that classifies all SQL sub-expressions, store it in
ParseState to show what kind of expression we are currently parsing, and
make transformAggregateCall, transformWindowFuncCall, and transformSubLink
check the expression type and throw error if the type indicates the
construct is disallowed. This allows removal of a large number of ad-hoc
checks scattered around the code base. The enum type is sufficiently
fine-grained that we can still produce error messages of at least the
same specificity as before.
Bringing these error checks together revealed that we'd been none too
consistent about phrasing of the error messages, so standardize the wording
a bit.
Also, rewrite checking of aggregate arguments so that it requires only one
traversal of the arguments, rather than up to three as before.
In passing, clean up some more comments left over from add_missing_from
support, and annotate some tests that I think are dead code now that that's
gone. (I didn't risk actually removing said dead code, though.)
2012-08-10 17:35:33 +02:00
|
|
|
if (list_length(pstate->p_rtable) != 0 ||
|
|
|
|
contain_var_clause(expr))
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("cannot use table references in domain check constraint")));
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
2002-12-12 16:49:42 +01:00
|
|
|
* Convert to string form for storage.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
ccbin = nodeToString(expr);
|
|
|
|
|
|
|
|
/*
|
2002-12-12 16:49:42 +01:00
|
|
|
* Deparse it to produce text for consrc.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
ccsrc = deparse_expression(expr,
|
2012-12-31 21:13:26 +01:00
|
|
|
NIL, false, false);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
2002-12-12 21:35:16 +01:00
|
|
|
/*
|
|
|
|
* Store the constraint in pg_constraint
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ccoid =
|
|
|
|
CreateConstraintEntry(constr->conname, /* Constraint Name */
|
|
|
|
domainNamespace, /* namespace */
|
|
|
|
CONSTRAINT_CHECK, /* Constraint Type */
|
|
|
|
false, /* Is Deferrable */
|
|
|
|
false, /* Is Deferred */
|
|
|
|
!constr->skip_validation, /* Is Validated */
|
|
|
|
InvalidOid, /* not a relation constraint */
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
domainOid, /* domain constraint */
|
|
|
|
InvalidOid, /* no associated index */
|
|
|
|
InvalidOid, /* Foreign key fields */
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
' ',
|
|
|
|
' ',
|
|
|
|
' ',
|
|
|
|
NULL, /* not an exclusion constraint */
|
|
|
|
expr, /* Tree form of check constraint */
|
|
|
|
ccbin, /* Binary form of check constraint */
|
|
|
|
ccsrc, /* Source form of check constraint */
|
|
|
|
true, /* is local */
|
|
|
|
0, /* inhcount */
|
|
|
|
false, /* connoinherit */
|
|
|
|
false); /* is_internal */
|
|
|
|
if (constrAddr)
|
|
|
|
ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
|
2002-12-06 06:00:34 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Return the compiled constraint expression so the calling routine can
|
|
|
|
* perform any additional required tests.
|
2002-12-06 06:00:34 +01:00
|
|
|
*/
|
|
|
|
return ccbin;
|
|
|
|
}
|
2003-01-06 01:31:45 +01:00
|
|
|
|
2008-03-19 19:38:30 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute ALTER TYPE RENAME
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2011-12-22 21:43:56 +01:00
|
|
|
RenameType(RenameStmt *stmt)
|
2008-03-19 19:38:30 +01:00
|
|
|
{
|
2011-12-22 21:43:56 +01:00
|
|
|
List *names = stmt->object;
|
|
|
|
const char *newTypeName = stmt->newname;
|
2008-03-19 19:38:30 +01:00
|
|
|
TypeName *typename;
|
|
|
|
Oid typeOid;
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Form_pg_type typTup;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2008-03-19 19:38:30 +01:00
|
|
|
|
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
typeOid = typenameTypeId(NULL, typename);
|
2008-03-19 19:38:30 +01:00
|
|
|
|
|
|
|
/* Look up the type in the type table */
|
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
|
2008-03-19 19:38:30 +01:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/* check permissions on type */
|
|
|
|
if (!pg_type_ownercheck(typeOid, GetUserId()))
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
|
2008-03-19 19:38:30 +01:00
|
|
|
|
2011-12-22 21:43:56 +01:00
|
|
|
/* ALTER DOMAIN used on a non-domain? */
|
|
|
|
if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("\"%s\" is not a domain",
|
|
|
|
format_type_be(typeOid))));
|
|
|
|
|
2008-03-19 19:38:30 +01:00
|
|
|
/*
|
|
|
|
* If it's a composite type, we need to check that it really is a
|
2009-06-11 16:49:15 +02:00
|
|
|
* free-standing composite type, and not a table's rowtype. We want people
|
|
|
|
* to use ALTER TABLE not ALTER TYPE for that case.
|
2008-03-19 19:38:30 +01:00
|
|
|
*/
|
|
|
|
if (typTup->typtype == TYPTYPE_COMPOSITE &&
|
|
|
|
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("%s is a table's row type",
|
|
|
|
format_type_be(typeOid)),
|
|
|
|
errhint("Use ALTER TABLE instead.")));
|
|
|
|
|
|
|
|
/* don't allow direct alteration of array types, either */
|
|
|
|
if (OidIsValid(typTup->typelem) &&
|
|
|
|
get_array_type(typTup->typelem) == typeOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("cannot alter array type %s",
|
|
|
|
format_type_be(typeOid)),
|
|
|
|
errhint("You can alter type %s, which will alter the array type as well.",
|
|
|
|
format_type_be(typTup->typelem))));
|
|
|
|
|
2009-06-11 16:49:15 +02:00
|
|
|
/*
|
2008-03-19 19:38:30 +01:00
|
|
|
* If type is composite we need to rename associated pg_class entry too.
|
|
|
|
* RenameRelationInternal will call RenameTypeInternal automatically.
|
|
|
|
*/
|
|
|
|
if (typTup->typtype == TYPTYPE_COMPOSITE)
|
2013-03-18 03:55:14 +01:00
|
|
|
RenameRelationInternal(typTup->typrelid, newTypeName, false);
|
2008-03-19 19:38:30 +01:00
|
|
|
else
|
|
|
|
RenameTypeInternal(typeOid, newTypeName,
|
|
|
|
typTup->typnamespace);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, typeOid);
|
2008-03-19 19:38:30 +01:00
|
|
|
/* Clean up */
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2008-03-19 19:38:30 +01:00
|
|
|
}
|
|
|
|
|
2003-01-06 01:31:45 +01:00
|
|
|
/*
|
2004-06-25 23:55:59 +02:00
|
|
|
* Change the owner of a type.
|
2003-01-06 01:31:45 +01:00
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2012-01-27 20:20:34 +01:00
|
|
|
AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
|
2003-01-06 01:31:45 +01:00
|
|
|
{
|
|
|
|
TypeName *typename;
|
|
|
|
Oid typeOid;
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
2007-11-11 20:22:49 +01:00
|
|
|
HeapTuple newtup;
|
2003-08-04 02:43:34 +02:00
|
|
|
Form_pg_type typTup;
|
2005-07-14 23:46:30 +02:00
|
|
|
AclResult aclresult;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2003-01-06 01:31:45 +01:00
|
|
|
|
2007-11-11 20:22:49 +01:00
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
|
|
|
|
2003-01-06 01:31:45 +01:00
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
2006-03-14 23:48:25 +01:00
|
|
|
typename = makeTypeNameFromNameList(names);
|
2003-01-06 01:31:45 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Use LookupTypeName here so that shell types can be processed */
|
2014-01-23 18:40:29 +01:00
|
|
|
tup = LookupTypeName(NULL, typename, NULL, false);
|
2007-11-11 20:22:49 +01:00
|
|
|
if (tup == NULL)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("type \"%s\" does not exist",
|
|
|
|
TypeNameToString(typename))));
|
2007-11-15 22:14:46 +01:00
|
|
|
typeOid = typeTypeId(tup);
|
2003-01-06 01:31:45 +01:00
|
|
|
|
2007-11-11 20:22:49 +01:00
|
|
|
/* Copy the syscache entry so we can scribble on it below */
|
|
|
|
newtup = heap_copytuple(tup);
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
tup = newtup;
|
2003-01-06 01:31:45 +01:00
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
2012-01-27 20:20:34 +01:00
|
|
|
/* Don't allow ALTER DOMAIN on a type */
|
|
|
|
if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("%s is not a domain",
|
|
|
|
format_type_be(typeOid))));
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
/*
|
2004-08-29 07:07:03 +02:00
|
|
|
* If it's a composite type, we need to check that it really is a
|
2007-11-15 22:14:46 +01:00
|
|
|
* free-standing composite type, and not a table's rowtype. We want people
|
|
|
|
* to use ALTER TABLE not ALTER TYPE for that case.
|
2004-06-25 23:55:59 +02:00
|
|
|
*/
|
2007-04-02 05:49:42 +02:00
|
|
|
if (typTup->typtype == TYPTYPE_COMPOSITE &&
|
2005-08-04 03:09:29 +02:00
|
|
|
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
|
2003-07-20 23:56:35 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2007-09-29 19:18:58 +02:00
|
|
|
errmsg("%s is a table's row type",
|
|
|
|
format_type_be(typeOid)),
|
|
|
|
errhint("Use ALTER TABLE instead.")));
|
2003-01-06 01:31:45 +01:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/* don't allow direct alteration of array types, either */
|
|
|
|
if (OidIsValid(typTup->typelem) &&
|
|
|
|
get_array_type(typTup->typelem) == typeOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("cannot alter array type %s",
|
|
|
|
format_type_be(typeOid)),
|
|
|
|
errhint("You can alter type %s, which will alter the array type as well.",
|
|
|
|
format_type_be(typTup->typelem))));
|
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2004-06-25 23:55:59 +02:00
|
|
|
* If the new owner is the same as the existing owner, consider the
|
|
|
|
* command to have succeeded. This is for dump restoration purposes.
|
|
|
|
*/
|
2005-06-28 07:09:14 +02:00
|
|
|
if (typTup->typowner != newOwnerId)
|
2004-06-25 23:55:59 +02:00
|
|
|
{
|
2005-08-22 19:38:20 +02:00
|
|
|
/* Superusers can always do it */
|
|
|
|
if (!superuser())
|
|
|
|
{
|
|
|
|
/* Otherwise, must be owner of the existing object */
|
2005-10-15 04:49:52 +02:00
|
|
|
if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
|
2005-08-22 19:38:20 +02:00
|
|
|
|
|
|
|
/* Must be able to become new owner */
|
|
|
|
check_is_member_of_role(GetUserId(), newOwnerId);
|
|
|
|
|
|
|
|
/* New owner must have CREATE privilege on namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(typTup->typnamespace,
|
|
|
|
newOwnerId,
|
|
|
|
ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(typTup->typnamespace));
|
|
|
|
}
|
2004-06-25 23:55:59 +02:00
|
|
|
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
AlterTypeOwner_oid(typeOid, newOwnerId, true);
|
2004-06-25 23:55:59 +02:00
|
|
|
}
|
2003-01-06 01:31:45 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, TypeRelationId, typeOid);
|
|
|
|
|
2003-01-06 01:31:45 +01:00
|
|
|
/* Clean up */
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2003-01-06 01:31:45 +01:00
|
|
|
}
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2005-08-04 03:09:29 +02:00
|
|
|
/*
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
* AlterTypeOwner_oid - change type owner unconditionally
|
|
|
|
*
|
|
|
|
* This function recurses to handle a pg_class entry, if necessary. It
|
|
|
|
* invokes any necessary access object hooks. If hasDependEntry is TRUE, this
|
|
|
|
* function modifies the pg_shdepend entry appropriately (this should be
|
|
|
|
* passed as FALSE only for table rowtypes and array types).
|
2005-08-04 03:09:29 +02:00
|
|
|
*
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
* This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
|
|
|
|
* OWNED BY. It assumes the caller has done all needed check.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Form_pg_type typTup;
|
|
|
|
|
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/*
|
2016-06-10 00:02:36 +02:00
|
|
|
* If it's a composite type, invoke ATExecChangeOwner so that we fix up
|
|
|
|
* the pg_class entry properly. That will call back to
|
|
|
|
* AlterTypeOwnerInternal to take care of the pg_type entry(s).
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
*/
|
|
|
|
if (typTup->typtype == TYPTYPE_COMPOSITE)
|
|
|
|
ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
|
|
|
|
else
|
|
|
|
AlterTypeOwnerInternal(typeOid, newOwnerId);
|
|
|
|
|
|
|
|
/* Update owner dependency reference */
|
|
|
|
if (hasDependEntry)
|
|
|
|
changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
|
|
|
|
|
|
|
|
InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterTypeOwnerInternal - bare-bones type owner change.
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
*
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
* This routine simply modifies the owner of a pg_type entry, and recurses
|
|
|
|
* to handle a possible array type.
|
2005-08-04 03:09:29 +02:00
|
|
|
*/
|
|
|
|
void
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
|
2005-08-04 03:09:29 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Form_pg_type typTup;
|
2015-01-22 18:36:34 +01:00
|
|
|
Datum repl_val[Natts_pg_type];
|
|
|
|
bool repl_null[Natts_pg_type];
|
|
|
|
bool repl_repl[Natts_pg_type];
|
|
|
|
Acl *newAcl;
|
|
|
|
Datum aclDatum;
|
|
|
|
bool isNull;
|
2005-08-04 03:09:29 +02:00
|
|
|
|
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
|
2005-08-04 03:09:29 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
|
|
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
2015-01-22 18:36:34 +01:00
|
|
|
memset(repl_null, false, sizeof(repl_null));
|
|
|
|
memset(repl_repl, false, sizeof(repl_repl));
|
|
|
|
|
|
|
|
repl_repl[Anum_pg_type_typowner - 1] = true;
|
|
|
|
repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
|
|
|
|
|
|
|
|
aclDatum = heap_getattr(tup,
|
|
|
|
Anum_pg_type_typacl,
|
|
|
|
RelationGetDescr(rel),
|
|
|
|
&isNull);
|
|
|
|
/* Null ACLs do not require changes */
|
|
|
|
if (!isNull)
|
|
|
|
{
|
|
|
|
newAcl = aclnewowner(DatumGetAclP(aclDatum),
|
|
|
|
typTup->typowner, newOwnerId);
|
|
|
|
repl_repl[Anum_pg_type_typacl - 1] = true;
|
|
|
|
repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
|
|
|
|
}
|
|
|
|
|
|
|
|
tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
|
|
|
|
repl_repl);
|
2005-08-04 03:09:29 +02:00
|
|
|
|
|
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
|
|
|
|
CatalogUpdateIndexes(rel, tup);
|
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/* If it has an array type, update that too */
|
|
|
|
if (OidIsValid(typTup->typarray))
|
Rework internals of changing a type's ownership
This is necessary so that REASSIGN OWNED does the right thing with
composite types, to wit, that it also alters ownership of the type's
pg_class entry -- previously, the pg_class entry remained owned by the
original user, which caused later other failures such as the new owner's
inability to use ALTER TYPE to rename an attribute of the affected
composite. Also, if the original owner is later dropped, the pg_class
entry becomes owned by a non-existant user which is bogus.
To fix, create a new routine AlterTypeOwner_oid which knows whether to
pass the request to ATExecChangeOwner or deal with it directly, and use
that in shdepReassignOwner rather than calling AlterTypeOwnerInternal
directly. AlterTypeOwnerInternal is now simpler in that it only
modifies the pg_type entry and recurses to handle a possible array type;
higher-level tasks are handled by either AlterTypeOwner directly or
AlterTypeOwner_oid.
I took the opportunity to add a few more objects to the test rig for
REASSIGN OWNED, so that more cases are exercised. Additional ones could
be added for superuser-only-ownable objects (such as FDWs and event
triggers) but I didn't want to push my luck by adding a new superuser to
the tests on a backpatchable bug fix.
Per bug #13666 reported by Chris Pacejo.
Backpatch to 9.5.
(I would back-patch this all the way back, except that it doesn't apply
cleanly in 9.4 and earlier because 59367fdf9 wasn't backpatched. If we
decide that we need this in earlier branches too, we should backpatch
both.)
2015-12-17 18:25:41 +01:00
|
|
|
AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
|
2013-03-18 03:55:14 +01:00
|
|
|
|
2005-08-04 03:09:29 +02:00
|
|
|
/* Clean up */
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
|
|
}
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
/*
|
|
|
|
* Execute ALTER TYPE SET SCHEMA
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
|
|
|
AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
|
|
|
|
Oid *oldschema)
|
2005-08-01 06:03:59 +02:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
TypeName *typename;
|
|
|
|
Oid typeOid;
|
|
|
|
Oid nspOid;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
Oid oldNspOid;
|
2013-05-29 22:58:43 +02:00
|
|
|
ObjectAddresses *objsMoved;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress myself;
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
/* Make a TypeName so we can use standard type lookup machinery */
|
|
|
|
typename = makeTypeNameFromNameList(names);
|
2010-10-25 20:40:46 +02:00
|
|
|
typeOid = typenameTypeId(NULL, typename);
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2012-01-27 20:20:34 +01:00
|
|
|
/* Don't allow ALTER DOMAIN on a type */
|
|
|
|
if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("%s is not a domain",
|
|
|
|
format_type_be(typeOid))));
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* get schema OID and check its permissions */
|
|
|
|
nspOid = LookupCreationNamespace(newschema);
|
|
|
|
|
2012-10-31 14:52:55 +01:00
|
|
|
objsMoved = new_object_addresses();
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
|
2012-10-31 14:52:55 +01:00
|
|
|
free_object_addresses(objsMoved);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
if (oldschema)
|
|
|
|
*oldschema = oldNspOid;
|
|
|
|
|
|
|
|
ObjectAddressSet(myself, TypeRelationId, typeOid);
|
|
|
|
|
|
|
|
return myself;
|
2011-02-08 22:08:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Oid
|
2012-10-31 14:52:55 +01:00
|
|
|
AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
|
2011-02-08 22:08:41 +01:00
|
|
|
{
|
|
|
|
Oid elemOid;
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
/* check permissions on type */
|
|
|
|
if (!pg_type_ownercheck(typeOid, GetUserId()))
|
2012-06-15 21:55:03 +02:00
|
|
|
aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
|
2005-08-01 06:03:59 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/* don't allow direct alteration of array types */
|
|
|
|
elemOid = get_element_type(typeOid);
|
|
|
|
if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("cannot alter array type %s",
|
|
|
|
format_type_be(typeOid)),
|
|
|
|
errhint("You can alter type %s, which will alter the array type as well.",
|
|
|
|
format_type_be(elemOid))));
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
/* and do the work */
|
2012-10-31 14:52:55 +01:00
|
|
|
return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
|
2005-08-01 06:03:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move specified type to new namespace.
|
|
|
|
*
|
|
|
|
* Caller must have already checked privileges.
|
|
|
|
*
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
* The function automatically recurses to process the type's array type,
|
2014-05-06 18:12:18 +02:00
|
|
|
* if any. isImplicitArray should be TRUE only when doing this internal
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
* recursion (outside callers must never try to move an array type directly).
|
|
|
|
*
|
2005-08-01 06:03:59 +02:00
|
|
|
* If errorOnTableType is TRUE, the function errors out if the type is
|
|
|
|
* a table type. ALTER TABLE has to be used to move a table to a new
|
|
|
|
* namespace.
|
2011-02-08 22:08:41 +01:00
|
|
|
*
|
|
|
|
* Returns the type's old namespace OID.
|
2005-08-01 06:03:59 +02:00
|
|
|
*/
|
2011-02-08 22:08:41 +01:00
|
|
|
Oid
|
2005-08-01 06:03:59 +02:00
|
|
|
AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
bool isImplicitArray,
|
2012-10-31 14:52:55 +01:00
|
|
|
bool errorOnTableType,
|
|
|
|
ObjectAddresses *objsMoved)
|
2005-08-01 06:03:59 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Form_pg_type typform;
|
|
|
|
Oid oldNspOid;
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
Oid arrayOid;
|
2005-08-01 06:03:59 +02:00
|
|
|
bool isCompositeType;
|
2012-10-31 14:52:55 +01:00
|
|
|
ObjectAddress thisobj;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we haven't moved this object previously.
|
|
|
|
*/
|
|
|
|
thisobj.classId = TypeRelationId;
|
|
|
|
thisobj.objectId = typeOid;
|
|
|
|
thisobj.objectSubId = 0;
|
|
|
|
|
|
|
|
if (object_address_present(&thisobj, objsMoved))
|
|
|
|
return InvalidOid;
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
rel = heap_open(TypeRelationId, RowExclusiveLock);
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
|
2005-08-01 06:03:59 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
|
|
|
typform = (Form_pg_type) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
oldNspOid = typform->typnamespace;
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
arrayOid = typform->typarray;
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2015-11-19 16:49:25 +01:00
|
|
|
/* If the type is already there, we scan skip these next few checks. */
|
|
|
|
if (oldNspOid != nspOid)
|
|
|
|
{
|
|
|
|
/* common checks on switching namespaces */
|
|
|
|
CheckSetNamespace(oldNspOid, nspOid);
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2015-11-19 16:49:25 +01:00
|
|
|
/* check for duplicate name (more friendly than unique-index failure) */
|
|
|
|
if (SearchSysCacheExists2(TYPENAMENSP,
|
2016-09-13 23:17:48 +02:00
|
|
|
NameGetDatum(&typform->typname),
|
2015-11-19 16:49:25 +01:00
|
|
|
ObjectIdGetDatum(nspOid)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("type \"%s\" already exists in schema \"%s\"",
|
|
|
|
NameStr(typform->typname),
|
|
|
|
get_namespace_name(nspOid))));
|
|
|
|
}
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
/* Detect whether type is a composite type (but not a table rowtype) */
|
|
|
|
isCompositeType =
|
2007-04-02 05:49:42 +02:00
|
|
|
(typform->typtype == TYPTYPE_COMPOSITE &&
|
2005-08-01 06:03:59 +02:00
|
|
|
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
|
|
|
|
|
|
|
|
/* Enforce not-table-type if requested */
|
2007-04-02 05:49:42 +02:00
|
|
|
if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
|
|
|
|
errorOnTableType)
|
2005-08-01 06:03:59 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
|
|
errmsg("%s is a table's row type",
|
|
|
|
format_type_be(typeOid)),
|
2007-09-29 19:18:58 +02:00
|
|
|
errhint("Use ALTER TABLE instead.")));
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2015-11-19 16:49:25 +01:00
|
|
|
if (oldNspOid != nspOid)
|
|
|
|
{
|
|
|
|
/* OK, modify the pg_type row */
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2015-11-19 16:49:25 +01:00
|
|
|
/* tup is a copy, so we can scribble directly on it */
|
|
|
|
typform->typnamespace = nspOid;
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2015-11-19 16:49:25 +01:00
|
|
|
simple_heap_update(rel, &tup->t_self, tup);
|
|
|
|
CatalogUpdateIndexes(rel, tup);
|
|
|
|
}
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Composite types have pg_class entries.
|
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We need to modify the pg_class tuple as well to reflect the change of
|
|
|
|
* schema.
|
2005-08-01 06:03:59 +02:00
|
|
|
*/
|
|
|
|
if (isCompositeType)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Relation classRel;
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
classRel = heap_open(RelationRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
AlterRelationNamespaceInternal(classRel, typform->typrelid,
|
|
|
|
oldNspOid, nspOid,
|
2012-10-31 14:52:55 +01:00
|
|
|
false, objsMoved);
|
2005-08-01 06:03:59 +02:00
|
|
|
|
|
|
|
heap_close(classRel, RowExclusiveLock);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check for constraints associated with the composite type (we don't
|
|
|
|
* currently support this, but probably will someday).
|
2005-08-01 06:03:59 +02:00
|
|
|
*/
|
|
|
|
AlterConstraintNamespaces(typform->typrelid, oldNspOid,
|
2012-10-31 14:52:55 +01:00
|
|
|
nspOid, false, objsMoved);
|
2005-08-01 06:03:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If it's a domain, it might have constraints */
|
2007-04-02 05:49:42 +02:00
|
|
|
if (typform->typtype == TYPTYPE_DOMAIN)
|
2012-10-31 14:52:55 +01:00
|
|
|
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
|
|
|
|
objsMoved);
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
}
|
2005-08-01 06:03:59 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/*
|
|
|
|
* Update dependency on schema, if any --- a table rowtype has not got
|
|
|
|
* one, and neither does an implicit array.
|
|
|
|
*/
|
2015-11-19 16:49:25 +01:00
|
|
|
if (oldNspOid != nspOid &&
|
|
|
|
(isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
!isImplicitArray)
|
|
|
|
if (changeDependencyFor(TypeRelationId, typeOid,
|
2005-10-15 04:49:52 +02:00
|
|
|
NamespaceRelationId, oldNspOid, nspOid) != 1)
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
elog(ERROR, "failed to change schema dependency for type %s",
|
|
|
|
format_type_be(typeOid));
|
2005-08-01 06:03:59 +02:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
heap_freetuple(tup);
|
|
|
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
|
2012-10-31 14:52:55 +01:00
|
|
|
add_exact_object_address(&thisobj, objsMoved);
|
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
/* Recursively alter the associated array type, if any */
|
|
|
|
if (OidIsValid(arrayOid))
|
2012-10-31 14:52:55 +01:00
|
|
|
AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
return oldNspOid;
|
2005-08-01 06:03:59 +02:00
|
|
|
}
|