This gets rid of a significant amount of duplicative code.
KaiGai Kohei, reviewed in earlier versions by Dimitri Fontaine, with
further review and cleanup by me.
#include "utils/syscache.h"
#include "utils/tqual.h"
-static ObjectAddress get_object_address_unqualified(ObjectType objtype,
- List *qualname, bool missing_ok);
-static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
- List *objname, Relation *relp,
- LOCKMODE lockmode, bool missing_ok);
-static ObjectAddress get_object_address_relobject(ObjectType objtype,
- List *objname, Relation *relp, bool missing_ok);
-static ObjectAddress get_object_address_attribute(ObjectType objtype,
- List *objname, Relation *relp,
- LOCKMODE lockmode, bool missing_ok);
-static ObjectAddress get_object_address_type(ObjectType objtype,
- List *objname, bool missing_ok);
-static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
- List *objargs, bool missing_ok);
-static bool object_exists(ObjectAddress address);
-
/*
* ObjectProperty
*
Oid class_oid; /* oid of catalog */
Oid oid_index_oid; /* oid of index on system oid column */
int oid_catcache_id; /* id of catcache on system oid column */
+ AttrNumber attnum_namespace; /* attnum of namespace field */
} ObjectPropertyType;
static ObjectPropertyType ObjectProperty[] =
{
CastRelationId,
CastOidIndexId,
- -1
+ -1,
+ InvalidAttrNumber
},
{
CollationRelationId,
CollationOidIndexId,
- COLLOID
+ COLLOID,
+ Anum_pg_collation_collnamespace
},
{
ConstraintRelationId,
ConstraintOidIndexId,
- CONSTROID
+ CONSTROID,
+ Anum_pg_constraint_connamespace
},
{
ConversionRelationId,
ConversionOidIndexId,
- CONVOID
+ CONVOID,
+ Anum_pg_conversion_connamespace
},
{
DatabaseRelationId,
DatabaseOidIndexId,
- DATABASEOID
+ DATABASEOID,
+ InvalidAttrNumber
},
{
ExtensionRelationId,
ExtensionOidIndexId,
- -1
+ -1,
+ Anum_pg_extension_extnamespace
},
{
ForeignDataWrapperRelationId,
ForeignDataWrapperOidIndexId,
- FOREIGNDATAWRAPPEROID
+ FOREIGNDATAWRAPPEROID,
+ InvalidAttrNumber
},
{
ForeignServerRelationId,
ForeignServerOidIndexId,
- FOREIGNSERVEROID
+ FOREIGNSERVEROID,
+ InvalidAttrNumber
},
{
ProcedureRelationId,
ProcedureOidIndexId,
- PROCOID
+ PROCOID,
+ Anum_pg_proc_pronamespace
},
{
LanguageRelationId,
LanguageOidIndexId,
- LANGOID
+ LANGOID,
+ InvalidAttrNumber,
},
{
LargeObjectMetadataRelationId,
LargeObjectMetadataOidIndexId,
- -1
+ -1,
+ InvalidAttrNumber
},
{
OperatorClassRelationId,
OpclassOidIndexId,
- CLAOID
+ CLAOID,
+ Anum_pg_opclass_opcnamespace,
},
{
OperatorRelationId,
OperatorOidIndexId,
- OPEROID
+ OPEROID,
+ Anum_pg_operator_oprnamespace
},
{
OperatorFamilyRelationId,
OpfamilyOidIndexId,
- OPFAMILYOID
+ OPFAMILYOID,
+ Anum_pg_opfamily_opfnamespace
},
{
AuthIdRelationId,
AuthIdOidIndexId,
- AUTHOID
+ AUTHOID,
+ InvalidAttrNumber
},
{
RewriteRelationId,
RewriteOidIndexId,
- -1
+ -1,
+ InvalidAttrNumber
},
{
NamespaceRelationId,
NamespaceOidIndexId,
- NAMESPACEOID
+ NAMESPACEOID,
+ InvalidAttrNumber
},
{
RelationRelationId,
ClassOidIndexId,
- RELOID
+ RELOID,
+ Anum_pg_class_relnamespace
},
{
TableSpaceRelationId,
TablespaceOidIndexId,
TABLESPACEOID,
+ InvalidAttrNumber
},
{
TriggerRelationId,
TriggerOidIndexId,
- -1
+ -1,
+ InvalidAttrNumber
},
{
TSConfigRelationId,
TSConfigOidIndexId,
- TSCONFIGOID
+ TSCONFIGOID,
+ Anum_pg_ts_config_cfgnamespace
},
{
TSDictionaryRelationId,
TSDictionaryOidIndexId,
- TSDICTOID
+ TSDICTOID,
+ Anum_pg_ts_dict_dictnamespace
},
{
TSParserRelationId,
TSParserOidIndexId,
- TSPARSEROID
+ TSPARSEROID,
+ Anum_pg_ts_parser_prsnamespace
},
{
TSTemplateRelationId,
TSTemplateOidIndexId,
- TSTEMPLATEOID
+ TSTEMPLATEOID,
+ Anum_pg_ts_template_tmplnamespace,
},
{
TypeRelationId,
TypeOidIndexId,
- TYPEOID
+ TYPEOID,
+ Anum_pg_type_typnamespace
}
};
+static ObjectAddress get_object_address_unqualified(ObjectType objtype,
+ List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+ List *objname, Relation *relp,
+ LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_relobject(ObjectType objtype,
+ List *objname, Relation *relp, bool missing_ok);
+static ObjectAddress get_object_address_attribute(ObjectType objtype,
+ List *objname, Relation *relp,
+ LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_type(ObjectType objtype,
+ List *objname, bool missing_ok);
+static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
+ List *objargs, bool missing_ok);
+static bool object_exists(ObjectAddress address);
+static ObjectPropertyType *get_object_property_data(Oid class_id);
+
/*
* Translate an object name and arguments (as passed by the parser) to an
* ObjectAddress.
ScanKeyData skey[1];
SysScanDesc sd;
bool found;
+ ObjectPropertyType *property;
/* Sub-objects require special treatment. */
if (address.objectSubId != 0)
}
return found;
}
- else
- {
- int index;
- /*
- * Weird backward compatibility hack: ObjectAddress notation uses
- * LargeObjectRelationId for large objects, but since PostgreSQL
- * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
- */
- if (address.classId == LargeObjectRelationId)
- address.classId = LargeObjectMetadataRelationId;
+ /*
+ * Weird backward compatibility hack: ObjectAddress notation uses
+ * LargeObjectRelationId for large objects, but since PostgreSQL
+ * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
+ */
+ if (address.classId == LargeObjectRelationId)
+ address.classId = LargeObjectMetadataRelationId;
- /*
- * For object types that have a relevant syscache, we use it; for
- * everything else, we'll have to do an index-scan. Search the
- * ObjectProperty array to find out which it is.
- */
- for (index = 0; index < lengthof(ObjectProperty); index++)
- {
- if (ObjectProperty[index].class_oid == address.classId)
- {
- cache = ObjectProperty[index].oid_catcache_id;
- indexoid = ObjectProperty[index].oid_index_oid;
- break;
- }
- }
- if (index == lengthof(ObjectProperty))
- elog(ERROR, "unrecognized classid: %u", address.classId);
- }
+ /*
+ * For object types that have a relevant syscache, we use it; for
+ * everything else, we'll have to do an index-scan.
+ */
+ property = get_object_property_data(address.classId);
+ cache = property->oid_catcache_id;
+ indexoid = property->oid_index_oid;
/* Found a syscache? */
if (cache != -1)
return found;
}
-
/*
* Check ownership of an object previously identified by get_object_address.
*/
(int) objtype);
}
}
+
+/*
+ * get_object_namespace
+ *
+ * Find the schema containing the specified object. For non-schema objects,
+ * this function returns InvalidOid.
+ */
+Oid
+get_object_namespace(const ObjectAddress *address)
+{
+ int cache;
+ HeapTuple tuple;
+ bool isnull;
+ Oid oid;
+ ObjectPropertyType *property;
+
+ /* If not owned by a namespace, just return InvalidOid. */
+ property = get_object_property_data(address->classId);
+ if (property->attnum_namespace == InvalidAttrNumber)
+ return InvalidOid;
+
+ /* Currently, we can only handle object types with system caches. */
+ cache = property->oid_catcache_id;
+ Assert(cache != -1);
+
+ /* Fetch tuple from syscache and extract namespace attribute. */
+ tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for cache %d oid %u",
+ cache, address->objectId);
+ oid = DatumGetObjectId(SysCacheGetAttr(cache,
+ tuple,
+ property->attnum_namespace,
+ &isnull));
+ Assert(!isnull);
+ ReleaseSysCache(tuple);
+
+ return oid;
+}
+
+/*
+ * Find ObjectProperty structure by class_id.
+ */
+static ObjectPropertyType *
+get_object_property_data(Oid class_id)
+{
+ int index;
+
+ for (index = 0; index < lengthof(ObjectProperty); index++)
+ if (ObjectProperty[index].class_oid == class_id)
+ return &ObjectProperty[index];
+
+ elog(ERROR, "unrecognized class id: %u", class_id);
+ return NULL; /* not reached */
+}
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o \
- dbcommands.o define.o discard.o explain.o extension.o \
+ dbcommands.o define.o discard.o dropcmds.o explain.o extension.o \
foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
(void) pg_newlocale_from_collation(newoid);
}
-/*
- * DROP COLLATION
- */
-void
-DropCollationsCommand(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the collations, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the collations depends on another. (Not that
- * that is very likely, but we may as well do this consistently.)
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *name = (List *) lfirst(cell);
- Oid collationOid;
- HeapTuple tuple;
- Form_pg_collation coll;
- ObjectAddress object;
-
- collationOid = get_collation_oid(name, drop->missing_ok);
-
- if (!OidIsValid(collationOid))
- {
- ereport(NOTICE,
- (errmsg("collation \"%s\" does not exist, skipping",
- NameListToString(name))));
- continue;
- }
-
- tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationOid));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for collation %u",
- collationOid);
- coll = (Form_pg_collation) GETSTRUCT(tuple);
-
- /* Permission check: must own collation or its namespace */
- if (!pg_collation_ownercheck(collationOid, GetUserId()) &&
- !pg_namespace_ownercheck(coll->collnamespace, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
- NameStr(coll->collname));
-
- object.classId = CollationRelationId;
- object.objectId = collationOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
-
- ReleaseSysCache(tuple);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Rename collation
*/
from_encoding, to_encoding, funcoid, stmt->def);
}
-/*
- * DROP CONVERSION
- */
-void
-DropConversionsCommand(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the conversions, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the conversions depends on another. (Not that
- * that is very likely, but we may as well do this consistently.)
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *name = (List *) lfirst(cell);
- Oid conversionOid;
- HeapTuple tuple;
- Form_pg_conversion con;
- ObjectAddress object;
-
- conversionOid = get_conversion_oid(name, drop->missing_ok);
-
- if (!OidIsValid(conversionOid))
- {
- ereport(NOTICE,
- (errmsg("conversion \"%s\" does not exist, skipping",
- NameListToString(name))));
- continue;
- }
-
- tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conversionOid));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for conversion %u",
- conversionOid);
- con = (Form_pg_conversion) GETSTRUCT(tuple);
-
- /* Permission check: must own conversion or its namespace */
- if (!pg_conversion_ownercheck(conversionOid, GetUserId()) &&
- !pg_namespace_ownercheck(con->connamespace, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
- NameStr(con->conname));
-
- object.classId = ConversionRelationId;
- object.objectId = conversionOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
-
- ReleaseSysCache(tuple);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Rename conversion
*/
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * dropcmds.c
+ * handle various "DROP" operations
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/catalog/dropcmds.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/dependency.h"
+#include "catalog/namespace.h"
+#include "catalog/objectaddress.h"
+#include "catalog/pg_class.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+
+static void does_not_exist_skipping(ObjectType objtype, List *objname);
+
+/*
+ * Drop one or more objects.
+ *
+ * We don't currently handle all object types here. Relations, for example,
+ * require special handling, because (for example) indexes have additional
+ * locking requirements.
+ *
+ * We look up all the objects first, and then delete them in a single
+ * performMultipleDeletions() call. This avoids unnecessary DROP RESTRICT
+ * errors if there are dependencies between them.
+ */
+void
+RemoveObjects(DropStmt *stmt)
+{
+ ObjectAddresses *objects;
+ ListCell *cell1;
+
+ objects = new_object_addresses();
+
+ foreach(cell1, stmt->objects)
+ {
+ ObjectAddress address;
+ List *objname = lfirst(cell1);
+ Relation relation = NULL;
+ Oid namespaceId;
+
+ /* Get an ObjectAddress for the object. */
+ address = get_object_address(stmt->removeType,
+ objname, NIL,
+ &relation,
+ AccessExclusiveLock,
+ stmt->missing_ok);
+
+ /* Issue NOTICE if supplied object was not found. */
+ if (!OidIsValid(address.objectId))
+ {
+ does_not_exist_skipping(stmt->removeType, objname);
+ continue;
+ }
+
+ /* Check permissions. */
+ namespaceId = get_object_namespace(&address);
+ if (!OidIsValid(namespaceId) ||
+ !pg_namespace_ownercheck(namespaceId, GetUserId()))
+ check_object_ownership(GetUserId(), stmt->removeType, address,
+ objname, NIL, relation);
+
+ /* Release any relcache reference count, but keep lock until commit. */
+ if (relation)
+ heap_close(relation, NoLock);
+
+ add_exact_object_address(&address, objects);
+ }
+
+ /* Here we really delete them. */
+ performMultipleDeletions(objects, stmt->behavior);
+
+ free_object_addresses(objects);
+}
+
+/*
+ * Generate a NOTICE stating that the named object was not found, and is
+ * being skipped. This is only relevant when "IF EXISTS" is used; otherwise,
+ * get_object_address() will throw an ERROR.
+ */
+static void
+does_not_exist_skipping(ObjectType objtype, List *objname)
+{
+ const char *msg = NULL;
+ char *name = NULL;
+
+ switch (objtype)
+ {
+ case OBJECT_TYPE:
+ case OBJECT_DOMAIN:
+ msg = gettext_noop("type \"%s\" does not exist, skipping");
+ name = TypeNameToString(makeTypeNameFromNameList(objname));
+ break;
+ case OBJECT_COLLATION:
+ msg = gettext_noop("collation \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_CONVERSION:
+ msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_SCHEMA:
+ msg = gettext_noop("schema \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_TSPARSER:
+ msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_TSDICTIONARY:
+ msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_TSTEMPLATE:
+ msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_TSCONFIGURATION:
+ msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ case OBJECT_EXTENSION:
+ msg = gettext_noop("extension \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
+ default:
+ elog(ERROR, "unexpected object type (%d)", (int)objtype);
+ break;
+ }
+
+ ereport(NOTICE, (errmsg(msg, name)));
+}
return extensionOid;
}
-
-/*
- * RemoveExtensions
- * Implements DROP EXTENSION.
- */
-void
-RemoveExtensions(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the extensions, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the extensions depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- char *extensionName;
- Oid extensionId;
- ObjectAddress object;
-
- if (list_length(names) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("extension name cannot be qualified")));
- extensionName = strVal(linitial(names));
-
- extensionId = get_extension_oid(extensionName, drop->missing_ok);
-
- if (!OidIsValid(extensionId))
- {
- ereport(NOTICE,
- (errmsg("extension \"%s\" does not exist, skipping",
- extensionName)));
- continue;
- }
-
- /* Permission check: must own extension */
- if (!pg_extension_ownercheck(extensionId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
- extensionName);
-
- object.classId = ExtensionRelationId;
- object.objectId = extensionId;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
- }
-
- /*
- * Do the deletions. Objects contained in the extension(s) are removed by
- * means of their dependency links to the extensions.
- */
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
-
/*
* Guts of extension deletion.
*
SetUserIdAndSecContext(saved_uid, save_sec_context);
}
-
-/*
- * RemoveSchemas
- * Implements DROP SCHEMA.
- */
-void
-RemoveSchemas(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the schemas, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the schemas depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- char *namespaceName;
- Oid namespaceId;
- ObjectAddress object;
-
- if (list_length(names) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("schema name cannot be qualified")));
- namespaceName = strVal(linitial(names));
-
- namespaceId = get_namespace_oid(namespaceName, drop->missing_ok);
-
- if (!OidIsValid(namespaceId))
- {
- ereport(NOTICE,
- (errmsg("schema \"%s\" does not exist, skipping",
- namespaceName)));
- continue;
- }
-
- /* Permission check */
- if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
- namespaceName);
-
- object.classId = NamespaceRelationId;
- object.objectId = namespaceId;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
- }
-
- /*
- * Do the deletions. Objects contained in the schema(s) are removed by
- * means of their dependency links to the schema.
- */
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
-
/*
* Guts of schema deletion.
*/
heap_close(prsRel, RowExclusiveLock);
}
-/*
- * DROP TEXT SEARCH PARSER
- */
-void
-RemoveTSParsers(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to drop text search parsers")));
-
- /*
- * First we identify all the objects, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the objects depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- Oid prsOid;
- ObjectAddress object;
-
- prsOid = get_ts_parser_oid(names, true);
-
- if (!OidIsValid(prsOid))
- {
- if (!drop->missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search parser \"%s\" does not exist",
- NameListToString(names))));
- }
- else
- {
- ereport(NOTICE,
- (errmsg("text search parser \"%s\" does not exist, skipping",
- NameListToString(names))));
- }
- continue;
- }
-
- object.classId = TSParserRelationId;
- object.objectId = prsOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Guts of TS parser deletion.
*/
return oldNspOid;
}
-/*
- * DROP TEXT SEARCH DICTIONARY
- */
-void
-RemoveTSDictionaries(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the objects, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the objects depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- Oid dictOid;
- ObjectAddress object;
- HeapTuple tup;
- Oid namespaceId;
-
- dictOid = get_ts_dict_oid(names, true);
-
- if (!OidIsValid(dictOid))
- {
- if (!drop->missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search dictionary \"%s\" does not exist",
- NameListToString(names))));
- }
- else
- {
- ereport(NOTICE,
- (errmsg("text search dictionary \"%s\" does not exist, skipping",
- NameListToString(names))));
- }
- continue;
- }
-
- tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictOid));
- if (!HeapTupleIsValid(tup)) /* should not happen */
- elog(ERROR, "cache lookup failed for text search dictionary %u",
- dictOid);
-
- /* Permission check: must own dictionary or its namespace */
- namespaceId = ((Form_pg_ts_dict) GETSTRUCT(tup))->dictnamespace;
- if (!pg_ts_dict_ownercheck(dictOid, GetUserId()) &&
- !pg_namespace_ownercheck(namespaceId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
- NameListToString(names));
-
- object.classId = TSDictionaryRelationId;
- object.objectId = dictOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
-
- ReleaseSysCache(tup);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Guts of TS dictionary deletion.
*/
return oldNspOid;
}
-/*
- * DROP TEXT SEARCH TEMPLATE
- */
-void
-RemoveTSTemplates(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to drop text search templates")));
-
- /*
- * First we identify all the objects, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the objects depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- Oid tmplOid;
- ObjectAddress object;
-
- tmplOid = get_ts_template_oid(names, true);
-
- if (!OidIsValid(tmplOid))
- {
- if (!drop->missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search template \"%s\" does not exist",
- NameListToString(names))));
- }
- else
- {
- ereport(NOTICE,
- (errmsg("text search template \"%s\" does not exist, skipping",
- NameListToString(names))));
- }
- continue;
- }
-
- object.classId = TSTemplateRelationId;
- object.objectId = tmplOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Guts of TS template deletion.
*/
return oldNspOid;
}
-/*
- * DROP TEXT SEARCH CONFIGURATION
- */
-void
-RemoveTSConfigurations(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the objects, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the objects depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- Oid cfgOid;
- Oid namespaceId;
- ObjectAddress object;
- HeapTuple tup;
-
- tup = GetTSConfigTuple(names);
-
- if (!HeapTupleIsValid(tup))
- {
- if (!drop->missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search configuration \"%s\" does not exist",
- NameListToString(names))));
- }
- else
- {
- ereport(NOTICE,
- (errmsg("text search configuration \"%s\" does not exist, skipping",
- NameListToString(names))));
- }
- continue;
- }
-
- /* Permission check: must own configuration or its namespace */
- cfgOid = HeapTupleGetOid(tup);
- namespaceId = ((Form_pg_ts_config) GETSTRUCT(tup))->cfgnamespace;
- if (!pg_ts_config_ownercheck(cfgOid, GetUserId()) &&
- !pg_namespace_ownercheck(namespaceId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
- NameListToString(names));
-
- object.classId = TSConfigRelationId;
- object.objectId = cfgOid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
-
- ReleaseSysCache(tup);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
/*
* Guts of TS configuration deletion.
*/
pfree(array_type);
}
-
-/*
- * RemoveTypes
- * Implements DROP TYPE and DROP DOMAIN
- *
- * Note: if DOMAIN is specified, we enforce that each type is a domain, but
- * we don't enforce the converse for DROP TYPE
- */
-void
-RemoveTypes(DropStmt *drop)
-{
- ObjectAddresses *objects;
- ListCell *cell;
-
- /*
- * First we identify all the types, then we delete them in a single
- * performMultipleDeletions() call. This is to avoid unwanted DROP
- * RESTRICT errors if one of the types depends on another.
- */
- objects = new_object_addresses();
-
- foreach(cell, drop->objects)
- {
- List *names = (List *) lfirst(cell);
- TypeName *typename;
- Oid typeoid;
- HeapTuple tup;
- ObjectAddress object;
- Form_pg_type typ;
-
- /* Make a TypeName so we can use standard type lookup machinery */
- typename = makeTypeNameFromNameList(names);
-
- /* Use LookupTypeName here so that shell types can be removed. */
- tup = LookupTypeName(NULL, typename, NULL);
- if (tup == NULL)
- {
- if (!drop->missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("type \"%s\" does not exist",
- TypeNameToString(typename))));
- }
- else
- {
- ereport(NOTICE,
- (errmsg("type \"%s\" does not exist, skipping",
- TypeNameToString(typename))));
- }
- continue;
- }
-
- typeoid = typeTypeId(tup);
- typ = (Form_pg_type) GETSTRUCT(tup);
-
- /* Permission check: must own type or its namespace */
- if (!pg_type_ownercheck(typeoid, GetUserId()) &&
- !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
- format_type_be(typeoid));
-
- if (drop->removeType == OBJECT_DOMAIN)
- {
- /* Check that this is actually a domain */
- if (typ->typtype != TYPTYPE_DOMAIN)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a domain",
- TypeNameToString(typename))));
- }
-
- /*
- * Note: we need no special check for array types here, as the normal
- * treatment of internal dependencies handles it just fine
- */
-
- object.classId = TypeRelationId;
- object.objectId = typeoid;
- object.objectSubId = 0;
-
- add_exact_object_address(&object, objects);
-
- ReleaseSysCache(tup);
- }
-
- performMultipleDeletions(objects, drop->behavior);
-
- free_object_addresses(objects);
-}
-
-
/*
* Guts of type deletion.
*/
break;
case T_DropStmt:
+ switch (((DropStmt *) parsetree)->removeType)
{
- DropStmt *stmt = (DropStmt *) parsetree;
-
- switch (stmt->removeType)
- {
- case OBJECT_TABLE:
- case OBJECT_SEQUENCE:
- case OBJECT_VIEW:
- case OBJECT_INDEX:
- case OBJECT_FOREIGN_TABLE:
- RemoveRelations(stmt);
- break;
-
- case OBJECT_TYPE:
- case OBJECT_DOMAIN:
- RemoveTypes(stmt);
- break;
-
- case OBJECT_COLLATION:
- DropCollationsCommand(stmt);
- break;
-
- case OBJECT_CONVERSION:
- DropConversionsCommand(stmt);
- break;
-
- case OBJECT_SCHEMA:
- RemoveSchemas(stmt);
- break;
-
- case OBJECT_TSPARSER:
- RemoveTSParsers(stmt);
- break;
-
- case OBJECT_TSDICTIONARY:
- RemoveTSDictionaries(stmt);
- break;
-
- case OBJECT_TSTEMPLATE:
- RemoveTSTemplates(stmt);
- break;
-
- case OBJECT_TSCONFIGURATION:
- RemoveTSConfigurations(stmt);
- break;
-
- case OBJECT_EXTENSION:
- RemoveExtensions(stmt);
- break;
-
- default:
- elog(ERROR, "unrecognized drop object type: %d",
- (int) stmt->removeType);
- break;
- }
+ case OBJECT_TABLE:
+ case OBJECT_SEQUENCE:
+ case OBJECT_VIEW:
+ case OBJECT_INDEX:
+ case OBJECT_FOREIGN_TABLE:
+ RemoveRelations((DropStmt *) parsetree);
+ break;
+ default:
+ RemoveObjects((DropStmt *) parsetree);
+ break;
}
break;
ObjectType objtype, ObjectAddress address,
List *objname, List *objargs, Relation relation);
+extern Oid get_object_namespace(const ObjectAddress *address);
+
#endif /* PARSE_OBJECT_H */
#include "nodes/parsenodes.h"
extern void DefineCollation(List *names, List *parameters);
-extern void DropCollationsCommand(DropStmt *drop);
extern void RenameCollation(List *name, const char *newname);
extern void AlterCollationOwner(List *name, Oid newOwnerId);
extern void AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId);
#include "nodes/parsenodes.h"
extern void CreateConversionCommand(CreateConversionStmt *parsetree);
-extern void DropConversionsCommand(DropStmt *drop);
extern void RenameConversion(List *name, const char *newname);
extern void AlterConversionOwner(List *name, Oid newOwnerId);
extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
#include "nodes/parsenodes.h"
+/* commands/dropcmds.c */
+extern void RemoveObjects(DropStmt *stmt);
/* commands/indexcmds.c */
extern Oid DefineIndex(RangeVar *heapRelation,
extern void RenameTSParser(List *oldname, const char *newname);
extern void AlterTSParserNamespace(List *name, const char *newschema);
extern Oid AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
-extern void RemoveTSParsers(DropStmt *drop);
extern void RemoveTSParserById(Oid prsId);
extern void DefineTSDictionary(List *names, List *parameters);
extern void RenameTSDictionary(List *oldname, const char *newname);
-extern void RemoveTSDictionaries(DropStmt *drop);
extern void RemoveTSDictionaryById(Oid dictId);
extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
extern void RenameTSTemplate(List *oldname, const char *newname);
extern void AlterTSTemplateNamespace(List *name, const char *newschema);
extern Oid AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
-extern void RemoveTSTemplates(DropStmt *stmt);
extern void RemoveTSTemplateById(Oid tmplId);
extern void DefineTSConfiguration(List *names, List *parameters);
extern void RenameTSConfiguration(List *oldname, const char *newname);
-extern void RemoveTSConfigurations(DropStmt *stmt);
extern void RemoveTSConfigurationById(Oid cfgId);
extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
extern void CreateExtension(CreateExtensionStmt *stmt);
-extern void RemoveExtensions(DropStmt *stmt);
extern void RemoveExtensionById(Oid extId);
extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
const char *queryString);
-extern void RemoveSchemas(DropStmt *drop);
extern void RemoveSchemaById(Oid schemaOid);
extern void RenameSchema(const char *oldname, const char *newname);
#define DEFAULT_TYPDELIM ','
extern void DefineType(List *names, List *parameters);
-extern void RemoveTypes(DropStmt *drop);
extern void RemoveTypeById(Oid typeOid);
extern void DefineDomain(CreateDomainStmt *stmt);
extern void DefineEnum(CreateEnumStmt *stmt);