Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_type.c
4 : * routines to support manipulation of the pg_type relation
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/catalog/pg_type.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/htup_details.h"
18 : #include "access/table.h"
19 : #include "access/xact.h"
20 : #include "catalog/binary_upgrade.h"
21 : #include "catalog/catalog.h"
22 : #include "catalog/dependency.h"
23 : #include "catalog/indexing.h"
24 : #include "catalog/objectaccess.h"
25 : #include "catalog/pg_collation.h"
26 : #include "catalog/pg_namespace.h"
27 : #include "catalog/pg_proc.h"
28 : #include "catalog/pg_type.h"
29 : #include "commands/defrem.h"
30 : #include "commands/typecmds.h"
31 : #include "mb/pg_wchar.h"
32 : #include "miscadmin.h"
33 : #include "parser/scansup.h"
34 : #include "utils/acl.h"
35 : #include "utils/builtins.h"
36 : #include "utils/fmgroids.h"
37 : #include "utils/lsyscache.h"
38 : #include "utils/rel.h"
39 : #include "utils/syscache.h"
40 :
41 : /* Potentially set by pg_upgrade_support functions */
42 : Oid binary_upgrade_next_pg_type_oid = InvalidOid;
43 :
44 : /* ----------------------------------------------------------------
45 : * TypeShellMake
46 : *
47 : * This procedure inserts a "shell" tuple into the pg_type relation.
48 : * The type tuple inserted has valid but dummy values, and its
49 : * "typisdefined" field is false indicating it's not really defined.
50 : *
51 : * This is used so that a tuple exists in the catalogs. The I/O
52 : * functions for the type will link to this tuple. When the full
53 : * CREATE TYPE command is issued, the bogus values will be replaced
54 : * with correct ones, and "typisdefined" will be set to true.
55 : * ----------------------------------------------------------------
9770 scrappy 56 ECB : */
57 : ObjectAddress
5157 tgl 58 GIC 107 : TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
59 : {
60 : Relation pg_type_desc;
61 : TupleDesc tupDesc;
62 : int i;
63 : HeapTuple tup;
64 : Datum values[Natts_pg_type];
65 : bool nulls[Natts_pg_type];
66 : Oid typoid;
67 : NameData name;
2959 alvherre 68 ECB : ObjectAddress address;
69 :
7681 tgl 70 GIC 107 : Assert(PointerIsValid(typeName));
71 :
72 : /*
7681 tgl 73 ECB : * open pg_type
74 : */
1539 andres 75 GIC 107 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
7681 tgl 76 107 : tupDesc = pg_type_desc->rd_att;
77 :
78 : /*
8053 bruce 79 ECB : * initialize our *nulls and *values arrays
80 : */
9345 bruce 81 CBC 3531 : for (i = 0; i < Natts_pg_type; ++i)
9345 bruce 82 ECB : {
5271 tgl 83 GIC 3424 : nulls[i] = false;
2118 84 3424 : values[i] = (Datum) NULL; /* redundant, but safe */
85 : }
86 :
87 : /*
88 : * initialize *values with the type name and dummy values
89 : *
90 : * The representational details are the same as int4 ... it doesn't really
91 : * matter what they are so long as they are consistent. Also note that we
92 : * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
6031 bruce 93 ECB : * mistaken for a usable type.
9345 94 : */
9139 scrappy 95 CBC 107 : namestrcpy(&name, typeName);
4315 tgl 96 107 : values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
97 107 : values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
98 107 : values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
3940 peter_e 99 107 : values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
4315 tgl 100 107 : values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
101 107 : values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
102 107 : values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
103 107 : values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
104 107 : values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
105 107 : values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
106 107 : values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
851 107 107 : values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid);
4315 108 107 : values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
109 107 : values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
110 107 : values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
111 107 : values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
112 107 : values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
113 107 : values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
114 107 : values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
115 107 : values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
116 107 : values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
1131 117 107 : values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
118 107 : values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
4315 119 107 : values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
120 107 : values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
121 107 : values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
122 107 : values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
123 107 : values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
124 107 : nulls[Anum_pg_type_typdefaultbin - 1] = true;
4315 tgl 125 GIC 107 : nulls[Anum_pg_type_typdefault - 1] = true;
4128 peter_e 126 107 : nulls[Anum_pg_type_typacl - 1] = true;
9345 bruce 127 ECB :
128 : /* Use binary-upgrade override for pg_type.oid? */
3149 bruce 129 CBC 107 : if (IsBinaryUpgrade)
4854 bruce 130 EUB : {
3149 bruce 131 GIC 8 : if (!OidIsValid(binary_upgrade_next_pg_type_oid))
3149 bruce 132 UIC 0 : ereport(ERROR,
133 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2118 tgl 134 ECB : errmsg("pg_type OID value not set when in binary upgrade mode")));
3149 bruce 135 :
1601 andres 136 GIC 8 : typoid = binary_upgrade_next_pg_type_oid;
4854 bruce 137 8 : binary_upgrade_next_pg_type_oid = InvalidOid;
138 : }
1601 andres 139 ECB : else
140 : {
1601 andres 141 GIC 99 : typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
142 : Anum_pg_type_oid);
1601 andres 143 ECB : }
144 :
1601 andres 145 GIC 107 : values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
146 :
147 : /*
1601 andres 148 ECB : * create a new type tuple
149 : */
1601 andres 150 GIC 107 : tup = heap_form_tuple(tupDesc, values, nulls);
151 :
152 : /*
8053 bruce 153 ECB : * insert the tuple in the relation and get the tuple's oid.
154 : */
1601 andres 155 GIC 107 : CatalogTupleInsert(pg_type_desc, tup);
156 :
157 : /*
7396 tgl 158 ECB : * Create dependencies. We can/must skip this in bootstrap mode.
159 : */
7396 tgl 160 GIC 107 : if (!IsBootstrapProcessingMode())
1129 161 107 : GenerateTypeDependencies(tup,
162 : pg_type_desc,
163 : NULL,
164 : NULL,
165 : 0,
166 : false,
167 : false,
168 : true, /* make extension dependency */
169 : false);
7396 tgl 170 ECB :
171 : /* Post creation hook for new shell type */
3686 rhaas 172 CBC 107 : InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
173 :
2959 alvherre 174 GIC 107 : ObjectAddressSet(address, TypeRelationId, typoid);
175 :
176 : /*
7681 tgl 177 ECB : * clean up and return the type-oid
9345 bruce 178 : */
8515 JanWieck 179 GIC 107 : heap_freetuple(tup);
1539 andres 180 CBC 107 : table_close(pg_type_desc, RowExclusiveLock);
181 :
2959 alvherre 182 GIC 107 : return address;
183 : }
184 :
185 : /* ----------------------------------------------------------------
186 : * TypeCreate
187 : *
188 : * This does all the necessary work needed to define a new type.
189 : *
190 : * Returns the ObjectAddress assigned to the new type.
191 : * If newTypeOid is zero (the normal case), a new OID is created;
192 : * otherwise we use exactly that OID.
193 : * ----------------------------------------------------------------
9770 scrappy 194 ECB : */
195 : ObjectAddress
5812 tgl 196 GIC 166616 : TypeCreate(Oid newTypeOid,
197 : const char *typeName,
198 : Oid typeNamespace,
199 : Oid relationOid, /* only for relation rowtypes */
200 : char relationKind, /* ditto */
201 : Oid ownerId,
202 : int16 internalSize,
203 : char typeType,
204 : char typeCategory,
205 : bool typePreferred,
206 : char typDelim,
207 : Oid inputProcedure,
208 : Oid outputProcedure,
209 : Oid receiveProcedure,
210 : Oid sendProcedure,
211 : Oid typmodinProcedure,
212 : Oid typmodoutProcedure,
213 : Oid analyzeProcedure,
214 : Oid subscriptProcedure,
215 : Oid elementType,
216 : bool isImplicitArray,
217 : Oid arrayType,
218 : Oid baseType,
219 : const char *defaultTypeValue, /* human-readable rep */
220 : char *defaultTypeBin, /* cooked rep */
221 : bool passedByValue,
222 : char alignment,
223 : char storage,
224 : int32 typeMod,
225 : int32 typNDims, /* Array dimensions for baseType */
226 : bool typeNotNull,
227 : Oid typeCollation)
228 : {
229 : Relation pg_type_desc;
9344 bruce 230 ECB : Oid typeObjectId;
231 : bool isDependentType;
7396 tgl 232 GIC 166616 : bool rebuildDeps = false;
233 : Acl *typacl;
234 : HeapTuple tup;
235 : bool nulls[Natts_pg_type];
236 : bool replaces[Natts_pg_type];
237 : Datum values[Natts_pg_type];
238 : NameData name;
239 : int i;
240 : ObjectAddress address;
241 :
242 : /*
243 : * We assume that the caller validated the arguments individually, but did
244 : * not check for bad combinations.
245 : *
246 : * Validate size specifications: either positive (fixed-length) or -1
5362 tgl 247 ECB : * (varlena) or -2 (cstring).
248 : */
7533 tgl 249 GIC 166616 : if (!(internalSize > 0 ||
7533 tgl 250 EUB : internalSize == -1 ||
251 : internalSize == -2))
7202 tgl 252 UIC 0 : ereport(ERROR,
253 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
254 : errmsg("invalid type internal size %d",
7202 tgl 255 ECB : internalSize)));
256 :
5362 tgl 257 GIC 166616 : if (passedByValue)
258 : {
259 : /*
260 : * Pass-by-value types must have a fixed length that is one of the
261 : * values supported by fetch_att() and store_att_byval(); and the
262 : * alignment had better agree, too. All this code must match
5362 tgl 263 ECB : * access/tupmacs.h!
264 : */
5362 tgl 265 CBC 991 : if (internalSize == (int16) sizeof(char))
5362 tgl 266 EUB : {
1131 tgl 267 GIC 6 : if (alignment != TYPALIGN_CHAR)
5362 tgl 268 UIC 0 : ereport(ERROR,
269 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
270 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
5362 tgl 271 ECB : alignment, internalSize)));
272 : }
5362 tgl 273 CBC 985 : else if (internalSize == (int16) sizeof(int16))
5362 tgl 274 EUB : {
1131 tgl 275 GIC 2 : if (alignment != TYPALIGN_SHORT)
5362 tgl 276 UIC 0 : ereport(ERROR,
277 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
278 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
5362 tgl 279 ECB : alignment, internalSize)));
280 : }
5362 tgl 281 CBC 983 : else if (internalSize == (int16) sizeof(int32))
5362 tgl 282 EUB : {
1131 tgl 283 GIC 656 : if (alignment != TYPALIGN_INT)
5362 tgl 284 UIC 0 : ereport(ERROR,
285 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
286 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
287 : alignment, internalSize)));
5362 tgl 288 ECB : }
289 : #if SIZEOF_DATUM == 8
5362 tgl 290 CBC 327 : else if (internalSize == (int16) sizeof(Datum))
5362 tgl 291 EUB : {
1131 tgl 292 GIC 327 : if (alignment != TYPALIGN_DOUBLE)
5362 tgl 293 UIC 0 : ereport(ERROR,
294 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
295 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
296 : alignment, internalSize)));
297 : }
5362 tgl 298 EUB : #endif
299 : else
5362 tgl 300 UIC 0 : ereport(ERROR,
301 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
302 : errmsg("internal size %d is invalid for passed-by-value type",
303 : internalSize)));
304 : }
305 : else
5362 tgl 306 ECB : {
307 : /* varlena types must have int align or better */
1131 tgl 308 GBC 165625 : if (internalSize == -1 &&
1131 tgl 309 GIC 162517 : !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE))
5362 tgl 310 UIC 0 : ereport(ERROR,
311 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
312 : errmsg("alignment \"%c\" is invalid for variable-length type",
2118 tgl 313 ECB : alignment)));
5362 tgl 314 EUB : /* cstring must have char alignment */
1131 tgl 315 GIC 165625 : if (internalSize == -2 && !(alignment == TYPALIGN_CHAR))
5362 tgl 316 UIC 0 : ereport(ERROR,
317 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
318 : errmsg("alignment \"%c\" is invalid for variable-length type",
319 : alignment)));
320 : }
7885 tgl 321 ECB :
7533 tgl 322 EUB : /* Only varlena types can be toasted */
1131 tgl 323 GIC 166616 : if (storage != TYPSTORAGE_PLAIN && internalSize != -1)
7202 tgl 324 UIC 0 : ereport(ERROR,
325 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
326 : errmsg("fixed-size types must have storage PLAIN")));
327 :
328 : /*
329 : * This is a dependent type if it's an implicitly-created array type, or
330 : * if it's a relation rowtype that's not a composite type. For such types
331 : * we'll leave the ACL empty, and we'll skip creating some dependency
332 : * records because there will be a dependency already through the
333 : * depended-on type or relation. (Caution: this is closely intertwined
1612 tgl 334 ECB : * with some behavior in GenerateTypeDependencies.)
335 : */
1612 tgl 336 GIC 247640 : isDependentType = isImplicitArray ||
337 81024 : (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
338 :
339 : /*
5271 tgl 340 ECB : * initialize arrays needed for heap_form_tuple or heap_modify_tuple
341 : */
9345 bruce 342 CBC 5498328 : for (i = 0; i < Natts_pg_type; ++i)
9345 bruce 343 ECB : {
5271 tgl 344 CBC 5331712 : nulls[i] = false;
5271 tgl 345 GIC 5331712 : replaces[i] = true;
7885 346 5331712 : values[i] = (Datum) 0;
347 : }
348 :
349 : /*
4315 tgl 350 ECB : * insert data values
9345 bruce 351 : */
8986 bruce 352 CBC 166616 : namestrcpy(&name, typeName);
4315 tgl 353 166616 : values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
354 166616 : values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
355 166616 : values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
356 166616 : values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
357 166616 : values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
358 166616 : values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
359 166616 : values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
360 166616 : values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
361 166616 : values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
362 166616 : values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
363 166616 : values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
851 364 166616 : values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(subscriptProcedure);
4315 365 166616 : values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
366 166616 : values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
367 166616 : values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
368 166616 : values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
369 166616 : values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
370 166616 : values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
371 166616 : values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
372 166616 : values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
373 166616 : values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
374 166616 : values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
375 166616 : values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
376 166616 : values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
377 166616 : values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
378 166616 : values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
4315 tgl 379 GIC 166616 : values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
380 166616 : values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
381 :
382 : /*
383 : * initialize the default binary value for this type. Check for nulls of
6385 bruce 384 ECB : * course.
7691 385 : */
7691 bruce 386 GIC 166616 : if (defaultTypeBin)
4315 tgl 387 CBC 324 : values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
388 : else
4315 tgl 389 GIC 166292 : nulls[Anum_pg_type_typdefaultbin - 1] = true;
390 :
391 : /*
8053 bruce 392 ECB : * initialize the default value for this type.
9345 393 : */
7885 tgl 394 GIC 166616 : if (defaultTypeValue)
4315 tgl 395 CBC 333 : values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
396 : else
4315 tgl 397 GIC 166283 : nulls[Anum_pg_type_typdefault - 1] = true;
398 :
399 : /*
1612 tgl 400 ECB : * Initialize the type's ACL, too. But dependent types don't get one.
401 : */
1612 tgl 402 GIC 166616 : if (isDependentType)
1612 tgl 403 CBC 164018 : typacl = NULL;
404 : else
405 2598 : typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
1612 tgl 406 ECB : typeNamespace);
4128 peter_e 407 GIC 166616 : if (typacl != NULL)
4128 peter_e 408 CBC 3 : values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
409 : else
4128 peter_e 410 GIC 166613 : nulls[Anum_pg_type_typacl - 1] = true;
411 :
412 : /*
413 : * open pg_type and prepare to insert or update a row.
414 : *
415 : * NOTE: updating will not work correctly in bootstrap mode; but we don't
7681 tgl 416 ECB : * expect to be overwriting any shell types in bootstrap mode.
417 : */
1539 andres 418 CBC 166616 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
419 :
4802 rhaas 420 GIC 166616 : tup = SearchSysCacheCopy2(TYPENAMENSP,
4802 rhaas 421 ECB : CStringGetDatum(typeName),
422 : ObjectIdGetDatum(typeNamespace));
9345 bruce 423 CBC 166616 : if (HeapTupleIsValid(tup))
424 : {
1601 andres 425 GIC 95 : Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
426 :
427 : /*
428 : * check that the type is not already defined. It may exist as a
6449 tgl 429 ECB : * shell type, however.
7681 tgl 430 EUB : */
1601 andres 431 GIC 95 : if (typform->typisdefined)
7202 tgl 432 UIC 0 : ereport(ERROR,
433 : (errcode(ERRCODE_DUPLICATE_OBJECT),
434 : errmsg("type \"%s\" already exists", typeName)));
435 :
436 : /*
6249 tgl 437 ECB : * shell type must have been created by same owner
6249 tgl 438 EUB : */
1601 andres 439 GIC 95 : if (typform->typowner != ownerId)
1954 peter_e 440 UIC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName);
6249 tgl 441 ECB :
5812 tgl 442 EUB : /* trouble if caller wanted to force the OID */
5812 tgl 443 GIC 95 : if (OidIsValid(newTypeOid))
5812 tgl 444 LBC 0 : elog(ERROR, "cannot assign new OID to existing shell type");
445 :
1601 andres 446 GIC 95 : replaces[Anum_pg_type_oid - 1] = false;
447 :
448 : /*
6249 tgl 449 ECB : * Okay to update existing shell type tuple
450 : */
5271 tgl 451 GIC 95 : tup = heap_modify_tuple(tup,
452 : RelationGetDescr(pg_type_desc),
453 : values,
454 : nulls,
5050 bruce 455 ECB : replaces);
456 :
2259 alvherre 457 CBC 95 : CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
458 :
1601 andres 459 95 : typeObjectId = typform->oid;
460 :
7396 tgl 461 GIC 95 : rebuildDeps = true; /* get rid of shell type's dependencies */
462 : }
463 : else
9345 bruce 464 ECB : {
4854 465 : /* Force the OID if requested by caller */
5812 tgl 466 GIC 166521 : if (OidIsValid(newTypeOid))
1601 andres 467 CBC 84892 : typeObjectId = newTypeOid;
468 : /* Use binary-upgrade override for pg_type.oid, if supplied. */
3149 bruce 469 81629 : else if (IsBinaryUpgrade)
4854 bruce 470 EUB : {
3149 bruce 471 GIC 705 : if (!OidIsValid(binary_upgrade_next_pg_type_oid))
3149 bruce 472 UIC 0 : ereport(ERROR,
473 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3149 bruce 474 ECB : errmsg("pg_type OID value not set when in binary upgrade mode")));
475 :
1601 andres 476 GIC 705 : typeObjectId = binary_upgrade_next_pg_type_oid;
4854 bruce 477 705 : binary_upgrade_next_pg_type_oid = InvalidOid;
478 : }
1601 andres 479 ECB : else
480 : {
1601 andres 481 GIC 80924 : typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
482 : Anum_pg_type_oid);
1601 andres 483 ECB : }
484 :
1601 andres 485 CBC 166521 : values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
486 :
1601 andres 487 GIC 166521 : tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
1601 andres 488 ECB : values, nulls);
489 :
1601 andres 490 GIC 166521 : CatalogTupleInsert(pg_type_desc, tup);
491 : }
492 :
493 : /*
7570 tgl 494 ECB : * Create dependencies. We can/must skip this in bootstrap mode.
7576 495 : */
7570 tgl 496 GIC 166616 : if (!IsBootstrapProcessingMode())
1129 497 130340 : GenerateTypeDependencies(tup,
1129 tgl 498 ECB : pg_type_desc,
499 : (defaultTypeBin ?
7396 tgl 500 GIC 324 : stringToNode(defaultTypeBin) :
501 : NULL),
502 : typacl,
503 : relationKind,
504 : isImplicitArray,
505 : isDependentType,
506 : true, /* make extension dependency */
507 : rebuildDeps);
7429 bruce 508 ECB :
509 : /* Post creation hook for new type */
3686 rhaas 510 CBC 166615 : InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
511 :
2959 alvherre 512 GIC 166615 : ObjectAddressSet(address, TypeRelationId, typeObjectId);
513 :
514 : /*
7429 bruce 515 ECB : * finish up
516 : */
1539 andres 517 CBC 166615 : table_close(pg_type_desc, RowExclusiveLock);
518 :
2959 alvherre 519 GIC 166615 : return address;
520 : }
521 :
522 : /*
523 : * GenerateTypeDependencies: build the dependencies needed for a type
524 : *
525 : * Most of what this function needs to know about the type is passed as the
526 : * new pg_type row, typeTuple. We make callers pass the pg_type Relation
527 : * as well, so that we have easy access to a tuple descriptor for the row.
528 : *
529 : * While this is able to extract the defaultExpr and typacl from the tuple,
530 : * doing so is relatively expensive, and callers may have those values at
531 : * hand already. Pass those if handy, otherwise pass NULL. (typacl is really
532 : * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
533 : *
534 : * relationKind and isImplicitArray are likewise somewhat expensive to deduce
535 : * from the tuple, so we make callers pass those (they're not optional).
536 : *
537 : * isDependentType is true if this is an implicit array or relation rowtype;
538 : * that means it doesn't need its own dependencies on owner etc.
539 : *
540 : * We make an extension-membership dependency if we're in an extension
541 : * script and makeExtensionDep is true (and isDependentType isn't true).
542 : * makeExtensionDep should be true when creating a new type or replacing a
543 : * shell type, but not for ALTER TYPE on an existing type. Passing false
544 : * causes the type's extension membership to be left alone.
545 : *
546 : * rebuild should be true if this is a pre-existing type. We will remove
547 : * existing dependencies and rebuild them from scratch. This is needed for
548 : * ALTER TYPE, and also when replacing a shell type. We don't remove any
549 : * existing extension dependency, though; hence, if makeExtensionDep is also
550 : * true and we're in an extension script, an error will occur unless the
551 : * type already belongs to the current extension. That's the behavior we
552 : * want when replacing a shell type, which is the only case where both flags
553 : * are true.
7396 tgl 554 ECB : */
555 : void
1129 tgl 556 GIC 130163 : GenerateTypeDependencies(HeapTuple typeTuple,
557 : Relation typeCatalog,
558 : Node *defaultExpr,
559 : void *typacl,
560 : char relationKind, /* only for relation rowtypes */
561 : bool isImplicitArray,
562 : bool isDependentType,
563 : bool makeExtensionDep,
7429 bruce 564 ECB : bool rebuild)
565 : {
1129 tgl 566 GIC 130163 : Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
567 130163 : Oid typeObjectId = typeForm->oid;
568 : Datum datum;
569 : bool isNull;
570 : ObjectAddress myself,
571 : referenced;
572 : ObjectAddresses *addrs_normal;
7429 bruce 573 ECB :
574 : /* Extract defaultExpr if caller didn't pass it */
1129 tgl 575 CBC 130163 : if (defaultExpr == NULL)
576 : {
577 129835 : datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
1129 tgl 578 EUB : RelationGetDescr(typeCatalog), &isNull);
1129 tgl 579 GIC 129835 : if (!isNull)
1129 tgl 580 UIC 0 : defaultExpr = stringToNode(TextDatumGetCString(datum));
1129 tgl 581 ECB : }
582 : /* Extract typacl if caller didn't pass it */
1129 tgl 583 CBC 130163 : if (typacl == NULL)
584 : {
585 130160 : datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
1129 tgl 586 EUB : RelationGetDescr(typeCatalog), &isNull);
1129 tgl 587 GIC 130160 : if (!isNull)
1129 tgl 588 UIC 0 : typacl = DatumGetAclPCopy(datum);
589 : }
1129 tgl 590 ECB :
591 : /* If rebuild, first flush old dependencies, except extension deps */
7429 bruce 592 CBC 130163 : if (rebuild)
6485 tgl 593 ECB : {
4443 tgl 594 GIC 135 : deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
5190 595 135 : deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
6485 tgl 596 ECB : }
597 :
1014 michael 598 GIC 130163 : ObjectAddressSet(myself, TypeRelationId, typeObjectId);
599 :
600 : /*
601 : * Make dependencies on namespace, owner, ACL, extension.
602 : *
603 : * Skip these for a dependent type, since it will have such dependencies
604 : * indirectly through its depended-on type or relation.
605 : */
946 michael 606 ECB :
607 : /* placeholder for all normal dependencies */
946 michael 608 CBC 130163 : addrs_normal = new_object_addresses();
609 :
1612 tgl 610 130163 : if (!isDependentType)
611 : {
1014 michael 612 2742 : ObjectAddressSet(referenced, NamespaceRelationId,
613 : typeForm->typnamespace);
7429 bruce 614 2742 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
615 :
1612 tgl 616 GIC 2742 : recordDependencyOnOwner(TypeRelationId, typeObjectId,
1612 tgl 617 ECB : typeForm->typowner);
618 :
1612 tgl 619 GIC 2742 : recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
1612 tgl 620 ECB : typeForm->typowner, typacl);
7429 bruce 621 :
600 tgl 622 GIC 2742 : if (makeExtensionDep)
623 2705 : recordDependencyOnCurrentExtension(&myself, rebuild);
624 : }
4278 tgl 625 ECB :
626 : /* Normal dependencies on the I/O and support functions */
1612 tgl 627 CBC 130162 : if (OidIsValid(typeForm->typinput))
7396 tgl 628 ECB : {
1014 michael 629 GIC 130162 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
946 630 130162 : add_exact_object_address(&referenced, addrs_normal);
7396 tgl 631 ECB : }
632 :
1612 tgl 633 CBC 130162 : if (OidIsValid(typeForm->typoutput))
7396 tgl 634 ECB : {
1014 michael 635 GIC 130162 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
946 636 130162 : add_exact_object_address(&referenced, addrs_normal);
7396 tgl 637 ECB : }
638 :
1612 tgl 639 CBC 130162 : if (OidIsValid(typeForm->typreceive))
7276 tgl 640 ECB : {
1014 michael 641 GIC 129967 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
946 642 129967 : add_exact_object_address(&referenced, addrs_normal);
7276 tgl 643 ECB : }
644 :
1612 tgl 645 CBC 130162 : if (OidIsValid(typeForm->typsend))
7276 tgl 646 ECB : {
1014 michael 647 GIC 129961 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
946 648 129961 : add_exact_object_address(&referenced, addrs_normal);
7276 tgl 649 ECB : }
650 :
1612 tgl 651 CBC 130162 : if (OidIsValid(typeForm->typmodin))
5944 tgl 652 ECB : {
1014 michael 653 GIC 14 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
946 654 14 : add_exact_object_address(&referenced, addrs_normal);
5944 tgl 655 ECB : }
656 :
1612 tgl 657 CBC 130162 : if (OidIsValid(typeForm->typmodout))
5944 tgl 658 ECB : {
1014 michael 659 GIC 14 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
946 660 14 : add_exact_object_address(&referenced, addrs_normal);
5944 tgl 661 ECB : }
662 :
1612 tgl 663 CBC 130162 : if (OidIsValid(typeForm->typanalyze))
6996 tgl 664 ECB : {
1014 michael 665 GIC 65213 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
946 666 65213 : add_exact_object_address(&referenced, addrs_normal);
946 michael 667 ECB : }
668 :
851 tgl 669 CBC 130162 : if (OidIsValid(typeForm->typsubscript))
851 tgl 670 ECB : {
851 tgl 671 GIC 65020 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsubscript);
672 65020 : add_exact_object_address(&referenced, addrs_normal);
673 : }
851 tgl 674 ECB :
675 : /* Normal dependency from a domain to its base type. */
946 michael 676 CBC 130162 : if (OidIsValid(typeForm->typbasetype))
946 michael 677 ECB : {
946 michael 678 GIC 1863 : ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
679 1863 : add_exact_object_address(&referenced, addrs_normal);
680 : }
681 :
682 : /*
683 : * Normal dependency from a domain to its collation. We know the default
946 michael 684 ECB : * collation is pinned, so don't bother recording it.
685 : */
946 michael 686 GIC 130162 : if (OidIsValid(typeForm->typcollation) &&
946 michael 687 CBC 2000 : typeForm->typcollation != DEFAULT_COLLATION_OID)
946 michael 688 ECB : {
946 michael 689 GIC 1850 : ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
690 1850 : add_exact_object_address(&referenced, addrs_normal);
6996 tgl 691 ECB : }
692 :
946 michael 693 GIC 130162 : record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
694 130162 : free_object_addresses(addrs_normal);
946 michael 695 ECB :
696 : /* Normal dependency on the default expression. */
946 michael 697 GIC 130162 : if (defaultExpr)
698 328 : recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
699 :
700 : /*
701 : * If the type is a rowtype for a relation, mark it as internally
702 : * dependent on the relation, *unless* it is a stand-alone composite type
703 : * relation. For the latter case, we have to reverse the dependency.
704 : *
705 : * In the former case, this allows the type to be auto-dropped when the
706 : * relation is, and not otherwise. And in the latter, of course we get the
6385 bruce 707 ECB : * opposite effect.
708 : */
1612 tgl 709 CBC 130162 : if (OidIsValid(typeForm->typrelid))
710 : {
1014 michael 711 62724 : ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
7429 bruce 712 ECB :
7429 bruce 713 GIC 62724 : if (relationKind != RELKIND_COMPOSITE_TYPE)
7429 bruce 714 CBC 62415 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
715 : else
7429 bruce 716 GIC 309 : recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
717 : }
718 :
719 : /*
720 : * If the type is an implicitly-created array type, mark it as internally
721 : * dependent on the element type. Otherwise, if it has an element type,
5812 tgl 722 ECB : * the dependency is a normal one.
723 : */
1612 tgl 724 CBC 130162 : if (OidIsValid(typeForm->typelem))
7429 bruce 725 ECB : {
1014 michael 726 GIC 65010 : ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
5812 tgl 727 65010 : recordDependencyOn(&myself, &referenced,
2118 tgl 728 ECB : isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
729 : }
9770 scrappy 730 GIC 130162 : }
731 :
732 : /*
733 : * RenameTypeInternal
734 : * This renames a type, as well as any associated array type.
735 : *
736 : * Caller must have already checked privileges.
737 : *
738 : * Currently this is used for renaming table rowtypes and for
739 : * ALTER TYPE RENAME TO command.
9770 scrappy 740 ECB : */
741 : void
5499 tgl 742 GIC 164 : RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
743 : {
744 : Relation pg_type_desc;
745 : HeapTuple tuple;
746 : Form_pg_type typ;
747 : Oid arrayOid;
2144 tgl 748 ECB : Oid oldTypeOid;
749 :
1539 andres 750 CBC 164 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
9345 bruce 751 ECB :
4802 rhaas 752 GBC 164 : tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
8179 tgl 753 CBC 164 : if (!HeapTupleIsValid(tuple))
5811 tgl 754 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
5811 tgl 755 GIC 164 : typ = (Form_pg_type) GETSTRUCT(tuple);
5811 tgl 756 ECB :
757 : /* We are not supposed to be changing schemas here */
5811 tgl 758 CBC 164 : Assert(typeNamespace == typ->typnamespace);
759 :
5811 tgl 760 GIC 164 : arrayOid = typ->typarray;
5811 tgl 761 ECB :
762 : /* Check for a conflicting type name. */
1601 andres 763 GIC 164 : oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
764 : CStringGetDatum(newTypeName),
765 : ObjectIdGetDatum(typeNamespace));
766 :
767 : /*
768 : * If there is one, see if it's an autogenerated array type, and if so
769 : * rename it out of the way. (But we must skip that for a shell type
770 : * because moveArrayTypeName will do the wrong thing in that case.)
771 : * Otherwise, we can at least give a more friendly error than unique-index
2144 tgl 772 ECB : * violation.
773 : */
2144 tgl 774 CBC 164 : if (OidIsValid(oldTypeOid))
2144 tgl 775 ECB : {
2144 tgl 776 GIC 12 : if (get_typisdefined(oldTypeOid) &&
777 6 : moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
2144 tgl 778 EUB : /* successfully dodged the problem */ ;
779 : else
2144 tgl 780 UIC 0 : ereport(ERROR,
781 : (errcode(ERRCODE_DUPLICATE_OBJECT),
782 : errmsg("type \"%s\" already exists", newTypeName)));
783 : }
8986 bruce 784 ECB :
785 : /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
5811 tgl 786 CBC 164 : namestrcpy(&(typ->typname), newTypeName);
787 :
2259 alvherre 788 164 : CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
789 :
3675 rhaas 790 164 : InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3675 rhaas 791 ECB :
8179 tgl 792 GIC 164 : heap_freetuple(tuple);
1539 andres 793 164 : table_close(pg_type_desc, RowExclusiveLock);
794 :
795 : /*
796 : * If the type has an array type, recurse to handle that. But we don't
797 : * need to do anything more if we already renamed that array type above
2144 tgl 798 ECB : * (which would happen when, eg, renaming "foo" to "_foo").
799 : */
2144 tgl 800 CBC 164 : if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
801 : {
5624 bruce 802 74 : char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
5811 tgl 803 ECB :
5499 tgl 804 GIC 74 : RenameTypeInternal(arrayOid, arrname, typeNamespace);
5811 tgl 805 CBC 74 : pfree(arrname);
806 : }
9770 scrappy 807 GIC 164 : }
808 :
809 :
810 : /*
811 : * makeArrayTypeName
812 : * - given a base type name, make an array type name for it
813 : *
814 : * the caller is responsible for pfreeing the result
9770 scrappy 815 ECB : */
816 : char *
5812 tgl 817 GIC 83390 : makeArrayTypeName(const char *typeName, Oid typeNamespace)
9770 scrappy 818 ECB : {
819 : char *arr_name;
257 tgl 820 GNC 83390 : int pass = 0;
821 : char suffix[NAMEDATALEN];
822 :
823 : /*
824 : * Per ancient Postgres tradition, array type names are made by prepending
825 : * an underscore to the base type name. Much client code knows that
826 : * convention, so don't muck with it. However, the tradition is less
827 : * clear about what to do in the corner cases where the resulting name is
828 : * too long or conflicts with an existing name. Our current rules are (1)
829 : * truncate the base name on the right as needed, and (2) if there is a
830 : * conflict, append another underscore and some digits chosen to make it
831 : * unique. This is similar to what ChooseRelationName() does.
832 : *
833 : * The actual name generation can be farmed out to makeObjectName() by
834 : * giving it an empty first name component.
835 : */
836 :
837 : /* First, try with no numeric suffix */
838 83390 : arr_name = makeObjectName("", typeName, NULL);
839 :
840 : for (;;)
841 : {
842 83400 : if (!SearchSysCacheExists2(TYPENAMENSP,
843 : CStringGetDatum(arr_name),
844 : ObjectIdGetDatum(typeNamespace)))
845 83390 : break;
846 :
847 : /* That attempt conflicted. Prepare a new name with some digits. */
848 10 : pfree(arr_name);
849 10 : snprintf(suffix, sizeof(suffix), "%d", ++pass);
850 10 : arr_name = makeObjectName("", typeName, suffix);
851 : }
852 :
853 83390 : return arr_name;
854 : }
855 :
856 :
857 : /*
858 : * moveArrayTypeName
859 : * - try to reassign an array type name that the user wants to use.
860 : *
5811 tgl 861 ECB : * The given type name has been discovered to already exist (with the given
862 : * OID). If it is an autogenerated array type, change the array type's name
863 : * to not conflict. This allows the user to create type "foo" followed by
864 : * type "_foo" without problems. (Of course, there are race conditions if
865 : * two backends try to create similarly-named types concurrently, but the
866 : * worst that can happen is an unnecessary failure --- anything we do here
867 : * will be rolled back if the type creation fails due to conflicting names.)
868 : *
869 : * Note that this must be called *before* calling makeArrayTypeName to
870 : * determine the new type's own array type name; else the latter will
871 : * certainly pick the same name.
872 : *
2062 peter_e 873 : * Returns true if successfully moved the type, false if not.
874 : *
875 : * We also return true if the given type is a shell type. In this case
5811 tgl 876 : * the type has not been renamed out of the way, but nonetheless it can
877 : * be expected that TypeCreate will succeed. This behavior is convenient
878 : * for most callers --- those that need to distinguish the shell-type case
879 : * must do their own typisdefined test.
880 : */
881 : bool
5811 tgl 882 GIC 20 : moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
883 : {
884 : Oid elemOid;
885 : char *newname;
886 :
887 : /* We need do nothing if it's a shell type. */
888 20 : if (!get_typisdefined(typeOid))
889 1 : return true;
890 :
891 : /* Can't change it if it's not an autogenerated array type. */
892 19 : elemOid = get_element_type(typeOid);
893 32 : if (!OidIsValid(elemOid) ||
894 13 : get_array_type(elemOid) != typeOid)
895 6 : return false;
896 :
897 : /*
898 : * OK, use makeArrayTypeName to pick an unused modification of the name.
899 : * Note that since makeArrayTypeName is an iterative process, this will
900 : * produce a name that it might have produced the first time, had the
901 : * conflicting type we are about to create already existed.
902 : */
903 13 : newname = makeArrayTypeName(typeName, typeNamespace);
904 :
5811 tgl 905 ECB : /* Apply the rename */
5499 tgl 906 GIC 13 : RenameTypeInternal(typeOid, newname, typeNamespace);
907 :
908 : /*
909 : * We must bump the command counter so that any subsequent use of
910 : * makeArrayTypeName sees what we just did and doesn't pick the same name.
5811 tgl 911 ECB : */
5811 tgl 912 CBC 13 : CommandCounterIncrement();
913 :
5811 tgl 914 GIC 13 : pfree(newname);
5811 tgl 915 ECB :
5811 tgl 916 CBC 13 : return true;
5811 tgl 917 ECB : }
840 akorotkov 918 :
919 :
920 : /*
921 : * makeMultirangeTypeName
922 : * - given a range type name, make a multirange type name for it
923 : *
924 : * caller is responsible for pfreeing the result
925 : */
926 : char *
840 akorotkov 927 GIC 60 : makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
928 : {
840 akorotkov 929 ECB : char *buf;
930 : char *rangestr;
931 :
932 : /*
933 : * If the range type name contains "range" then change that to
934 : * "multirange". Otherwise add "_multirange" to the end.
935 : */
840 akorotkov 936 GIC 60 : rangestr = strstr(rangeTypeName, "range");
840 akorotkov 937 CBC 60 : if (rangestr)
938 : {
939 51 : char *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
940 :
840 akorotkov 941 GIC 51 : buf = psprintf("%s%s%s", prefix, "multi", rangestr);
942 : }
943 : else
944 9 : buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
945 :
946 : /* clip it at NAMEDATALEN-1 bytes */
947 60 : buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
948 :
949 60 : if (SearchSysCacheExists2(TYPENAMENSP,
840 akorotkov 950 ECB : CStringGetDatum(buf),
951 : ObjectIdGetDatum(typeNamespace)))
840 akorotkov 952 GIC 6 : ereport(ERROR,
953 : (errcode(ERRCODE_DUPLICATE_OBJECT),
954 : errmsg("type \"%s\" already exists", buf),
955 : errdetail("Failed while creating a multirange type for type \"%s\".", rangeTypeName),
956 : errhint("You can manually specify a multirange type name using the \"multirange_type_name\" attribute.")));
957 :
958 54 : return pstrdup(buf);
840 akorotkov 959 ECB : }
|