2003-06-27 16:45:32 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* alter.c
|
|
|
|
* Drivers for generic alter commands
|
|
|
|
*
|
2014-01-07 22:05:30 +01:00
|
|
|
* Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
|
2003-06-27 16:45:32 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/commands/alter.c
|
2003-06-27 16:45:32 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2012-10-03 23:02:38 +02:00
|
|
|
#include "access/sysattr.h"
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/indexing.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "catalog/namespace.h"
|
2013-03-18 03:55:14 +01:00
|
|
|
#include "catalog/objectaccess.h"
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
#include "catalog/pg_collation.h"
|
|
|
|
#include "catalog/pg_conversion.h"
|
2013-01-21 16:06:41 +01:00
|
|
|
#include "catalog/pg_event_trigger.h"
|
|
|
|
#include "catalog/pg_foreign_data_wrapper.h"
|
|
|
|
#include "catalog/pg_foreign_server.h"
|
|
|
|
#include "catalog/pg_language.h"
|
2009-12-11 04:34:57 +01:00
|
|
|
#include "catalog/pg_largeobject.h"
|
2012-10-03 23:02:38 +02:00
|
|
|
#include "catalog/pg_largeobject_metadata.h"
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "catalog/pg_namespace.h"
|
2013-01-21 16:06:41 +01:00
|
|
|
#include "catalog/pg_opclass.h"
|
|
|
|
#include "catalog/pg_opfamily.h"
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_ts_config.h"
|
|
|
|
#include "catalog/pg_ts_dict.h"
|
|
|
|
#include "catalog/pg_ts_parser.h"
|
|
|
|
#include "catalog/pg_ts_template.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/alter.h"
|
2011-02-12 14:54:13 +01:00
|
|
|
#include "commands/collationcmds.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/conversioncmds.h"
|
|
|
|
#include "commands/dbcommands.h"
|
|
|
|
#include "commands/defrem.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "commands/event_trigger.h"
|
2011-02-08 22:08:41 +01:00
|
|
|
#include "commands/extension.h"
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
#include "commands/policy.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/proclang.h"
|
|
|
|
#include "commands/schemacmds.h"
|
|
|
|
#include "commands/tablecmds.h"
|
2004-06-25 23:55:59 +02:00
|
|
|
#include "commands/tablespace.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/trigger.h"
|
2004-06-25 23:55:59 +02:00
|
|
|
#include "commands/typecmds.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/user.h"
|
2013-01-21 16:06:41 +01:00
|
|
|
#include "parser/parse_func.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "miscadmin.h"
|
2013-02-09 05:58:40 +01:00
|
|
|
#include "rewrite/rewriteDefine.h"
|
2003-07-22 21:00:12 +02:00
|
|
|
#include "tcop/utility.h"
|
2010-06-13 19:43:13 +02:00
|
|
|
#include "utils/builtins.h"
|
2012-10-03 23:02:38 +02:00
|
|
|
#include "utils/fmgroids.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "utils/syscache.h"
|
2012-10-03 23:02:38 +02:00
|
|
|
#include "utils/tqual.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
|
|
|
|
|
2013-05-29 22:58:43 +02:00
|
|
|
static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
/*
|
2013-01-21 16:06:41 +01:00
|
|
|
* Raise an error to the effect that an object of the given name is already
|
|
|
|
* present in the given namespace.
|
2004-06-25 23:55:59 +02:00
|
|
|
*/
|
2013-01-21 16:06:41 +01:00
|
|
|
static void
|
|
|
|
report_name_conflict(Oid classId, const char *name)
|
2003-06-27 16:45:32 +02:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
char *msgfmt;
|
2013-01-21 16:06:41 +01:00
|
|
|
|
|
|
|
switch (classId)
|
2003-06-27 16:45:32 +02:00
|
|
|
{
|
2013-01-21 16:06:41 +01:00
|
|
|
case EventTriggerRelationId:
|
|
|
|
msgfmt = gettext_noop("event trigger \"%s\" already exists");
|
|
|
|
break;
|
|
|
|
case ForeignDataWrapperRelationId:
|
|
|
|
msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
|
|
|
|
break;
|
|
|
|
case ForeignServerRelationId:
|
|
|
|
msgfmt = gettext_noop("server \"%s\" already exists");
|
|
|
|
break;
|
|
|
|
case LanguageRelationId:
|
|
|
|
msgfmt = gettext_noop("language \"%s\" already exists");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unsupported object class %u", classId);
|
|
|
|
break;
|
|
|
|
}
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg(msgfmt, name)));
|
|
|
|
}
|
2011-02-12 14:54:13 +01:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
static void
|
|
|
|
report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
char *msgfmt;
|
2012-03-10 19:19:13 +01:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
Assert(OidIsValid(nspOid));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
switch (classId)
|
|
|
|
{
|
|
|
|
case ConversionRelationId:
|
|
|
|
Assert(OidIsValid(nspOid));
|
|
|
|
msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
|
|
|
|
break;
|
|
|
|
case TSParserRelationId:
|
|
|
|
Assert(OidIsValid(nspOid));
|
|
|
|
msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
|
|
|
|
break;
|
|
|
|
case TSDictionaryRelationId:
|
|
|
|
Assert(OidIsValid(nspOid));
|
|
|
|
msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
|
|
|
|
break;
|
|
|
|
case TSTemplateRelationId:
|
|
|
|
Assert(OidIsValid(nspOid));
|
|
|
|
msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
|
|
|
|
break;
|
|
|
|
case TSConfigRelationId:
|
|
|
|
Assert(OidIsValid(nspOid));
|
|
|
|
msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unsupported object class %u", classId);
|
|
|
|
break;
|
|
|
|
}
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg(msgfmt, name, get_namespace_name(nspOid))));
|
|
|
|
}
|
2011-12-09 19:42:30 +01:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
/*
|
|
|
|
* AlterObjectRename_internal
|
|
|
|
*
|
|
|
|
* Generic function to rename the given object, for simple cases (won't
|
|
|
|
* work for tables, nor other cases where we need to do more than change
|
|
|
|
* the name column of a single catalog entry).
|
|
|
|
*
|
|
|
|
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
|
|
|
|
* objectId: OID of object to be renamed
|
|
|
|
* new_name: CString representation of new name
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
|
|
|
|
{
|
|
|
|
Oid classId = RelationGetRelid(rel);
|
|
|
|
int oidCacheId = get_object_catcache_oid(classId);
|
|
|
|
int nameCacheId = get_object_catcache_name(classId);
|
|
|
|
AttrNumber Anum_name = get_object_attnum_name(classId);
|
|
|
|
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
|
|
|
|
AttrNumber Anum_owner = get_object_attnum_owner(classId);
|
|
|
|
AclObjectKind acl_kind = get_object_aclkind(classId);
|
|
|
|
HeapTuple oldtup;
|
|
|
|
HeapTuple newtup;
|
|
|
|
Datum datum;
|
|
|
|
bool isnull;
|
|
|
|
Oid namespaceId;
|
|
|
|
Oid ownerId;
|
|
|
|
char *old_name;
|
|
|
|
AclResult aclresult;
|
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
bool *replaces;
|
2013-06-13 01:49:50 +02:00
|
|
|
NameData nameattrdata;
|
2011-12-09 19:42:30 +01:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
|
|
|
|
if (!HeapTupleIsValid(oldtup))
|
|
|
|
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
|
|
|
|
objectId, RelationGetRelationName(rel));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
datum = heap_getattr(oldtup, Anum_name,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
old_name = NameStr(*(DatumGetName(datum)));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
/* Get OID of namespace */
|
|
|
|
if (Anum_namespace > 0)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(oldtup, Anum_namespace,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
namespaceId = DatumGetObjectId(datum);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
namespaceId = InvalidOid;
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
/* Permission checks ... superusers can always do it */
|
|
|
|
if (!superuser())
|
|
|
|
{
|
|
|
|
/* Fail if object does not have an explicit owner */
|
|
|
|
if (Anum_owner <= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
(errmsg("must be superuser to rename %s",
|
|
|
|
getObjectDescriptionOids(classId, objectId)))));
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
/* Otherwise, must be owner of the existing object */
|
|
|
|
datum = heap_getattr(oldtup, Anum_owner,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
ownerId = DatumGetObjectId(datum);
|
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind, old_name);
|
|
|
|
|
|
|
|
/* User must have CREATE privilege on the namespace */
|
|
|
|
if (OidIsValid(namespaceId))
|
|
|
|
{
|
|
|
|
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
|
|
|
|
ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
|
|
|
get_namespace_name(namespaceId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Check for duplicate name (more friendly than unique-index failure).
|
|
|
|
* Since this is just a friendliness check, we can just skip it in cases
|
|
|
|
* where there isn't suitable support.
|
|
|
|
*/
|
2013-01-21 16:06:41 +01:00
|
|
|
if (classId == ProcedureRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
|
|
|
|
|
|
|
|
IsThereFunctionInNamespace(new_name, proc->pronargs,
|
2013-06-13 01:50:37 +02:00
|
|
|
&proc->proargtypes, proc->pronamespace);
|
2013-01-21 16:06:41 +01:00
|
|
|
}
|
|
|
|
else if (classId == CollationRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(oldtup);
|
|
|
|
|
|
|
|
IsThereCollationInNamespace(new_name, coll->collnamespace);
|
|
|
|
}
|
|
|
|
else if (classId == OperatorClassRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
|
|
|
|
|
|
|
|
IsThereOpClassInNamespace(new_name, opc->opcmethod,
|
|
|
|
opc->opcnamespace);
|
|
|
|
}
|
|
|
|
else if (classId == OperatorFamilyRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(oldtup);
|
|
|
|
|
|
|
|
IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
|
|
|
|
opf->opfnamespace);
|
|
|
|
}
|
|
|
|
else if (nameCacheId >= 0)
|
|
|
|
{
|
|
|
|
if (OidIsValid(namespaceId))
|
|
|
|
{
|
|
|
|
if (SearchSysCacheExists2(nameCacheId,
|
|
|
|
CStringGetDatum(new_name),
|
|
|
|
ObjectIdGetDatum(namespaceId)))
|
|
|
|
report_namespace_conflict(classId, new_name, namespaceId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (SearchSysCacheExists1(nameCacheId,
|
|
|
|
CStringGetDatum(new_name)))
|
|
|
|
report_name_conflict(classId, new_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build modified tuple */
|
|
|
|
values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
|
|
|
|
nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
|
|
|
replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
2013-06-13 01:49:50 +02:00
|
|
|
namestrcpy(&nameattrdata, new_name);
|
|
|
|
values[Anum_name - 1] = NameGetDatum(&nameattrdata);
|
2013-01-21 16:06:41 +01:00
|
|
|
replaces[Anum_name - 1] = true;
|
|
|
|
newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
|
|
values, nulls, replaces);
|
|
|
|
|
|
|
|
/* Perform actual update */
|
|
|
|
simple_heap_update(rel, &oldtup->t_self, newtup);
|
|
|
|
CatalogUpdateIndexes(rel, newtup);
|
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(classId, objectId, 0);
|
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
/* Release memory */
|
|
|
|
pfree(values);
|
|
|
|
pfree(nulls);
|
|
|
|
pfree(replaces);
|
|
|
|
heap_freetuple(newtup);
|
|
|
|
|
|
|
|
ReleaseSysCache(oldtup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
|
2013-01-21 16:06:41 +01:00
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
ExecRenameStmt(RenameStmt *stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->renameType)
|
|
|
|
{
|
2014-12-23 13:06:44 +01:00
|
|
|
case OBJECT_TABCONSTRAINT:
|
|
|
|
case OBJECT_DOMCONSTRAINT:
|
2013-01-21 16:06:41 +01:00
|
|
|
return RenameConstraint(stmt);
|
|
|
|
|
|
|
|
case OBJECT_DATABASE:
|
|
|
|
return RenameDatabase(stmt->subname, stmt->newname);
|
2007-01-23 06:07:18 +01:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
case OBJECT_ROLE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return RenameRole(stmt->subname, stmt->newname);
|
2005-06-28 07:09:14 +02:00
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_SCHEMA:
|
2012-12-24 00:25:03 +01:00
|
|
|
return RenameSchema(stmt->subname, stmt->newname);
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
case OBJECT_TABLESPACE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return RenameTableSpace(stmt->subname, stmt->newname);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_TABLE:
|
2007-07-03 03:30:37 +02:00
|
|
|
case OBJECT_SEQUENCE:
|
|
|
|
case OBJECT_VIEW:
|
2013-03-04 01:23:31 +01:00
|
|
|
case OBJECT_MATVIEW:
|
2004-08-22 02:08:28 +02:00
|
|
|
case OBJECT_INDEX:
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
case OBJECT_FOREIGN_TABLE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return RenameRelation(stmt);
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_COLUMN:
|
2010-09-26 13:41:03 +02:00
|
|
|
case OBJECT_ATTRIBUTE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return renameatt(stmt);
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
|
2013-02-09 05:58:40 +01:00
|
|
|
case OBJECT_RULE:
|
|
|
|
return RenameRewriteRule(stmt->relation, stmt->subname,
|
|
|
|
stmt->newname);
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_TRIGGER:
|
2012-12-24 00:25:03 +01:00
|
|
|
return renametrig(stmt);
|
2003-06-27 16:45:32 +02:00
|
|
|
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
case OBJECT_POLICY:
|
|
|
|
return rename_policy(stmt);
|
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
case OBJECT_DOMAIN:
|
|
|
|
case OBJECT_TYPE:
|
|
|
|
return RenameType(stmt);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
case OBJECT_AGGREGATE:
|
|
|
|
case OBJECT_COLLATION:
|
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
case OBJECT_EVENT_TRIGGER:
|
|
|
|
case OBJECT_FDW:
|
|
|
|
case OBJECT_FOREIGN_SERVER:
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
case OBJECT_OPFAMILY:
|
|
|
|
case OBJECT_LANGUAGE:
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
2007-08-21 03:11:32 +02:00
|
|
|
case OBJECT_TSDICTIONARY:
|
2013-01-21 16:06:41 +01:00
|
|
|
case OBJECT_TSPARSER:
|
2007-08-21 03:11:32 +02:00
|
|
|
case OBJECT_TSTEMPLATE:
|
2013-01-21 16:06:41 +01:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
ObjectAddress address;
|
|
|
|
Relation catalog;
|
|
|
|
Relation relation;
|
2007-08-21 03:11:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
address = get_object_address(stmt->renameType,
|
|
|
|
stmt->object, stmt->objarg,
|
|
|
|
&relation,
|
|
|
|
AccessExclusiveLock, false);
|
|
|
|
Assert(relation == NULL);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
catalog = heap_open(address.classId, RowExclusiveLock);
|
|
|
|
AlterObjectRename_internal(catalog,
|
|
|
|
address.objectId,
|
|
|
|
stmt->newname);
|
|
|
|
heap_close(catalog, RowExclusiveLock);
|
|
|
|
|
|
|
|
return address.objectId;
|
|
|
|
}
|
2008-03-19 19:38:30 +01:00
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
default:
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized rename stmt type: %d",
|
|
|
|
(int) stmt->renameType);
|
2013-05-29 22:58:43 +02:00
|
|
|
return InvalidOid; /* keep compiler happy */
|
2003-06-27 16:45:32 +02:00
|
|
|
}
|
|
|
|
}
|
2004-06-25 23:55:59 +02:00
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
/*
|
|
|
|
* Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
|
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
2012-12-24 00:25:03 +01:00
|
|
|
Oid
|
2005-08-01 06:03:59 +02:00
|
|
|
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->objectType)
|
|
|
|
{
|
2011-02-08 22:08:41 +01:00
|
|
|
case OBJECT_EXTENSION:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterExtensionNamespace(stmt->object, stmt->newschema);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_FOREIGN_TABLE:
|
2005-08-01 06:03:59 +02:00
|
|
|
case OBJECT_SEQUENCE:
|
|
|
|
case OBJECT_TABLE:
|
2008-06-15 03:25:54 +02:00
|
|
|
case OBJECT_VIEW:
|
2013-03-04 01:23:31 +01:00
|
|
|
case OBJECT_MATVIEW:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterTableNamespace(stmt);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2012-09-27 23:13:09 +02:00
|
|
|
case OBJECT_DOMAIN:
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_TYPE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterTypeNamespace(stmt->object, stmt->newschema,
|
|
|
|
stmt->objectType);
|
2010-11-26 23:27:23 +01:00
|
|
|
|
2012-09-27 23:13:09 +02:00
|
|
|
/* generic code path */
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_AGGREGATE:
|
|
|
|
case OBJECT_COLLATION:
|
2012-09-27 23:13:09 +02:00
|
|
|
case OBJECT_CONVERSION:
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_FUNCTION:
|
2012-09-27 23:13:09 +02:00
|
|
|
case OBJECT_OPERATOR:
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
case OBJECT_OPFAMILY:
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_TSCONFIGURATION:
|
2010-11-26 23:27:23 +01:00
|
|
|
case OBJECT_TSDICTIONARY:
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OBJECT_TSPARSER:
|
2010-11-26 23:27:23 +01:00
|
|
|
case OBJECT_TSTEMPLATE:
|
2012-09-27 23:13:09 +02:00
|
|
|
{
|
|
|
|
Relation catalog;
|
|
|
|
Relation relation;
|
|
|
|
Oid classId;
|
|
|
|
Oid nspOid;
|
|
|
|
ObjectAddress address;
|
|
|
|
|
|
|
|
address = get_object_address(stmt->objectType,
|
|
|
|
stmt->object,
|
|
|
|
stmt->objarg,
|
|
|
|
&relation,
|
|
|
|
AccessExclusiveLock,
|
|
|
|
false);
|
|
|
|
Assert(relation == NULL);
|
|
|
|
classId = address.classId;
|
|
|
|
catalog = heap_open(classId, RowExclusiveLock);
|
|
|
|
nspOid = LookupCreationNamespace(stmt->newschema);
|
|
|
|
|
|
|
|
AlterObjectNamespace_internal(catalog, address.objectId,
|
|
|
|
nspOid);
|
|
|
|
heap_close(catalog, RowExclusiveLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
|
|
|
return address.objectId;
|
2012-09-27 23:13:09 +02:00
|
|
|
}
|
2005-08-01 06:03:59 +02:00
|
|
|
break;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
2012-12-24 00:25:03 +01:00
|
|
|
return InvalidOid; /* keep compiler happy */
|
2005-08-01 06:03:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/*
|
|
|
|
* Change an object's namespace given its classOid and object Oid.
|
|
|
|
*
|
|
|
|
* Objects that don't have a namespace should be ignored.
|
|
|
|
*
|
|
|
|
* This function is currently used only by ALTER EXTENSION SET SCHEMA,
|
|
|
|
* so it only needs to cover object types that can be members of an
|
|
|
|
* extension, and it doesn't have to deal with certain special cases
|
|
|
|
* such as not wanting to process array types --- those should never
|
|
|
|
* be direct members of an extension anyway.
|
|
|
|
*
|
|
|
|
* Returns the OID of the object's previous namespace, or InvalidOid if
|
|
|
|
* object doesn't have a schema.
|
|
|
|
*/
|
|
|
|
Oid
|
2012-10-31 14:52:55 +01:00
|
|
|
AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
|
|
|
|
ObjectAddresses *objsMoved)
|
2011-02-08 22:08:41 +01:00
|
|
|
{
|
|
|
|
Oid oldNspOid = InvalidOid;
|
|
|
|
ObjectAddress dep;
|
|
|
|
|
|
|
|
dep.classId = classId;
|
|
|
|
dep.objectId = objid;
|
|
|
|
dep.objectSubId = 0;
|
|
|
|
|
|
|
|
switch (getObjectClass(&dep))
|
|
|
|
{
|
|
|
|
case OCLASS_CLASS:
|
2011-04-10 17:42:00 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
rel = relation_open(objid, AccessExclusiveLock);
|
|
|
|
oldNspOid = RelationGetNamespace(rel);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2012-10-31 14:52:55 +01:00
|
|
|
AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
relation_close(rel, NoLock);
|
|
|
|
break;
|
|
|
|
}
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
case OCLASS_TYPE:
|
2012-10-31 14:52:55 +01:00
|
|
|
oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
|
2011-02-08 22:08:41 +01:00
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OCLASS_COLLATION:
|
2011-02-08 22:08:41 +01:00
|
|
|
case OCLASS_CONVERSION:
|
|
|
|
case OCLASS_OPERATOR:
|
|
|
|
case OCLASS_OPCLASS:
|
|
|
|
case OCLASS_OPFAMILY:
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
case OCLASS_PROC:
|
2011-02-08 22:08:41 +01:00
|
|
|
case OCLASS_TSPARSER:
|
|
|
|
case OCLASS_TSDICT:
|
|
|
|
case OCLASS_TSTEMPLATE:
|
|
|
|
case OCLASS_TSCONFIG:
|
2012-09-27 23:13:09 +02:00
|
|
|
{
|
|
|
|
Relation catalog;
|
|
|
|
|
|
|
|
catalog = heap_open(classId, RowExclusiveLock);
|
|
|
|
|
|
|
|
oldNspOid = AlterObjectNamespace_internal(catalog, objid,
|
|
|
|
nspOid);
|
|
|
|
|
|
|
|
heap_close(catalog, RowExclusiveLock);
|
|
|
|
}
|
2011-02-08 22:08:41 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return oldNspOid;
|
|
|
|
}
|
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
/*
|
|
|
|
* Generic function to change the namespace of a given object, for simple
|
2011-02-08 22:08:41 +01:00
|
|
|
* cases (won't work for tables, nor other cases where we need to do more
|
|
|
|
* than change the namespace column of a single catalog entry).
|
2010-11-26 23:27:23 +01:00
|
|
|
*
|
2011-02-08 22:08:41 +01:00
|
|
|
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
|
|
|
|
* objid: OID of object to change the namespace of
|
|
|
|
* nspOid: OID of new namespace
|
|
|
|
*
|
|
|
|
* Returns the OID of the object's previous namespace.
|
2010-11-26 23:27:23 +01:00
|
|
|
*/
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
static Oid
|
2012-09-27 23:13:09 +02:00
|
|
|
AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
|
2010-11-26 23:27:23 +01:00
|
|
|
{
|
2011-02-08 22:08:41 +01:00
|
|
|
Oid classId = RelationGetRelid(rel);
|
2012-09-27 23:13:09 +02:00
|
|
|
int oidCacheId = get_object_catcache_oid(classId);
|
|
|
|
int nameCacheId = get_object_catcache_name(classId);
|
|
|
|
AttrNumber Anum_name = get_object_attnum_name(classId);
|
|
|
|
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
|
|
|
|
AttrNumber Anum_owner = get_object_attnum_owner(classId);
|
|
|
|
AclObjectKind acl_kind = get_object_aclkind(classId);
|
2010-11-26 23:27:23 +01:00
|
|
|
Oid oldNspOid;
|
2011-04-10 17:42:00 +02:00
|
|
|
Datum name,
|
|
|
|
namespace;
|
|
|
|
bool isnull;
|
|
|
|
HeapTuple tup,
|
|
|
|
newtup;
|
2010-11-26 23:27:23 +01:00
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
bool *replaces;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
|
2010-11-26 23:27:23 +01:00
|
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
2011-02-08 22:08:41 +01:00
|
|
|
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
|
|
|
|
objid, RelationGetRelationName(rel));
|
2010-11-26 23:27:23 +01:00
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
2012-09-27 23:13:09 +02:00
|
|
|
namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
|
|
|
|
&isnull);
|
2011-02-08 22:08:41 +01:00
|
|
|
Assert(!isnull);
|
2010-11-26 23:27:23 +01:00
|
|
|
oldNspOid = DatumGetObjectId(namespace);
|
|
|
|
|
|
|
|
/* Check basic namespace related issues */
|
|
|
|
CheckSetNamespace(oldNspOid, nspOid, classId, objid);
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* Permission checks ... superusers can always do it */
|
2010-11-26 23:27:23 +01:00
|
|
|
if (!superuser())
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
Datum owner;
|
2010-11-26 23:27:23 +01:00
|
|
|
Oid ownerId;
|
|
|
|
AclResult aclresult;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* Fail if object does not have an explicit owner */
|
|
|
|
if (Anum_owner <= 0)
|
2010-11-26 23:27:23 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2011-07-08 06:37:04 +02:00
|
|
|
(errmsg("must be superuser to set schema of %s",
|
2010-11-26 23:27:23 +01:00
|
|
|
getObjectDescriptionOids(classId, objid)))));
|
|
|
|
|
|
|
|
/* Otherwise, must be owner of the existing object */
|
2011-02-08 22:08:41 +01:00
|
|
|
owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
2010-11-26 23:27:23 +01:00
|
|
|
ownerId = DatumGetObjectId(owner);
|
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), ownerId))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
|
|
|
|
NameStr(*(DatumGetName(name))));
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* User must have CREATE privilege on new namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
|
2010-11-26 23:27:23 +01:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
2011-02-08 22:08:41 +01:00
|
|
|
get_namespace_name(nspOid));
|
2010-11-26 23:27:23 +01:00
|
|
|
}
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/*
|
|
|
|
* Check for duplicate name (more friendly than unique-index failure).
|
|
|
|
* Since this is just a friendliness check, we can just skip it in cases
|
2013-01-21 16:06:41 +01:00
|
|
|
* where there isn't suitable support.
|
2011-02-08 22:08:41 +01:00
|
|
|
*/
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
if (classId == ProcedureRelationId)
|
|
|
|
{
|
2013-01-21 16:06:41 +01:00
|
|
|
Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
|
|
|
|
IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
|
2013-06-13 01:50:37 +02:00
|
|
|
&proc->proargtypes, nspOid);
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
}
|
|
|
|
else if (classId == CollationRelationId)
|
|
|
|
{
|
2013-01-21 16:06:41 +01:00
|
|
|
Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
|
|
|
|
}
|
|
|
|
else if (classId == OperatorClassRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
IsThereOpClassInNamespace(NameStr(opc->opcname),
|
|
|
|
opc->opcmethod, nspOid);
|
|
|
|
}
|
|
|
|
else if (classId == OperatorFamilyRelationId)
|
|
|
|
{
|
|
|
|
Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
|
2013-01-21 16:06:41 +01:00
|
|
|
IsThereOpFamilyInNamespace(NameStr(opf->opfname),
|
|
|
|
opf->opfmethod, nspOid);
|
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already
was, for most objects classes we were correctly complaining about
exactly that ("object is already in schema"); but for some other object
classes, such as functions, we were instead complaining of a name
collision ("object already exists in schema"). The latter is wrong and
misleading, per complaint from Robert Haas in
CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com
To fix, refactor the way these checks are done. As a bonus, the
resulting code is smaller and can also share some code with Rename
cases.
While at it, remove use of getObjectDescriptionOids() in error messages.
These are normally disallowed because of translatability considerations,
but this one had slipped through since 9.1. (Not sure that this is
worth backpatching, though, as it would create some untranslated
messages in back branches.)
This is loosely based on a patch by KaiGai Kohei, heavily reworked by
me.
2013-01-15 17:23:43 +01:00
|
|
|
}
|
|
|
|
else if (nameCacheId >= 0 &&
|
|
|
|
SearchSysCacheExists2(nameCacheId, name,
|
|
|
|
ObjectIdGetDatum(nspOid)))
|
|
|
|
report_namespace_conflict(classId,
|
|
|
|
NameStr(*(DatumGetName(name))),
|
|
|
|
nspOid);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
/* Build modified tuple */
|
|
|
|
values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
|
|
|
|
nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
|
|
|
replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
|
|
|
values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
|
2010-11-26 23:27:23 +01:00
|
|
|
replaces[Anum_namespace - 1] = true;
|
2011-02-08 22:08:41 +01:00
|
|
|
newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
|
|
|
|
values, nulls, replaces);
|
2010-11-26 23:27:23 +01:00
|
|
|
|
|
|
|
/* Perform actual update */
|
|
|
|
simple_heap_update(rel, &tup->t_self, newtup);
|
|
|
|
CatalogUpdateIndexes(rel, newtup);
|
|
|
|
|
|
|
|
/* Release memory */
|
|
|
|
pfree(values);
|
|
|
|
pfree(nulls);
|
|
|
|
pfree(replaces);
|
|
|
|
|
|
|
|
/* update dependencies to point to the new schema */
|
|
|
|
changeDependencyFor(classId, objid,
|
|
|
|
NamespaceRelationId, oldNspOid, nspOid);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(classId, objid, 0);
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
return oldNspOid;
|
2010-11-26 23:27:23 +01:00
|
|
|
}
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
/*
|
|
|
|
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
|
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
2012-12-24 00:25:03 +01:00
|
|
|
Oid
|
2004-06-25 23:55:59 +02:00
|
|
|
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|
|
|
{
|
2010-08-05 16:45:09 +02:00
|
|
|
Oid newowner = get_role_oid(stmt->newowner, false);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
|
|
|
switch (stmt->objectType)
|
|
|
|
{
|
|
|
|
case OBJECT_DATABASE:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
|
|
|
case OBJECT_SCHEMA:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
|
|
|
case OBJECT_TYPE:
|
|
|
|
case OBJECT_DOMAIN: /* same as TYPE */
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterTypeOwner(stmt->object, newowner, stmt->objectType);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
2008-12-19 17:25:19 +01:00
|
|
|
case OBJECT_FDW:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
|
|
|
|
newowner);
|
2008-12-19 17:25:19 +01:00
|
|
|
|
|
|
|
case OBJECT_FOREIGN_SERVER:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterForeignServerOwner(strVal(linitial(stmt->object)),
|
|
|
|
newowner);
|
2008-12-19 17:25:19 +01:00
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
case OBJECT_EVENT_TRIGGER:
|
2012-12-24 00:25:03 +01:00
|
|
|
return AlterEventTriggerOwner(strVal(linitial(stmt->object)),
|
|
|
|
newowner);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
2013-05-29 22:58:43 +02:00
|
|
|
/* Generic cases */
|
2012-10-03 23:02:38 +02:00
|
|
|
case OBJECT_AGGREGATE:
|
|
|
|
case OBJECT_COLLATION:
|
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
case OBJECT_LANGUAGE:
|
|
|
|
case OBJECT_LARGEOBJECT:
|
|
|
|
case OBJECT_OPERATOR:
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
case OBJECT_OPFAMILY:
|
|
|
|
case OBJECT_TABLESPACE:
|
|
|
|
case OBJECT_TSDICTIONARY:
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
|
|
|
{
|
|
|
|
Relation catalog;
|
|
|
|
Relation relation;
|
|
|
|
Oid classId;
|
2013-05-29 22:58:43 +02:00
|
|
|
ObjectAddress address;
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
address = get_object_address(stmt->objectType,
|
|
|
|
stmt->object,
|
|
|
|
stmt->objarg,
|
|
|
|
&relation,
|
|
|
|
AccessExclusiveLock,
|
|
|
|
false);
|
|
|
|
Assert(relation == NULL);
|
|
|
|
classId = address.classId;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - get_object_address returns Oid of pg_largeobject
|
|
|
|
* catalog for OBJECT_LARGEOBJECT because of historical
|
|
|
|
* reasons. Fix up it here.
|
|
|
|
*/
|
|
|
|
if (classId == LargeObjectRelationId)
|
|
|
|
classId = LargeObjectMetadataRelationId;
|
|
|
|
|
|
|
|
catalog = heap_open(classId, RowExclusiveLock);
|
|
|
|
|
|
|
|
AlterObjectOwner_internal(catalog, address.objectId, newowner);
|
|
|
|
heap_close(catalog, RowExclusiveLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
|
|
|
return address.objectId;
|
2012-10-03 23:02:38 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
|
|
|
return InvalidOid; /* keep compiler happy */
|
2004-06-25 23:55:59 +02:00
|
|
|
}
|
|
|
|
}
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic function to change the ownership of a given object, for simple
|
|
|
|
* cases (won't work for tables, nor other cases where we need to do more than
|
|
|
|
* change the ownership column of a single catalog entry).
|
|
|
|
*
|
|
|
|
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
|
|
|
|
* objectId: OID of object to change the ownership of
|
|
|
|
* new_ownerId: OID of new object owner
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
|
|
|
|
{
|
|
|
|
Oid classId = RelationGetRelid(rel);
|
|
|
|
AttrNumber Anum_owner = get_object_attnum_owner(classId);
|
|
|
|
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
|
|
|
|
AttrNumber Anum_acl = get_object_attnum_acl(classId);
|
|
|
|
AttrNumber Anum_name = get_object_attnum_name(classId);
|
|
|
|
HeapTuple oldtup;
|
|
|
|
Datum datum;
|
|
|
|
bool isnull;
|
|
|
|
Oid old_ownerId;
|
|
|
|
Oid namespaceId = InvalidOid;
|
|
|
|
|
|
|
|
oldtup = get_catalog_object_by_oid(rel, objectId);
|
|
|
|
if (oldtup == NULL)
|
|
|
|
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
|
|
|
|
objectId, RelationGetRelationName(rel));
|
|
|
|
|
|
|
|
datum = heap_getattr(oldtup, Anum_owner,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
old_ownerId = DatumGetObjectId(datum);
|
|
|
|
|
|
|
|
if (Anum_namespace != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(oldtup, Anum_namespace,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
namespaceId = DatumGetObjectId(datum);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_ownerId != new_ownerId)
|
|
|
|
{
|
|
|
|
AttrNumber nattrs;
|
|
|
|
HeapTuple newtup;
|
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
bool *replaces;
|
|
|
|
|
|
|
|
/* Superusers can bypass permission checks */
|
|
|
|
if (!superuser())
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
AclObjectKind aclkind = get_object_aclkind(classId);
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
/* must be owner */
|
|
|
|
if (!has_privs_of_role(GetUserId(), old_ownerId))
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
char *objname;
|
|
|
|
char namebuf[NAMEDATALEN];
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
if (Anum_name != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(oldtup, Anum_name,
|
|
|
|
RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
objname = NameStr(*DatumGetName(datum));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snprintf(namebuf, sizeof(namebuf), "%u",
|
|
|
|
HeapTupleGetOid(oldtup));
|
|
|
|
objname = namebuf;
|
|
|
|
}
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
|
|
|
|
}
|
|
|
|
/* Must be able to become new owner */
|
|
|
|
check_is_member_of_role(GetUserId(), new_ownerId);
|
|
|
|
|
|
|
|
/* New owner must have CREATE privilege on namespace */
|
|
|
|
if (OidIsValid(namespaceId))
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
AclResult aclresult;
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
|
|
|
|
ACL_CREATE);
|
|
|
|
if (aclresult != ACLCHECK_OK)
|
2013-01-07 17:54:59 +01:00
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
2012-10-03 23:02:38 +02:00
|
|
|
get_namespace_name(namespaceId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build a modified tuple */
|
|
|
|
nattrs = RelationGetNumberOfAttributes(rel);
|
|
|
|
values = palloc0(nattrs * sizeof(Datum));
|
|
|
|
nulls = palloc0(nattrs * sizeof(bool));
|
|
|
|
replaces = palloc0(nattrs * sizeof(bool));
|
|
|
|
values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
|
|
|
|
replaces[Anum_owner - 1] = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine the modified ACL for the new owner. This is only
|
|
|
|
* necessary when the ACL is non-null.
|
|
|
|
*/
|
|
|
|
if (Anum_acl != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(oldtup,
|
|
|
|
Anum_acl, RelationGetDescr(rel), &isnull);
|
|
|
|
if (!isnull)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
Acl *newAcl;
|
2012-10-03 23:02:38 +02:00
|
|
|
|
|
|
|
newAcl = aclnewowner(DatumGetAclP(datum),
|
|
|
|
old_ownerId, new_ownerId);
|
|
|
|
values[Anum_acl - 1] = PointerGetDatum(newAcl);
|
|
|
|
replaces[Anum_acl - 1] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
|
|
|
values, nulls, replaces);
|
|
|
|
|
|
|
|
/* Perform actual update */
|
|
|
|
simple_heap_update(rel, &newtup->t_self, newtup);
|
|
|
|
CatalogUpdateIndexes(rel, newtup);
|
|
|
|
|
|
|
|
/* Update owner dependency reference */
|
|
|
|
if (classId == LargeObjectMetadataRelationId)
|
|
|
|
classId = LargeObjectRelationId;
|
|
|
|
changeDependencyOnOwner(classId, HeapTupleGetOid(newtup), new_ownerId);
|
|
|
|
|
|
|
|
/* Release memory */
|
|
|
|
pfree(values);
|
|
|
|
pfree(nulls);
|
|
|
|
pfree(replaces);
|
|
|
|
}
|
2013-03-18 03:55:14 +01:00
|
|
|
|
|
|
|
InvokeObjectPostAlterHook(classId, objectId, 0);
|
2012-10-03 23:02:38 +02:00
|
|
|
}
|