aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/utility.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-06-14 18:04:34 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-06-14 18:04:34 +0000
commit0cefb50f3ce964d6097aad64dabd9b544c3d2e68 (patch)
tree4e1ee9454bc958d35194062eee8894205cd08da5 /src/backend/tcop/utility.c
parent95ce4ee943f226152ac8c147da178af5d1a95909 (diff)
downloadpostgresql-0cefb50f3ce964d6097aad64dabd9b544c3d2e68.tar.gz
postgresql-0cefb50f3ce964d6097aad64dabd9b544c3d2e68.zip
Refactor the handling of the various DropStmt variants so that when multiple
objects are specified, we drop them all in a single performMultipleDeletions call. This makes the RESTRICT/CASCADE checks more relaxed: it's not counted as a cascade if one of the later objects has a dependency on an earlier one. NOTICE messages about such cases go away, too. In passing, fix the permissions check for DROP CONVERSION, which for some reason was never made role-aware, and omitted the namespace-owner exemption too. Alex Hunsaker, with further fiddling by me.
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r--src/backend/tcop/utility.c282
1 files changed, 40 insertions, 242 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1bebfec182b..6c839650b43 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -58,161 +58,6 @@
/*
- * 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.
*
* If noCatalogs is true then we also deny access to system catalogs,
@@ -603,96 +448,49 @@ ProcessUtility(Node *parsetree,
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;