* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.75 2008/06/11 21:53:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.76 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
ObjectAddresses *targetObjects;
int i;
+ /* No work if no objects... */
+ if (objects->numrefs <= 0)
+ return;
+
/*
* We save some cycles by opening pg_depend just once and passing the
* Relation pointer down to all the recursive deletion steps.
/*
* Check if deletion is allowed, and report about cascaded deletes.
+ *
+ * If there's exactly one object being deleted, report it the same
+ * way as in performDeletion(), else we have to be vaguer.
*/
reportDependentObjects(targetObjects,
behavior,
NOTICE,
- NULL);
+ (objects->numrefs == 1 ? objects->refs : NULL));
/*
* Delete all the objects in the proper order.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.43 2008/05/12 00:00:47 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.44 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
-#include "catalog/namespace.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_conversion_fn.h"
#include "catalog/pg_namespace.h"
return oid;
}
-/*
- * ConversionDrop
- *
- * Drop a conversion after doing permission checks.
- */
-void
-ConversionDrop(Oid conversionOid, DropBehavior behavior)
-{
- HeapTuple tuple;
- ObjectAddress object;
-
- tuple = SearchSysCache(CONVOID,
- ObjectIdGetDatum(conversionOid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
-
- if (!superuser() &&
- ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
- NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname));
-
- ReleaseSysCache(tuple);
-
- /*
- * Do the deletion
- */
- object.classId = ConversionRelationId;
- object.objectId = conversionOid;
- object.objectSubId = 0;
-
- performDeletion(&object, behavior);
-}
-
/*
* RemoveConversionById
*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.33 2008/03/27 03:57:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.34 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* DROP CONVERSION
*/
void
-DropConversionCommand(List *name, DropBehavior behavior, bool missing_ok)
+DropConversionsCommand(DropStmt *drop)
{
- Oid conversionOid;
+ ObjectAddresses *objects;
+ ListCell *cell;
- conversionOid = FindConversionByName(name);
- if (!OidIsValid(conversionOid))
+ /*
+ * 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)
{
- if (!missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("conversion \"%s\" does not exist",
- NameListToString(name))));
- }
- else
+ List *name = (List *) lfirst(cell);
+ Oid conversionOid;
+ HeapTuple tuple;
+ Form_pg_conversion con;
+ ObjectAddress object;
+
+ conversionOid = FindConversionByName(name);
+
+ if (!OidIsValid(conversionOid))
{
- ereport(NOTICE,
- (errmsg("conversion \"%s\" does not exist, skipping",
- NameListToString(name))));
+ if (!drop->missing_ok)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("conversion \"%s\" does not exist",
+ NameListToString(name))));
+ }
+ else
+ {
+ ereport(NOTICE,
+ (errmsg("conversion \"%s\" does not exist, skipping",
+ NameListToString(name))));
+ }
+ continue;
}
- return;
+ tuple = SearchSysCache(CONVOID,
+ ObjectIdGetDatum(conversionOid),
+ 0, 0, 0);
+ 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);
}
- ConversionDrop(conversionOid, behavior);
+ performMultipleDeletions(objects, drop->behavior);
+
+ free_object_addresses(objects);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.176 2008/05/12 20:01:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.177 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
-#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
return result;
}
-
-/*
- * RemoveIndex
- * Deletes an index.
- */
-void
-RemoveIndex(RangeVar *relation, DropBehavior behavior)
-{
- Oid indOid;
- char relkind;
- ObjectAddress object;
-
- indOid = RangeVarGetRelid(relation, false);
- relkind = get_rel_relkind(indOid);
- if (relkind != RELKIND_INDEX)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not an index",
- relation->relname)));
-
- object.classId = RelationRelationId;
- object.objectId = indOid;
- object.objectSubId = 0;
-
- performDeletion(&object, behavior);
-}
-
/*
* ReindexIndex
* Recreate a specific index.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.49 2008/01/03 21:23:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.50 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * RemoveSchema
- * Removes a schema.
+ * RemoveSchemas
+ * Implements DROP SCHEMA.
*/
void
-RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
+RemoveSchemas(DropStmt *drop)
{
- char *namespaceName;
- Oid namespaceId;
- ObjectAddress object;
+ ObjectAddresses *objects;
+ ListCell *cell;
- if (list_length(names) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("schema name cannot be qualified")));
- namespaceName = strVal(linitial(names));
-
- namespaceId = GetSysCacheOid(NAMESPACENAME,
- CStringGetDatum(namespaceName),
- 0, 0, 0);
- if (!OidIsValid(namespaceId))
+ /*
+ * 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)
{
- if (!missing_ok)
- {
+ List *names = (List *) lfirst(cell);
+ char *namespaceName;
+ Oid namespaceId;
+ ObjectAddress object;
+
+ if (list_length(names) != 1)
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_SCHEMA),
- errmsg("schema \"%s\" does not exist", namespaceName)));
- }
- else
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("schema name cannot be qualified")));
+ namespaceName = strVal(linitial(names));
+
+ namespaceId = GetSysCacheOid(NAMESPACENAME,
+ CStringGetDatum(namespaceName),
+ 0, 0, 0);
+
+ if (!OidIsValid(namespaceId))
{
- ereport(NOTICE,
- (errmsg("schema \"%s\" does not exist, skipping",
- namespaceName)));
+ if (!drop->missing_ok)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_SCHEMA),
+ errmsg("schema \"%s\" does not exist",
+ namespaceName)));
+ }
+ else
+ {
+ ereport(NOTICE,
+ (errmsg("schema \"%s\" does not exist, skipping",
+ namespaceName)));
+ }
+ continue;
}
- return;
- }
+ /* Permission check */
+ if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ namespaceName);
- /* 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 deletion. Objects contained in the schema are removed by means
- * of their dependency links to the schema.
+ * Do the deletions. Objects contained in the schema(s) are removed by
+ * means of their dependency links to the schema.
*/
- object.classId = NamespaceRelationId;
- object.objectId = namespaceId;
- object.objectSubId = 0;
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.255 2008/05/19 04:14:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.256 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
+#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
ExprState *exprstate; /* execution state */
} NewColumnValue;
+/*
+ * Error-reporting support for RemoveRelations
+ */
+struct dropmsgstrings
+{
+ char kind;
+ int nonexistent_code;
+ const char *nonexistent_msg;
+ const char *skipping_msg;
+ const char *nota_msg;
+ const char *drophint_msg;
+};
+
+static const struct dropmsgstrings dropmsgstringarray[] = {
+ {RELKIND_RELATION,
+ ERRCODE_UNDEFINED_TABLE,
+ gettext_noop("table \"%s\" does not exist"),
+ gettext_noop("table \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not a table"),
+ gettext_noop("Use DROP TABLE to remove a table.")},
+ {RELKIND_SEQUENCE,
+ ERRCODE_UNDEFINED_TABLE,
+ gettext_noop("sequence \"%s\" does not exist"),
+ gettext_noop("sequence \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not a sequence"),
+ gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
+ {RELKIND_VIEW,
+ ERRCODE_UNDEFINED_TABLE,
+ gettext_noop("view \"%s\" does not exist"),
+ gettext_noop("view \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not a view"),
+ gettext_noop("Use DROP VIEW to remove a view.")},
+ {RELKIND_INDEX,
+ ERRCODE_UNDEFINED_OBJECT,
+ gettext_noop("index \"%s\" does not exist"),
+ gettext_noop("index \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not an index"),
+ gettext_noop("Use DROP INDEX to remove an index.")},
+ {RELKIND_COMPOSITE_TYPE,
+ ERRCODE_UNDEFINED_OBJECT,
+ gettext_noop("type \"%s\" does not exist"),
+ gettext_noop("type \"%s\" does not exist, skipping"),
+ gettext_noop("\"%s\" is not a type"),
+ gettext_noop("Use DROP TYPE to remove a type.")},
+ {'\0', 0, NULL, NULL, NULL, NULL}
+};
+
static void truncate_check_rel(Relation rel);
static List *MergeAttributes(List *schema, List *supers, bool istemp,
}
/*
- * RemoveRelation
- * Deletes a relation.
+ * Emit the right error or warning message for a "DROP" command issued on a
+ * non-existent relation
+ */
+static void
+DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+{
+ const struct dropmsgstrings *rentry;
+
+ for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
+ {
+ if (rentry->kind == rightkind)
+ {
+ if (!missing_ok)
+ {
+ ereport(ERROR,
+ (errcode(rentry->nonexistent_code),
+ errmsg(rentry->nonexistent_msg, relname)));
+ }
+ else
+ {
+ ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
+ break;
+ }
+ }
+ }
+
+ Assert(rentry->kind != '\0'); /* Should be impossible */
+}
+
+/*
+ * Emit the right error message for a "DROP" command issued on a
+ * relation of the wrong type
+ */
+static void
+DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
+{
+ const struct dropmsgstrings *rentry;
+ const struct dropmsgstrings *wentry;
+
+ for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
+ if (rentry->kind == rightkind)
+ break;
+ Assert(rentry->kind != '\0');
+
+ for (wentry = dropmsgstringarray; wentry->kind != '\0'; wentry++)
+ if (wentry->kind == wrongkind)
+ break;
+ /* wrongkind could be something we don't have in our table... */
+
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg(rentry->nota_msg, relname),
+ (wentry->kind != '\0') ? errhint(wentry->drophint_msg) : 0));
+}
+
+/*
+ * RemoveRelations
+ * Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW
*/
void
-RemoveRelation(const RangeVar *relation, DropBehavior behavior)
+RemoveRelations(DropStmt *drop)
{
- Oid relOid;
- ObjectAddress object;
+ ObjectAddresses *objects;
+ char relkind;
+ ListCell *cell;
- relOid = RangeVarGetRelid(relation, false);
+ /*
+ * First we identify all the relations, then we delete them in a single
+ * performMultipleDeletions() call. This is to avoid unwanted
+ * DROP RESTRICT errors if one of the relations depends on another.
+ */
- object.classId = RelationRelationId;
- object.objectId = relOid;
- object.objectSubId = 0;
+ /* Determine required relkind */
+ switch (drop->removeType)
+ {
+ case OBJECT_TABLE:
+ relkind = RELKIND_RELATION;
+ break;
- performDeletion(&object, behavior);
+ case OBJECT_INDEX:
+ relkind = RELKIND_INDEX;
+ break;
+
+ case OBJECT_SEQUENCE:
+ relkind = RELKIND_SEQUENCE;
+ break;
+
+ case OBJECT_VIEW:
+ relkind = RELKIND_VIEW;
+ break;
+
+ default:
+ elog(ERROR, "unrecognized drop object type: %d",
+ (int) drop->removeType);
+ relkind = 0; /* keep compiler quiet */
+ break;
+ }
+
+ /* Lock and validate each relation; build a list of object addresses */
+ objects = new_object_addresses();
+
+ foreach(cell, drop->objects)
+ {
+ RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
+ Oid relOid;
+ HeapTuple tuple;
+ Form_pg_class classform;
+ ObjectAddress obj;
+
+ /*
+ * These next few steps are a great deal like relation_openrv, but we
+ * don't bother building a relcache entry since we don't need it.
+ *
+ * Check for shared-cache-inval messages before trying to access the
+ * relation. This is needed to cover the case where the name
+ * identifies a rel that has been dropped and recreated since the
+ * start of our transaction: if we don't flush the old syscache entry,
+ * then we'll latch onto that entry and suffer an error later.
+ */
+ AcceptInvalidationMessages();
+
+ /* Look up the appropriate relation using namespace search */
+ relOid = RangeVarGetRelid(rel, true);
+
+ /* Not there? */
+ if (!OidIsValid(relOid))
+ {
+ DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+ continue;
+ }
+
+ /* Get the lock before trying to fetch the syscache entry */
+ LockRelationOid(relOid, AccessExclusiveLock);
+
+ tuple = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relOid);
+ classform = (Form_pg_class) GETSTRUCT(tuple);
+
+ if (classform->relkind != relkind)
+ DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
+
+ /* Allow DROP to either table owner or schema owner */
+ if (!pg_class_ownercheck(relOid, GetUserId()) &&
+ !pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ rel->relname);
+
+ if (!allowSystemTableMods && IsSystemClass(classform))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied: \"%s\" is a system catalog",
+ rel->relname)));
+
+ /* OK, we're ready to delete this one */
+ obj.classId = RelationRelationId;
+ obj.objectId = relOid;
+ obj.objectSubId = 0;
+
+ add_exact_object_address(&obj, objects);
+
+ ReleaseSysCache(tuple);
+ }
+
+ performMultipleDeletions(objects, drop->behavior);
+
+ free_object_addresses(objects);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tsearchcmds.c,v 1.11 2008/03/26 21:10:38 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tsearchcmds.c,v 1.12 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* DROP TEXT SEARCH PARSER
*/
void
-RemoveTSParser(List *names, DropBehavior behavior, bool missing_ok)
+RemoveTSParsers(DropStmt *drop)
{
- Oid prsOid;
- ObjectAddress object;
+ ObjectAddresses *objects;
+ ListCell *cell;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to drop text search parsers")));
- prsOid = TSParserGetPrsid(names, true);
- if (!OidIsValid(prsOid))
+ /*
+ * 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)
{
- if (!missing_ok)
+ List *names = (List *) lfirst(cell);
+ Oid prsOid;
+ ObjectAddress object;
+
+ prsOid = TSParserGetPrsid(names, true);
+
+ if (!OidIsValid(prsOid))
{
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search parser \"%s\" does not exist",
+ 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;
}
- else
- {
- ereport(NOTICE,
- (errmsg("text search parser \"%s\" does not exist, skipping",
- NameListToString(names))));
- }
- return;
+
+ object.classId = TSParserRelationId;
+ object.objectId = prsOid;
+ object.objectSubId = 0;
+
+ add_exact_object_address(&object, objects);
}
- object.classId = TSParserRelationId;
- object.objectId = prsOid;
- object.objectSubId = 0;
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
/*
* DROP TEXT SEARCH DICTIONARY
*/
void
-RemoveTSDictionary(List *names, DropBehavior behavior, bool missing_ok)
+RemoveTSDictionaries(DropStmt *drop)
{
- Oid dictOid;
- ObjectAddress object;
- HeapTuple tup;
- Oid namespaceId;
+ 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();
- dictOid = TSDictionaryGetDictid(names, true);
- if (!OidIsValid(dictOid))
+ foreach(cell, drop->objects)
{
- if (!missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search dictionary \"%s\" does not exist",
- NameListToString(names))));
- }
- else
+ List *names = (List *) lfirst(cell);
+ Oid dictOid;
+ ObjectAddress object;
+ HeapTuple tup;
+ Oid namespaceId;
+
+ dictOid = TSDictionaryGetDictid(names, true);
+
+ if (!OidIsValid(dictOid))
{
- ereport(NOTICE,
- (errmsg("text search dictionary \"%s\" does not exist, skipping",
- NameListToString(names))));
+ 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;
}
- return;
- }
- tup = SearchSysCache(TSDICTOID,
- ObjectIdGetDatum(dictOid),
- 0, 0, 0);
+ tup = SearchSysCache(TSDICTOID,
+ ObjectIdGetDatum(dictOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for text search dictionary %u",
+ 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));
- /* 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;
- ReleaseSysCache(tup);
+ add_exact_object_address(&object, objects);
- object.classId = TSDictionaryRelationId;
- object.objectId = dictOid;
- object.objectSubId = 0;
+ ReleaseSysCache(tup);
+ }
+
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
/*
* DROP TEXT SEARCH TEMPLATE
*/
void
-RemoveTSTemplate(List *names, DropBehavior behavior, bool missing_ok)
+RemoveTSTemplates(DropStmt *drop)
{
- Oid tmplOid;
- ObjectAddress object;
+ ObjectAddresses *objects;
+ ListCell *cell;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to drop text search templates")));
- tmplOid = TSTemplateGetTmplid(names, true);
- if (!OidIsValid(tmplOid))
+ /*
+ * 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)
{
- if (!missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search template \"%s\" does not exist",
- NameListToString(names))));
- }
- else
+ List *names = (List *) lfirst(cell);
+ Oid tmplOid;
+ ObjectAddress object;
+
+ tmplOid = TSTemplateGetTmplid(names, true);
+
+ if (!OidIsValid(tmplOid))
{
- ereport(NOTICE,
- (errmsg("text search template \"%s\" does not exist, skipping",
- NameListToString(names))));
+ 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;
}
- return;
+
+ object.classId = TSTemplateRelationId;
+ object.objectId = tmplOid;
+ object.objectSubId = 0;
+
+ add_exact_object_address(&object, objects);
}
- object.classId = TSTemplateRelationId;
- object.objectId = tmplOid;
- object.objectSubId = 0;
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
/*
* DROP TEXT SEARCH CONFIGURATION
*/
void
-RemoveTSConfiguration(List *names, DropBehavior behavior, bool missing_ok)
+RemoveTSConfigurations(DropStmt *drop)
{
- Oid cfgOid;
- Oid namespaceId;
- ObjectAddress object;
- HeapTuple tup;
+ ObjectAddresses *objects;
+ ListCell *cell;
- tup = GetTSConfigTuple(names);
+ /*
+ * 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();
- if (!HeapTupleIsValid(tup))
+ foreach(cell, drop->objects)
{
- if (!missing_ok)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("text search configuration \"%s\" does not exist",
- NameListToString(names))));
- }
- else
+ List *names = (List *) lfirst(cell);
+ Oid cfgOid;
+ Oid namespaceId;
+ ObjectAddress object;
+ HeapTuple tup;
+
+ tup = GetTSConfigTuple(names);
+
+ if (!HeapTupleIsValid(tup))
{
- ereport(NOTICE,
- (errmsg("text search configuration \"%s\" does not exist, skipping",
- NameListToString(names))));
+ 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;
}
- return;
- }
- /* 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));
+ /* 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));
- ReleaseSysCache(tup);
+ object.classId = TSConfigRelationId;
+ object.objectId = cfgOid;
+ object.objectSubId = 0;
+
+ add_exact_object_address(&object, objects);
+
+ ReleaseSysCache(tup);
+ }
- object.classId = TSConfigRelationId;
- object.objectId = cfgOid;
- object.objectSubId = 0;
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.118 2008/05/09 23:32:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.119 2008/06/14 18:04:33 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
/*
- * RemoveType
- * Removes a datatype.
+ * 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
-RemoveType(List *names, DropBehavior behavior, bool missing_ok)
+RemoveTypes(DropStmt *drop)
{
- TypeName *typename;
- Oid typeoid;
- HeapTuple tup;
- ObjectAddress object;
- Form_pg_type typ;
+ ObjectAddresses *objects;
+ ListCell *cell;
- /* Make a TypeName so we can use standard type lookup machinery */
- typename = makeTypeNameFromNameList(names);
+ /*
+ * 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();
- /* Use LookupTypeName here so that shell types can be removed. */
- tup = LookupTypeName(NULL, typename, NULL);
- if (tup == NULL)
+ foreach(cell, drop->objects)
{
- if (!missing_ok)
+ 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)
{
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("type \"%s\" does not exist",
- TypeNameToString(typename))));
+ 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;
}
- else
+
+ 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,
+ TypeNameToString(typename));
+
+ if (drop->removeType == OBJECT_DOMAIN)
{
- ereport(NOTICE,
- (errmsg("type \"%s\" does not exist, skipping",
- TypeNameToString(typename))));
+ /* 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))));
}
- return;
- }
-
- typeoid = typeTypeId(tup);
- typ = (Form_pg_type) GETSTRUCT(tup);
+ /*
+ * Note: we need no special check for array types here, as the normal
+ * treatment of internal dependencies handles it just fine
+ */
- /* 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,
- TypeNameToString(typename));
+ object.classId = TypeRelationId;
+ object.objectId = typeoid;
+ object.objectSubId = 0;
- /*
- * Note: we need no special check for array types here, as the normal
- * treatment of internal dependencies handles it just fine
- */
+ add_exact_object_address(&object, objects);
- ReleaseSysCache(tup);
+ ReleaseSysCache(tup);
+ }
- /*
- * Do the deletion
- */
- object.classId = TypeRelationId;
- object.objectId = typeoid;
- object.objectSubId = 0;
+ performMultipleDeletions(objects, drop->behavior);
- performDeletion(&object, behavior);
+ free_object_addresses(objects);
}
}
-/*
- * RemoveDomain
- * Removes a domain.
- *
- * This is identical to RemoveType except we insist it be a domain.
- */
-void
-RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
-{
- TypeName *typename;
- Oid typeoid;
- HeapTuple tup;
- char typtype;
- ObjectAddress object;
-
- /* 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 (!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))));
- }
-
- return;
- }
-
- typeoid = typeTypeId(tup);
-
- /* Permission check: must own type or its namespace */
- if (!pg_type_ownercheck(typeoid, GetUserId()) &&
- !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
- GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
- TypeNameToString(typename));
-
- /* Check that this is actually a domain */
- typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
-
- if (typtype != TYPTYPE_DOMAIN)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a domain",
- TypeNameToString(typename))));
-
- ReleaseSysCache(tup);
-
- /*
- * Do the deletion
- */
- object.classId = TypeRelationId;
- object.objectId = typeoid;
- object.objectSubId = 0;
-
- performDeletion(&object, behavior);
-}
-
/*
* DefineEnum
* Registers a new enum.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.104 2008/01/01 19:45:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.105 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "access/xact.h"
-#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
*/
DefineViewRules(viewOid, viewParse, stmt->replace);
}
-
-/*
- * RemoveView
- *
- * Remove a view given its name
- *
- * We just have to drop the relation; the associated rules will be
- * cleaned up automatically.
- */
-void
-RemoveView(const RangeVar *view, DropBehavior behavior)
-{
- Oid viewOid;
- ObjectAddress object;
-
- viewOid = RangeVarGetRelid(view, false);
-
- object.classId = RelationRelationId;
- object.objectId = viewOid;
- object.objectSubId = 0;
-
- performDeletion(&object, behavior);
-}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.292 2008/06/05 15:47:32 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.293 2008/06/14 18:04:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
-/*
- * Error-checking support for DROP commands
- */
-
-struct msgstrings
-{
- char kind;
- int nonexistent_code;
- const char *nonexistent_msg;
- const char *skipping_msg;
- const char *nota_msg;
- const char *drophint_msg;
-};
-
-static const struct msgstrings msgstringarray[] = {
- {RELKIND_RELATION,
- ERRCODE_UNDEFINED_TABLE,
- gettext_noop("table \"%s\" does not exist"),
- gettext_noop("table \"%s\" does not exist, skipping"),
- gettext_noop("\"%s\" is not a table"),
- gettext_noop("Use DROP TABLE to remove a table.")},
- {RELKIND_SEQUENCE,
- ERRCODE_UNDEFINED_TABLE,
- gettext_noop("sequence \"%s\" does not exist"),
- gettext_noop("sequence \"%s\" does not exist, skipping"),
- gettext_noop("\"%s\" is not a sequence"),
- gettext_noop("Use DROP SEQUENCE to remove a sequence.")},
- {RELKIND_VIEW,
- ERRCODE_UNDEFINED_TABLE,
- gettext_noop("view \"%s\" does not exist"),
- gettext_noop("view \"%s\" does not exist, skipping"),
- gettext_noop("\"%s\" is not a view"),
- gettext_noop("Use DROP VIEW to remove a view.")},
- {RELKIND_INDEX,
- ERRCODE_UNDEFINED_OBJECT,
- gettext_noop("index \"%s\" does not exist"),
- gettext_noop("index \"%s\" does not exist, skipping"),
- gettext_noop("\"%s\" is not an index"),
- gettext_noop("Use DROP INDEX to remove an index.")},
- {RELKIND_COMPOSITE_TYPE,
- ERRCODE_UNDEFINED_OBJECT,
- gettext_noop("type \"%s\" does not exist"),
- gettext_noop("type \"%s\" does not exist, skipping"),
- gettext_noop("\"%s\" is not a type"),
- gettext_noop("Use DROP TYPE to remove a type.")},
- {'\0', 0, NULL, NULL, NULL}
-};
-
-
-/*
- * Emit the right error message for a "DROP" command issued on a
- * relation of the wrong type
- */
-static void
-DropErrorMsgWrongType(char *relname, char wrongkind, char rightkind)
-{
- const struct msgstrings *rentry;
- const struct msgstrings *wentry;
-
- for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)
- if (rentry->kind == rightkind)
- break;
- Assert(rentry->kind != '\0');
-
- for (wentry = msgstringarray; wentry->kind != '\0'; wentry++)
- if (wentry->kind == wrongkind)
- break;
- /* wrongkind could be something we don't have in our table... */
-
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg(rentry->nota_msg, relname),
- (wentry->kind != '\0') ? errhint(wentry->drophint_msg) : 0));
-}
-
-/*
- * Emit the right error message for a "DROP" command issued on a
- * non-existent relation
- */
-static void
-DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
-{
- const struct msgstrings *rentry;
-
- for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)
- {
- if (rentry->kind == rightkind)
- {
- if (!missing_ok)
- {
- ereport(ERROR,
- (errcode(rentry->nonexistent_code),
- errmsg(rentry->nonexistent_msg, rel->relname)));
- }
- else
- {
- ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
- break;
- }
- }
- }
-
- Assert(rentry->kind != '\0'); /* Should be impossible */
-}
-
-/*
- * returns false if missing_ok is true and the object does not exist,
- * true if object exists and permissions are OK,
- * errors otherwise
- *
- */
-
-static bool
-CheckDropPermissions(RangeVar *rel, char rightkind, bool missing_ok)
-{
- Oid relOid;
- HeapTuple tuple;
- Form_pg_class classform;
-
- relOid = RangeVarGetRelid(rel, true);
- if (!OidIsValid(relOid))
- {
- DropErrorMsgNonExistent(rel, rightkind, missing_ok);
- return false;
- }
-
- tuple = SearchSysCache(RELOID,
- ObjectIdGetDatum(relOid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for relation %u", relOid);
-
- classform = (Form_pg_class) GETSTRUCT(tuple);
-
- if (classform->relkind != rightkind)
- DropErrorMsgWrongType(rel->relname, classform->relkind,
- rightkind);
-
- /* Allow DROP to either table owner or schema owner */
- if (!pg_class_ownercheck(relOid, GetUserId()) &&
- !pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
- rel->relname);
-
- if (!allowSystemTableMods && IsSystemClass(classform))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied: \"%s\" is a system catalog",
- rel->relname)));
-
- ReleaseSysCache(tuple);
-
- return true;
-}
-
/*
* Verify user has ownership of specified relation, else ereport.
*
case T_DropStmt:
{
DropStmt *stmt = (DropStmt *) parsetree;
- ListCell *arg;
- foreach(arg, stmt->objects)
+ switch (stmt->removeType)
{
- List *names = (List *) lfirst(arg);
- RangeVar *rel;
+ case OBJECT_TABLE:
+ case OBJECT_SEQUENCE:
+ case OBJECT_VIEW:
+ case OBJECT_INDEX:
+ RemoveRelations(stmt);
+ break;
- switch (stmt->removeType)
- {
- case OBJECT_TABLE:
- rel = makeRangeVarFromNameList(names);
- if (CheckDropPermissions(rel, RELKIND_RELATION,
- stmt->missing_ok))
- RemoveRelation(rel, stmt->behavior);
- break;
-
- case OBJECT_SEQUENCE:
- rel = makeRangeVarFromNameList(names);
- if (CheckDropPermissions(rel, RELKIND_SEQUENCE,
- stmt->missing_ok))
- RemoveRelation(rel, stmt->behavior);
- break;
-
- case OBJECT_VIEW:
- rel = makeRangeVarFromNameList(names);
- if (CheckDropPermissions(rel, RELKIND_VIEW,
- stmt->missing_ok))
- RemoveView(rel, stmt->behavior);
- break;
-
- case OBJECT_INDEX:
- rel = makeRangeVarFromNameList(names);
- if (CheckDropPermissions(rel, RELKIND_INDEX,
- stmt->missing_ok))
- RemoveIndex(rel, stmt->behavior);
- break;
-
- case OBJECT_TYPE:
- /* RemoveType does its own permissions checks */
- RemoveType(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_DOMAIN:
- /* RemoveDomain does its own permissions checks */
- RemoveDomain(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_CONVERSION:
- DropConversionCommand(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_SCHEMA:
- /* RemoveSchema does its own permissions checks */
- RemoveSchema(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_TSPARSER:
- RemoveTSParser(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_TSDICTIONARY:
- RemoveTSDictionary(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_TSTEMPLATE:
- RemoveTSTemplate(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- case OBJECT_TSCONFIGURATION:
- RemoveTSConfiguration(names, stmt->behavior,
- stmt->missing_ok);
- break;
-
- default:
- elog(ERROR, "unrecognized drop object type: %d",
- (int) stmt->removeType);
- break;
- }
+ case OBJECT_TYPE:
+ case OBJECT_DOMAIN:
+ RemoveTypes(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;
- /*
- * We used to need to do CommandCounterIncrement() here,
- * but now it's done inside performDeletion().
- */
+ case OBJECT_TSCONFIGURATION:
+ RemoveTSConfigurations(stmt);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized drop object type: %d",
+ (int) stmt->removeType);
+ break;
}
}
break;
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_conversion_fn.h,v 1.1 2008/03/27 03:57:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_conversion_fn.h,v 1.2 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PG_CONVERSION_FN_H
#define PG_CONVERSION_FN_H
-#include "nodes/parsenodes.h"
-
extern Oid ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
Oid conproc, bool def);
-extern void ConversionDrop(Oid conversionOid, DropBehavior behavior);
extern void RemoveConversionById(Oid conversionOid);
extern Oid FindConversion(const char *conname, Oid connamespace);
extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.16 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/conversioncmds.h,v 1.17 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/parsenodes.h"
extern void CreateConversionCommand(CreateConversionStmt *parsetree);
-extern void DropConversionCommand(List *conversion_name,
- DropBehavior behavior, bool missing_ok);
+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);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.88 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.89 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool skip_build,
bool quiet,
bool concurrent);
-extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
extern void ReindexIndex(RangeVar *indexRelation);
extern void ReindexTable(RangeVar *relation);
extern void ReindexDatabase(const char *databaseName,
/* commands/tsearchcmds.c */
extern void DefineTSParser(List *names, List *parameters);
extern void RenameTSParser(List *oldname, const char *newname);
-extern void RemoveTSParser(List *names, DropBehavior behavior,
- bool missing_ok);
+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 RemoveTSDictionary(List *names, DropBehavior behavior,
- bool missing_ok);
+extern void RemoveTSDictionaries(DropStmt *drop);
extern void RemoveTSDictionaryById(Oid dictId);
extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
extern void DefineTSTemplate(List *names, List *parameters);
extern void RenameTSTemplate(List *oldname, const char *newname);
-extern void RemoveTSTemplate(List *names, DropBehavior behavior,
- bool missing_ok);
+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 RemoveTSConfiguration(List *names, DropBehavior behavior,
- bool missing_ok);
+extern void RemoveTSConfigurations(DropStmt *stmt);
extern void RemoveTSConfigurationById(Oid cfgId);
extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.18 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.19 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
const char *queryString);
-extern void RemoveSchema(List *names, DropBehavior behavior, bool missing_ok);
+extern void RemoveSchemas(DropStmt *drop);
extern void RemoveSchemaById(Oid schemaOid);
extern void RenameSchema(const char *oldname, const char *newname);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.38 2008/03/19 18:38:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.39 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
-extern void RemoveRelation(const RangeVar *relation, DropBehavior behavior);
+extern void RemoveRelations(DropStmt *drop);
extern void AlterTable(AlterTableStmt *stmt);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.23 2008/03/19 18:38:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.24 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define DEFAULT_TYPDELIM ','
extern void DefineType(List *names, List *parameters);
-extern void RemoveType(List *names, DropBehavior behavior, bool missing_ok);
+extern void RemoveTypes(DropStmt *drop);
extern void RemoveTypeById(Oid typeOid);
extern void DefineDomain(CreateDomainStmt *stmt);
-extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok);
extern void DefineEnum(CreateEnumStmt *stmt);
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/view.h,v 1.26 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/view.h,v 1.27 2008/06/14 18:04:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/parsenodes.h"
extern void DefineView(ViewStmt *stmt, const char *queryString);
-extern void RemoveView(const RangeVar *view, DropBehavior behavior);
#endif /* VIEW_H */
COMMIT;
ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey"
DETAIL: Key (fk)=(200) is not present in table "pktable".
-DROP TABLE pktable, fktable CASCADE;
-NOTICE: drop cascades to constraint fktable_fk_fkey on table fktable
+DROP TABLE pktable, fktable;
-- test notice about expensive referential integrity checks,
-- where the index cannot be used because of type incompatibilities.
CREATE TEMP TABLE pktable (
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
ERROR: foreign key constraint "fk_241_132" cannot be implemented
DETAIL: Key columns "x2" and "id1" are of incompatible types: character varying and integer.
-DROP TABLE pktable, fktable CASCADE;
-NOTICE: drop cascades to 9 other objects
-DETAIL: drop cascades to constraint fktable_x3_fkey on table fktable
-drop cascades to constraint fk_1_3 on table fktable
-drop cascades to constraint fktable_x2_fkey on table fktable
-drop cascades to constraint fk_4_2 on table fktable
-drop cascades to constraint fktable_x1_fkey on table fktable
-drop cascades to constraint fk_5_1 on table fktable
-drop cascades to constraint fk_123_123 on table fktable
-drop cascades to constraint fk_213_213 on table fktable
-drop cascades to constraint fk_253_213 on table fktable
+DROP TABLE pktable, fktable;
-- test a tricky case: we can elide firing the FK check trigger during
-- an UPDATE if the UPDATE did not change the foreign key
-- field. However, we can't do this if our transaction was the one that
(0 rows)
DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to constraint trunc_b_a_fkey on table trunc_b
-drop cascades to constraint trunc_e_a_fkey on table trunc_e
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to constraint trunc_d_a_fkey on table trunc_d
-drop cascades to constraint trunc_e_b_fkey on table trunc_e
-- Test ON TRUNCATE triggers
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
-- error here on commit
COMMIT;
-DROP TABLE pktable, fktable CASCADE;
+DROP TABLE pktable, fktable;
-- test notice about expensive referential integrity checks,
-- where the index cannot be used because of type incompatibilities.
ALTER TABLE fktable ADD CONSTRAINT fk_241_132
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
-DROP TABLE pktable, fktable CASCADE;
+DROP TABLE pktable, fktable;
-- test a tricky case: we can elide firing the FK check trigger during
-- an UPDATE if the UPDATE did not change the foreign key