mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -259,6 +259,10 @@ performMultipleDeletions(const ObjectAddresses *objects,
|
|||||||
ObjectAddresses *targetObjects;
|
ObjectAddresses *targetObjects;
|
||||||
int i;
|
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
|
* We save some cycles by opening pg_depend just once and passing the
|
||||||
* Relation pointer down to all the recursive deletion steps.
|
* Relation pointer down to all the recursive deletion steps.
|
||||||
@ -295,11 +299,14 @@ performMultipleDeletions(const ObjectAddresses *objects,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if deletion is allowed, and report about cascaded deletes.
|
* 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,
|
reportDependentObjects(targetObjects,
|
||||||
behavior,
|
behavior,
|
||||||
NOTICE,
|
NOTICE,
|
||||||
NULL);
|
(objects->numrefs == 1 ? objects->refs : NULL));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete all the objects in the proper order.
|
* Delete all the objects in the proper order.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -18,7 +18,6 @@
|
|||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/namespace.h"
|
|
||||||
#include "catalog/pg_conversion.h"
|
#include "catalog/pg_conversion.h"
|
||||||
#include "catalog/pg_conversion_fn.h"
|
#include "catalog/pg_conversion_fn.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
@ -138,40 +137,6 @@ ConversionCreate(const char *conname, Oid connamespace,
|
|||||||
return oid;
|
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
|
* RemoveConversionById
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -99,14 +99,32 @@ CreateConversionCommand(CreateConversionStmt *stmt)
|
|||||||
* DROP CONVERSION
|
* DROP CONVERSION
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
DropConversionCommand(List *name, DropBehavior behavior, bool missing_ok)
|
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;
|
Oid conversionOid;
|
||||||
|
HeapTuple tuple;
|
||||||
|
Form_pg_conversion con;
|
||||||
|
ObjectAddress object;
|
||||||
|
|
||||||
conversionOid = FindConversionByName(name);
|
conversionOid = FindConversionByName(name);
|
||||||
|
|
||||||
if (!OidIsValid(conversionOid))
|
if (!OidIsValid(conversionOid))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -119,11 +137,35 @@ DropConversionCommand(List *name, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("conversion \"%s\" does not exist, skipping",
|
(errmsg("conversion \"%s\" does not exist, skipping",
|
||||||
NameListToString(name))));
|
NameListToString(name))));
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionDrop(conversionOid, behavior);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -21,7 +21,6 @@
|
|||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/dependency.h"
|
|
||||||
#include "catalog/heap.h"
|
#include "catalog/heap.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
@ -1256,33 +1255,6 @@ relationHasPrimaryKey(Relation rel)
|
|||||||
return result;
|
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
|
* ReindexIndex
|
||||||
* Recreate a specific index.
|
* Recreate a specific index.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -148,12 +148,25 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveSchema
|
* RemoveSchemas
|
||||||
* Removes a schema.
|
* Implements DROP SCHEMA.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
|
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;
|
char *namespaceName;
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
ObjectAddress object;
|
ObjectAddress object;
|
||||||
@ -167,13 +180,15 @@ RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
namespaceId = GetSysCacheOid(NAMESPACENAME,
|
namespaceId = GetSysCacheOid(NAMESPACENAME,
|
||||||
CStringGetDatum(namespaceName),
|
CStringGetDatum(namespaceName),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
if (!OidIsValid(namespaceId))
|
if (!OidIsValid(namespaceId))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||||
errmsg("schema \"%s\" does not exist", namespaceName)));
|
errmsg("schema \"%s\" does not exist",
|
||||||
|
namespaceName)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -181,8 +196,7 @@ RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("schema \"%s\" does not exist, skipping",
|
(errmsg("schema \"%s\" does not exist, skipping",
|
||||||
namespaceName)));
|
namespaceName)));
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Permission check */
|
/* Permission check */
|
||||||
@ -190,15 +204,20 @@ RemoveSchema(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
|
||||||
namespaceName);
|
namespaceName);
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the deletion. Objects contained in the schema are removed by means
|
|
||||||
* of their dependency links to the schema.
|
|
||||||
*/
|
|
||||||
object.classId = NamespaceRelationId;
|
object.classId = NamespaceRelationId;
|
||||||
object.objectId = namespaceId;
|
object.objectId = namespaceId;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -61,6 +61,7 @@
|
|||||||
#include "rewrite/rewriteDefine.h"
|
#include "rewrite/rewriteDefine.h"
|
||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
|
#include "storage/lmgr.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
@ -168,6 +169,53 @@ typedef struct NewColumnValue
|
|||||||
ExprState *exprstate; /* execution state */
|
ExprState *exprstate; /* execution state */
|
||||||
} NewColumnValue;
|
} 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 void truncate_check_rel(Relation rel);
|
||||||
static List *MergeAttributes(List *schema, List *supers, bool istemp,
|
static List *MergeAttributes(List *schema, List *supers, bool istemp,
|
||||||
@ -497,22 +545,175 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveRelation
|
* Emit the right error or warning message for a "DROP" command issued on a
|
||||||
* Deletes a relation.
|
* 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
|
void
|
||||||
RemoveRelation(const RangeVar *relation, DropBehavior behavior)
|
RemoveRelations(DropStmt *drop)
|
||||||
{
|
{
|
||||||
|
ObjectAddresses *objects;
|
||||||
|
char relkind;
|
||||||
|
ListCell *cell;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Determine required relkind */
|
||||||
|
switch (drop->removeType)
|
||||||
|
{
|
||||||
|
case OBJECT_TABLE:
|
||||||
|
relkind = RELKIND_RELATION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
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;
|
Oid relOid;
|
||||||
ObjectAddress object;
|
HeapTuple tuple;
|
||||||
|
Form_pg_class classform;
|
||||||
|
ObjectAddress obj;
|
||||||
|
|
||||||
relOid = RangeVarGetRelid(relation, false);
|
/*
|
||||||
|
* 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();
|
||||||
|
|
||||||
object.classId = RelationRelationId;
|
/* Look up the appropriate relation using namespace search */
|
||||||
object.objectId = relOid;
|
relOid = RangeVarGetRelid(rel, true);
|
||||||
object.objectSubId = 0;
|
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -271,20 +271,34 @@ DefineTSParser(List *names, List *parameters)
|
|||||||
* DROP TEXT SEARCH PARSER
|
* DROP TEXT SEARCH PARSER
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveTSParser(List *names, DropBehavior behavior, bool missing_ok)
|
RemoveTSParsers(DropStmt *drop)
|
||||||
{
|
{
|
||||||
Oid prsOid;
|
ObjectAddresses *objects;
|
||||||
ObjectAddress object;
|
ListCell *cell;
|
||||||
|
|
||||||
if (!superuser())
|
if (!superuser())
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
errmsg("must be superuser to drop text search parsers")));
|
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 = TSParserGetPrsid(names, true);
|
prsOid = TSParserGetPrsid(names, true);
|
||||||
|
|
||||||
if (!OidIsValid(prsOid))
|
if (!OidIsValid(prsOid))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -297,14 +311,19 @@ RemoveTSParser(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("text search parser \"%s\" does not exist, skipping",
|
(errmsg("text search parser \"%s\" does not exist, skipping",
|
||||||
NameListToString(names))));
|
NameListToString(names))));
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
object.classId = TSParserRelationId;
|
object.classId = TSParserRelationId;
|
||||||
object.objectId = prsOid;
|
object.objectId = prsOid;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
add_exact_object_address(&object, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -613,17 +632,31 @@ RenameTSDictionary(List *oldname, const char *newname)
|
|||||||
* DROP TEXT SEARCH DICTIONARY
|
* DROP TEXT SEARCH DICTIONARY
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveTSDictionary(List *names, DropBehavior behavior, bool missing_ok)
|
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;
|
Oid dictOid;
|
||||||
ObjectAddress object;
|
ObjectAddress object;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
|
|
||||||
dictOid = TSDictionaryGetDictid(names, true);
|
dictOid = TSDictionaryGetDictid(names, true);
|
||||||
|
|
||||||
if (!OidIsValid(dictOid))
|
if (!OidIsValid(dictOid))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -636,13 +669,12 @@ RemoveTSDictionary(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("text search dictionary \"%s\" does not exist, skipping",
|
(errmsg("text search dictionary \"%s\" does not exist, skipping",
|
||||||
NameListToString(names))));
|
NameListToString(names))));
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
tup = SearchSysCache(TSDICTOID,
|
tup = SearchSysCache(TSDICTOID,
|
||||||
ObjectIdGetDatum(dictOid),
|
ObjectIdGetDatum(dictOid),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||||
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
||||||
dictOid);
|
dictOid);
|
||||||
@ -654,13 +686,18 @@ RemoveTSDictionary(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
|
||||||
NameListToString(names));
|
NameListToString(names));
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
|
||||||
|
|
||||||
object.classId = TSDictionaryRelationId;
|
object.classId = TSDictionaryRelationId;
|
||||||
object.objectId = dictOid;
|
object.objectId = dictOid;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
add_exact_object_address(&object, objects);
|
||||||
|
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1086,20 +1123,34 @@ RenameTSTemplate(List *oldname, const char *newname)
|
|||||||
* DROP TEXT SEARCH TEMPLATE
|
* DROP TEXT SEARCH TEMPLATE
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveTSTemplate(List *names, DropBehavior behavior, bool missing_ok)
|
RemoveTSTemplates(DropStmt *drop)
|
||||||
{
|
{
|
||||||
Oid tmplOid;
|
ObjectAddresses *objects;
|
||||||
ObjectAddress object;
|
ListCell *cell;
|
||||||
|
|
||||||
if (!superuser())
|
if (!superuser())
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||||
errmsg("must be superuser to drop text search templates")));
|
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 = TSTemplateGetTmplid(names, true);
|
tmplOid = TSTemplateGetTmplid(names, true);
|
||||||
|
|
||||||
if (!OidIsValid(tmplOid))
|
if (!OidIsValid(tmplOid))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -1112,14 +1163,19 @@ RemoveTSTemplate(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("text search template \"%s\" does not exist, skipping",
|
(errmsg("text search template \"%s\" does not exist, skipping",
|
||||||
NameListToString(names))));
|
NameListToString(names))));
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
object.classId = TSTemplateRelationId;
|
object.classId = TSTemplateRelationId;
|
||||||
object.objectId = tmplOid;
|
object.objectId = tmplOid;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
add_exact_object_address(&object, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1474,8 +1530,21 @@ RenameTSConfiguration(List *oldname, const char *newname)
|
|||||||
* DROP TEXT SEARCH CONFIGURATION
|
* DROP TEXT SEARCH CONFIGURATION
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveTSConfiguration(List *names, DropBehavior behavior, bool missing_ok)
|
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 cfgOid;
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
ObjectAddress object;
|
ObjectAddress object;
|
||||||
@ -1485,7 +1554,7 @@ RemoveTSConfiguration(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
|
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -1498,7 +1567,7 @@ RemoveTSConfiguration(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("text search configuration \"%s\" does not exist, skipping",
|
(errmsg("text search configuration \"%s\" does not exist, skipping",
|
||||||
NameListToString(names))));
|
NameListToString(names))));
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Permission check: must own configuration or its namespace */
|
/* Permission check: must own configuration or its namespace */
|
||||||
@ -1509,13 +1578,18 @@ RemoveTSConfiguration(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
|
||||||
NameListToString(names));
|
NameListToString(names));
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
|
||||||
|
|
||||||
object.classId = TSConfigRelationId;
|
object.classId = TSConfigRelationId;
|
||||||
object.objectId = cfgOid;
|
object.objectId = cfgOid;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
add_exact_object_address(&object, objects);
|
||||||
|
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
@ -483,12 +483,28 @@ DefineType(List *names, List *parameters)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveType
|
* RemoveTypes
|
||||||
* Removes a datatype.
|
* 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
|
void
|
||||||
RemoveType(List *names, DropBehavior behavior, bool missing_ok)
|
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;
|
TypeName *typename;
|
||||||
Oid typeoid;
|
Oid typeoid;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
@ -502,7 +518,7 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
tup = LookupTypeName(NULL, typename, NULL);
|
tup = LookupTypeName(NULL, typename, NULL);
|
||||||
if (tup == NULL)
|
if (tup == NULL)
|
||||||
{
|
{
|
||||||
if (!missing_ok)
|
if (!drop->missing_ok)
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -515,8 +531,7 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
(errmsg("type \"%s\" does not exist, skipping",
|
(errmsg("type \"%s\" does not exist, skipping",
|
||||||
TypeNameToString(typename))));
|
TypeNameToString(typename))));
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typeoid = typeTypeId(tup);
|
typeoid = typeTypeId(tup);
|
||||||
@ -528,21 +543,33 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
|
|||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
|
||||||
TypeNameToString(typename));
|
TypeNameToString(typename));
|
||||||
|
|
||||||
|
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
|
* Note: we need no special check for array types here, as the normal
|
||||||
* treatment of internal dependencies handles it just fine
|
* treatment of internal dependencies handles it just fine
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the deletion
|
|
||||||
*/
|
|
||||||
object.classId = TypeRelationId;
|
object.classId = TypeRelationId;
|
||||||
object.objectId = typeoid;
|
object.objectId = typeoid;
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
|
|
||||||
performDeletion(&object, behavior);
|
add_exact_object_address(&object, objects);
|
||||||
|
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
performMultipleDeletions(objects, drop->behavior);
|
||||||
|
|
||||||
|
free_object_addresses(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -923,75 +950,6 @@ DefineDomain(CreateDomainStmt *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
* DefineEnum
|
||||||
* Registers a new enum.
|
* Registers a new enum.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/dependency.h"
|
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
@ -446,26 +445,3 @@ DefineView(ViewStmt *stmt, const char *queryString)
|
|||||||
*/
|
*/
|
||||||
DefineViewRules(viewOid, viewParse, stmt->replace);
|
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);
|
|
||||||
}
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -57,161 +57,6 @@
|
|||||||
#include "utils/syscache.h"
|
#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.
|
* Verify user has ownership of specified relation, else ereport.
|
||||||
*
|
*
|
||||||
@ -603,84 +448,43 @@ ProcessUtility(Node *parsetree,
|
|||||||
case T_DropStmt:
|
case T_DropStmt:
|
||||||
{
|
{
|
||||||
DropStmt *stmt = (DropStmt *) parsetree;
|
DropStmt *stmt = (DropStmt *) parsetree;
|
||||||
ListCell *arg;
|
|
||||||
|
|
||||||
foreach(arg, stmt->objects)
|
|
||||||
{
|
|
||||||
List *names = (List *) lfirst(arg);
|
|
||||||
RangeVar *rel;
|
|
||||||
|
|
||||||
switch (stmt->removeType)
|
switch (stmt->removeType)
|
||||||
{
|
{
|
||||||
case OBJECT_TABLE:
|
case OBJECT_TABLE:
|
||||||
rel = makeRangeVarFromNameList(names);
|
|
||||||
if (CheckDropPermissions(rel, RELKIND_RELATION,
|
|
||||||
stmt->missing_ok))
|
|
||||||
RemoveRelation(rel, stmt->behavior);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OBJECT_SEQUENCE:
|
case OBJECT_SEQUENCE:
|
||||||
rel = makeRangeVarFromNameList(names);
|
|
||||||
if (CheckDropPermissions(rel, RELKIND_SEQUENCE,
|
|
||||||
stmt->missing_ok))
|
|
||||||
RemoveRelation(rel, stmt->behavior);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OBJECT_VIEW:
|
case OBJECT_VIEW:
|
||||||
rel = makeRangeVarFromNameList(names);
|
|
||||||
if (CheckDropPermissions(rel, RELKIND_VIEW,
|
|
||||||
stmt->missing_ok))
|
|
||||||
RemoveView(rel, stmt->behavior);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OBJECT_INDEX:
|
case OBJECT_INDEX:
|
||||||
rel = makeRangeVarFromNameList(names);
|
RemoveRelations(stmt);
|
||||||
if (CheckDropPermissions(rel, RELKIND_INDEX,
|
|
||||||
stmt->missing_ok))
|
|
||||||
RemoveIndex(rel, stmt->behavior);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_TYPE:
|
case OBJECT_TYPE:
|
||||||
/* RemoveType does its own permissions checks */
|
|
||||||
RemoveType(names, stmt->behavior,
|
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OBJECT_DOMAIN:
|
case OBJECT_DOMAIN:
|
||||||
/* RemoveDomain does its own permissions checks */
|
RemoveTypes(stmt);
|
||||||
RemoveDomain(names, stmt->behavior,
|
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_CONVERSION:
|
case OBJECT_CONVERSION:
|
||||||
DropConversionCommand(names, stmt->behavior,
|
DropConversionsCommand(stmt);
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_SCHEMA:
|
case OBJECT_SCHEMA:
|
||||||
/* RemoveSchema does its own permissions checks */
|
RemoveSchemas(stmt);
|
||||||
RemoveSchema(names, stmt->behavior,
|
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_TSPARSER:
|
case OBJECT_TSPARSER:
|
||||||
RemoveTSParser(names, stmt->behavior,
|
RemoveTSParsers(stmt);
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_TSDICTIONARY:
|
case OBJECT_TSDICTIONARY:
|
||||||
RemoveTSDictionary(names, stmt->behavior,
|
RemoveTSDictionaries(stmt);
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_TSTEMPLATE:
|
case OBJECT_TSTEMPLATE:
|
||||||
RemoveTSTemplate(names, stmt->behavior,
|
RemoveTSTemplates(stmt);
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJECT_TSCONFIGURATION:
|
case OBJECT_TSCONFIGURATION:
|
||||||
RemoveTSConfiguration(names, stmt->behavior,
|
RemoveTSConfigurations(stmt);
|
||||||
stmt->missing_ok);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -688,12 +492,6 @@ ProcessUtility(Node *parsetree,
|
|||||||
(int) stmt->removeType);
|
(int) stmt->removeType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We used to need to do CommandCounterIncrement() here,
|
|
||||||
* but now it's done inside performDeletion().
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -7,20 +7,17 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef PG_CONVERSION_FN_H
|
||||||
#define PG_CONVERSION_FN_H
|
#define PG_CONVERSION_FN_H
|
||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
|
||||||
|
|
||||||
extern Oid ConversionCreate(const char *conname, Oid connamespace,
|
extern Oid ConversionCreate(const char *conname, Oid connamespace,
|
||||||
Oid conowner,
|
Oid conowner,
|
||||||
int32 conforencoding, int32 contoencoding,
|
int32 conforencoding, int32 contoencoding,
|
||||||
Oid conproc, bool def);
|
Oid conproc, bool def);
|
||||||
extern void ConversionDrop(Oid conversionOid, DropBehavior behavior);
|
|
||||||
extern void RemoveConversionById(Oid conversionOid);
|
extern void RemoveConversionById(Oid conversionOid);
|
||||||
extern Oid FindConversion(const char *conname, Oid connamespace);
|
extern Oid FindConversion(const char *conname, Oid connamespace);
|
||||||
extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);
|
extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -18,8 +18,7 @@
|
|||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
extern void CreateConversionCommand(CreateConversionStmt *parsetree);
|
extern void CreateConversionCommand(CreateConversionStmt *parsetree);
|
||||||
extern void DropConversionCommand(List *conversion_name,
|
extern void DropConversionsCommand(DropStmt *drop);
|
||||||
DropBehavior behavior, bool missing_ok);
|
|
||||||
extern void RenameConversion(List *name, const char *newname);
|
extern void RenameConversion(List *name, const char *newname);
|
||||||
extern void AlterConversionOwner(List *name, Oid newOwnerId);
|
extern void AlterConversionOwner(List *name, Oid newOwnerId);
|
||||||
extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
|
extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,7 +34,6 @@ extern void DefineIndex(RangeVar *heapRelation,
|
|||||||
bool skip_build,
|
bool skip_build,
|
||||||
bool quiet,
|
bool quiet,
|
||||||
bool concurrent);
|
bool concurrent);
|
||||||
extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
|
|
||||||
extern void ReindexIndex(RangeVar *indexRelation);
|
extern void ReindexIndex(RangeVar *indexRelation);
|
||||||
extern void ReindexTable(RangeVar *relation);
|
extern void ReindexTable(RangeVar *relation);
|
||||||
extern void ReindexDatabase(const char *databaseName,
|
extern void ReindexDatabase(const char *databaseName,
|
||||||
@ -94,28 +93,24 @@ extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwn
|
|||||||
/* commands/tsearchcmds.c */
|
/* commands/tsearchcmds.c */
|
||||||
extern void DefineTSParser(List *names, List *parameters);
|
extern void DefineTSParser(List *names, List *parameters);
|
||||||
extern void RenameTSParser(List *oldname, const char *newname);
|
extern void RenameTSParser(List *oldname, const char *newname);
|
||||||
extern void RemoveTSParser(List *names, DropBehavior behavior,
|
extern void RemoveTSParsers(DropStmt *drop);
|
||||||
bool missing_ok);
|
|
||||||
extern void RemoveTSParserById(Oid prsId);
|
extern void RemoveTSParserById(Oid prsId);
|
||||||
|
|
||||||
extern void DefineTSDictionary(List *names, List *parameters);
|
extern void DefineTSDictionary(List *names, List *parameters);
|
||||||
extern void RenameTSDictionary(List *oldname, const char *newname);
|
extern void RenameTSDictionary(List *oldname, const char *newname);
|
||||||
extern void RemoveTSDictionary(List *names, DropBehavior behavior,
|
extern void RemoveTSDictionaries(DropStmt *drop);
|
||||||
bool missing_ok);
|
|
||||||
extern void RemoveTSDictionaryById(Oid dictId);
|
extern void RemoveTSDictionaryById(Oid dictId);
|
||||||
extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
|
extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
|
||||||
extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
|
extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
|
||||||
|
|
||||||
extern void DefineTSTemplate(List *names, List *parameters);
|
extern void DefineTSTemplate(List *names, List *parameters);
|
||||||
extern void RenameTSTemplate(List *oldname, const char *newname);
|
extern void RenameTSTemplate(List *oldname, const char *newname);
|
||||||
extern void RemoveTSTemplate(List *names, DropBehavior behavior,
|
extern void RemoveTSTemplates(DropStmt *stmt);
|
||||||
bool missing_ok);
|
|
||||||
extern void RemoveTSTemplateById(Oid tmplId);
|
extern void RemoveTSTemplateById(Oid tmplId);
|
||||||
|
|
||||||
extern void DefineTSConfiguration(List *names, List *parameters);
|
extern void DefineTSConfiguration(List *names, List *parameters);
|
||||||
extern void RenameTSConfiguration(List *oldname, const char *newname);
|
extern void RenameTSConfiguration(List *oldname, const char *newname);
|
||||||
extern void RemoveTSConfiguration(List *names, DropBehavior behavior,
|
extern void RemoveTSConfigurations(DropStmt *stmt);
|
||||||
bool missing_ok);
|
|
||||||
extern void RemoveTSConfigurationById(Oid cfgId);
|
extern void RemoveTSConfigurationById(Oid cfgId);
|
||||||
extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
|
extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
|
||||||
extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
|
extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,7 +20,7 @@
|
|||||||
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
|
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
|
||||||
const char *queryString);
|
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 RemoveSchemaById(Oid schemaOid);
|
||||||
|
|
||||||
extern void RenameSchema(const char *oldname, const char *newname);
|
extern void RenameSchema(const char *oldname, const char *newname);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
|
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);
|
extern void AlterTable(AlterTableStmt *stmt);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,10 +20,9 @@
|
|||||||
#define DEFAULT_TYPDELIM ','
|
#define DEFAULT_TYPDELIM ','
|
||||||
|
|
||||||
extern void DefineType(List *names, List *parameters);
|
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 RemoveTypeById(Oid typeOid);
|
||||||
extern void DefineDomain(CreateDomainStmt *stmt);
|
extern void DefineDomain(CreateDomainStmt *stmt);
|
||||||
extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok);
|
|
||||||
extern void DefineEnum(CreateEnumStmt *stmt);
|
extern void DefineEnum(CreateEnumStmt *stmt);
|
||||||
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
|
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -17,6 +17,5 @@
|
|||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
extern void DefineView(ViewStmt *stmt, const char *queryString);
|
extern void DefineView(ViewStmt *stmt, const char *queryString);
|
||||||
extern void RemoveView(const RangeVar *view, DropBehavior behavior);
|
|
||||||
|
|
||||||
#endif /* VIEW_H */
|
#endif /* VIEW_H */
|
||||||
|
@ -1086,8 +1086,7 @@ INSERT INTO fktable VALUES (100, 200);
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey"
|
ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey"
|
||||||
DETAIL: Key (fk)=(200) is not present in table "pktable".
|
DETAIL: Key (fk)=(200) is not present in table "pktable".
|
||||||
DROP TABLE pktable, fktable CASCADE;
|
DROP TABLE pktable, fktable;
|
||||||
NOTICE: drop cascades to constraint fktable_fk_fkey on table fktable
|
|
||||||
-- test notice about expensive referential integrity checks,
|
-- test notice about expensive referential integrity checks,
|
||||||
-- where the index cannot be used because of type incompatibilities.
|
-- where the index cannot be used because of type incompatibilities.
|
||||||
CREATE TEMP TABLE pktable (
|
CREATE TEMP TABLE pktable (
|
||||||
@ -1156,17 +1155,7 @@ ALTER TABLE fktable ADD CONSTRAINT fk_241_132
|
|||||||
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
|
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
|
||||||
ERROR: foreign key constraint "fk_241_132" cannot be implemented
|
ERROR: foreign key constraint "fk_241_132" cannot be implemented
|
||||||
DETAIL: Key columns "x2" and "id1" are of incompatible types: character varying and integer.
|
DETAIL: Key columns "x2" and "id1" are of incompatible types: character varying and integer.
|
||||||
DROP TABLE pktable, fktable CASCADE;
|
DROP TABLE pktable, fktable;
|
||||||
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
|
|
||||||
-- test a tricky case: we can elide firing the FK check trigger during
|
-- test a tricky case: we can elide firing the FK check trigger during
|
||||||
-- an UPDATE if the UPDATE did not change the foreign key
|
-- 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
|
-- field. However, we can't do this if our transaction was the one that
|
||||||
|
@ -141,12 +141,6 @@ SELECT * FROM trunc_e;
|
|||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
|
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
|
-- Test ON TRUNCATE triggers
|
||||||
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
|
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
|
||||||
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
|
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
|
||||||
|
@ -724,7 +724,7 @@ INSERT INTO fktable VALUES (100, 200);
|
|||||||
-- error here on commit
|
-- error here on commit
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
DROP TABLE pktable, fktable CASCADE;
|
DROP TABLE pktable, fktable;
|
||||||
|
|
||||||
-- test notice about expensive referential integrity checks,
|
-- test notice about expensive referential integrity checks,
|
||||||
-- where the index cannot be used because of type incompatibilities.
|
-- where the index cannot be used because of type incompatibilities.
|
||||||
@ -799,7 +799,7 @@ FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1);
|
|||||||
ALTER TABLE fktable ADD CONSTRAINT fk_241_132
|
ALTER TABLE fktable ADD CONSTRAINT fk_241_132
|
||||||
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
|
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
|
-- test a tricky case: we can elide firing the FK check trigger during
|
||||||
-- an UPDATE if the UPDATE did not change the foreign key
|
-- an UPDATE if the UPDATE did not change the foreign key
|
||||||
|
Reference in New Issue
Block a user