#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_conversion.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_ts_config.h"
+#include "catalog/pg_ts_dict.h"
+#include "catalog/pg_ts_parser.h"
+#include "catalog/pg_ts_template.h"
#include "commands/alter.h"
#include "commands/collationcmds.h"
#include "commands/conversioncmds.h"
#include "utils/tqual.h"
+static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
+
/*
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
* type, the function appropriate to that type is executed.
{
switch (stmt->objectType)
{
- case OBJECT_AGGREGATE:
- return AlterFunctionNamespace(stmt->object, stmt->objarg, true,
- stmt->newschema);
-
- case OBJECT_COLLATION:
- return AlterCollationNamespace(stmt->object, stmt->newschema);
-
case OBJECT_EXTENSION:
return AlterExtensionNamespace(stmt->object, stmt->newschema);
- case OBJECT_FUNCTION:
- return AlterFunctionNamespace(stmt->object, stmt->objarg, false,
- stmt->newschema);
-
+ case OBJECT_FOREIGN_TABLE:
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
- case OBJECT_FOREIGN_TABLE:
return AlterTableNamespace(stmt);
- case OBJECT_TYPE:
case OBJECT_DOMAIN:
+ case OBJECT_TYPE:
return AlterTypeNamespace(stmt->object, stmt->newschema,
stmt->objectType);
/* generic code path */
+ case OBJECT_AGGREGATE:
+ case OBJECT_COLLATION:
case OBJECT_CONVERSION:
+ case OBJECT_FUNCTION:
case OBJECT_OPERATOR:
case OBJECT_OPCLASS:
case OBJECT_OPFAMILY:
- case OBJECT_TSPARSER:
+ case OBJECT_TSCONFIGURATION:
case OBJECT_TSDICTIONARY:
+ case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
- case OBJECT_TSCONFIGURATION:
{
Relation catalog;
Relation relation;
break;
}
- case OCLASS_PROC:
- oldNspOid = AlterFunctionNamespace_oid(objid, nspOid);
- break;
-
case OCLASS_TYPE:
oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
break;
case OCLASS_COLLATION:
- oldNspOid = AlterCollationNamespace_oid(objid, nspOid);
- break;
-
case OCLASS_CONVERSION:
case OCLASS_OPERATOR:
case OCLASS_OPCLASS:
case OCLASS_OPFAMILY:
+ case OCLASS_PROC:
case OCLASS_TSPARSER:
case OCLASS_TSDICT:
case OCLASS_TSTEMPLATE:
return oldNspOid;
}
+/*
+ * Raise an error to the effect that an object of the given name is already
+ * present in the given namespace.
+ */
+static void
+report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
+{
+ char *msgfmt;
+
+ Assert(OidIsValid(nspOid));
+ switch (classId)
+ {
+ case ConversionRelationId:
+ msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
+ break;
+ case TSParserRelationId:
+ msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
+ break;
+ case TSDictionaryRelationId:
+ msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
+ break;
+ case TSTemplateRelationId:
+ msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
+ break;
+ case TSConfigRelationId:
+ msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
+ break;
+ default:
+ elog(ERROR, "unsupported object class %u", classId);
+ break;
+ }
+
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg(msgfmt, name, get_namespace_name(nspOid))));
+}
+
/*
* Generic function to change the namespace of a given object, for simple
* cases (won't work for tables, nor other cases where we need to do more
*
* Returns the OID of the object's previous namespace.
*/
-Oid
+static Oid
AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
{
Oid classId = RelationGetRelid(rel);
* Since this is just a friendliness check, we can just skip it in cases
* where there isn't a suitable syscache available.
*/
- if (nameCacheId >= 0 &&
- SearchSysCacheExists2(nameCacheId, name, ObjectIdGetDatum(nspOid)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("%s already exists in schema \"%s\"",
- getObjectDescriptionOids(classId, objid),
- get_namespace_name(nspOid))));
+ if (classId == ProcedureRelationId)
+ {
+ HeapTuple tup;
+ Form_pg_proc proc;
+
+ tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(objid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for function %u", objid);
+ proc = (Form_pg_proc) GETSTRUCT(tup);
+
+ IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
+ proc->proargtypes, nspOid);
+ heap_freetuple(tup);
+ }
+ else if (classId == CollationRelationId)
+ {
+ char *collname;
+
+ collname = get_collation_name(objid);
+ if (!collname)
+ elog(ERROR, "cache lookup failed for collation %u", objid);
+ IsThereCollationInNamespace(collname, nspOid);
+ pfree(collname);
+ }
+ else if (nameCacheId >= 0 &&
+ SearchSysCacheExists2(nameCacheId, name,
+ ObjectIdGetDatum(nspOid)))
+ report_namespace_conflict(classId,
+ NameStr(*(DatumGetName(name))),
+ nspOid);
/* Build modified tuple */
values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
return oldNspOid;
}
-
/*
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
* type, the function appropriate to that type is executed.
namespaceOid = ((Form_pg_collation) GETSTRUCT(tup))->collnamespace;
/* make sure the new name doesn't exist */
- if (SearchSysCacheExists3(COLLNAMEENCNSP,
- CStringGetDatum(newname),
- Int32GetDatum(GetDatabaseEncoding()),
- ObjectIdGetDatum(namespaceOid)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
- newname,
- GetDatabaseEncodingName(),
- get_namespace_name(namespaceOid))));
-
- /* mustn't match an any-encoding entry, either */
- if (SearchSysCacheExists3(COLLNAMEENCNSP,
- CStringGetDatum(newname),
- Int32GetDatum(-1),
- ObjectIdGetDatum(namespaceOid)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("collation \"%s\" already exists in schema \"%s\"",
- newname,
- get_namespace_name(namespaceOid))));
+ IsThereCollationInNamespace(newname, namespaceOid);
/* must be owner */
if (!pg_collation_ownercheck(collationOid, GetUserId()))
}
/*
- * Execute ALTER COLLATION SET SCHEMA
- */
-Oid
-AlterCollationNamespace(List *name, const char *newschema)
-{
- Oid collOid,
- nspOid;
-
- collOid = get_collation_oid(name, false);
-
- nspOid = LookupCreationNamespace(newschema);
-
- AlterCollationNamespace_oid(collOid, nspOid);
-
- return collOid;
-}
-
-/*
- * Change collation schema, by oid
+ * Subroutine for ALTER COLLATION SET SCHEMA and RENAME
+ *
+ * Is there a collation with the same name of the given collation already in
+ * the given namespace? If so, raise an appropriate error message.
*/
-Oid
-AlterCollationNamespace_oid(Oid collOid, Oid newNspOid)
+void
+IsThereCollationInNamespace(const char *collname, Oid nspOid)
{
- Oid oldNspOid;
- Relation rel;
- char *collation_name;
-
- rel = heap_open(CollationRelationId, RowExclusiveLock);
-
- /*
- * We have to check for name collision ourselves, because
- * AlterObjectNamespace_internal doesn't know how to deal with the encoding
- * considerations.
- */
- collation_name = get_collation_name(collOid);
- if (!collation_name)
- elog(ERROR, "cache lookup failed for collation %u", collOid);
-
/* make sure the name doesn't already exist in new schema */
if (SearchSysCacheExists3(COLLNAMEENCNSP,
- CStringGetDatum(collation_name),
+ CStringGetDatum(collname),
Int32GetDatum(GetDatabaseEncoding()),
- ObjectIdGetDatum(newNspOid)))
+ ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
- collation_name,
- GetDatabaseEncodingName(),
- get_namespace_name(newNspOid))));
+ collname, GetDatabaseEncodingName(),
+ get_namespace_name(nspOid))));
/* mustn't match an any-encoding entry, either */
if (SearchSysCacheExists3(COLLNAMEENCNSP,
- CStringGetDatum(collation_name),
+ CStringGetDatum(collname),
Int32GetDatum(-1),
- ObjectIdGetDatum(newNspOid)))
+ ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("collation \"%s\" already exists in schema \"%s\"",
- collation_name,
- get_namespace_name(newNspOid))));
-
- /* OK, do the work */
- oldNspOid = AlterObjectNamespace_internal(rel, collOid, newNspOid);
-
- heap_close(rel, RowExclusiveLock);
-
- return oldNspOid;
+ collname, get_namespace_name(nspOid))));
}
namespaceOid = procForm->pronamespace;
/* make sure the new name doesn't exist */
- if (SearchSysCacheExists3(PROCNAMEARGSNSP,
- CStringGetDatum(newname),
- PointerGetDatum(&procForm->proargtypes),
- ObjectIdGetDatum(namespaceOid)))
- {
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_FUNCTION),
- errmsg("function %s already exists in schema \"%s\"",
- funcname_signature_string(newname,
- procForm->pronargs,
- NIL,
- procForm->proargtypes.values),
- get_namespace_name(namespaceOid))));
- }
+ IsThereFunctionInNamespace(newname, procForm->pronargs,
+ procForm->proargtypes,
+ namespaceOid);
/* must be owner */
if (!pg_proc_ownercheck(procOid, GetUserId()))
}
/*
- * Execute ALTER FUNCTION/AGGREGATE SET SCHEMA
+ * Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA
*
- * These commands are identical except for the lookup procedure, so share code.
+ * Is there a function with the given name and signature already in the given
+ * namespace? If so, raise an appropriate error message.
*/
-Oid
-AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
- const char *newschema)
-{
- Oid procOid;
- Oid nspOid;
-
- /* get function OID */
- if (isagg)
- procOid = LookupAggNameTypeNames(name, argtypes, false);
- else
- procOid = LookupFuncNameTypeNames(name, argtypes, false);
-
- /* get schema OID and check its permissions */
- nspOid = LookupCreationNamespace(newschema);
-
- AlterFunctionNamespace_oid(procOid, nspOid);
-
- return procOid;
-}
-
-Oid
-AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+void
+IsThereFunctionInNamespace(const char *proname, int pronargs,
+ oidvector proargtypes, Oid nspOid)
{
- Oid oldNspOid;
- HeapTuple tup;
- Relation procRel;
- Form_pg_proc proc;
-
- procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
-
- /*
- * We have to check for name collisions ourselves, because
- * AlterObjectNamespace_internal doesn't know how to deal with the
- * argument types.
- */
- tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for function %u", procOid);
- proc = (Form_pg_proc) GETSTRUCT(tup);
-
/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists3(PROCNAMEARGSNSP,
- CStringGetDatum(NameStr(proc->proname)),
- PointerGetDatum(&proc->proargtypes),
+ CStringGetDatum(proname),
+ PointerGetDatum(&proargtypes),
ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
- errmsg("function \"%s\" already exists in schema \"%s\"",
- NameStr(proc->proname),
+ errmsg("function %s already exists in schema \"%s\"",
+ funcname_signature_string(proname, pronargs,
+ NIL, proargtypes.values),
get_namespace_name(nspOid))));
-
- /* OK, do the work */
- oldNspOid = AlterObjectNamespace_internal(procRel, procOid, nspOid);
-
- heap_close(procRel, RowExclusiveLock);
-
- return oldNspOid;
}
-
/*
* ExecuteDoStmt
* Execute inline procedural-language code
extern Oid ExecRenameStmt(RenameStmt *stmt);
extern Oid ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
-extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
+extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
ObjectAddresses *objsMoved);
-extern Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
extern Oid ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
extern void AlterObjectOwner_internal(Relation catalog, Oid objectId,
extern Oid DefineCollation(List *names, List *parameters);
extern Oid RenameCollation(List *name, const char *newname);
-extern Oid AlterCollationNamespace(List *name, const char *newschema);
-extern Oid AlterCollationNamespace_oid(Oid collOid, Oid newNspOid);
+extern void IsThereCollationInNamespace(const char *collname, Oid newNspOid);
#endif /* COLLATIONCMDS_H */
extern Oid AlterFunction(AlterFunctionStmt *stmt);
extern Oid CreateCast(CreateCastStmt *stmt);
extern void DropCastById(Oid castOid);
-extern Oid AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
- const char *newschema);
-extern Oid AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
+extern void IsThereFunctionInNamespace(const char *proname, int pronargs,
+ oidvector proargtypes, Oid nspOid);
extern void ExecuteDoStmt(DoStmt *stmt);
extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
ALTER FUNCTION alt_func3(int) SET SCHEMA alt_nsp2; -- failed (not owner)
ERROR: must be owner of function alt_func3
ALTER FUNCTION alt_func2(int) SET SCHEMA alt_nsp2; -- failed (name conflicts)
-ERROR: function "alt_func2" already exists in schema "alt_nsp2"
+ERROR: function alt_func2(integer) already exists in schema "alt_nsp2"
ALTER AGGREGATE alt_agg3(int) RENAME TO alt_agg4; -- failed (not owner)
ERROR: must be owner of function alt_agg3
ALTER AGGREGATE alt_agg1(int) RENAME TO alt_agg4; -- OK
ALTER AGGREGATE alt_agg3(int) SET SCHEMA alt_nsp2; -- failed (not owner)
ERROR: must be owner of function alt_agg3
ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: function "alt_agg2" already exists in schema "alt_nsp2"
+ERROR: function alt_agg2(integer) already exists in schema "alt_nsp2"
RESET SESSION AUTHORIZATION;
SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname
FROM pg_proc p, pg_namespace n, pg_authid a
ALTER CONVERSION alt_conv3 SET SCHEMA alt_nsp2; -- failed (not owner)
ERROR: must be owner of conversion alt_conv3
ALTER CONVERSION alt_conv2 SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: conversion alt_conv2 already exists in schema "alt_nsp2"
+ERROR: conversion "alt_conv2" already exists in schema "alt_nsp2"
RESET SESSION AUTHORIZATION;
SELECT n.nspname, c.conname, a.rolname
FROM pg_conversion c, pg_namespace n, pg_authid a
ALTER TEXT SEARCH DICTIONARY alt_ts_dict3 SET SCHEMA alt_nsp2; -- failed (not owner)
ERROR: must be owner of text search dictionary alt_ts_dict3
ALTER TEXT SEARCH DICTIONARY alt_ts_dict2 SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: text search dictionary alt_ts_dict2 already exists in schema "alt_nsp2"
+ERROR: text search dictionary "alt_ts_dict2" already exists in schema "alt_nsp2"
RESET SESSION AUTHORIZATION;
SELECT nspname, dictname, rolname
FROM pg_ts_dict t, pg_namespace n, pg_authid a
ALTER TEXT SEARCH CONFIGURATION alt_ts_conf3 SET SCHEMA alt_nsp2; -- failed (not owner)
ERROR: must be owner of text search configuration alt_ts_conf3
ALTER TEXT SEARCH CONFIGURATION alt_ts_conf2 SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: text search configuration alt_ts_conf2 already exists in schema "alt_nsp2"
+ERROR: text search configuration "alt_ts_conf2" already exists in schema "alt_nsp2"
RESET SESSION AUTHORIZATION;
SELECT nspname, cfgname, rolname
FROM pg_ts_config t, pg_namespace n, pg_authid a
ALTER TEXT SEARCH TEMPLATE alt_ts_temp2 SET SCHEMA alt_nsp2; -- OK
CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
ALTER TEXT SEARCH TEMPLATE alt_ts_temp2 SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: text search template alt_ts_temp2 already exists in schema "alt_nsp2"
+ERROR: text search template "alt_ts_temp2" already exists in schema "alt_nsp2"
SELECT nspname, tmplname
FROM pg_ts_template t, pg_namespace n
WHERE t.tmplnamespace = n.oid AND nspname like 'alt_nsp%'
CREATE TEXT SEARCH PARSER alt_ts_prs2
(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
ALTER TEXT SEARCH PARSER alt_ts_prs2 SET SCHEMA alt_nsp2; -- failed (name conflict)
-ERROR: text search parser alt_ts_prs2 already exists in schema "alt_nsp2"
+ERROR: text search parser "alt_ts_prs2" already exists in schema "alt_nsp2"
SELECT nspname, prsname
FROM pg_ts_parser t, pg_namespace n
WHERE t.prsnamespace = n.oid AND nspname like 'alt_nsp%'