Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7ac5760

Browse files
committed
Rework order of checks in ALTER / SET SCHEMA
When attempting to move an object into the schema in which it already was, for most objects classes we were correctly complaining about exactly that ("object is already in schema"); but for some other object classes, such as functions, we were instead complaining of a name collision ("object already exists in schema"). The latter is wrong and misleading, per complaint from Robert Haas in CA+TgmoZ0+gNf7RDKRc3u5rHXffP=QjqPZKGxb4BsPz65k7qnHQ@mail.gmail.com To fix, refactor the way these checks are done. As a bonus, the resulting code is smaller and can also share some code with Rename cases. While at it, remove use of getObjectDescriptionOids() in error messages. These are normally disallowed because of translatability considerations, but this one had slipped through since 9.1. (Not sure that this is worth backpatching, though, as it would create some untranslated messages in back branches.) This is loosely based on a patch by KaiGai Kohei, heavily reworked by me.
1 parent ffda059 commit 7ac5760

File tree

7 files changed

+124
-186
lines changed

7 files changed

+124
-186
lines changed

src/backend/commands/alter.c

+85-31
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@
1919
#include "catalog/dependency.h"
2020
#include "catalog/indexing.h"
2121
#include "catalog/namespace.h"
22+
#include "catalog/pg_collation.h"
23+
#include "catalog/pg_conversion.h"
2224
#include "catalog/pg_largeobject.h"
2325
#include "catalog/pg_largeobject_metadata.h"
2426
#include "catalog/pg_namespace.h"
27+
#include "catalog/pg_proc.h"
28+
#include "catalog/pg_ts_config.h"
29+
#include "catalog/pg_ts_dict.h"
30+
#include "catalog/pg_ts_parser.h"
31+
#include "catalog/pg_ts_template.h"
2532
#include "commands/alter.h"
2633
#include "commands/collationcmds.h"
2734
#include "commands/conversioncmds.h"
@@ -46,6 +53,8 @@
4653
#include "utils/tqual.h"
4754

4855

56+
static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
57+
4958
/*
5059
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
5160
* type, the function appropriate to that type is executed.
@@ -146,40 +155,32 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
146155
{
147156
switch (stmt->objectType)
148157
{
149-
case OBJECT_AGGREGATE:
150-
return AlterFunctionNamespace(stmt->object, stmt->objarg, true,
151-
stmt->newschema);
152-
153-
case OBJECT_COLLATION:
154-
return AlterCollationNamespace(stmt->object, stmt->newschema);
155-
156158
case OBJECT_EXTENSION:
157159
return AlterExtensionNamespace(stmt->object, stmt->newschema);
158160

159-
case OBJECT_FUNCTION:
160-
return AlterFunctionNamespace(stmt->object, stmt->objarg, false,
161-
stmt->newschema);
162-
161+
case OBJECT_FOREIGN_TABLE:
163162
case OBJECT_SEQUENCE:
164163
case OBJECT_TABLE:
165164
case OBJECT_VIEW:
166-
case OBJECT_FOREIGN_TABLE:
167165
return AlterTableNamespace(stmt);
168166

169-
case OBJECT_TYPE:
170167
case OBJECT_DOMAIN:
168+
case OBJECT_TYPE:
171169
return AlterTypeNamespace(stmt->object, stmt->newschema,
172170
stmt->objectType);
173171

174172
/* generic code path */
173+
case OBJECT_AGGREGATE:
174+
case OBJECT_COLLATION:
175175
case OBJECT_CONVERSION:
176+
case OBJECT_FUNCTION:
176177
case OBJECT_OPERATOR:
177178
case OBJECT_OPCLASS:
178179
case OBJECT_OPFAMILY:
179-
case OBJECT_TSPARSER:
180+
case OBJECT_TSCONFIGURATION:
180181
case OBJECT_TSDICTIONARY:
182+
case OBJECT_TSPARSER:
181183
case OBJECT_TSTEMPLATE:
182-
case OBJECT_TSCONFIGURATION:
183184
{
184185
Relation catalog;
185186
Relation relation;
@@ -253,22 +254,16 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
253254
break;
254255
}
255256

256-
case OCLASS_PROC:
257-
oldNspOid = AlterFunctionNamespace_oid(objid, nspOid);
258-
break;
259-
260257
case OCLASS_TYPE:
261258
oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
262259
break;
263260

264261
case OCLASS_COLLATION:
265-
oldNspOid = AlterCollationNamespace_oid(objid, nspOid);
266-
break;
267-
268262
case OCLASS_CONVERSION:
269263
case OCLASS_OPERATOR:
270264
case OCLASS_OPCLASS:
271265
case OCLASS_OPFAMILY:
266+
case OCLASS_PROC:
272267
case OCLASS_TSPARSER:
273268
case OCLASS_TSDICT:
274269
case OCLASS_TSTEMPLATE:
@@ -292,6 +287,43 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
292287
return oldNspOid;
293288
}
294289

290+
/*
291+
* Raise an error to the effect that an object of the given name is already
292+
* present in the given namespace.
293+
*/
294+
static void
295+
report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
296+
{
297+
char *msgfmt;
298+
299+
Assert(OidIsValid(nspOid));
300+
switch (classId)
301+
{
302+
case ConversionRelationId:
303+
msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
304+
break;
305+
case TSParserRelationId:
306+
msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
307+
break;
308+
case TSDictionaryRelationId:
309+
msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
310+
break;
311+
case TSTemplateRelationId:
312+
msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
313+
break;
314+
case TSConfigRelationId:
315+
msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
316+
break;
317+
default:
318+
elog(ERROR, "unsupported object class %u", classId);
319+
break;
320+
}
321+
322+
ereport(ERROR,
323+
(errcode(ERRCODE_DUPLICATE_OBJECT),
324+
errmsg(msgfmt, name, get_namespace_name(nspOid))));
325+
}
326+
295327
/*
296328
* Generic function to change the namespace of a given object, for simple
297329
* cases (won't work for tables, nor other cases where we need to do more
@@ -303,7 +335,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
303335
*
304336
* Returns the OID of the object's previous namespace.
305337
*/
306-
Oid
338+
static Oid
307339
AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
308340
{
309341
Oid classId = RelationGetRelid(rel);
@@ -373,13 +405,36 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
373405
* Since this is just a friendliness check, we can just skip it in cases
374406
* where there isn't a suitable syscache available.
375407
*/
376-
if (nameCacheId >= 0 &&
377-
SearchSysCacheExists2(nameCacheId, name, ObjectIdGetDatum(nspOid)))
378-
ereport(ERROR,
379-
(errcode(ERRCODE_DUPLICATE_OBJECT),
380-
errmsg("%s already exists in schema \"%s\"",
381-
getObjectDescriptionOids(classId, objid),
382-
get_namespace_name(nspOid))));
408+
if (classId == ProcedureRelationId)
409+
{
410+
HeapTuple tup;
411+
Form_pg_proc proc;
412+
413+
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(objid));
414+
if (!HeapTupleIsValid(tup))
415+
elog(ERROR, "cache lookup failed for function %u", objid);
416+
proc = (Form_pg_proc) GETSTRUCT(tup);
417+
418+
IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
419+
proc->proargtypes, nspOid);
420+
heap_freetuple(tup);
421+
}
422+
else if (classId == CollationRelationId)
423+
{
424+
char *collname;
425+
426+
collname = get_collation_name(objid);
427+
if (!collname)
428+
elog(ERROR, "cache lookup failed for collation %u", objid);
429+
IsThereCollationInNamespace(collname, nspOid);
430+
pfree(collname);
431+
}
432+
else if (nameCacheId >= 0 &&
433+
SearchSysCacheExists2(nameCacheId, name,
434+
ObjectIdGetDatum(nspOid)))
435+
report_namespace_conflict(classId,
436+
NameStr(*(DatumGetName(name))),
437+
nspOid);
383438

384439
/* Build modified tuple */
385440
values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
@@ -406,7 +461,6 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
406461
return oldNspOid;
407462
}
408463

409-
410464
/*
411465
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
412466
* type, the function appropriate to that type is executed.

src/backend/commands/collationcmds.c

+14-73
Original file line numberDiff line numberDiff line change
@@ -167,27 +167,7 @@ RenameCollation(List *name, const char *newname)
167167
namespaceOid = ((Form_pg_collation) GETSTRUCT(tup))->collnamespace;
168168

169169
/* make sure the new name doesn't exist */
170-
if (SearchSysCacheExists3(COLLNAMEENCNSP,
171-
CStringGetDatum(newname),
172-
Int32GetDatum(GetDatabaseEncoding()),
173-
ObjectIdGetDatum(namespaceOid)))
174-
ereport(ERROR,
175-
(errcode(ERRCODE_DUPLICATE_OBJECT),
176-
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
177-
newname,
178-
GetDatabaseEncodingName(),
179-
get_namespace_name(namespaceOid))));
180-
181-
/* mustn't match an any-encoding entry, either */
182-
if (SearchSysCacheExists3(COLLNAMEENCNSP,
183-
CStringGetDatum(newname),
184-
Int32GetDatum(-1),
185-
ObjectIdGetDatum(namespaceOid)))
186-
ereport(ERROR,
187-
(errcode(ERRCODE_DUPLICATE_OBJECT),
188-
errmsg("collation \"%s\" already exists in schema \"%s\"",
189-
newname,
190-
get_namespace_name(namespaceOid))));
170+
IsThereCollationInNamespace(newname, namespaceOid);
191171

192172
/* must be owner */
193173
if (!pg_collation_ownercheck(collationOid, GetUserId()))
@@ -213,71 +193,32 @@ RenameCollation(List *name, const char *newname)
213193
}
214194

215195
/*
216-
* Execute ALTER COLLATION SET SCHEMA
217-
*/
218-
Oid
219-
AlterCollationNamespace(List *name, const char *newschema)
220-
{
221-
Oid collOid,
222-
nspOid;
223-
224-
collOid = get_collation_oid(name, false);
225-
226-
nspOid = LookupCreationNamespace(newschema);
227-
228-
AlterCollationNamespace_oid(collOid, nspOid);
229-
230-
return collOid;
231-
}
232-
233-
/*
234-
* Change collation schema, by oid
196+
* Subroutine for ALTER COLLATION SET SCHEMA and RENAME
197+
*
198+
* Is there a collation with the same name of the given collation already in
199+
* the given namespace? If so, raise an appropriate error message.
235200
*/
236-
Oid
237-
AlterCollationNamespace_oid(Oid collOid, Oid newNspOid)
201+
void
202+
IsThereCollationInNamespace(const char *collname, Oid nspOid)
238203
{
239-
Oid oldNspOid;
240-
Relation rel;
241-
char *collation_name;
242-
243-
rel = heap_open(CollationRelationId, RowExclusiveLock);
244-
245-
/*
246-
* We have to check for name collision ourselves, because
247-
* AlterObjectNamespace_internal doesn't know how to deal with the encoding
248-
* considerations.
249-
*/
250-
collation_name = get_collation_name(collOid);
251-
if (!collation_name)
252-
elog(ERROR, "cache lookup failed for collation %u", collOid);
253-
254204
/* make sure the name doesn't already exist in new schema */
255205
if (SearchSysCacheExists3(COLLNAMEENCNSP,
256-
CStringGetDatum(collation_name),
206+
CStringGetDatum(collname),
257207
Int32GetDatum(GetDatabaseEncoding()),
258-
ObjectIdGetDatum(newNspOid)))
208+
ObjectIdGetDatum(nspOid)))
259209
ereport(ERROR,
260210
(errcode(ERRCODE_DUPLICATE_OBJECT),
261211
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
262-
collation_name,
263-
GetDatabaseEncodingName(),
264-
get_namespace_name(newNspOid))));
212+
collname, GetDatabaseEncodingName(),
213+
get_namespace_name(nspOid))));
265214

266215
/* mustn't match an any-encoding entry, either */
267216
if (SearchSysCacheExists3(COLLNAMEENCNSP,
268-
CStringGetDatum(collation_name),
217+
CStringGetDatum(collname),
269218
Int32GetDatum(-1),
270-
ObjectIdGetDatum(newNspOid)))
219+
ObjectIdGetDatum(nspOid)))
271220
ereport(ERROR,
272221
(errcode(ERRCODE_DUPLICATE_OBJECT),
273222
errmsg("collation \"%s\" already exists in schema \"%s\"",
274-
collation_name,
275-
get_namespace_name(newNspOid))));
276-
277-
/* OK, do the work */
278-
oldNspOid = AlterObjectNamespace_internal(rel, collOid, newNspOid);
279-
280-
heap_close(rel, RowExclusiveLock);
281-
282-
return oldNspOid;
223+
collname, get_namespace_name(nspOid))));
283224
}

0 commit comments

Comments
 (0)