Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * typecmds.c
4 : * Routines for SQL commands that manipulate types (and domains).
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/commands/typecmds.c
12 : *
13 : * DESCRIPTION
14 : * The "DefineFoo" routines take the parse tree and pick out the
15 : * appropriate arguments/flags, passing the results to the
16 : * corresponding "FooDefine" routines (in src/catalog) that do
17 : * the actual catalog-munging. These routines also verify permission
18 : * of the user to execute the command.
19 : *
20 : * NOTES
21 : * These things must be defined and committed in the following order:
22 : * "create function":
23 : * input/output, recv/send functions
24 : * "create type":
25 : * type
26 : * "create operator":
27 : * operators
28 : *
29 : *
30 : *-------------------------------------------------------------------------
31 : */
32 : #include "postgres.h"
33 :
34 : #include "access/genam.h"
35 : #include "access/heapam.h"
36 : #include "access/htup_details.h"
37 : #include "access/tableam.h"
38 : #include "access/xact.h"
39 : #include "catalog/binary_upgrade.h"
40 : #include "catalog/catalog.h"
41 : #include "catalog/heap.h"
42 : #include "catalog/objectaccess.h"
43 : #include "catalog/pg_am.h"
44 : #include "catalog/pg_authid.h"
45 : #include "catalog/pg_cast.h"
46 : #include "catalog/pg_collation.h"
47 : #include "catalog/pg_constraint.h"
48 : #include "catalog/pg_depend.h"
49 : #include "catalog/pg_enum.h"
50 : #include "catalog/pg_language.h"
51 : #include "catalog/pg_namespace.h"
52 : #include "catalog/pg_proc.h"
53 : #include "catalog/pg_range.h"
54 : #include "catalog/pg_type.h"
55 : #include "commands/defrem.h"
56 : #include "commands/tablecmds.h"
57 : #include "commands/typecmds.h"
58 : #include "executor/executor.h"
59 : #include "miscadmin.h"
60 : #include "nodes/makefuncs.h"
61 : #include "optimizer/optimizer.h"
62 : #include "parser/parse_coerce.h"
63 : #include "parser/parse_collate.h"
64 : #include "parser/parse_expr.h"
65 : #include "parser/parse_func.h"
66 : #include "parser/parse_type.h"
67 : #include "utils/builtins.h"
68 : #include "utils/fmgroids.h"
69 : #include "utils/inval.h"
70 : #include "utils/lsyscache.h"
71 : #include "utils/memutils.h"
72 : #include "utils/rel.h"
73 : #include "utils/ruleutils.h"
74 : #include "utils/snapmgr.h"
75 : #include "utils/syscache.h"
76 :
77 :
78 : /* result structure for get_rels_with_domain() */
79 : typedef struct
80 : {
81 : Relation rel; /* opened and locked relation */
82 : int natts; /* number of attributes of interest */
83 : int *atts; /* attribute numbers */
84 : /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
85 : } RelToCheck;
86 :
87 : /* parameter structure for AlterTypeRecurse() */
88 : typedef struct
89 : {
90 : /* Flags indicating which type attributes to update */
91 : bool updateStorage;
92 : bool updateReceive;
93 : bool updateSend;
94 : bool updateTypmodin;
95 : bool updateTypmodout;
96 : bool updateAnalyze;
97 : bool updateSubscript;
98 : /* New values for relevant attributes */
99 : char storage;
100 : Oid receiveOid;
101 : Oid sendOid;
102 : Oid typmodinOid;
103 : Oid typmodoutOid;
104 : Oid analyzeOid;
105 : Oid subscriptOid;
106 : } AlterTypeRecurseParams;
107 :
108 : /* Potentially set by pg_upgrade_support functions */
109 : Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
110 : Oid binary_upgrade_next_mrng_pg_type_oid = InvalidOid;
111 : Oid binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid;
112 :
113 : static void makeRangeConstructors(const char *name, Oid namespace,
114 : Oid rangeOid, Oid subtype);
115 : static void makeMultirangeConstructors(const char *name, Oid namespace,
116 : Oid multirangeOid, Oid rangeOid,
117 : Oid rangeArrayOid, Oid *castFuncOid);
118 : static Oid findTypeInputFunction(List *procname, Oid typeOid);
119 : static Oid findTypeOutputFunction(List *procname, Oid typeOid);
120 : static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
121 : static Oid findTypeSendFunction(List *procname, Oid typeOid);
122 : static Oid findTypeTypmodinFunction(List *procname);
123 : static Oid findTypeTypmodoutFunction(List *procname);
124 : static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
125 : static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid);
126 : static Oid findRangeSubOpclass(List *opcname, Oid subtype);
127 : static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
128 : static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
129 : static void validateDomainConstraint(Oid domainoid, char *ccbin);
130 : static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
131 : static void checkEnumOwner(HeapTuple tup);
132 : static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
133 : Oid baseTypeOid,
134 : int typMod, Constraint *constr,
135 : const char *domainName, ObjectAddress *constrAddr);
136 : static Node *replace_domain_constraint_value(ParseState *pstate,
137 : ColumnRef *cref);
138 : static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
139 : HeapTuple tup, Relation catalog,
140 : AlterTypeRecurseParams *atparams);
141 :
142 :
143 : /*
144 : * DefineType
145 : * Registers a new base type.
146 : */
147 : ObjectAddress
2406 peter_e 148 CBC 180 : DefineType(ParseState *pstate, List *names, List *parameters)
149 : {
150 : char *typeName;
151 : Oid typeNamespace;
7276 tgl 152 180 : int16 internalLength = -1; /* default: variable-length */
7664 153 180 : List *inputName = NIL;
154 180 : List *outputName = NIL;
7276 155 180 : List *receiveName = NIL;
156 180 : List *sendName = NIL;
5944 157 180 : List *typmodinName = NIL;
158 180 : List *typmodoutName = NIL;
6996 159 180 : List *analyzeName = NIL;
851 160 180 : List *subscriptName = NIL;
5366 161 180 : char category = TYPCATEGORY_USER;
162 180 : bool preferred = false;
7664 163 180 : char delimiter = DEFAULT_TYPDELIM;
5243 164 180 : Oid elemType = InvalidOid;
165 180 : char *defaultValue = NULL;
166 180 : bool byValue = false;
1131 167 180 : char alignment = TYPALIGN_INT; /* default alignment */
168 180 : char storage = TYPSTORAGE_PLAIN; /* default TOAST storage method */
4443 peter_e 169 180 : Oid collation = InvalidOid;
5050 bruce 170 180 : DefElem *likeTypeEl = NULL;
171 180 : DefElem *internalLengthEl = NULL;
172 180 : DefElem *inputNameEl = NULL;
173 180 : DefElem *outputNameEl = NULL;
174 180 : DefElem *receiveNameEl = NULL;
175 180 : DefElem *sendNameEl = NULL;
176 180 : DefElem *typmodinNameEl = NULL;
177 180 : DefElem *typmodoutNameEl = NULL;
178 180 : DefElem *analyzeNameEl = NULL;
851 tgl 179 180 : DefElem *subscriptNameEl = NULL;
5050 bruce 180 180 : DefElem *categoryEl = NULL;
181 180 : DefElem *preferredEl = NULL;
182 180 : DefElem *delimiterEl = NULL;
183 180 : DefElem *elemTypeEl = NULL;
184 180 : DefElem *defaultValueEl = NULL;
185 180 : DefElem *byValueEl = NULL;
186 180 : DefElem *alignmentEl = NULL;
187 180 : DefElem *storageEl = NULL;
4382 188 180 : DefElem *collatableEl = NULL;
189 : Oid inputOid;
190 : Oid outputOid;
7276 tgl 191 180 : Oid receiveOid = InvalidOid;
192 180 : Oid sendOid = InvalidOid;
5944 193 180 : Oid typmodinOid = InvalidOid;
194 180 : Oid typmodoutOid = InvalidOid;
6996 195 180 : Oid analyzeOid = InvalidOid;
851 196 180 : Oid subscriptOid = InvalidOid;
197 : char *array_type;
198 : Oid array_oid;
199 : Oid typoid;
200 : ListCell *pl;
201 : ObjectAddress address;
202 :
203 : /*
204 : * As of Postgres 8.4, we require superuser privilege to create a base
205 : * type. This is simple paranoia: there are too many ways to mess up the
206 : * system with an incorrect type definition (for instance, representation
207 : * parameters that don't match what the C code expects). In practice it
208 : * takes superuser privilege to create the I/O functions, and so the
209 : * former requirement that you own the I/O functions pretty much forced
210 : * superuserness anyway. We're just making doubly sure here.
211 : *
212 : * XXX re-enable NOT_USED code sections below if you remove this test.
213 : */
5365 214 180 : if (!superuser())
5365 tgl 215 UBC 0 : ereport(ERROR,
216 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
217 : errmsg("must be superuser to create a base type")));
218 :
219 : /* Convert list of names to a name and namespace */
7664 tgl 220 CBC 180 : typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
221 :
222 : #ifdef NOT_USED
223 : /* XXX this is unnecessary given the superuser check above */
224 : /* Check we have creation rights in target namespace */
225 : aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
226 : if (aclresult != ACLCHECK_OK)
227 : aclcheck_error(aclresult, OBJECT_SCHEMA,
228 : get_namespace_name(typeNamespace));
229 : #endif
230 :
231 : /*
232 : * Look to see if type already exists.
233 : */
1601 andres 234 180 : typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
235 : CStringGetDatum(typeName),
236 : ObjectIdGetDatum(typeNamespace));
237 :
238 : /*
239 : * If it's not a shell, see if it's an autogenerated array type, and if so
240 : * rename it out of the way.
241 : */
5811 tgl 242 180 : if (OidIsValid(typoid) && get_typisdefined(typoid))
243 : {
244 3 : if (moveArrayTypeName(typoid, typeName, typeNamespace))
5811 tgl 245 UBC 0 : typoid = InvalidOid;
246 : else
1130 tgl 247 CBC 3 : ereport(ERROR,
248 : (errcode(ERRCODE_DUPLICATE_OBJECT),
249 : errmsg("type \"%s\" already exists", typeName)));
250 : }
251 :
252 : /*
253 : * If this command is a parameterless CREATE TYPE, then we're just here to
254 : * make a shell type, so do that (or fail if there already is a shell).
255 : */
256 177 : if (parameters == NIL)
257 : {
258 74 : if (OidIsValid(typoid))
6249 259 3 : ereport(ERROR,
260 : (errcode(ERRCODE_DUPLICATE_OBJECT),
261 : errmsg("type \"%s\" already exists", typeName)));
262 :
1130 263 71 : address = TypeShellMake(typeName, typeNamespace, GetUserId());
264 71 : return address;
265 : }
266 :
267 : /*
268 : * Otherwise, we must already have a shell type, since there is no other
269 : * way that the I/O functions could have been created.
270 : */
271 103 : if (!OidIsValid(typoid))
272 3 : ereport(ERROR,
273 : (errcode(ERRCODE_DUPLICATE_OBJECT),
274 : errmsg("type \"%s\" does not exist", typeName),
275 : errhint("Create the type as a shell type, then create its I/O functions, then do a full CREATE TYPE.")));
276 :
277 : /* Extract the parameters from the parameter list */
7664 278 520 : foreach(pl, parameters)
279 : {
280 420 : DefElem *defel = (DefElem *) lfirst(pl);
281 : DefElem **defelp;
282 :
1899 283 420 : if (strcmp(defel->defname, "like") == 0)
5243 284 25 : defelp = &likeTypeEl;
1899 285 395 : else if (strcmp(defel->defname, "internallength") == 0)
5243 286 64 : defelp = &internalLengthEl;
1899 287 331 : else if (strcmp(defel->defname, "input") == 0)
5243 288 97 : defelp = &inputNameEl;
1899 289 234 : else if (strcmp(defel->defname, "output") == 0)
5243 290 97 : defelp = &outputNameEl;
1899 291 137 : else if (strcmp(defel->defname, "receive") == 0)
5243 292 9 : defelp = &receiveNameEl;
1899 293 128 : else if (strcmp(defel->defname, "send") == 0)
5243 294 9 : defelp = &sendNameEl;
1899 295 119 : else if (strcmp(defel->defname, "typmod_in") == 0)
5243 296 4 : defelp = &typmodinNameEl;
1899 297 115 : else if (strcmp(defel->defname, "typmod_out") == 0)
5243 298 4 : defelp = &typmodoutNameEl;
1899 299 111 : else if (strcmp(defel->defname, "analyze") == 0 ||
300 111 : strcmp(defel->defname, "analyse") == 0)
5243 tgl 301 UBC 0 : defelp = &analyzeNameEl;
851 tgl 302 CBC 111 : else if (strcmp(defel->defname, "subscript") == 0)
303 1 : defelp = &subscriptNameEl;
1899 304 110 : else if (strcmp(defel->defname, "category") == 0)
5243 305 6 : defelp = &categoryEl;
1899 306 104 : else if (strcmp(defel->defname, "preferred") == 0)
5243 307 6 : defelp = &preferredEl;
1899 308 98 : else if (strcmp(defel->defname, "delimiter") == 0)
5243 tgl 309 UBC 0 : defelp = &delimiterEl;
1899 tgl 310 CBC 98 : else if (strcmp(defel->defname, "element") == 0)
5243 311 7 : defelp = &elemTypeEl;
1899 312 91 : else if (strcmp(defel->defname, "default") == 0)
5243 313 9 : defelp = &defaultValueEl;
1899 314 82 : else if (strcmp(defel->defname, "passedbyvalue") == 0)
5243 315 7 : defelp = &byValueEl;
1899 316 75 : else if (strcmp(defel->defname, "alignment") == 0)
5243 317 27 : defelp = &alignmentEl;
1899 318 48 : else if (strcmp(defel->defname, "storage") == 0)
5243 319 28 : defelp = &storageEl;
1899 320 20 : else if (strcmp(defel->defname, "collatable") == 0)
4443 peter_e 321 2 : defelp = &collatableEl;
322 : else
323 : {
324 : /* WARNING, not ERROR, for historical backwards-compatibility */
7203 tgl 325 18 : ereport(WARNING,
326 : (errcode(ERRCODE_SYNTAX_ERROR),
327 : errmsg("type attribute \"%s\" not recognized",
328 : defel->defname),
329 : parser_errposition(pstate, defel->location)));
5243 330 18 : continue;
331 : }
332 402 : if (*defelp != NULL)
633 dean.a.rasheed 333 UBC 0 : errorConflictingDefElem(defel, pstate);
5243 tgl 334 CBC 402 : *defelp = defel;
335 : }
336 :
337 : /*
338 : * Now interpret the options; we do this separately so that LIKE can be
339 : * overridden by other options regardless of the ordering in the parameter
340 : * list.
341 : */
342 100 : if (likeTypeEl)
343 : {
344 : Type likeType;
345 : Form_pg_type likeForm;
346 :
4414 347 25 : likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
5243 348 25 : likeForm = (Form_pg_type) GETSTRUCT(likeType);
349 25 : internalLength = likeForm->typlen;
350 25 : byValue = likeForm->typbyval;
351 25 : alignment = likeForm->typalign;
352 25 : storage = likeForm->typstorage;
353 25 : ReleaseSysCache(likeType);
354 : }
355 100 : if (internalLengthEl)
356 64 : internalLength = defGetTypeLength(internalLengthEl);
357 100 : if (inputNameEl)
358 97 : inputName = defGetQualifiedName(inputNameEl);
359 100 : if (outputNameEl)
360 97 : outputName = defGetQualifiedName(outputNameEl);
361 100 : if (receiveNameEl)
362 9 : receiveName = defGetQualifiedName(receiveNameEl);
363 100 : if (sendNameEl)
364 9 : sendName = defGetQualifiedName(sendNameEl);
365 100 : if (typmodinNameEl)
366 4 : typmodinName = defGetQualifiedName(typmodinNameEl);
367 100 : if (typmodoutNameEl)
368 4 : typmodoutName = defGetQualifiedName(typmodoutNameEl);
369 100 : if (analyzeNameEl)
5243 tgl 370 UBC 0 : analyzeName = defGetQualifiedName(analyzeNameEl);
851 tgl 371 CBC 100 : if (subscriptNameEl)
372 1 : subscriptName = defGetQualifiedName(subscriptNameEl);
5243 373 100 : if (categoryEl)
374 : {
375 6 : char *p = defGetString(categoryEl);
376 :
377 6 : category = p[0];
378 : /* restrict to non-control ASCII */
379 6 : if (category < 32 || category > 126)
5243 tgl 380 UBC 0 : ereport(ERROR,
381 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
382 : errmsg("invalid type category \"%s\": must be simple ASCII",
383 : p)));
384 : }
5243 tgl 385 CBC 100 : if (preferredEl)
386 6 : preferred = defGetBoolean(preferredEl);
387 100 : if (delimiterEl)
388 : {
5243 tgl 389 UBC 0 : char *p = defGetString(delimiterEl);
390 :
391 0 : delimiter = p[0];
392 : /* XXX shouldn't we restrict the delimiter? */
393 : }
5243 tgl 394 CBC 100 : if (elemTypeEl)
395 : {
4549 peter_e 396 7 : elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
397 : /* disallow arrays of pseudotypes */
5243 tgl 398 7 : if (get_typtype(elemType) == TYPTYPE_PSEUDO)
5243 tgl 399 UBC 0 : ereport(ERROR,
400 : (errcode(ERRCODE_DATATYPE_MISMATCH),
401 : errmsg("array element type cannot be %s",
402 : format_type_be(elemType))));
403 : }
5243 tgl 404 CBC 100 : if (defaultValueEl)
405 9 : defaultValue = defGetString(defaultValueEl);
406 100 : if (byValueEl)
407 7 : byValue = defGetBoolean(byValueEl);
408 100 : if (alignmentEl)
409 : {
410 27 : char *a = defGetString(alignmentEl);
411 :
412 : /*
413 : * Note: if argument was an unquoted identifier, parser will have
414 : * applied translations to it, so be prepared to recognize translated
415 : * type names as well as the nominal form.
416 : */
417 45 : if (pg_strcasecmp(a, "double") == 0 ||
418 36 : pg_strcasecmp(a, "float8") == 0 ||
419 18 : pg_strcasecmp(a, "pg_catalog.float8") == 0)
1131 420 9 : alignment = TYPALIGN_DOUBLE;
5243 421 21 : else if (pg_strcasecmp(a, "int4") == 0 ||
422 3 : pg_strcasecmp(a, "pg_catalog.int4") == 0)
1131 423 18 : alignment = TYPALIGN_INT;
5243 tgl 424 UBC 0 : else if (pg_strcasecmp(a, "int2") == 0 ||
425 0 : pg_strcasecmp(a, "pg_catalog.int2") == 0)
1131 426 0 : alignment = TYPALIGN_SHORT;
5243 427 0 : else if (pg_strcasecmp(a, "char") == 0 ||
428 0 : pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
1131 429 0 : alignment = TYPALIGN_CHAR;
430 : else
5243 431 0 : ereport(ERROR,
432 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
433 : errmsg("alignment \"%s\" not recognized", a)));
434 : }
5243 tgl 435 CBC 100 : if (storageEl)
436 : {
437 28 : char *a = defGetString(storageEl);
438 :
439 28 : if (pg_strcasecmp(a, "plain") == 0)
1131 440 9 : storage = TYPSTORAGE_PLAIN;
5243 441 19 : else if (pg_strcasecmp(a, "external") == 0)
1131 tgl 442 UBC 0 : storage = TYPSTORAGE_EXTERNAL;
5243 tgl 443 CBC 19 : else if (pg_strcasecmp(a, "extended") == 0)
1131 444 16 : storage = TYPSTORAGE_EXTENDED;
5243 445 3 : else if (pg_strcasecmp(a, "main") == 0)
1131 446 3 : storage = TYPSTORAGE_MAIN;
447 : else
5243 tgl 448 UBC 0 : ereport(ERROR,
449 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
450 : errmsg("storage \"%s\" not recognized", a)));
451 : }
4443 peter_e 452 CBC 100 : if (collatableEl)
453 2 : collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
454 :
455 : /*
456 : * make sure we have our required definitions
457 : */
7664 tgl 458 100 : if (inputName == NIL)
7203 459 3 : ereport(ERROR,
460 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
461 : errmsg("type input function must be specified")));
7664 462 97 : if (outputName == NIL)
7203 tgl 463 UBC 0 : ereport(ERROR,
464 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
465 : errmsg("type output function must be specified")));
466 :
5944 tgl 467 CBC 97 : if (typmodinName == NIL && typmodoutName != NIL)
5944 tgl 468 UBC 0 : ereport(ERROR,
469 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
470 : errmsg("type modifier output function is useless without a type modifier input function")));
471 :
472 : /*
473 : * Convert I/O proc names to OIDs
474 : */
7276 tgl 475 CBC 97 : inputOid = findTypeInputFunction(inputName, typoid);
476 94 : outputOid = findTypeOutputFunction(outputName, typoid);
477 94 : if (receiveName)
478 9 : receiveOid = findTypeReceiveFunction(receiveName, typoid);
479 94 : if (sendName)
480 9 : sendOid = findTypeSendFunction(sendName, typoid);
481 :
482 : /*
483 : * Convert typmodin/out function proc names to OIDs.
484 : */
5944 485 94 : if (typmodinName)
486 4 : typmodinOid = findTypeTypmodinFunction(typmodinName);
487 94 : if (typmodoutName)
488 4 : typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
489 :
490 : /*
491 : * Convert analysis function proc name to an OID. If no analysis function
492 : * is specified, we'll use zero to select the built-in default algorithm.
493 : */
6996 494 94 : if (analyzeName)
6996 tgl 495 UBC 0 : analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
496 :
497 : /*
498 : * Likewise look up the subscripting function if any. If it is not
499 : * specified, but a typelem is specified, allow that if
500 : * raw_array_subscript_handler can be used. (This is for backwards
501 : * compatibility; maybe someday we should throw an error instead.)
502 : */
851 tgl 503 CBC 94 : if (subscriptName)
504 1 : subscriptOid = findTypeSubscriptingFunction(subscriptName, typoid);
505 93 : else if (OidIsValid(elemType))
506 : {
507 3 : if (internalLength > 0 && !byValue && get_typlen(elemType) > 0)
508 3 : subscriptOid = F_RAW_ARRAY_SUBSCRIPT_HANDLER;
509 : else
851 tgl 510 UBC 0 : ereport(ERROR,
511 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
512 : errmsg("element type cannot be specified without a subscripting function")));
513 : }
514 :
515 : /*
516 : * Check permissions on functions. We choose to require the creator/owner
517 : * of a type to also own the underlying functions. Since creating a type
518 : * is tantamount to granting public execute access on the functions, the
519 : * minimum sane check would be for execute-with-grant-option. But we
520 : * don't have a way to make the type go away if the grant option is
521 : * revoked, so ownership seems better.
522 : *
523 : * XXX For now, this is all unnecessary given the superuser check above.
524 : * If we ever relax that, these calls likely should be moved into
525 : * findTypeInputFunction et al, where they could be shared by AlterType.
526 : */
527 : #ifdef NOT_USED
528 : if (inputOid && !object_ownercheck(ProcedureRelationId, inputOid, GetUserId()))
529 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
530 : NameListToString(inputName));
531 : if (outputOid && !object_ownercheck(ProcedureRelationId, outputOid, GetUserId()))
532 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
533 : NameListToString(outputName));
534 : if (receiveOid && !object_ownercheck(ProcedureRelationId, receiveOid, GetUserId()))
535 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
536 : NameListToString(receiveName));
537 : if (sendOid && !object_ownercheck(ProcedureRelationId, sendOid, GetUserId()))
538 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
539 : NameListToString(sendName));
540 : if (typmodinOid && !object_ownercheck(ProcedureRelationId, typmodinOid, GetUserId()))
541 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
542 : NameListToString(typmodinName));
543 : if (typmodoutOid && !object_ownercheck(ProcedureRelationId, typmodoutOid, GetUserId()))
544 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
545 : NameListToString(typmodoutName));
546 : if (analyzeOid && !object_ownercheck(ProcedureRelationId, analyzeOid, GetUserId()))
547 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
548 : NameListToString(analyzeName));
549 : if (subscriptOid && !object_ownercheck(ProcedureRelationId, subscriptOid, GetUserId()))
550 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
551 : NameListToString(subscriptName));
552 : #endif
553 :
554 : /*
555 : * OK, we're done checking, time to make the type. We must assign the
556 : * array type OID ahead of calling TypeCreate, since the base type and
557 : * array type each refer to the other.
558 : */
4854 bruce 559 CBC 94 : array_oid = AssignTypeArrayOid();
560 :
561 : /*
562 : * now have TypeCreate do all the real work.
563 : *
564 : * Note: the pg_type.oid is stored in user tables as array elements (base
565 : * types) in ArrayType and in composite types in DatumTupleFields. This
566 : * oid must be preserved by binary upgrades.
567 : */
568 : address =
5812 tgl 569 94 : TypeCreate(InvalidOid, /* no predetermined type OID */
570 : typeName, /* type name */
571 : typeNamespace, /* namespace */
572 : InvalidOid, /* relation oid (n/a here) */
573 : 0, /* relation kind (ditto) */
574 : GetUserId(), /* owner's ID */
575 : internalLength, /* internal size */
576 : TYPTYPE_BASE, /* type-type (base type) */
577 : category, /* type-category */
578 : preferred, /* is it a preferred type? */
579 : delimiter, /* array element delimiter */
580 : inputOid, /* input procedure */
581 : outputOid, /* output procedure */
582 : receiveOid, /* receive procedure */
583 : sendOid, /* send procedure */
584 : typmodinOid, /* typmodin procedure */
585 : typmodoutOid, /* typmodout procedure */
586 : analyzeOid, /* analyze procedure */
587 : subscriptOid, /* subscript procedure */
588 : elemType, /* element type ID */
589 : false, /* this is not an implicit array type */
590 : array_oid, /* array type we are about to create */
591 : InvalidOid, /* base type ID (only for domains) */
592 : defaultValue, /* default type value */
593 : NULL, /* no binary form available */
594 : byValue, /* passed by value */
595 : alignment, /* required alignment */
596 : storage, /* TOAST strategy */
597 : -1, /* typMod (Domains only) */
598 : 0, /* Array Dimensions of typbasetype */
599 : false, /* Type NOT NULL */
600 : collation); /* type's collation */
2909 alvherre 601 94 : Assert(typoid == address.objectId);
602 :
603 : /*
604 : * Create the array type that goes with it.
605 : */
5812 tgl 606 94 : array_type = makeArrayTypeName(typeName, typeNamespace);
607 :
608 : /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
1131 609 94 : alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
610 :
3149 alvherre 611 94 : TypeCreate(array_oid, /* force assignment of this type OID */
612 : array_type, /* type name */
613 : typeNamespace, /* namespace */
614 : InvalidOid, /* relation oid (n/a here) */
615 : 0, /* relation kind (ditto) */
616 : GetUserId(), /* owner's ID */
617 : -1, /* internal size (always varlena) */
618 : TYPTYPE_BASE, /* type-type (base type) */
619 : TYPCATEGORY_ARRAY, /* type-category (array) */
620 : false, /* array types are never preferred */
621 : delimiter, /* array element delimiter */
622 : F_ARRAY_IN, /* input procedure */
623 : F_ARRAY_OUT, /* output procedure */
624 : F_ARRAY_RECV, /* receive procedure */
625 : F_ARRAY_SEND, /* send procedure */
626 : typmodinOid, /* typmodin procedure */
627 : typmodoutOid, /* typmodout procedure */
628 : F_ARRAY_TYPANALYZE, /* analyze procedure */
629 : F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
630 : typoid, /* element type ID */
631 : true, /* yes this is an array type */
632 : InvalidOid, /* no further array type */
633 : InvalidOid, /* base type ID */
634 : NULL, /* never a default type value */
635 : NULL, /* binary default isn't sent either */
636 : false, /* never passed by value */
637 : alignment, /* see above */
638 : TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
639 : -1, /* typMod (Domains only) */
640 : 0, /* Array dimensions of typbasetype */
641 : false, /* Type NOT NULL */
642 : collation); /* type's collation */
643 :
5812 tgl 644 94 : pfree(array_type);
645 :
2959 alvherre 646 94 : return address;
647 : }
648 :
649 : /*
650 : * Guts of type deletion.
651 : */
652 : void
7576 tgl 653 29759 : RemoveTypeById(Oid typeOid)
654 : {
655 : Relation relation;
656 : HeapTuple tup;
657 :
1539 andres 658 29759 : relation = table_open(TypeRelationId, RowExclusiveLock);
659 :
4802 rhaas 660 29759 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
7664 tgl 661 29759 : if (!HeapTupleIsValid(tup))
7203 tgl 662 UBC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
663 :
2258 tgl 664 CBC 29759 : CatalogTupleDelete(relation, &tup->t_self);
665 :
666 : /*
667 : * If it is an enum, delete the pg_enum entries too; we don't bother with
668 : * making dependency entries for those, so it has to be done "by hand"
669 : * here.
670 : */
5851 671 29759 : if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
672 156 : EnumValuesDelete(typeOid);
673 :
674 : /*
675 : * If it is a range type, delete the pg_range entry too; we don't bother
676 : * with making a dependency entry for that, so it has to be done "by hand"
677 : * here.
678 : */
4175 heikki.linnakangas 679 29759 : if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
680 45 : RangeDelete(typeOid);
681 :
7664 tgl 682 29759 : ReleaseSysCache(tup);
683 :
1539 andres 684 29759 : table_close(relation, RowExclusiveLock);
7664 tgl 685 29759 : }
686 :
687 :
688 : /*
689 : * DefineDomain
690 : * Registers a new domain.
691 : */
692 : ObjectAddress
693 1862 : DefineDomain(CreateDomainStmt *stmt)
694 : {
695 : char *domainName;
696 : char *domainArrayName;
697 : Oid domainNamespace;
698 : AclResult aclresult;
699 : int16 internalLength;
700 : Oid inputProcedure;
701 : Oid outputProcedure;
702 : Oid receiveProcedure;
703 : Oid sendProcedure;
704 : Oid analyzeProcedure;
705 : bool byValue;
706 : char category;
707 : char delimiter;
708 : char alignment;
709 : char storage;
710 : char typtype;
711 : Datum datum;
712 : bool isnull;
713 1862 : char *defaultValue = NULL;
714 1862 : char *defaultValueBin = NULL;
5772 715 1862 : bool saw_default = false;
7664 716 1862 : bool typNotNull = false;
7572 717 1862 : bool nullDefined = false;
5015 peter_e 718 1862 : int32 typNDims = list_length(stmt->typeName->arrayBounds);
719 : HeapTuple typeTup;
7664 tgl 720 1862 : List *schema = stmt->constraints;
721 : ListCell *listptr;
722 : Oid basetypeoid;
723 : Oid old_type_oid;
724 : Oid domaincoll;
725 : Oid domainArrayOid;
726 : Form_pg_type baseType;
727 : int32 basetypeMod;
728 : Oid baseColl;
729 : ObjectAddress address;
730 :
731 : /* Convert list of names to a name and namespace */
732 1862 : domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
733 : &domainName);
734 :
735 : /* Check we have creation rights in target namespace */
147 peter 736 GNC 1862 : aclresult = object_aclcheck(NamespaceRelationId, domainNamespace, GetUserId(),
737 : ACL_CREATE);
7652 tgl 738 CBC 1862 : if (aclresult != ACLCHECK_OK)
1954 peter_e 739 UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7191 tgl 740 0 : get_namespace_name(domainNamespace));
741 :
742 : /*
743 : * Check for collision with an existing type name. If there is one and
744 : * it's an autogenerated array, we can rename it out of the way.
745 : */
1601 andres 746 CBC 1862 : old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
747 : CStringGetDatum(domainName),
748 : ObjectIdGetDatum(domainNamespace));
5811 tgl 749 1862 : if (OidIsValid(old_type_oid))
750 : {
5811 tgl 751 UBC 0 : if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
752 0 : ereport(ERROR,
753 : (errcode(ERRCODE_DUPLICATE_OBJECT),
754 : errmsg("type \"%s\" already exists", domainName)));
755 : }
756 :
757 : /*
758 : * Look up the base type.
759 : */
4414 tgl 760 CBC 1862 : typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
7576 761 1862 : baseType = (Form_pg_type) GETSTRUCT(typeTup);
1601 andres 762 1862 : basetypeoid = baseType->oid;
763 :
764 : /*
765 : * Base type must be a plain base type, a composite type, another domain,
766 : * an enum or a range type. Domains over pseudotypes would create a
767 : * security hole. (It would be shorter to code this to just check for
768 : * pseudotypes; but it seems safer to call out the specific typtypes that
769 : * are supported, rather than assume that all future typtypes would be
770 : * automatically supported.)
771 : */
7576 tgl 772 1862 : typtype = baseType->typtype;
5851 773 1862 : if (typtype != TYPTYPE_BASE &&
1991 774 31 : typtype != TYPTYPE_COMPOSITE &&
5851 775 9 : typtype != TYPTYPE_DOMAIN &&
4175 heikki.linnakangas 776 6 : typtype != TYPTYPE_ENUM &&
840 akorotkov 777 3 : typtype != TYPTYPE_RANGE &&
778 : typtype != TYPTYPE_MULTIRANGE)
7203 tgl 779 UBC 0 : ereport(ERROR,
780 : (errcode(ERRCODE_DATATYPE_MISMATCH),
781 : errmsg("\"%s\" is not a valid base type for a domain",
782 : TypeNameToString(stmt->typeName))));
783 :
147 peter 784 GNC 1862 : aclresult = object_aclcheck(TypeRelationId, basetypeoid, GetUserId(), ACL_USAGE);
4128 peter_e 785 CBC 1862 : if (aclresult != ACLCHECK_OK)
3950 786 3 : aclcheck_error_type(aclresult, basetypeoid);
787 :
788 : /*
789 : * Collect the properties of the new domain. Some are inherited from the
790 : * base type, some are not. If you change any of this inheritance
791 : * behavior, be sure to update AlterTypeRecurse() to match!
792 : */
793 :
794 : /*
795 : * Identify the collation if any
796 : */
4414 tgl 797 1859 : baseColl = baseType->typcollation;
798 1859 : if (stmt->collClause)
4412 799 631 : domaincoll = get_collation_oid(stmt->collClause->collname, false);
800 : else
4414 801 1228 : domaincoll = baseColl;
802 :
803 : /* Complain if COLLATE is applied to an uncollatable type */
804 1859 : if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
805 9 : ereport(ERROR,
806 : (errcode(ERRCODE_DATATYPE_MISMATCH),
807 : errmsg("collations are not supported by type %s",
808 : format_type_be(basetypeoid))));
809 :
810 : /* passed by value */
7576 811 1850 : byValue = baseType->typbyval;
812 :
813 : /* Required Alignment */
814 1850 : alignment = baseType->typalign;
815 :
816 : /* TOAST Strategy */
817 1850 : storage = baseType->typstorage;
818 :
819 : /* Storage Length */
820 1850 : internalLength = baseType->typlen;
821 :
822 : /* Type Category */
5366 823 1850 : category = baseType->typcategory;
824 :
825 : /* Array element Delimiter */
7576 826 1850 : delimiter = baseType->typdelim;
827 :
828 : /* I/O Functions */
6213 829 1850 : inputProcedure = F_DOMAIN_IN;
7576 830 1850 : outputProcedure = baseType->typoutput;
6213 831 1850 : receiveProcedure = F_DOMAIN_RECV;
7276 832 1850 : sendProcedure = baseType->typsend;
833 :
834 : /* Domains never accept typmods, so no typmodin/typmodout needed */
835 :
836 : /* Analysis function */
6996 837 1850 : analyzeProcedure = baseType->typanalyze;
838 :
839 : /*
840 : * Domains don't need a subscript function, since they are not
841 : * subscriptable on their own. If the base type is subscriptable, the
842 : * parser will reduce the type to the base type before subscripting.
843 : */
844 :
845 : /* Inherited default value */
7522 bruce 846 1850 : datum = SysCacheGetAttr(TYPEOID, typeTup,
847 : Anum_pg_type_typdefault, &isnull);
7664 tgl 848 1850 : if (!isnull)
5493 tgl 849 UBC 0 : defaultValue = TextDatumGetCString(datum);
850 :
851 : /* Inherited default binary value */
7522 bruce 852 CBC 1850 : datum = SysCacheGetAttr(TYPEOID, typeTup,
853 : Anum_pg_type_typdefaultbin, &isnull);
7664 tgl 854 1850 : if (!isnull)
5493 tgl 855 UBC 0 : defaultValueBin = TextDatumGetCString(datum);
856 :
857 : /*
858 : * Run through constraints manually to avoid the additional processing
859 : * conducted by DefineRelation() and friends.
860 : */
7664 tgl 861 CBC 2939 : foreach(listptr, schema)
862 : {
5001 863 1089 : Constraint *constr = lfirst(listptr);
864 :
865 1089 : if (!IsA(constr, Constraint))
7203 tgl 866 UBC 0 : elog(ERROR, "unrecognized node type: %d",
867 : (int) nodeTag(constr));
7203 tgl 868 CBC 1089 : switch (constr->contype)
869 : {
7426 870 324 : case CONSTR_DEFAULT:
871 :
872 : /*
873 : * The inherited default value may be overridden by the user
874 : * with the DEFAULT <expr> clause ... but only once.
875 : */
5772 876 324 : if (saw_default)
7203 tgl 877 UBC 0 : ereport(ERROR,
878 : (errcode(ERRCODE_SYNTAX_ERROR),
879 : errmsg("multiple default expressions")));
5772 tgl 880 CBC 324 : saw_default = true;
881 :
882 324 : if (constr->raw_expr)
883 : {
884 : ParseState *pstate;
885 : Node *defaultExpr;
886 :
887 : /* Create a dummy ParseState for transformExpr */
888 324 : pstate = make_parsestate(NULL);
889 :
890 : /*
891 : * Cook the constr->raw_expr into an expression. Note:
892 : * name is strictly for error message
893 : */
894 324 : defaultExpr = cookDefault(pstate, constr->raw_expr,
895 : basetypeoid,
896 : basetypeMod,
897 : domainName,
898 : 0);
899 :
900 : /*
901 : * If the expression is just a NULL constant, we treat it
902 : * like not having a default.
903 : *
904 : * Note that if the basetype is another domain, we'll see
905 : * a CoerceToDomain expr here and not discard the default.
906 : * This is critical because the domain default needs to be
907 : * retained to override any default that the base domain
908 : * might have.
909 : */
5641 910 324 : if (defaultExpr == NULL ||
911 324 : (IsA(defaultExpr, Const) &&
912 12 : ((Const *) defaultExpr)->constisnull))
913 : {
5641 tgl 914 UBC 0 : defaultValue = NULL;
915 0 : defaultValueBin = NULL;
916 : }
917 : else
918 : {
919 : /*
920 : * Expression must be stored as a nodeToString result,
921 : * but we also require a valid textual representation
922 : * (mainly to make life easier for pg_dump).
923 : */
924 : defaultValue =
5641 tgl 925 CBC 324 : deparse_expression(defaultExpr,
926 : NIL, false, false);
927 324 : defaultValueBin = nodeToString(defaultExpr);
928 : }
929 : }
930 : else
931 : {
932 : /* No default (can this still happen?) */
5772 tgl 933 UBC 0 : defaultValue = NULL;
934 0 : defaultValueBin = NULL;
935 : }
7664 tgl 936 CBC 324 : break;
937 :
938 30 : case CONSTR_NOTNULL:
7423 939 30 : if (nullDefined && !typNotNull)
7203 tgl 940 UBC 0 : ereport(ERROR,
941 : (errcode(ERRCODE_SYNTAX_ERROR),
942 : errmsg("conflicting NULL/NOT NULL constraints")));
7572 tgl 943 CBC 30 : typNotNull = true;
944 30 : nullDefined = true;
7522 bruce 945 30 : break;
946 :
7664 tgl 947 UBC 0 : case CONSTR_NULL:
7423 948 0 : if (nullDefined && typNotNull)
7203 949 0 : ereport(ERROR,
950 : (errcode(ERRCODE_SYNTAX_ERROR),
951 : errmsg("conflicting NULL/NOT NULL constraints")));
7572 952 0 : typNotNull = false;
953 0 : nullDefined = true;
7188 bruce 954 0 : break;
955 :
7188 bruce 956 CBC 735 : case CONSTR_CHECK:
957 :
958 : /*
959 : * Check constraints are handled after domain creation, as
960 : * they require the Oid of the domain; at this point we can
961 : * only check that they're not marked NO INHERIT, because that
962 : * would be bogus.
963 : */
3911 alvherre 964 735 : if (constr->is_no_inherit)
3911 alvherre 965 UBC 0 : ereport(ERROR,
966 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
967 : errmsg("check constraints for domains cannot be marked NO INHERIT")));
7188 bruce 968 CBC 735 : break;
969 :
970 : /*
971 : * All else are error cases
972 : */
7188 bruce 973 UBC 0 : case CONSTR_UNIQUE:
974 0 : ereport(ERROR,
975 : (errcode(ERRCODE_SYNTAX_ERROR),
976 : errmsg("unique constraints not possible for domains")));
977 : break;
978 :
979 0 : case CONSTR_PRIMARY:
980 0 : ereport(ERROR,
981 : (errcode(ERRCODE_SYNTAX_ERROR),
982 : errmsg("primary key constraints not possible for domains")));
983 : break;
984 :
4871 tgl 985 0 : case CONSTR_EXCLUSION:
986 0 : ereport(ERROR,
987 : (errcode(ERRCODE_SYNTAX_ERROR),
988 : errmsg("exclusion constraints not possible for domains")));
989 : break;
990 :
5001 991 0 : case CONSTR_FOREIGN:
992 0 : ereport(ERROR,
993 : (errcode(ERRCODE_SYNTAX_ERROR),
994 : errmsg("foreign key constraints not possible for domains")));
995 : break;
996 :
7188 bruce 997 0 : case CONSTR_ATTR_DEFERRABLE:
998 : case CONSTR_ATTR_NOT_DEFERRABLE:
999 : case CONSTR_ATTR_DEFERRED:
1000 : case CONSTR_ATTR_IMMEDIATE:
1001 0 : ereport(ERROR,
1002 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1003 : errmsg("specifying constraint deferrability not supported for domains")));
1004 : break;
1005 :
7664 tgl 1006 0 : default:
7203 1007 0 : elog(ERROR, "unrecognized constraint subtype: %d",
1008 : (int) constr->contype);
1009 : break;
1010 : }
1011 : }
1012 :
1013 : /* Allocate OID for array type */
2017 tgl 1014 CBC 1850 : domainArrayOid = AssignTypeArrayOid();
1015 :
1016 : /*
1017 : * Have TypeCreate do all the real work.
1018 : */
1019 : address =
5812 1020 1850 : TypeCreate(InvalidOid, /* no predetermined type OID */
1021 : domainName, /* type name */
1022 : domainNamespace, /* namespace */
1023 : InvalidOid, /* relation oid (n/a here) */
1024 : 0, /* relation kind (ditto) */
1025 : GetUserId(), /* owner's ID */
1026 : internalLength, /* internal size */
1027 : TYPTYPE_DOMAIN, /* type-type (domain type) */
1028 : category, /* type-category */
1029 : false, /* domain types are never preferred */
1030 : delimiter, /* array element delimiter */
1031 : inputProcedure, /* input procedure */
1032 : outputProcedure, /* output procedure */
1033 : receiveProcedure, /* receive procedure */
1034 : sendProcedure, /* send procedure */
1035 : InvalidOid, /* typmodin procedure - none */
1036 : InvalidOid, /* typmodout procedure - none */
1037 : analyzeProcedure, /* analyze procedure */
1038 : InvalidOid, /* subscript procedure - none */
1039 : InvalidOid, /* no array element type */
1040 : false, /* this isn't an array */
1041 : domainArrayOid, /* array type we are about to create */
1042 : basetypeoid, /* base type ID */
1043 : defaultValue, /* default type value (text) */
1044 : defaultValueBin, /* default type value (binary) */
1045 : byValue, /* passed by value */
1046 : alignment, /* required alignment */
1047 : storage, /* TOAST strategy */
1048 : basetypeMod, /* typeMod value */
1049 : typNDims, /* Array dimensions for base type */
1050 : typNotNull, /* Type NOT NULL */
1051 : domaincoll); /* type's collation */
1052 :
1053 : /*
1054 : * Create the array type that goes with it.
1055 : */
2017 1056 1850 : domainArrayName = makeArrayTypeName(domainName, domainNamespace);
1057 :
1058 : /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
1131 1059 1850 : alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1060 :
2017 1061 1850 : TypeCreate(domainArrayOid, /* force assignment of this type OID */
1062 : domainArrayName, /* type name */
1063 : domainNamespace, /* namespace */
1064 : InvalidOid, /* relation oid (n/a here) */
1065 : 0, /* relation kind (ditto) */
1066 : GetUserId(), /* owner's ID */
1067 : -1, /* internal size (always varlena) */
1068 : TYPTYPE_BASE, /* type-type (base type) */
1069 : TYPCATEGORY_ARRAY, /* type-category (array) */
1070 : false, /* array types are never preferred */
1071 : delimiter, /* array element delimiter */
1072 : F_ARRAY_IN, /* input procedure */
1073 : F_ARRAY_OUT, /* output procedure */
1074 : F_ARRAY_RECV, /* receive procedure */
1075 : F_ARRAY_SEND, /* send procedure */
1076 : InvalidOid, /* typmodin procedure - none */
1077 : InvalidOid, /* typmodout procedure - none */
1078 : F_ARRAY_TYPANALYZE, /* analyze procedure */
1079 : F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1080 : address.objectId, /* element type ID */
1081 : true, /* yes this is an array type */
1082 : InvalidOid, /* no further array type */
1083 : InvalidOid, /* base type ID */
1084 : NULL, /* never a default type value */
1085 : NULL, /* binary default isn't sent either */
1086 : false, /* never passed by value */
1087 : alignment, /* see above */
1088 : TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1089 : -1, /* typMod (Domains only) */
1090 : 0, /* Array dimensions of typbasetype */
1091 : false, /* Type NOT NULL */
1092 : domaincoll); /* type's collation */
1093 :
1094 1850 : pfree(domainArrayName);
1095 :
1096 : /*
1097 : * Process constraints which refer to the domain ID returned by TypeCreate
1098 : */
7450 bruce 1099 2939 : foreach(listptr, schema)
1100 : {
1101 1089 : Constraint *constr = lfirst(listptr);
1102 :
1103 : /* it must be a Constraint, per check above */
1104 :
1105 1089 : switch (constr->contype)
1106 : {
7188 1107 735 : case CONSTR_CHECK:
2959 alvherre 1108 735 : domainAddConstraint(address.objectId, domainNamespace,
1109 : basetypeoid, basetypeMod,
1110 : constr, domainName, NULL);
7188 bruce 1111 735 : break;
1112 :
1113 : /* Other constraint types were fully processed above */
1114 :
7450 1115 354 : default:
7188 1116 354 : break;
1117 : }
1118 :
1119 : /* CCI so we can detect duplicate constraint names */
6877 tgl 1120 1089 : CommandCounterIncrement();
1121 : }
1122 :
1123 : /*
1124 : * Now we can clean up.
1125 : */
7664 1126 1850 : ReleaseSysCache(typeTup);
1127 :
2959 alvherre 1128 1850 : return address;
1129 : }
1130 :
1131 :
1132 : /*
1133 : * DefineEnum
1134 : * Registers a new enum.
1135 : */
1136 : ObjectAddress
5624 bruce 1137 208 : DefineEnum(CreateEnumStmt *stmt)
1138 : {
1139 : char *enumName;
1140 : char *enumArrayName;
1141 : Oid enumNamespace;
1142 : AclResult aclresult;
1143 : Oid old_type_oid;
1144 : Oid enumArrayOid;
1145 : ObjectAddress enumTypeAddr;
1146 :
1147 : /* Convert list of names to a name and namespace */
5015 peter_e 1148 208 : enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1149 : &enumName);
1150 :
1151 : /* Check we have creation rights in target namespace */
147 peter 1152 GNC 208 : aclresult = object_aclcheck(NamespaceRelationId, enumNamespace, GetUserId(), ACL_CREATE);
5851 tgl 1153 CBC 208 : if (aclresult != ACLCHECK_OK)
1954 peter_e 1154 UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
5851 tgl 1155 0 : get_namespace_name(enumNamespace));
1156 :
1157 : /*
1158 : * Check for collision with an existing type name. If there is one and
1159 : * it's an autogenerated array, we can rename it out of the way.
1160 : */
1601 andres 1161 CBC 208 : old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1162 : CStringGetDatum(enumName),
1163 : ObjectIdGetDatum(enumNamespace));
5811 tgl 1164 208 : if (OidIsValid(old_type_oid))
1165 : {
1166 4 : if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
5811 tgl 1167 UBC 0 : ereport(ERROR,
1168 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1169 : errmsg("type \"%s\" already exists", enumName)));
1170 : }
1171 :
1172 : /* Allocate OID for array type */
4854 bruce 1173 CBC 208 : enumArrayOid = AssignTypeArrayOid();
1174 :
1175 : /* Create the pg_type entry */
1176 : enumTypeAddr =
5624 1177 208 : TypeCreate(InvalidOid, /* no predetermined type OID */
1178 : enumName, /* type name */
1179 : enumNamespace, /* namespace */
1180 : InvalidOid, /* relation oid (n/a here) */
1181 : 0, /* relation kind (ditto) */
1182 : GetUserId(), /* owner's ID */
1183 : sizeof(Oid), /* internal size */
1184 : TYPTYPE_ENUM, /* type-type (enum type) */
1185 : TYPCATEGORY_ENUM, /* type-category (enum type) */
1186 : false, /* enum types are never preferred */
1187 : DEFAULT_TYPDELIM, /* array element delimiter */
1188 : F_ENUM_IN, /* input procedure */
1189 : F_ENUM_OUT, /* output procedure */
1190 : F_ENUM_RECV, /* receive procedure */
1191 : F_ENUM_SEND, /* send procedure */
1192 : InvalidOid, /* typmodin procedure - none */
1193 : InvalidOid, /* typmodout procedure - none */
1194 : InvalidOid, /* analyze procedure - default */
1195 : InvalidOid, /* subscript procedure - none */
1196 : InvalidOid, /* element type ID */
1197 : false, /* this is not an array type */
1198 : enumArrayOid, /* array type we are about to create */
1199 : InvalidOid, /* base type ID (only for domains) */
1200 : NULL, /* never a default type value */
1201 : NULL, /* binary default isn't sent either */
1202 : true, /* always passed by value */
1203 : TYPALIGN_INT, /* int alignment */
1204 : TYPSTORAGE_PLAIN, /* TOAST strategy always plain */
1205 : -1, /* typMod (Domains only) */
1206 : 0, /* Array dimensions of typbasetype */
1207 : false, /* Type NOT NULL */
1208 : InvalidOid); /* type's collation */
1209 :
1210 : /* Enter the enum's values into pg_enum */
2959 alvherre 1211 207 : EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1212 :
1213 : /*
1214 : * Create the array type that goes with it.
1215 : */
5812 tgl 1216 207 : enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1217 :
1218 207 : TypeCreate(enumArrayOid, /* force assignment of this type OID */
1219 : enumArrayName, /* type name */
1220 : enumNamespace, /* namespace */
1221 : InvalidOid, /* relation oid (n/a here) */
1222 : 0, /* relation kind (ditto) */
1223 : GetUserId(), /* owner's ID */
1224 : -1, /* internal size (always varlena) */
1225 : TYPTYPE_BASE, /* type-type (base type) */
1226 : TYPCATEGORY_ARRAY, /* type-category (array) */
1227 : false, /* array types are never preferred */
1228 : DEFAULT_TYPDELIM, /* array element delimiter */
1229 : F_ARRAY_IN, /* input procedure */
1230 : F_ARRAY_OUT, /* output procedure */
1231 : F_ARRAY_RECV, /* receive procedure */
1232 : F_ARRAY_SEND, /* send procedure */
1233 : InvalidOid, /* typmodin procedure - none */
1234 : InvalidOid, /* typmodout procedure - none */
1235 : F_ARRAY_TYPANALYZE, /* analyze procedure */
1236 : F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1237 : enumTypeAddr.objectId, /* element type ID */
1238 : true, /* yes this is an array type */
1239 : InvalidOid, /* no further array type */
1240 : InvalidOid, /* base type ID */
1241 : NULL, /* never a default type value */
1242 : NULL, /* binary default isn't sent either */
1243 : false, /* never passed by value */
1244 : TYPALIGN_INT, /* enums have int align, so do their arrays */
1245 : TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1246 : -1, /* typMod (Domains only) */
1247 : 0, /* Array dimensions of typbasetype */
1248 : false, /* Type NOT NULL */
1249 : InvalidOid); /* type's collation */
1250 :
5851 1251 207 : pfree(enumArrayName);
1252 :
2959 alvherre 1253 207 : return enumTypeAddr;
1254 : }
1255 :
1256 : /*
1257 : * AlterEnum
1258 : * Adds a new label to an existing enum.
1259 : */
1260 : ObjectAddress
1643 tmunro 1261 191 : AlterEnum(AlterEnumStmt *stmt)
1262 : {
1263 : Oid enum_type_oid;
1264 : TypeName *typename;
1265 : HeapTuple tup;
1266 : ObjectAddress address;
1267 :
1268 : /* Make a TypeName so we can use standard type lookup machinery */
4157 tgl 1269 191 : typename = makeTypeNameFromNameList(stmt->typeName);
1270 191 : enum_type_oid = typenameTypeId(NULL, typename);
1271 :
1272 191 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1273 191 : if (!HeapTupleIsValid(tup))
4157 tgl 1274 UBC 0 : elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1275 :
1276 : /* Check it's an enum and check user has permission to ALTER the enum */
4157 tgl 1277 CBC 191 : checkEnumOwner(tup);
1278 :
1643 tmunro 1279 191 : ReleaseSysCache(tup);
1280 :
2405 tgl 1281 191 : if (stmt->oldVal)
1282 : {
1283 : /* Rename an existing label */
1284 12 : RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1285 : }
1286 : else
1287 : {
1288 : /* Add a new label */
1289 179 : AddEnumLabel(enum_type_oid, stmt->newVal,
1290 179 : stmt->newValNeighbor, stmt->newValIsAfter,
1291 179 : stmt->skipIfNewValExists);
1292 : }
1293 :
3675 rhaas 1294 176 : InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1295 :
2959 alvherre 1296 176 : ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1297 :
1298 176 : return address;
1299 : }
1300 :
1301 :
1302 : /*
1303 : * checkEnumOwner
1304 : *
1305 : * Check that the type is actually an enum and that the current user
1306 : * has permission to do ALTER TYPE on it. Throw an error if not.
1307 : */
1308 : static void
4157 tgl 1309 191 : checkEnumOwner(HeapTuple tup)
1310 : {
1311 191 : Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1312 :
1313 : /* Check that this is actually an enum */
1314 191 : if (typTup->typtype != TYPTYPE_ENUM)
4157 tgl 1315 UBC 0 : ereport(ERROR,
1316 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1317 : errmsg("%s is not an enum",
1318 : format_type_be(typTup->oid))));
1319 :
1320 : /* Permission check: must own type */
147 peter 1321 GNC 191 : if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
1601 andres 1322 UBC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
4157 tgl 1323 CBC 191 : }
1324 :
1325 :
1326 : /*
1327 : * DefineRange
1328 : * Registers a new range type.
1329 : *
1330 : * Perhaps it might be worthwhile to set pg_type.typelem to the base type,
1331 : * and likewise on multiranges to set it to the range type. But having a
1332 : * non-zero typelem is treated elsewhere as a synonym for being an array,
1333 : * and users might have queries with that same assumption.
1334 : */
1335 : ObjectAddress
633 dean.a.rasheed 1336 76 : DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
1337 : {
1338 : char *typeName;
1339 : Oid typeNamespace;
1340 : Oid typoid;
1341 : char *rangeArrayName;
840 akorotkov 1342 76 : char *multirangeTypeName = NULL;
1343 : char *multirangeArrayName;
1344 76 : Oid multirangeNamespace = InvalidOid;
1345 : Oid rangeArrayOid;
1346 : Oid multirangeOid;
1347 : Oid multirangeArrayOid;
4157 tgl 1348 76 : Oid rangeSubtype = InvalidOid;
4164 bruce 1349 76 : List *rangeSubOpclassName = NIL;
1350 76 : List *rangeCollationName = NIL;
4157 tgl 1351 76 : List *rangeCanonicalName = NIL;
1352 76 : List *rangeSubtypeDiffName = NIL;
1353 : Oid rangeSubOpclass;
1354 : Oid rangeCollation;
1355 : regproc rangeCanonical;
1356 : regproc rangeSubtypeDiff;
1357 : int16 subtyplen;
1358 : bool subtypbyval;
1359 : char subtypalign;
1360 : char alignment;
1361 : AclResult aclresult;
1362 : ListCell *lc;
1363 : ObjectAddress address;
1364 : ObjectAddress mltrngaddress PG_USED_FOR_ASSERTS_ONLY;
1365 : Oid castFuncOid;
1366 :
1367 : /* Convert list of names to a name and namespace */
4175 heikki.linnakangas 1368 76 : typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1369 : &typeName);
1370 :
1371 : /* Check we have creation rights in target namespace */
147 peter 1372 GNC 76 : aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
4175 heikki.linnakangas 1373 CBC 76 : if (aclresult != ACLCHECK_OK)
1954 peter_e 1374 UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
4175 heikki.linnakangas 1375 0 : get_namespace_name(typeNamespace));
1376 :
1377 : /*
1378 : * Look to see if type already exists.
1379 : */
1601 andres 1380 CBC 76 : typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1381 : CStringGetDatum(typeName),
1382 : ObjectIdGetDatum(typeNamespace));
1383 :
1384 : /*
1385 : * If it's not a shell, see if it's an autogenerated array type, and if so
1386 : * rename it out of the way.
1387 : */
4175 heikki.linnakangas 1388 76 : if (OidIsValid(typoid) && get_typisdefined(typoid))
1389 : {
4175 heikki.linnakangas 1390 UBC 0 : if (moveArrayTypeName(typoid, typeName, typeNamespace))
1391 0 : typoid = InvalidOid;
1392 : else
4157 tgl 1393 0 : ereport(ERROR,
1394 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1395 : errmsg("type \"%s\" already exists", typeName)));
1396 : }
1397 :
1398 : /*
1399 : * Unlike DefineType(), we don't insist on a shell type existing first, as
1400 : * it's only needed if the user wants to specify a canonical function.
1401 : */
1402 :
1403 : /* Extract the parameters from the parameter list */
4175 heikki.linnakangas 1404 CBC 205 : foreach(lc, stmt->params)
1405 : {
4157 tgl 1406 129 : DefElem *defel = (DefElem *) lfirst(lc);
1407 :
1899 1408 129 : if (strcmp(defel->defname, "subtype") == 0)
1409 : {
4175 heikki.linnakangas 1410 76 : if (OidIsValid(rangeSubtype))
633 dean.a.rasheed 1411 UBC 0 : errorConflictingDefElem(defel, pstate);
1412 : /* we can look up the subtype name immediately */
4175 heikki.linnakangas 1413 CBC 76 : rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1414 : }
1899 tgl 1415 53 : else if (strcmp(defel->defname, "subtype_opclass") == 0)
1416 : {
4157 1417 1 : if (rangeSubOpclassName != NIL)
633 dean.a.rasheed 1418 UBC 0 : errorConflictingDefElem(defel, pstate);
4157 tgl 1419 CBC 1 : rangeSubOpclassName = defGetQualifiedName(defel);
1420 : }
1899 1421 52 : else if (strcmp(defel->defname, "collation") == 0)
1422 : {
4175 heikki.linnakangas 1423 32 : if (rangeCollationName != NIL)
633 dean.a.rasheed 1424 UBC 0 : errorConflictingDefElem(defel, pstate);
4175 heikki.linnakangas 1425 CBC 32 : rangeCollationName = defGetQualifiedName(defel);
1426 : }
1899 tgl 1427 20 : else if (strcmp(defel->defname, "canonical") == 0)
1428 : {
4157 tgl 1429 UBC 0 : if (rangeCanonicalName != NIL)
633 dean.a.rasheed 1430 0 : errorConflictingDefElem(defel, pstate);
4157 tgl 1431 0 : rangeCanonicalName = defGetQualifiedName(defel);
1432 : }
1899 tgl 1433 CBC 20 : else if (strcmp(defel->defname, "subtype_diff") == 0)
1434 : {
4157 1435 7 : if (rangeSubtypeDiffName != NIL)
633 dean.a.rasheed 1436 UBC 0 : errorConflictingDefElem(defel, pstate);
4157 tgl 1437 CBC 7 : rangeSubtypeDiffName = defGetQualifiedName(defel);
1438 : }
840 akorotkov 1439 13 : else if (strcmp(defel->defname, "multirange_type_name") == 0)
1440 : {
1441 13 : if (multirangeTypeName != NULL)
633 dean.a.rasheed 1442 UBC 0 : errorConflictingDefElem(defel, pstate);
1443 : /* we can look up the subtype name immediately */
840 akorotkov 1444 CBC 13 : multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
1445 : &multirangeTypeName);
1446 : }
1447 : else
4175 heikki.linnakangas 1448 UBC 0 : ereport(ERROR,
1449 : (errcode(ERRCODE_SYNTAX_ERROR),
1450 : errmsg("type attribute \"%s\" not recognized",
1451 : defel->defname)));
1452 : }
1453 :
1454 : /* Must have a subtype */
4175 heikki.linnakangas 1455 CBC 76 : if (!OidIsValid(rangeSubtype))
4164 bruce 1456 UBC 0 : ereport(ERROR,
1457 : (errcode(ERRCODE_SYNTAX_ERROR),
1458 : errmsg("type attribute \"subtype\" is required")));
1459 : /* disallow ranges of pseudotypes */
4157 tgl 1460 CBC 76 : if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
4157 tgl 1461 UBC 0 : ereport(ERROR,
1462 : (errcode(ERRCODE_DATATYPE_MISMATCH),
1463 : errmsg("range subtype cannot be %s",
1464 : format_type_be(rangeSubtype))));
1465 :
1466 : /* Identify subopclass */
4157 tgl 1467 CBC 76 : rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1468 :
1469 : /* Identify collation to use, if any */
4175 heikki.linnakangas 1470 76 : if (type_is_collatable(rangeSubtype))
1471 : {
4157 tgl 1472 32 : if (rangeCollationName != NIL)
4175 heikki.linnakangas 1473 32 : rangeCollation = get_collation_oid(rangeCollationName, false);
1474 : else
4157 tgl 1475 UBC 0 : rangeCollation = get_typcollation(rangeSubtype);
1476 : }
1477 : else
1478 : {
4157 tgl 1479 CBC 44 : if (rangeCollationName != NIL)
4157 tgl 1480 UBC 0 : ereport(ERROR,
1481 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1482 : errmsg("range collation specified but subtype does not support collation")));
4157 tgl 1483 CBC 44 : rangeCollation = InvalidOid;
1484 : }
1485 :
1486 : /* Identify support functions, if provided */
1487 76 : if (rangeCanonicalName != NIL)
1488 : {
1130 tgl 1489 UBC 0 : if (!OidIsValid(typoid))
1490 0 : ereport(ERROR,
1491 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1492 : errmsg("cannot specify a canonical function without a pre-created shell type"),
1493 : errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
4157 1494 0 : rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1495 : typoid);
1496 : }
1497 : else
4157 tgl 1498 CBC 76 : rangeCanonical = InvalidOid;
1499 :
4175 heikki.linnakangas 1500 76 : if (rangeSubtypeDiffName != NIL)
4164 tgl 1501 7 : rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1502 : rangeSubtype);
1503 : else
4157 1504 69 : rangeSubtypeDiff = InvalidOid;
1505 :
4164 1506 73 : get_typlenbyvalalign(rangeSubtype,
1507 : &subtyplen, &subtypbyval, &subtypalign);
1508 :
1509 : /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
1131 1510 73 : alignment = (subtypalign == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1511 :
1512 : /* Allocate OID for array type, its multirange, and its multirange array */
4175 heikki.linnakangas 1513 73 : rangeArrayOid = AssignTypeArrayOid();
840 akorotkov 1514 73 : multirangeOid = AssignTypeMultirangeOid();
1515 73 : multirangeArrayOid = AssignTypeMultirangeArrayOid();
1516 :
1517 : /* Create the pg_type entry */
1518 : address =
4175 heikki.linnakangas 1519 73 : TypeCreate(InvalidOid, /* no predetermined type OID */
1520 : typeName, /* type name */
1521 : typeNamespace, /* namespace */
1522 : InvalidOid, /* relation oid (n/a here) */
1523 : 0, /* relation kind (ditto) */
1524 : GetUserId(), /* owner's ID */
1525 : -1, /* internal size (always varlena) */
1526 : TYPTYPE_RANGE, /* type-type (range type) */
1527 : TYPCATEGORY_RANGE, /* type-category (range type) */
1528 : false, /* range types are never preferred */
1529 : DEFAULT_TYPDELIM, /* array element delimiter */
1530 : F_RANGE_IN, /* input procedure */
1531 : F_RANGE_OUT, /* output procedure */
1532 : F_RANGE_RECV, /* receive procedure */
1533 : F_RANGE_SEND, /* send procedure */
1534 : InvalidOid, /* typmodin procedure - none */
1535 : InvalidOid, /* typmodout procedure - none */
1536 : F_RANGE_TYPANALYZE, /* analyze procedure */
1537 : InvalidOid, /* subscript procedure - none */
1538 : InvalidOid, /* element type ID - none */
1539 : false, /* this is not an array type */
1540 : rangeArrayOid, /* array type we are about to create */
1541 : InvalidOid, /* base type ID (only for domains) */
1542 : NULL, /* never a default type value */
1543 : NULL, /* no binary form available either */
1544 : false, /* never passed by value */
1545 : alignment, /* alignment */
1546 : TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
1547 : -1, /* typMod (Domains only) */
1548 : 0, /* Array dimensions of typbasetype */
1549 : false, /* Type NOT NULL */
1550 : InvalidOid); /* type's collation (ranges never have one) */
1130 tgl 1551 73 : Assert(typoid == InvalidOid || typoid == address.objectId);
1552 73 : typoid = address.objectId;
1553 :
1554 : /* Create the multirange that goes with it */
840 akorotkov 1555 73 : if (multirangeTypeName)
1556 : {
1557 : Oid old_typoid;
1558 :
1559 : /*
1560 : * Look to see if multirange type already exists.
1561 : */
1562 13 : old_typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1563 : CStringGetDatum(multirangeTypeName),
1564 : ObjectIdGetDatum(multirangeNamespace));
1565 :
1566 : /*
1567 : * If it's not a shell, see if it's an autogenerated array type, and
1568 : * if so rename it out of the way.
1569 : */
1570 13 : if (OidIsValid(old_typoid) && get_typisdefined(old_typoid))
1571 : {
1572 6 : if (!moveArrayTypeName(old_typoid, multirangeTypeName, multirangeNamespace))
1573 3 : ereport(ERROR,
1574 : (errcode(ERRCODE_DUPLICATE_OBJECT),
1575 : errmsg("type \"%s\" already exists", multirangeTypeName)));
1576 : }
1577 : }
1578 : else
1579 : {
1580 : /* Generate multirange name automatically */
1581 60 : multirangeNamespace = typeNamespace;
1582 60 : multirangeTypeName = makeMultirangeTypeName(typeName, multirangeNamespace);
1583 : }
1584 :
1585 : mltrngaddress =
1586 64 : TypeCreate(multirangeOid, /* force assignment of this type OID */
1587 : multirangeTypeName, /* type name */
1588 : multirangeNamespace, /* namespace */
1589 : InvalidOid, /* relation oid (n/a here) */
1590 : 0, /* relation kind (ditto) */
1591 : GetUserId(), /* owner's ID */
1592 : -1, /* internal size (always varlena) */
1593 : TYPTYPE_MULTIRANGE, /* type-type (multirange type) */
1594 : TYPCATEGORY_RANGE, /* type-category (range type) */
1595 : false, /* multirange types are never preferred */
1596 : DEFAULT_TYPDELIM, /* array element delimiter */
1597 : F_MULTIRANGE_IN, /* input procedure */
1598 : F_MULTIRANGE_OUT, /* output procedure */
1599 : F_MULTIRANGE_RECV, /* receive procedure */
1600 : F_MULTIRANGE_SEND, /* send procedure */
1601 : InvalidOid, /* typmodin procedure - none */
1602 : InvalidOid, /* typmodout procedure - none */
1603 : F_MULTIRANGE_TYPANALYZE, /* analyze procedure */
1604 : InvalidOid, /* subscript procedure - none */
1605 : InvalidOid, /* element type ID - none */
1606 : false, /* this is not an array type */
1607 : multirangeArrayOid, /* array type we are about to create */
1608 : InvalidOid, /* base type ID (only for domains) */
1609 : NULL, /* never a default type value */
1610 : NULL, /* no binary form available either */
1611 : false, /* never passed by value */
1612 : alignment, /* alignment */
1613 : 'x', /* TOAST strategy (always extended) */
1614 : -1, /* typMod (Domains only) */
1615 : 0, /* Array dimensions of typbasetype */
1616 : false, /* Type NOT NULL */
1617 : InvalidOid); /* type's collation (ranges never have one) */
1618 64 : Assert(multirangeOid == mltrngaddress.objectId);
1619 :
1620 : /* Create the entry in pg_range */
4175 heikki.linnakangas 1621 64 : RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1622 : rangeCanonical, rangeSubtypeDiff, multirangeOid);
1623 :
1624 : /*
1625 : * Create the array type that goes with it.
1626 : */
1627 64 : rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1628 :
1629 64 : TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1630 : rangeArrayName, /* type name */
1631 : typeNamespace, /* namespace */
1632 : InvalidOid, /* relation oid (n/a here) */
1633 : 0, /* relation kind (ditto) */
1634 : GetUserId(), /* owner's ID */
1635 : -1, /* internal size (always varlena) */
1636 : TYPTYPE_BASE, /* type-type (base type) */
1637 : TYPCATEGORY_ARRAY, /* type-category (array) */
1638 : false, /* array types are never preferred */
1639 : DEFAULT_TYPDELIM, /* array element delimiter */
1640 : F_ARRAY_IN, /* input procedure */
1641 : F_ARRAY_OUT, /* output procedure */
1642 : F_ARRAY_RECV, /* receive procedure */
1643 : F_ARRAY_SEND, /* send procedure */
1644 : InvalidOid, /* typmodin procedure - none */
1645 : InvalidOid, /* typmodout procedure - none */
1646 : F_ARRAY_TYPANALYZE, /* analyze procedure */
1647 : F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1648 : typoid, /* element type ID */
1649 : true, /* yes this is an array type */
1650 : InvalidOid, /* no further array type */
1651 : InvalidOid, /* base type ID */
1652 : NULL, /* never a default type value */
1653 : NULL, /* binary default isn't sent either */
1654 : false, /* never passed by value */
1655 : alignment, /* alignment - same as range's */
1656 : TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1657 : -1, /* typMod (Domains only) */
1658 : 0, /* Array dimensions of typbasetype */
1659 : false, /* Type NOT NULL */
1660 : InvalidOid); /* typcollation */
1661 :
1662 64 : pfree(rangeArrayName);
1663 :
1664 : /* Create the multirange's array type */
1665 :
840 akorotkov 1666 64 : multirangeArrayName = makeArrayTypeName(multirangeTypeName, typeNamespace);
1667 :
1668 64 : TypeCreate(multirangeArrayOid, /* force assignment of this type OID */
1669 : multirangeArrayName, /* type name */
1670 : multirangeNamespace, /* namespace */
1671 : InvalidOid, /* relation oid (n/a here) */
1672 : 0, /* relation kind (ditto) */
1673 : GetUserId(), /* owner's ID */
1674 : -1, /* internal size (always varlena) */
1675 : TYPTYPE_BASE, /* type-type (base type) */
1676 : TYPCATEGORY_ARRAY, /* type-category (array) */
1677 : false, /* array types are never preferred */
1678 : DEFAULT_TYPDELIM, /* array element delimiter */
1679 : F_ARRAY_IN, /* input procedure */
1680 : F_ARRAY_OUT, /* output procedure */
1681 : F_ARRAY_RECV, /* receive procedure */
1682 : F_ARRAY_SEND, /* send procedure */
1683 : InvalidOid, /* typmodin procedure - none */
1684 : InvalidOid, /* typmodout procedure - none */
1685 : F_ARRAY_TYPANALYZE, /* analyze procedure */
1686 : F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1687 : multirangeOid, /* element type ID */
1688 : true, /* yes this is an array type */
1689 : InvalidOid, /* no further array type */
1690 : InvalidOid, /* base type ID */
1691 : NULL, /* never a default type value */
1692 : NULL, /* binary default isn't sent either */
1693 : false, /* never passed by value */
1694 : alignment, /* alignment - same as range's */
1695 : 'x', /* ARRAY is always toastable */
1696 : -1, /* typMod (Domains only) */
1697 : 0, /* Array dimensions of typbasetype */
1698 : false, /* Type NOT NULL */
1699 : InvalidOid); /* typcollation */
1700 :
1701 : /* And create the constructor functions for this range type */
4157 tgl 1702 64 : makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
840 akorotkov 1703 64 : makeMultirangeConstructors(multirangeTypeName, typeNamespace,
1704 : multirangeOid, typoid, rangeArrayOid,
1705 : &castFuncOid);
1706 :
1707 : /* Create cast from the range type to its multirange type */
174 tgl 1708 GNC 64 : CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
1709 : COERCION_CODE_EXPLICIT, COERCION_METHOD_FUNCTION,
1710 : DEPENDENCY_INTERNAL);
1711 :
840 akorotkov 1712 GIC 64 : pfree(multirangeArrayName);
1713 :
2959 alvherre 1714 CBC 64 : return address;
1715 : }
4175 heikki.linnakangas 1716 ECB :
1717 : /*
1718 : * Because there may exist several range types over the same subtype, the
1719 : * range type can't be uniquely determined from the subtype. So it's
1720 : * impossible to define a polymorphic constructor; we have to generate new
1721 : * constructor functions explicitly for each range type.
1722 : *
1723 : * We actually define 4 functions, with 0 through 3 arguments. This is just
1724 : * to offer more convenience for the user.
1725 : */
1726 : static void
4157 tgl 1727 GIC 64 : makeRangeConstructors(const char *name, Oid namespace,
1728 : Oid rangeOid, Oid subtype)
4175 heikki.linnakangas 1729 ECB : {
1730 : static const char *const prosrc[2] = {"range_constructor2",
1731 : "range_constructor3"};
1732 : static const int pronargs[2] = {2, 3};
1733 :
1734 : Oid constructorArgTypes[3];
1735 : ObjectAddress myself,
1736 : referenced;
1737 : int i;
1738 :
4175 heikki.linnakangas 1739 GIC 64 : constructorArgTypes[0] = subtype;
1740 64 : constructorArgTypes[1] = subtype;
4175 heikki.linnakangas 1741 CBC 64 : constructorArgTypes[2] = TEXTOID;
4175 heikki.linnakangas 1742 ECB :
4157 tgl 1743 CBC 64 : referenced.classId = TypeRelationId;
4157 tgl 1744 GIC 64 : referenced.objectId = rangeOid;
4157 tgl 1745 CBC 64 : referenced.objectSubId = 0;
4157 tgl 1746 ECB :
4157 tgl 1747 CBC 192 : for (i = 0; i < lengthof(prosrc); i++)
1748 : {
4164 bruce 1749 ECB : oidvector *constructorArgTypesVector;
1750 :
4157 tgl 1751 GIC 128 : constructorArgTypesVector = buildoidvector(constructorArgTypes,
1752 128 : pronargs[i]);
4175 heikki.linnakangas 1753 ECB :
2959 alvherre 1754 CBC 128 : myself = ProcedureCreate(name, /* name: same as range type */
1755 : namespace, /* namespace */
2959 alvherre 1756 ECB : false, /* replace */
1757 : false, /* returns set */
1758 : rangeOid, /* return type */
1759 : BOOTSTRAP_SUPERUSERID, /* proowner */
1760 : INTERNALlanguageId, /* language */
1761 : F_FMGR_INTERNAL_VALIDATOR, /* language validator */
2118 tgl 1762 GIC 128 : prosrc[i], /* prosrc */
1763 : NULL, /* probin */
732 peter 1764 ECB : NULL, /* prosqlbody */
1765 : PROKIND_FUNCTION,
1766 : false, /* security_definer */
1767 : false, /* leakproof */
1768 : false, /* isStrict */
1769 : PROVOLATILE_IMMUTABLE, /* volatility */
1770 : PROPARALLEL_SAFE, /* parallel safety */
1771 : constructorArgTypesVector, /* parameterTypes */
1772 : PointerGetDatum(NULL), /* allParameterTypes */
1773 : PointerGetDatum(NULL), /* parameterModes */
1774 : PointerGetDatum(NULL), /* parameterNames */
1775 : NIL, /* parameterDefaults */
1776 : PointerGetDatum(NULL), /* trftypes */
1777 : PointerGetDatum(NULL), /* proconfig */
1778 : InvalidOid, /* prosupport */
1779 : 1.0, /* procost */
1780 : 0.0); /* prorows */
1781 :
1782 : /*
1783 : * Make the constructors internally-dependent on the range type so
1784 : * that they go away silently when the type is dropped. Note that
1785 : * pg_dump depends on this choice to avoid dumping the constructors.
1786 : */
4175 heikki.linnakangas 1787 GIC 128 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1788 : }
4175 heikki.linnakangas 1789 CBC 64 : }
1790 :
840 akorotkov 1791 ECB : /*
1792 : * We make a separate multirange constructor for each range type
1793 : * so its name can include the base type, like range constructors do.
1794 : * If we had an anyrangearray polymorphic type we could use it here,
1795 : * but since each type has its own constructor name there's no need.
1796 : *
1797 : * Sets castFuncOid to the oid of the new constructor that can be used
1798 : * to cast from a range to a multirange.
1799 : */
1800 : static void
840 akorotkov 1801 GIC 64 : makeMultirangeConstructors(const char *name, Oid namespace,
1802 : Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid,
663 akorotkov 1803 ECB : Oid *castFuncOid)
1804 : {
1805 : ObjectAddress myself,
1806 : referenced;
1807 : oidvector *argtypes;
1808 : Datum allParamTypes;
1809 : ArrayType *allParameterTypes;
1810 : Datum paramModes;
1811 : ArrayType *parameterModes;
1812 :
840 akorotkov 1813 GIC 64 : referenced.classId = TypeRelationId;
1814 64 : referenced.objectId = multirangeOid;
840 akorotkov 1815 CBC 64 : referenced.objectSubId = 0;
840 akorotkov 1816 ECB :
1817 : /* 0-arg constructor - for empty multiranges */
840 akorotkov 1818 GIC 64 : argtypes = buildoidvector(NULL, 0);
1819 64 : myself = ProcedureCreate(name, /* name: same as multirange type */
840 akorotkov 1820 ECB : namespace,
1821 : false, /* replace */
1822 : false, /* returns set */
1823 : multirangeOid, /* return type */
1824 : BOOTSTRAP_SUPERUSERID, /* proowner */
1825 : INTERNALlanguageId, /* language */
1826 : F_FMGR_INTERNAL_VALIDATOR,
1827 : "multirange_constructor0", /* prosrc */
1828 : NULL, /* probin */
1829 : NULL, /* prosqlbody */
1830 : PROKIND_FUNCTION,
1831 : false, /* security_definer */
1832 : false, /* leakproof */
1833 : true, /* isStrict */
1834 : PROVOLATILE_IMMUTABLE, /* volatility */
1835 : PROPARALLEL_SAFE, /* parallel safety */
1836 : argtypes, /* parameterTypes */
1837 : PointerGetDatum(NULL), /* allParameterTypes */
1838 : PointerGetDatum(NULL), /* parameterModes */
1839 : PointerGetDatum(NULL), /* parameterNames */
1840 : NIL, /* parameterDefaults */
1841 : PointerGetDatum(NULL), /* trftypes */
1842 : PointerGetDatum(NULL), /* proconfig */
1843 : InvalidOid, /* prosupport */
1844 : 1.0, /* procost */
1845 : 0.0); /* prorows */
1846 :
1847 : /*
1848 : * Make the constructor internally-dependent on the multirange type so
1849 : * that they go away silently when the type is dropped. Note that pg_dump
1850 : * depends on this choice to avoid dumping the constructors.
1851 : */
840 akorotkov 1852 GIC 64 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1853 64 : pfree(argtypes);
840 akorotkov 1854 ECB :
1855 : /*
1856 : * 1-arg constructor - for casts
1857 : *
1858 : * In theory we shouldn't need both this and the vararg (n-arg)
1859 : * constructor, but having a separate 1-arg function lets us define casts
1860 : * against it.
1861 : */
840 akorotkov 1862 GIC 64 : argtypes = buildoidvector(&rangeOid, 1);
1863 64 : myself = ProcedureCreate(name, /* name: same as multirange type */
840 akorotkov 1864 ECB : namespace,
1865 : false, /* replace */
1866 : false, /* returns set */
1867 : multirangeOid, /* return type */
1868 : BOOTSTRAP_SUPERUSERID, /* proowner */
1869 : INTERNALlanguageId, /* language */
1870 : F_FMGR_INTERNAL_VALIDATOR,
1871 : "multirange_constructor1", /* prosrc */
1872 : NULL, /* probin */
1873 : NULL, /* prosqlbody */
1874 : PROKIND_FUNCTION,
1875 : false, /* security_definer */
1876 : false, /* leakproof */
1877 : true, /* isStrict */
1878 : PROVOLATILE_IMMUTABLE, /* volatility */
1879 : PROPARALLEL_SAFE, /* parallel safety */
1880 : argtypes, /* parameterTypes */
1881 : PointerGetDatum(NULL), /* allParameterTypes */
1882 : PointerGetDatum(NULL), /* parameterModes */
1883 : PointerGetDatum(NULL), /* parameterNames */
1884 : NIL, /* parameterDefaults */
1885 : PointerGetDatum(NULL), /* trftypes */
1886 : PointerGetDatum(NULL), /* proconfig */
1887 : InvalidOid, /* prosupport */
1888 : 1.0, /* procost */
1889 : 0.0); /* prorows */
1890 : /* ditto */
840 akorotkov 1891 GIC 64 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1892 64 : pfree(argtypes);
663 akorotkov 1893 CBC 64 : *castFuncOid = myself.objectId;
840 akorotkov 1894 ECB :
1895 : /* n-arg constructor - vararg */
840 akorotkov 1896 GIC 64 : argtypes = buildoidvector(&rangeArrayOid, 1);
1897 64 : allParamTypes = ObjectIdGetDatum(rangeArrayOid);
282 peter 1898 GNC 64 : allParameterTypes = construct_array_builtin(&allParamTypes, 1, OIDOID);
840 akorotkov 1899 CBC 64 : paramModes = CharGetDatum(FUNC_PARAM_VARIADIC);
282 peter 1900 GNC 64 : parameterModes = construct_array_builtin(¶mModes, 1, CHAROID);
840 akorotkov 1901 GIC 64 : myself = ProcedureCreate(name, /* name: same as multirange type */
1902 : namespace,
1903 : false, /* replace */
1904 : false, /* returns set */
1905 : multirangeOid, /* return type */
1906 : BOOTSTRAP_SUPERUSERID, /* proowner */
1907 : INTERNALlanguageId, /* language */
1908 : F_FMGR_INTERNAL_VALIDATOR,
1909 : "multirange_constructor2", /* prosrc */
1910 : NULL, /* probin */
1911 : NULL, /* prosqlbody */
1912 : PROKIND_FUNCTION,
1913 : false, /* security_definer */
1914 : false, /* leakproof */
1915 : true, /* isStrict */
1916 : PROVOLATILE_IMMUTABLE, /* volatility */
1917 : PROPARALLEL_SAFE, /* parallel safety */
1918 : argtypes, /* parameterTypes */
1919 : PointerGetDatum(allParameterTypes), /* allParameterTypes */
1920 : PointerGetDatum(parameterModes), /* parameterModes */
1921 : PointerGetDatum(NULL), /* parameterNames */
1922 : NIL, /* parameterDefaults */
1923 : PointerGetDatum(NULL), /* trftypes */
1924 : PointerGetDatum(NULL), /* proconfig */
1925 : InvalidOid, /* prosupport */
1926 : 1.0, /* procost */
1927 : 0.0); /* prorows */
840 akorotkov 1928 ECB : /* ditto */
840 akorotkov 1929 CBC 64 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1930 64 : pfree(argtypes);
1931 64 : pfree(allParameterTypes);
1932 64 : pfree(parameterModes);
840 akorotkov 1933 GIC 64 : }
1934 :
1935 : /*
1936 : * Find suitable I/O and other support functions for a type.
1937 : *
1938 : * typeOid is the type's OID (which will already exist, if only as a shell
1939 : * type).
1940 : */
1941 :
7664 tgl 1942 ECB : static Oid
7276 tgl 1943 GIC 97 : findTypeInputFunction(List *procname, Oid typeOid)
1944 : {
1945 : Oid argList[3];
1946 : Oid procOid;
1947 : Oid procOid2;
1948 :
1949 : /*
1950 : * Input functions can take a single argument of type CSTRING, or three
1951 : * arguments (string, typioparam OID, typmod). Whine about ambiguity if
1952 : * both forms exist.
7276 tgl 1953 ECB : */
7276 tgl 1954 CBC 97 : argList[0] = CSTRINGOID;
972 1955 97 : argList[1] = OIDOID;
972 tgl 1956 GIC 97 : argList[2] = INT4OID;
7276 tgl 1957 ECB :
7219 tgl 1958 CBC 97 : procOid = LookupFuncName(procname, 1, argList, true);
972 1959 97 : procOid2 = LookupFuncName(procname, 3, argList, true);
972 tgl 1960 GIC 97 : if (OidIsValid(procOid))
7664 tgl 1961 ECB : {
972 tgl 1962 GBC 89 : if (OidIsValid(procOid2))
972 tgl 1963 UIC 0 : ereport(ERROR,
1964 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1965 : errmsg("type input function %s has multiple matches",
1966 : NameListToString(procname))));
1967 : }
1968 : else
972 tgl 1969 ECB : {
972 tgl 1970 GIC 8 : procOid = procOid2;
972 tgl 1971 ECB : /* If not found, reference the 1-argument signature in error msg */
1130 tgl 1972 GBC 8 : if (!OidIsValid(procOid))
1130 tgl 1973 UIC 0 : ereport(ERROR,
1974 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
1975 : errmsg("function %s does not exist",
1976 : func_signature_string(procname, 1, NIL, argList))));
1977 : }
1978 :
972 tgl 1979 ECB : /* Input functions must return the target type. */
1130 tgl 1980 CBC 97 : if (get_func_rettype(procOid) != typeOid)
1130 tgl 1981 GIC 3 : ereport(ERROR,
1982 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1983 : errmsg("type input function %s must return type %s",
1984 : NameListToString(procname), format_type_be(typeOid))));
1985 :
1986 : /*
1987 : * Print warnings if any of the type's I/O functions are marked volatile.
1988 : * There is a general assumption that I/O functions are stable or
1989 : * immutable; this allows us for example to mark record_in/record_out
1990 : * stable rather than volatile. Ideally we would throw errors not just
1991 : * warnings here; but since this check is new as of 9.5, and since the
1992 : * volatility marking might be just an error-of-omission and not a true
1993 : * indication of how the function behaves, we'll let it pass as a warning
1994 : * for now.
1129 tgl 1995 ECB : */
1129 tgl 1996 GBC 94 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 1997 UIC 0 : ereport(WARNING,
1998 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1999 : errmsg("type input function %s should not be volatile",
2000 : NameListToString(procname))));
1129 tgl 2001 ECB :
1130 tgl 2002 GIC 94 : return procOid;
2003 : }
2004 :
7276 tgl 2005 ECB : static Oid
7276 tgl 2006 GIC 94 : findTypeOutputFunction(List *procname, Oid typeOid)
2007 : {
2008 : Oid argList[1];
2009 : Oid procOid;
2010 :
2011 : /*
2012 : * Output functions always take a single argument of the type and return
2013 : * cstring.
7276 tgl 2014 ECB : */
7276 tgl 2015 GIC 94 : argList[0] = typeOid;
7535 tgl 2016 ECB :
7219 tgl 2017 CBC 94 : procOid = LookupFuncName(procname, 1, argList, true);
1130 tgl 2018 GBC 94 : if (!OidIsValid(procOid))
1130 tgl 2019 UIC 0 : ereport(ERROR,
2020 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2021 : errmsg("function %s does not exist",
2022 : func_signature_string(procname, 1, NIL, argList))));
7664 tgl 2023 ECB :
1130 tgl 2024 GBC 94 : if (get_func_rettype(procOid) != CSTRINGOID)
1130 tgl 2025 UIC 0 : ereport(ERROR,
2026 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2027 : errmsg("type output function %s must return type %s",
2028 : NameListToString(procname), "cstring")));
2029 :
1129 tgl 2030 ECB : /* Just a warning for now, per comments in findTypeInputFunction */
1129 tgl 2031 GBC 94 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 2032 UIC 0 : ereport(WARNING,
2033 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2034 : errmsg("type output function %s should not be volatile",
2035 : NameListToString(procname))));
1129 tgl 2036 ECB :
1130 tgl 2037 GIC 94 : return procOid;
2038 : }
2039 :
7276 tgl 2040 ECB : static Oid
7276 tgl 2041 GIC 23 : findTypeReceiveFunction(List *procname, Oid typeOid)
2042 : {
2043 : Oid argList[3];
2044 : Oid procOid;
2045 : Oid procOid2;
2046 :
2047 : /*
2048 : * Receive functions can take a single argument of type INTERNAL, or three
2049 : * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2050 : * both forms exist.
7276 tgl 2051 ECB : */
7276 tgl 2052 CBC 23 : argList[0] = INTERNALOID;
972 2053 23 : argList[1] = OIDOID;
972 tgl 2054 GIC 23 : argList[2] = INT4OID;
7535 tgl 2055 ECB :
7219 tgl 2056 CBC 23 : procOid = LookupFuncName(procname, 1, argList, true);
972 2057 23 : procOid2 = LookupFuncName(procname, 3, argList, true);
972 tgl 2058 GIC 23 : if (OidIsValid(procOid))
1130 tgl 2059 ECB : {
972 tgl 2060 GBC 18 : if (OidIsValid(procOid2))
972 tgl 2061 UIC 0 : ereport(ERROR,
2062 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
2063 : errmsg("type receive function %s has multiple matches",
2064 : NameListToString(procname))));
2065 : }
2066 : else
972 tgl 2067 ECB : {
972 tgl 2068 GIC 5 : procOid = procOid2;
972 tgl 2069 ECB : /* If not found, reference the 1-argument signature in error msg */
1130 tgl 2070 GBC 5 : if (!OidIsValid(procOid))
1130 tgl 2071 UIC 0 : ereport(ERROR,
2072 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2073 : errmsg("function %s does not exist",
2074 : func_signature_string(procname, 1, NIL, argList))));
2075 : }
2076 :
972 tgl 2077 ECB : /* Receive functions must return the target type. */
1130 tgl 2078 GBC 23 : if (get_func_rettype(procOid) != typeOid)
1130 tgl 2079 UIC 0 : ereport(ERROR,
2080 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2081 : errmsg("type receive function %s must return type %s",
2082 : NameListToString(procname), format_type_be(typeOid))));
2083 :
1129 tgl 2084 ECB : /* Just a warning for now, per comments in findTypeInputFunction */
1129 tgl 2085 GBC 23 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 2086 UIC 0 : ereport(WARNING,
2087 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2088 : errmsg("type receive function %s should not be volatile",
2089 : NameListToString(procname))));
1129 tgl 2090 ECB :
1130 tgl 2091 GIC 23 : return procOid;
2092 : }
2093 :
7276 tgl 2094 ECB : static Oid
7276 tgl 2095 GIC 23 : findTypeSendFunction(List *procname, Oid typeOid)
2096 : {
2097 : Oid argList[1];
2098 : Oid procOid;
2099 :
2100 : /*
2101 : * Send functions always take a single argument of the type and return
2102 : * bytea.
7276 tgl 2103 ECB : */
7276 tgl 2104 GIC 23 : argList[0] = typeOid;
7276 tgl 2105 ECB :
7219 tgl 2106 CBC 23 : procOid = LookupFuncName(procname, 1, argList, true);
1130 tgl 2107 GBC 23 : if (!OidIsValid(procOid))
1130 tgl 2108 UIC 0 : ereport(ERROR,
2109 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2110 : errmsg("function %s does not exist",
2111 : func_signature_string(procname, 1, NIL, argList))));
7276 tgl 2112 ECB :
1130 tgl 2113 GBC 23 : if (get_func_rettype(procOid) != BYTEAOID)
1130 tgl 2114 UIC 0 : ereport(ERROR,
2115 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2116 : errmsg("type send function %s must return type %s",
2117 : NameListToString(procname), "bytea")));
2118 :
1129 tgl 2119 ECB : /* Just a warning for now, per comments in findTypeInputFunction */
1129 tgl 2120 GBC 23 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 2121 UIC 0 : ereport(WARNING,
2122 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2123 : errmsg("type send function %s should not be volatile",
2124 : NameListToString(procname))));
1129 tgl 2125 ECB :
1130 tgl 2126 GIC 23 : return procOid;
2127 : }
2128 :
5944 tgl 2129 ECB : static Oid
5944 tgl 2130 GIC 7 : findTypeTypmodinFunction(List *procname)
2131 : {
2132 : Oid argList[1];
2133 : Oid procOid;
2134 :
2135 : /*
2136 : * typmodin functions always take one cstring[] argument and return int4.
5944 tgl 2137 ECB : */
5777 tgl 2138 GIC 7 : argList[0] = CSTRINGARRAYOID;
5944 tgl 2139 ECB :
5944 tgl 2140 CBC 7 : procOid = LookupFuncName(procname, 1, argList, true);
5944 tgl 2141 GBC 7 : if (!OidIsValid(procOid))
5944 tgl 2142 UIC 0 : ereport(ERROR,
2143 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2144 : errmsg("function %s does not exist",
2145 : func_signature_string(procname, 1, NIL, argList))));
5944 tgl 2146 ECB :
5944 tgl 2147 GBC 7 : if (get_func_rettype(procOid) != INT4OID)
5944 tgl 2148 UIC 0 : ereport(ERROR,
2149 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2150 : errmsg("typmod_in function %s must return type %s",
2151 : NameListToString(procname), "integer")));
2152 :
1129 tgl 2153 ECB : /* Just a warning for now, per comments in findTypeInputFunction */
1129 tgl 2154 GBC 7 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 2155 UIC 0 : ereport(WARNING,
2156 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2157 : errmsg("type modifier input function %s should not be volatile",
2158 : NameListToString(procname))));
1129 tgl 2159 ECB :
5944 tgl 2160 GIC 7 : return procOid;
2161 : }
2162 :
5944 tgl 2163 ECB : static Oid
5944 tgl 2164 GIC 7 : findTypeTypmodoutFunction(List *procname)
2165 : {
2166 : Oid argList[1];
2167 : Oid procOid;
2168 :
2169 : /*
2170 : * typmodout functions always take one int4 argument and return cstring.
5944 tgl 2171 ECB : */
5944 tgl 2172 GIC 7 : argList[0] = INT4OID;
5944 tgl 2173 ECB :
5944 tgl 2174 CBC 7 : procOid = LookupFuncName(procname, 1, argList, true);
5944 tgl 2175 GBC 7 : if (!OidIsValid(procOid))
5944 tgl 2176 UIC 0 : ereport(ERROR,
2177 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2178 : errmsg("function %s does not exist",
2179 : func_signature_string(procname, 1, NIL, argList))));
5944 tgl 2180 ECB :
5944 tgl 2181 GBC 7 : if (get_func_rettype(procOid) != CSTRINGOID)
5944 tgl 2182 UIC 0 : ereport(ERROR,
2183 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2184 : errmsg("typmod_out function %s must return type %s",
2185 : NameListToString(procname), "cstring")));
2186 :
1129 tgl 2187 ECB : /* Just a warning for now, per comments in findTypeInputFunction */
1129 tgl 2188 GBC 7 : if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1129 tgl 2189 UIC 0 : ereport(WARNING,
2190 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2191 : errmsg("type modifier output function %s should not be volatile",
2192 : NameListToString(procname))));
1129 tgl 2193 ECB :
5944 tgl 2194 GIC 7 : return procOid;
2195 : }
2196 :
6996 tgl 2197 ECB : static Oid
6996 tgl 2198 GIC 3 : findTypeAnalyzeFunction(List *procname, Oid typeOid)
2199 : {
2200 : Oid argList[1];
2201 : Oid procOid;
2202 :
2203 : /*
2204 : * Analyze functions always take one INTERNAL argument and return bool.
6996 tgl 2205 ECB : */
6996 tgl 2206 GIC 3 : argList[0] = INTERNALOID;
6996 tgl 2207 ECB :
6996 tgl 2208 CBC 3 : procOid = LookupFuncName(procname, 1, argList, true);
6996 tgl 2209 GBC 3 : if (!OidIsValid(procOid))
6996 tgl 2210 UIC 0 : ereport(ERROR,
2211 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2212 : errmsg("function %s does not exist",
2213 : func_signature_string(procname, 1, NIL, argList))));
6996 tgl 2214 ECB :
6996 tgl 2215 GBC 3 : if (get_func_rettype(procOid) != BOOLOID)
6996 tgl 2216 UIC 0 : ereport(ERROR,
2217 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2218 : errmsg("type analyze function %s must return type %s",
2219 : NameListToString(procname), "boolean")));
6996 tgl 2220 ECB :
6996 tgl 2221 GIC 3 : return procOid;
2222 : }
2223 :
851 tgl 2224 ECB : static Oid
851 tgl 2225 GIC 11 : findTypeSubscriptingFunction(List *procname, Oid typeOid)
2226 : {
2227 : Oid argList[1];
2228 : Oid procOid;
2229 :
2230 : /*
2231 : * Subscripting support functions always take one INTERNAL argument and
2232 : * return INTERNAL. (The argument is not used, but we must have it to
2233 : * maintain type safety.)
851 tgl 2234 ECB : */
851 tgl 2235 GIC 11 : argList[0] = INTERNALOID;
851 tgl 2236 ECB :
851 tgl 2237 CBC 11 : procOid = LookupFuncName(procname, 1, argList, true);
851 tgl 2238 GBC 11 : if (!OidIsValid(procOid))
851 tgl 2239 UIC 0 : ereport(ERROR,
2240 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2241 : errmsg("function %s does not exist",
2242 : func_signature_string(procname, 1, NIL, argList))));
851 tgl 2243 ECB :
851 tgl 2244 GBC 11 : if (get_func_rettype(procOid) != INTERNALOID)
851 tgl 2245 UIC 0 : ereport(ERROR,
2246 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2247 : errmsg("type subscripting function %s must return type %s",
2248 : NameListToString(procname), "internal")));
2249 :
2250 : /*
2251 : * We disallow array_subscript_handler() from being selected explicitly,
2252 : * since that must only be applied to autogenerated array types.
851 tgl 2253 ECB : */
851 tgl 2254 GBC 11 : if (procOid == F_ARRAY_SUBSCRIPT_HANDLER)
851 tgl 2255 UIC 0 : ereport(ERROR,
2256 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2257 : errmsg("user-defined types cannot use subscripting function %s",
2258 : NameListToString(procname))));
851 tgl 2259 ECB :
851 tgl 2260 GIC 11 : return procOid;
2261 : }
2262 :
2263 : /*
2264 : * Find suitable support functions and opclasses for a range type.
2265 : */
2266 :
2267 : /*
2268 : * Find named btree opclass for subtype, or default btree opclass if
2269 : * opcname is NIL.
2270 : */
4175 heikki.linnakangas 2271 ECB : static Oid
4175 heikki.linnakangas 2272 GIC 76 : findRangeSubOpclass(List *opcname, Oid subtype)
2273 : {
2274 : Oid opcid;
2275 : Oid opInputType;
4157 tgl 2276 ECB :
4157 tgl 2277 GIC 76 : if (opcname != NIL)
4157 tgl 2278 ECB : {
4157 tgl 2279 GIC 1 : opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
2280 :
2281 : /*
2282 : * Verify that the operator class accepts this datatype. Note we will
2283 : * accept binary compatibility.
4157 tgl 2284 ECB : */
4157 tgl 2285 CBC 1 : opInputType = get_opclass_input_type(opcid);
4157 tgl 2286 GBC 1 : if (!IsBinaryCoercible(subtype, opInputType))
4157 tgl 2287 UIC 0 : ereport(ERROR,
2288 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2289 : errmsg("operator class \"%s\" does not accept data type %s",
2290 : NameListToString(opcname),
2291 : format_type_be(subtype))));
2292 : }
2293 : else
4175 heikki.linnakangas 2294 ECB : {
4175 heikki.linnakangas 2295 CBC 75 : opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
4175 heikki.linnakangas 2296 GIC 75 : if (!OidIsValid(opcid))
2297 : {
1815 sfrost 2298 EUB : /* We spell the error message identically to ResolveOpClass */
4175 heikki.linnakangas 2299 UIC 0 : ereport(ERROR,
2300 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2301 : errmsg("data type %s has no default operator class for access method \"%s\"",
2302 : format_type_be(subtype), "btree"),
2303 : errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2304 : }
2305 : }
4175 heikki.linnakangas 2306 ECB :
4175 heikki.linnakangas 2307 GIC 76 : return opcid;
2308 : }
2309 :
4175 heikki.linnakangas 2310 EUB : static Oid
4157 tgl 2311 UIC 0 : findRangeCanonicalFunction(List *procname, Oid typeOid)
2312 : {
2313 : Oid argList[1];
2314 : Oid procOid;
2315 : AclResult aclresult;
2316 :
2317 : /*
2318 : * Range canonical functions must take and return the range type, and must
2319 : * be immutable.
4157 tgl 2320 EUB : */
4175 heikki.linnakangas 2321 UIC 0 : argList[0] = typeOid;
4175 heikki.linnakangas 2322 EUB :
4157 tgl 2323 UIC 0 : procOid = LookupFuncName(procname, 1, argList, true);
4175 heikki.linnakangas 2324 EUB :
4175 heikki.linnakangas 2325 UBC 0 : if (!OidIsValid(procOid))
4175 heikki.linnakangas 2326 UIC 0 : ereport(ERROR,
2327 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2328 : errmsg("function %s does not exist",
2329 : func_signature_string(procname, 1, NIL, argList))));
4175 heikki.linnakangas 2330 EUB :
4157 tgl 2331 UBC 0 : if (get_func_rettype(procOid) != typeOid)
4175 heikki.linnakangas 2332 UIC 0 : ereport(ERROR,
2333 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2334 : errmsg("range canonical function %s must return range type",
2335 : func_signature_string(procname, 1, NIL, argList))));
4175 heikki.linnakangas 2336 EUB :
4175 heikki.linnakangas 2337 UBC 0 : if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
4175 heikki.linnakangas 2338 UIC 0 : ereport(ERROR,
2339 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2340 : errmsg("range canonical function %s must be immutable",
2341 : func_signature_string(procname, 1, NIL, argList))));
2342 :
4155 tgl 2343 EUB : /* Also, range type's creator must have permission to call function */
147 peter 2344 UNC 0 : aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
4155 tgl 2345 UBC 0 : if (aclresult != ACLCHECK_OK)
1954 peter_e 2346 UIC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
4155 tgl 2347 EUB :
4175 heikki.linnakangas 2348 UIC 0 : return procOid;
2349 : }
2350 :
4175 heikki.linnakangas 2351 ECB : static Oid
4157 tgl 2352 GIC 7 : findRangeSubtypeDiffFunction(List *procname, Oid subtype)
2353 : {
2354 : Oid argList[2];
2355 : Oid procOid;
2356 : AclResult aclresult;
2357 :
2358 : /*
2359 : * Range subtype diff functions must take two arguments of the subtype,
2360 : * must return float8, and must be immutable.
4157 tgl 2361 ECB : */
4157 tgl 2362 CBC 7 : argList[0] = subtype;
4157 tgl 2363 GIC 7 : argList[1] = subtype;
4175 heikki.linnakangas 2364 ECB :
4157 tgl 2365 GIC 7 : procOid = LookupFuncName(procname, 2, argList, true);
4175 heikki.linnakangas 2366 ECB :
4175 heikki.linnakangas 2367 CBC 7 : if (!OidIsValid(procOid))
4175 heikki.linnakangas 2368 GIC 3 : ereport(ERROR,
2369 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2370 : errmsg("function %s does not exist",
2371 : func_signature_string(procname, 2, NIL, argList))));
4175 heikki.linnakangas 2372 ECB :
4157 tgl 2373 GBC 4 : if (get_func_rettype(procOid) != FLOAT8OID)
4175 heikki.linnakangas 2374 UIC 0 : ereport(ERROR,
2375 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2376 : errmsg("range subtype diff function %s must return type %s",
2377 : func_signature_string(procname, 2, NIL, argList),
2378 : "double precision")));
4175 heikki.linnakangas 2379 ECB :
4175 heikki.linnakangas 2380 GBC 4 : if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
4175 heikki.linnakangas 2381 UIC 0 : ereport(ERROR,
2382 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2383 : errmsg("range subtype diff function %s must be immutable",
2384 : func_signature_string(procname, 2, NIL, argList))));
2385 :
4155 tgl 2386 ECB : /* Also, range type's creator must have permission to call function */
147 peter 2387 GNC 4 : aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
4155 tgl 2388 GBC 4 : if (aclresult != ACLCHECK_OK)
1954 peter_e 2389 UIC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
4155 tgl 2390 ECB :
4175 heikki.linnakangas 2391 GIC 4 : return procOid;
2392 : }
2393 :
2394 : /*
2395 : * AssignTypeArrayOid
2396 : *
2397 : * Pre-assign the type's array OID for use in pg_type.typarray
2398 : */
4854 bruce 2399 ECB : Oid
4854 bruce 2400 GIC 83250 : AssignTypeArrayOid(void)
2401 : {
2402 : Oid type_array_oid;
2403 :
3149 bruce 2404 ECB : /* Use binary-upgrade override for pg_type.typarray? */
3149 bruce 2405 GIC 83250 : if (IsBinaryUpgrade)
4854 bruce 2406 ECB : {
3149 bruce 2407 GBC 712 : if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
3149 bruce 2408 UIC 0 : ereport(ERROR,
2409 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2410 : errmsg("pg_type array OID value not set when in binary upgrade mode")));
3149 bruce 2411 ECB :
4475 bruce 2412 CBC 712 : type_array_oid = binary_upgrade_next_array_pg_type_oid;
4475 bruce 2413 GIC 712 : binary_upgrade_next_array_pg_type_oid = InvalidOid;
2414 : }
2415 : else
4854 bruce 2416 ECB : {
1539 andres 2417 GIC 82538 : Relation pg_type = table_open(TypeRelationId, AccessShareLock);
4854 bruce 2418 ECB :
1601 andres 2419 GIC 82538 : type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
1601 andres 2420 ECB : Anum_pg_type_oid);
1539 andres 2421 GIC 82538 : table_close(pg_type, AccessShareLock);
2422 : }
4854 bruce 2423 ECB :
4854 bruce 2424 GIC 83250 : return type_array_oid;
2425 : }
2426 :
2427 : /*
2428 : * AssignTypeMultirangeOid
2429 : *
2430 : * Pre-assign the range type's multirange OID for use in pg_type.oid
2431 : */
840 akorotkov 2432 ECB : Oid
840 akorotkov 2433 GIC 73 : AssignTypeMultirangeOid(void)
2434 : {
2435 : Oid type_multirange_oid;
2436 :
840 akorotkov 2437 ECB : /* Use binary-upgrade override for pg_type.oid? */
840 akorotkov 2438 GIC 73 : if (IsBinaryUpgrade)
840 akorotkov 2439 ECB : {
840 akorotkov 2440 GBC 4 : if (!OidIsValid(binary_upgrade_next_mrng_pg_type_oid))
840 akorotkov 2441 UIC 0 : ereport(ERROR,
2442 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2443 : errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
840 akorotkov 2444 ECB :
840 akorotkov 2445 CBC 4 : type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
840 akorotkov 2446 GIC 4 : binary_upgrade_next_mrng_pg_type_oid = InvalidOid;
2447 : }
2448 : else
840 akorotkov 2449 ECB : {
840 akorotkov 2450 GIC 69 : Relation pg_type = table_open(TypeRelationId, AccessShareLock);
840 akorotkov 2451 ECB :
840 akorotkov 2452 GIC 69 : type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
840 akorotkov 2453 ECB : Anum_pg_type_oid);
840 akorotkov 2454 GIC 69 : table_close(pg_type, AccessShareLock);
2455 : }
840 akorotkov 2456 ECB :
840 akorotkov 2457 GIC 73 : return type_multirange_oid;
2458 : }
2459 :
2460 : /*
2461 : * AssignTypeMultirangeArrayOid
2462 : *
2463 : * Pre-assign the range type's multirange array OID for use in pg_type.typarray
2464 : */
840 akorotkov 2465 ECB : Oid
840 akorotkov 2466 GIC 73 : AssignTypeMultirangeArrayOid(void)
2467 : {
2468 : Oid type_multirange_array_oid;
2469 :
840 akorotkov 2470 ECB : /* Use binary-upgrade override for pg_type.oid? */
840 akorotkov 2471 GIC 73 : if (IsBinaryUpgrade)
840 akorotkov 2472 ECB : {
840 akorotkov 2473 GBC 4 : if (!OidIsValid(binary_upgrade_next_mrng_array_pg_type_oid))
840 akorotkov 2474 UIC 0 : ereport(ERROR,
2475 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2476 : errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
840 akorotkov 2477 ECB :
840 akorotkov 2478 CBC 4 : type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
840 akorotkov 2479 GIC 4 : binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid;
2480 : }
2481 : else
840 akorotkov 2482 ECB : {
840 akorotkov 2483 GIC 69 : Relation pg_type = table_open(TypeRelationId, AccessShareLock);
840 akorotkov 2484 ECB :
840 akorotkov 2485 GIC 69 : type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
840 akorotkov 2486 ECB : Anum_pg_type_oid);
840 akorotkov 2487 GIC 69 : table_close(pg_type, AccessShareLock);
2488 : }
840 akorotkov 2489 ECB :
840 akorotkov 2490 GIC 73 : return type_multirange_array_oid;
2491 : }
2492 :
2493 :
2494 : /*-------------------------------------------------------------------
2495 : * DefineCompositeType
2496 : *
2497 : * Create a Composite Type relation.
2498 : * `DefineRelation' does all the work, we just provide the correct
2499 : * arguments!
2500 : *
2501 : * If the relation already exists, then 'DefineRelation' will abort
2502 : * the xact...
2503 : *
2504 : * Return type is the new type's object address.
2505 : *-------------------------------------------------------------------
2506 : */
2959 alvherre 2507 ECB : ObjectAddress
4060 peter_e 2508 GIC 315 : DefineCompositeType(RangeVar *typevar, List *coldeflist)
7542 bruce 2509 ECB : {
7542 bruce 2510 GIC 315 : CreateStmt *createStmt = makeNode(CreateStmt);
2511 : Oid old_type_oid;
2512 : Oid typeNamespace;
2513 : ObjectAddress address;
2514 :
2515 : /*
2516 : * now set the parameters for keys/inheritance etc. All of these are
2517 : * uninteresting for composite types...
7542 bruce 2518 ECB : */
4060 peter_e 2519 CBC 315 : createStmt->relation = typevar;
7542 bruce 2520 315 : createStmt->tableElts = coldeflist;
2521 315 : createStmt->inhRelations = NIL;
2522 315 : createStmt->constraints = NIL;
3649 tgl 2523 315 : createStmt->options = NIL;
7454 2524 315 : createStmt->oncommit = ONCOMMIT_NOOP;
6869 2525 315 : createStmt->tablespacename = NULL;
4641 rhaas 2526 GIC 315 : createStmt->if_not_exists = false;
2527 :
2528 : /*
2529 : * Check for collision with an existing type name. If there is one and
2530 : * it's an autogenerated array, we can rename it out of the way. This
2531 : * check is here mainly to get a better error message about a "type"
2532 : * instead of below about a "relation".
4827 peter_e 2533 ECB : */
4101 rhaas 2534 GIC 315 : typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
4101 rhaas 2535 ECB : NoLock, NULL);
4298 rhaas 2536 GIC 315 : RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
4802 rhaas 2537 ECB : old_type_oid =
1601 andres 2538 GIC 315 : GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2539 : CStringGetDatum(createStmt->relation->relname),
4802 rhaas 2540 ECB : ObjectIdGetDatum(typeNamespace));
4827 peter_e 2541 GIC 315 : if (OidIsValid(old_type_oid))
4827 peter_e 2542 EUB : {
4827 peter_e 2543 UBC 0 : if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
4827 peter_e 2544 UIC 0 : ereport(ERROR,
2545 : (errcode(ERRCODE_DUPLICATE_OBJECT),
2546 : errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2547 : }
2548 :
2549 : /*
2550 : * Finally create the relation. This also creates the type.
7542 bruce 2551 ECB : */
2314 rhaas 2552 GIC 315 : DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2553 : NULL);
2959 alvherre 2554 ECB :
2959 alvherre 2555 GIC 309 : return address;
2556 : }
2557 :
2558 : /*
2559 : * AlterDomainDefault
2560 : *
2561 : * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2562 : *
2563 : * Returns ObjectAddress of the modified domain.
2564 : */
2959 alvherre 2565 ECB : ObjectAddress
7429 bruce 2566 GIC 7 : AlterDomainDefault(List *names, Node *defaultRaw)
2567 : {
2568 : TypeName *typename;
2569 : Oid domainoid;
2570 : HeapTuple tup;
2571 : ParseState *pstate;
2572 : Relation rel;
7429 bruce 2573 ECB : char *defaultValue;
2118 tgl 2574 CBC 7 : Node *defaultExpr = NULL; /* NULL if no default specified */
267 peter 2575 GNC 7 : Datum new_record[Natts_pg_type] = {0};
2576 7 : bool new_record_nulls[Natts_pg_type] = {0};
2577 7 : bool new_record_repl[Natts_pg_type] = {0};
2578 : HeapTuple newtuple;
2579 : Form_pg_type typTup;
2580 : ObjectAddress address;
2581 :
7429 bruce 2582 ECB : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 2583 CBC 7 : typename = makeTypeNameFromNameList(names);
4549 peter_e 2584 GIC 7 : domainoid = typenameTypeId(NULL, typename);
2585 :
6235 tgl 2586 ECB : /* Look up the domain in the type table */
1539 andres 2587 GIC 7 : rel = table_open(TypeRelationId, RowExclusiveLock);
7429 bruce 2588 ECB :
4802 rhaas 2589 CBC 7 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
7429 bruce 2590 GBC 7 : if (!HeapTupleIsValid(tup))
7203 tgl 2591 LBC 0 : elog(ERROR, "cache lookup failed for type %u", domainoid);
6235 tgl 2592 GIC 7 : typTup = (Form_pg_type) GETSTRUCT(tup);
2593 :
6235 tgl 2594 ECB : /* Check it's a domain and check user has permission for ALTER DOMAIN */
4550 tgl 2595 GIC 7 : checkDomainOwner(tup);
2596 :
2597 : /* Setup new tuple */
2598 :
5641 tgl 2599 ECB : /* Store the new default into the tuple */
7429 bruce 2600 GIC 7 : if (defaultRaw)
2601 : {
2602 : /* Create a dummy ParseState for transformExpr */
2603 4 : pstate = make_parsestate(NULL);
2604 :
7429 bruce 2605 ECB : /*
2606 : * Cook the colDef->raw_expr into an expression. Note: Name is
2607 : * strictly for error message
2608 : */
7429 bruce 2609 GIC 4 : defaultExpr = cookDefault(pstate, defaultRaw,
2610 : typTup->typbasetype,
2611 : typTup->typtypmod,
1471 peter 2612 4 : NameStr(typTup->typname),
2613 : 0);
2614 :
2615 : /*
5641 tgl 2616 ECB : * If the expression is just a NULL constant, we treat the command
2617 : * like ALTER ... DROP DEFAULT. (But see note for same test in
2618 : * DefineDomain.)
2619 : */
5641 tgl 2620 GBC 4 : if (defaultExpr == NULL ||
1058 2621 4 : (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
5641 tgl 2622 EUB : {
2623 : /* Default is NULL, drop it */
1129 tgl 2624 UBC 0 : defaultExpr = NULL;
5271 tgl 2625 UIC 0 : new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2626 0 : new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2627 0 : new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2628 0 : new_record_repl[Anum_pg_type_typdefault - 1] = true;
2629 : }
2630 : else
2631 : {
2632 : /*
5641 tgl 2633 ECB : * Expression must be stored as a nodeToString result, but we also
2634 : * require a valid textual representation (mainly to make life
2635 : * easier for pg_dump).
2636 : */
5641 tgl 2637 GIC 4 : defaultValue = deparse_expression(defaultExpr,
2638 : NIL, false, false);
7188 bruce 2639 ECB :
2640 : /*
5641 tgl 2641 : * Form an updated tuple with the new default and write it back.
2642 : */
5493 tgl 2643 CBC 4 : new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2644 :
5271 tgl 2645 GIC 4 : new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
5493 2646 4 : new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
5271 2647 4 : new_record_repl[Anum_pg_type_typdefault - 1] = true;
2648 : }
7429 bruce 2649 ECB : }
7188 2650 : else
7429 2651 : {
5641 tgl 2652 : /* ALTER ... DROP DEFAULT */
5271 tgl 2653 GIC 3 : new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2654 3 : new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
5271 tgl 2655 CBC 3 : new_record_nulls[Anum_pg_type_typdefault - 1] = true;
5271 tgl 2656 GIC 3 : new_record_repl[Anum_pg_type_typdefault - 1] = true;
2657 : }
2658 :
5271 tgl 2659 CBC 7 : newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2660 : new_record, new_record_nulls,
2661 : new_record_repl);
7429 bruce 2662 ECB :
2259 alvherre 2663 GIC 7 : CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2664 :
2665 : /* Rebuild dependencies */
1129 tgl 2666 7 : GenerateTypeDependencies(newtuple,
2667 : rel,
2668 : defaultExpr,
2669 : NULL, /* don't have typacl handy */
2670 : 0, /* relation kind is n/a */
2671 : false, /* a domain isn't an implicit array */
1612 tgl 2672 ECB : false, /* nor is it any kind of dependent type */
2673 : false, /* don't touch extension membership */
2674 : true); /* We do need to rebuild dependencies */
2675 :
3675 rhaas 2676 GIC 7 : InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
3675 rhaas 2677 ECB :
2959 alvherre 2678 CBC 7 : ObjectAddressSet(address, TypeRelationId, domainoid);
2679 :
7429 bruce 2680 ECB : /* Clean up */
1539 andres 2681 GIC 7 : table_close(rel, RowExclusiveLock);
7429 bruce 2682 7 : heap_freetuple(newtuple);
2683 :
2959 alvherre 2684 7 : return address;
2685 : }
2686 :
2687 : /*
2688 : * AlterDomainNotNull
2689 : *
2690 : * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2959 alvherre 2691 ECB : *
2692 : * Returns ObjectAddress of the modified domain.
2693 : */
2694 : ObjectAddress
7429 bruce 2695 GIC 18 : AlterDomainNotNull(List *names, bool notNull)
2696 : {
2697 : TypeName *typename;
7429 bruce 2698 ECB : Oid domainoid;
2699 : Relation typrel;
2700 : HeapTuple tup;
7188 2701 : Form_pg_type typTup;
2959 alvherre 2702 CBC 18 : ObjectAddress address = InvalidObjectAddress;
2703 :
2704 : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 2705 18 : typename = makeTypeNameFromNameList(names);
4549 peter_e 2706 GIC 18 : domainoid = typenameTypeId(NULL, typename);
7429 bruce 2707 ECB :
6235 tgl 2708 : /* Look up the domain in the type table */
1539 andres 2709 GBC 18 : typrel = table_open(TypeRelationId, RowExclusiveLock);
7429 bruce 2710 ECB :
4802 rhaas 2711 GIC 18 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
7429 bruce 2712 18 : if (!HeapTupleIsValid(tup))
7203 tgl 2713 LBC 0 : elog(ERROR, "cache lookup failed for type %u", domainoid);
7400 tgl 2714 GIC 18 : typTup = (Form_pg_type) GETSTRUCT(tup);
2715 :
6235 tgl 2716 ECB : /* Check it's a domain and check user has permission for ALTER DOMAIN */
4550 tgl 2717 GIC 18 : checkDomainOwner(tup);
7429 bruce 2718 EUB :
7400 tgl 2719 : /* Is the domain already set to the desired constraint? */
7429 bruce 2720 GIC 18 : if (typTup->typnotnull == notNull)
2721 : {
1539 andres 2722 UIC 0 : table_close(typrel, RowExclusiveLock);
2959 alvherre 2723 LBC 0 : return address;
2724 : }
2725 :
2726 : /* Adding a NOT NULL constraint requires checking existing columns */
7429 bruce 2727 GIC 18 : if (notNull)
2728 : {
2729 : List *rels;
2730 : ListCell *rt;
7429 bruce 2731 ECB :
2732 : /* Fetch relation list with attributes based on this domain */
7400 tgl 2733 : /* ShareLock is sufficient to prevent concurrent data changes */
2734 :
7400 tgl 2735 CBC 12 : rels = get_rels_with_domain(domainoid, ShareLock);
7429 bruce 2736 ECB :
7188 bruce 2737 CBC 15 : foreach(rt, rels)
2738 : {
7400 tgl 2739 GIC 9 : RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2740 9 : Relation testrel = rtc->rel;
2741 9 : TupleDesc tupdesc = RelationGetDescr(testrel);
2742 : TupleTableSlot *slot;
1490 andres 2743 ECB : TableScanDesc scan;
3568 rhaas 2744 : Snapshot snapshot;
7429 bruce 2745 :
7400 tgl 2746 : /* Scan all tuples in this relation */
3568 rhaas 2747 GIC 9 : snapshot = RegisterSnapshot(GetLatestSnapshot());
1490 andres 2748 9 : scan = table_beginscan(testrel, snapshot, 0, NULL);
2749 9 : slot = table_slot_create(testrel, NULL);
2750 12 : while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
7429 bruce 2751 ECB : {
2752 : int i;
2753 :
7400 tgl 2754 : /* Test attributes that are of the domain */
7429 bruce 2755 GIC 18 : for (i = 0; i < rtc->natts; i++)
7429 bruce 2756 ECB : {
7188 bruce 2757 GIC 15 : int attnum = rtc->atts[i];
2058 andres 2758 15 : Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2759 :
1490 2760 15 : if (slot_attisnull(slot, attnum))
2761 : {
2762 : /*
2763 : * In principle the auxiliary information for this
2764 : * error should be errdatatype(), but errtablecol()
2765 : * seems considerably more useful in practice. Since
3722 tgl 2766 ECB : * this code only executes in an ALTER DOMAIN command,
2767 : * the client should already know which domain is in
2768 : * question.
2769 : */
7203 tgl 2770 GIC 6 : ereport(ERROR,
2771 : (errcode(ERRCODE_NOT_NULL_VIOLATION),
2772 : errmsg("column \"%s\" of table \"%s\" contains null values",
2773 : NameStr(attr->attname),
2774 : RelationGetRelationName(testrel)),
3722 tgl 2775 ECB : errtablecol(testrel, attnum)));
2776 : }
7429 bruce 2777 : }
2778 : }
1490 andres 2779 GIC 3 : ExecDropSingleTupleTableSlot(slot);
1490 andres 2780 CBC 3 : table_endscan(scan);
3568 rhaas 2781 GIC 3 : UnregisterSnapshot(snapshot);
2782 :
2783 : /* Close each rel after processing, but keep lock */
1539 andres 2784 3 : table_close(testrel, NoLock);
2785 : }
2786 : }
2787 :
7400 tgl 2788 ECB : /*
2789 : * Okay to update pg_type row. We can scribble on typTup because it's a
6385 bruce 2790 : * copy.
2791 : */
7400 tgl 2792 CBC 12 : typTup->typnotnull = notNull;
2793 :
2259 alvherre 2794 12 : CatalogTupleUpdate(typrel, &tup->t_self, tup);
2795 :
3675 rhaas 2796 GIC 12 : InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
3675 rhaas 2797 ECB :
2959 alvherre 2798 CBC 12 : ObjectAddressSet(address, TypeRelationId, domainoid);
2799 :
7429 bruce 2800 ECB : /* Clean up */
7400 tgl 2801 GIC 12 : heap_freetuple(tup);
1539 andres 2802 12 : table_close(typrel, RowExclusiveLock);
2803 :
2959 alvherre 2804 12 : return address;
2805 : }
2806 :
2807 : /*
2808 : * AlterDomainDropConstraint
2809 : *
2810 : * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1678 tgl 2811 ECB : *
2812 : * Returns ObjectAddress of the modified domain.
2813 : */
2814 : ObjectAddress
6235 tgl 2815 GIC 21 : AlterDomainDropConstraint(List *names, const char *constrName,
2816 : DropBehavior behavior, bool missing_ok)
2817 : {
2818 : TypeName *typename;
2819 : Oid domainoid;
2820 : HeapTuple tup;
2821 : Relation rel;
7429 bruce 2822 ECB : Relation conrel;
2823 : SysScanDesc conscan;
2824 : ScanKeyData skey[3];
2825 : HeapTuple contup;
4112 peter_e 2826 CBC 21 : bool found = false;
1678 tgl 2827 ECB : ObjectAddress address;
2828 :
2829 : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 2830 CBC 21 : typename = makeTypeNameFromNameList(names);
4549 peter_e 2831 GIC 21 : domainoid = typenameTypeId(NULL, typename);
7429 bruce 2832 ECB :
6235 tgl 2833 : /* Look up the domain in the type table */
1539 andres 2834 GBC 21 : rel = table_open(TypeRelationId, RowExclusiveLock);
2835 :
4802 rhaas 2836 GIC 21 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
7429 bruce 2837 CBC 21 : if (!HeapTupleIsValid(tup))
7203 tgl 2838 UIC 0 : elog(ERROR, "cache lookup failed for type %u", domainoid);
2839 :
6235 tgl 2840 ECB : /* Check it's a domain and check user has permission for ALTER DOMAIN */
4550 tgl 2841 GIC 21 : checkDomainOwner(tup);
2842 :
7429 bruce 2843 ECB : /* Grab an appropriate lock on the pg_constraint relation */
1539 andres 2844 GIC 21 : conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2845 :
2846 : /* Find and remove the target constraint */
1678 tgl 2847 CBC 21 : ScanKeyInit(&skey[0],
2848 : Anum_pg_constraint_conrelid,
2849 : BTEqualStrategyNumber, F_OIDEQ,
2850 : ObjectIdGetDatum(InvalidOid));
2851 21 : ScanKeyInit(&skey[1],
2852 : Anum_pg_constraint_contypid,
2853 : BTEqualStrategyNumber, F_OIDEQ,
2854 : ObjectIdGetDatum(domainoid));
1678 tgl 2855 GIC 21 : ScanKeyInit(&skey[2],
1678 tgl 2856 ECB : Anum_pg_constraint_conname,
2857 : BTEqualStrategyNumber, F_NAMEEQ,
2858 : CStringGetDatum(constrName));
2859 :
1678 tgl 2860 CBC 21 : conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2861 : NULL, 3, skey);
2862 :
2863 : /* There can be at most one matching row */
2864 21 : if ((contup = systable_getnext(conscan)) != NULL)
7429 bruce 2865 ECB : {
1678 tgl 2866 : ObjectAddress conobj;
2867 :
1678 tgl 2868 CBC 15 : conobj.classId = ConstraintRelationId;
1601 andres 2869 15 : conobj.objectId = ((Form_pg_constraint) GETSTRUCT(contup))->oid;
1678 tgl 2870 GIC 15 : conobj.objectSubId = 0;
2871 :
2872 15 : performDeletion(&conobj, behavior, 0);
1678 tgl 2873 CBC 15 : found = true;
7429 bruce 2874 ECB : }
2875 :
2876 : /* Clean up after the scan */
7429 bruce 2877 GIC 21 : systable_endscan(conscan);
1539 andres 2878 CBC 21 : table_close(conrel, RowExclusiveLock);
7429 bruce 2879 ECB :
4112 peter_e 2880 GIC 21 : if (!found)
2881 : {
2882 6 : if (!missing_ok)
2883 3 : ereport(ERROR,
4112 peter_e 2884 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
2885 : errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2886 : constrName, TypeNameToString(typename))));
2887 : else
4112 peter_e 2888 GIC 3 : ereport(NOTICE,
2889 : (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2890 : constrName, TypeNameToString(typename))));
2891 : }
2892 :
2893 : /*
1578 tgl 2894 ECB : * We must send out an sinval message for the domain, to ensure that any
2895 : * dependent plans get rebuilt. Since this command doesn't change the
2896 : * domain's pg_type row, that won't happen automatically; do it manually.
2897 : */
1578 tgl 2898 GIC 18 : CacheInvalidateHeapTuple(rel, tup, NULL);
1578 tgl 2899 ECB :
1678 tgl 2900 GIC 18 : ObjectAddressSet(address, TypeRelationId, domainoid);
1678 tgl 2901 ECB :
2902 : /* Clean up */
1539 andres 2903 GIC 18 : table_close(rel, RowExclusiveLock);
2904 :
2959 alvherre 2905 18 : return address;
2906 : }
2907 :
2908 : /*
2909 : * AlterDomainAddConstraint
7429 bruce 2910 ECB : *
2911 : * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2912 : */
2913 : ObjectAddress
2959 alvherre 2914 GIC 72 : AlterDomainAddConstraint(List *names, Node *newConstraint,
2915 : ObjectAddress *constrAddr)
2916 : {
2917 : TypeName *typename;
2918 : Oid domainoid;
2919 : Relation typrel;
2920 : HeapTuple tup;
2921 : Form_pg_type typTup;
2922 : Constraint *constr;
4330 alvherre 2923 ECB : char *ccbin;
2959 2924 : ObjectAddress address;
2925 :
2926 : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 2927 CBC 72 : typename = makeTypeNameFromNameList(names);
4549 peter_e 2928 GIC 72 : domainoid = typenameTypeId(NULL, typename);
7429 bruce 2929 ECB :
6235 tgl 2930 : /* Look up the domain in the type table */
1539 andres 2931 GBC 72 : typrel = table_open(TypeRelationId, RowExclusiveLock);
7429 bruce 2932 ECB :
4802 rhaas 2933 GIC 72 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
7429 bruce 2934 72 : if (!HeapTupleIsValid(tup))
7203 tgl 2935 LBC 0 : elog(ERROR, "cache lookup failed for type %u", domainoid);
7426 tgl 2936 GIC 72 : typTup = (Form_pg_type) GETSTRUCT(tup);
7429 bruce 2937 ECB :
6235 tgl 2938 EUB : /* Check it's a domain and check user has permission for ALTER DOMAIN */
4550 tgl 2939 GIC 72 : checkDomainOwner(tup);
2940 :
7426 tgl 2941 CBC 72 : if (!IsA(newConstraint, Constraint))
7203 tgl 2942 UIC 0 : elog(ERROR, "unrecognized node type: %d",
7203 tgl 2943 ECB : (int) nodeTag(newConstraint));
2944 :
7429 bruce 2945 CBC 72 : constr = (Constraint *) newConstraint;
2946 :
2947 72 : switch (constr->contype)
2948 : {
7188 bruce 2949 GBC 72 : case CONSTR_CHECK:
7426 tgl 2950 EUB : /* processed below */
7188 bruce 2951 GIC 72 : break;
2952 :
7426 tgl 2953 UIC 0 : case CONSTR_UNIQUE:
7203 2954 0 : ereport(ERROR,
7152 peter_e 2955 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
6385 bruce 2956 : errmsg("unique constraints not possible for domains")));
2957 : break;
2958 :
7426 tgl 2959 UIC 0 : case CONSTR_PRIMARY:
7203 2960 0 : ereport(ERROR,
7152 peter_e 2961 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
2118 tgl 2962 : errmsg("primary key constraints not possible for domains")));
2963 : break;
2964 :
4871 tgl 2965 UIC 0 : case CONSTR_EXCLUSION:
2966 0 : ereport(ERROR,
4871 tgl 2967 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
2118 2968 : errmsg("exclusion constraints not possible for domains")));
2969 : break;
2970 :
5001 tgl 2971 UIC 0 : case CONSTR_FOREIGN:
2972 0 : ereport(ERROR,
5001 tgl 2973 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
2974 : errmsg("foreign key constraints not possible for domains")));
2975 : break;
2976 :
7426 tgl 2977 UBC 0 : case CONSTR_ATTR_DEFERRABLE:
2978 : case CONSTR_ATTR_NOT_DEFERRABLE:
2979 : case CONSTR_ATTR_DEFERRED:
2980 : case CONSTR_ATTR_IMMEDIATE:
7203 tgl 2981 UIC 0 : ereport(ERROR,
7203 tgl 2982 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7152 peter_e 2983 : errmsg("specifying constraint deferrability not supported for domains")));
2984 : break;
2985 :
7429 bruce 2986 UIC 0 : default:
7203 tgl 2987 0 : elog(ERROR, "unrecognized constraint subtype: %d",
2988 : (int) constr->contype);
2989 : break;
2990 : }
2991 :
2992 : /*
2993 : * Since all other constraint types throw errors, this must be a check
3260 bruce 2994 ECB : * constraint. First, process the constraint expression and add an entry
2995 : * to pg_constraint.
7426 tgl 2996 : */
2997 :
3722 tgl 2998 GIC 72 : ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2999 : typTup->typbasetype, typTup->typtypmod,
2959 alvherre 3000 72 : constr, NameStr(typTup->typname), constrAddr);
3001 :
7426 tgl 3002 ECB : /*
4330 alvherre 3003 : * If requested to validate the constraint, test all values stored in the
3004 : * attributes based on the domain the constraint is being added to.
3005 : */
4330 alvherre 3006 GIC 69 : if (!constr->skip_validation)
3007 66 : validateDomainConstraint(domainoid, ccbin);
3008 :
3009 : /*
1578 tgl 3010 ECB : * We must send out an sinval message for the domain, to ensure that any
3011 : * dependent plans get rebuilt. Since this command doesn't change the
3012 : * domain's pg_type row, that won't happen automatically; do it manually.
3013 : */
1578 tgl 3014 GIC 39 : CacheInvalidateHeapTuple(typrel, tup, NULL);
1578 tgl 3015 ECB :
2959 alvherre 3016 GIC 39 : ObjectAddressSet(address, TypeRelationId, domainoid);
2959 alvherre 3017 ECB :
3018 : /* Clean up */
1539 andres 3019 GIC 39 : table_close(typrel, RowExclusiveLock);
3020 :
2959 alvherre 3021 39 : return address;
3022 : }
3023 :
3024 : /*
3025 : * AlterDomainValidateConstraint
4330 alvherre 3026 ECB : *
3027 : * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
3028 : */
3029 : ObjectAddress
1986 peter_e 3030 GIC 6 : AlterDomainValidateConstraint(List *names, const char *constrName)
3031 : {
3032 : TypeName *typename;
3033 : Oid domainoid;
3034 : Relation typrel;
3035 : Relation conrel;
3036 : HeapTuple tup;
3037 : Form_pg_constraint con;
3038 : Form_pg_constraint copy_con;
3039 : char *conbin;
3040 : SysScanDesc scan;
3041 : Datum val;
3042 : HeapTuple tuple;
4330 alvherre 3043 ECB : HeapTuple copyTuple;
1678 tgl 3044 : ScanKeyData skey[3];
3045 : ObjectAddress address;
3046 :
4330 alvherre 3047 : /* Make a TypeName so we can use standard type lookup machinery */
4330 alvherre 3048 GIC 6 : typename = makeTypeNameFromNameList(names);
4330 alvherre 3049 CBC 6 : domainoid = typenameTypeId(NULL, typename);
4330 alvherre 3050 ECB :
4330 alvherre 3051 EUB : /* Look up the domain in the type table */
1539 andres 3052 GIC 6 : typrel = table_open(TypeRelationId, AccessShareLock);
3053 :
4330 alvherre 3054 CBC 6 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
4330 alvherre 3055 GIC 6 : if (!HeapTupleIsValid(tup))
4330 alvherre 3056 UIC 0 : elog(ERROR, "cache lookup failed for type %u", domainoid);
3057 :
3058 : /* Check it's a domain and check user has permission for ALTER DOMAIN */
4330 alvherre 3059 CBC 6 : checkDomainOwner(tup);
3060 :
4330 alvherre 3061 ECB : /*
3062 : * Find and check the target constraint
3063 : */
1539 andres 3064 GIC 6 : conrel = table_open(ConstraintRelationId, RowExclusiveLock);
1678 tgl 3065 ECB :
1678 tgl 3066 GIC 6 : ScanKeyInit(&skey[0],
3067 : Anum_pg_constraint_conrelid,
3068 : BTEqualStrategyNumber, F_OIDEQ,
1678 tgl 3069 ECB : ObjectIdGetDatum(InvalidOid));
1678 tgl 3070 GIC 6 : ScanKeyInit(&skey[1],
3071 : Anum_pg_constraint_contypid,
3072 : BTEqualStrategyNumber, F_OIDEQ,
3073 : ObjectIdGetDatum(domainoid));
1678 tgl 3074 CBC 6 : ScanKeyInit(&skey[2],
3075 : Anum_pg_constraint_conname,
3076 : BTEqualStrategyNumber, F_NAMEEQ,
3077 : CStringGetDatum(constrName));
4330 alvherre 3078 ECB :
1678 tgl 3079 GBC 6 : scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
3080 : NULL, 3, skey);
3081 :
3082 : /* There can be at most one matching row */
1678 tgl 3083 GIC 6 : if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
4330 alvherre 3084 LBC 0 : ereport(ERROR,
4330 alvherre 3085 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
4330 alvherre 3086 EUB : errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3087 : constrName, TypeNameToString(typename))));
3088 :
1678 tgl 3089 GIC 6 : con = (Form_pg_constraint) GETSTRUCT(tuple);
4330 alvherre 3090 6 : if (con->contype != CONSTRAINT_CHECK)
4330 alvherre 3091 LBC 0 : ereport(ERROR,
4330 alvherre 3092 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3093 : errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2118 tgl 3094 : constrName, TypeNameToString(typename))));
3095 :
15 dgustafsson 3096 GNC 6 : val = SysCacheGetAttrNotNull(CONSTROID, tuple, Anum_pg_constraint_conbin);
4330 alvherre 3097 CBC 6 : conbin = TextDatumGetCString(val);
3098 :
3099 6 : validateDomainConstraint(domainoid, conbin);
3100 :
4330 alvherre 3101 ECB : /*
3102 : * Now update the catalog, while we have the door open.
3103 : */
4330 alvherre 3104 GIC 3 : copyTuple = heap_copytuple(tuple);
4330 alvherre 3105 CBC 3 : copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
4330 alvherre 3106 GIC 3 : copy_con->convalidated = true;
2259 alvherre 3107 CBC 3 : CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple);
3675 rhaas 3108 ECB :
1601 andres 3109 GIC 3 : InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
3675 rhaas 3110 ECB :
2959 alvherre 3111 GIC 3 : ObjectAddressSet(address, TypeRelationId, domainoid);
2959 alvherre 3112 ECB :
4330 alvherre 3113 GIC 3 : heap_freetuple(copyTuple);
3114 :
3115 3 : systable_endscan(scan);
4330 alvherre 3116 ECB :
1539 andres 3117 GIC 3 : table_close(typrel, AccessShareLock);
1539 andres 3118 CBC 3 : table_close(conrel, RowExclusiveLock);
3119 :
4330 alvherre 3120 GIC 3 : ReleaseSysCache(tup);
3121 :
2959 3122 3 : return address;
3123 : }
3124 :
3125 : static void
4330 alvherre 3126 CBC 72 : validateDomainConstraint(Oid domainoid, char *ccbin)
4330 alvherre 3127 ECB : {
4330 alvherre 3128 GIC 72 : Expr *expr = (Expr *) stringToNode(ccbin);
3129 : List *rels;
4330 alvherre 3130 ECB : ListCell *rt;
3131 : EState *estate;
3132 : ExprContext *econtext;
3133 : ExprState *exprstate;
3134 :
7420 tgl 3135 : /* Need an EState to run ExecEvalExpr */
7420 tgl 3136 GIC 72 : estate = CreateExecutorState();
7420 tgl 3137 CBC 72 : econtext = GetPerTupleExprContext(estate);
3138 :
7420 tgl 3139 ECB : /* build execution state for expr */
7420 tgl 3140 CBC 72 : exprstate = ExecPrepareExpr(expr, estate);
7423 tgl 3141 ECB :
3142 : /* Fetch relation list with attributes based on this domain */
3143 : /* ShareLock is sufficient to prevent concurrent data changes */
3144 :
7400 tgl 3145 GIC 72 : rels = get_rels_with_domain(domainoid, ShareLock);
3146 :
7188 bruce 3147 CBC 75 : foreach(rt, rels)
7429 bruce 3148 ECB : {
7400 tgl 3149 CBC 36 : RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3150 36 : Relation testrel = rtc->rel;
7400 tgl 3151 GIC 36 : TupleDesc tupdesc = RelationGetDescr(testrel);
3152 : TupleTableSlot *slot;
3153 : TableScanDesc scan;
3154 : Snapshot snapshot;
7429 bruce 3155 ECB :
3156 : /* Scan all tuples in this relation */
3568 rhaas 3157 CBC 36 : snapshot = RegisterSnapshot(GetLatestSnapshot());
1490 andres 3158 GIC 36 : scan = table_beginscan(testrel, snapshot, 0, NULL);
3159 36 : slot = table_slot_create(testrel, NULL);
3160 84 : while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
7429 bruce 3161 ECB : {
3162 : int i;
3163 :
3164 : /* Test attributes that are of the domain */
7429 bruce 3165 CBC 114 : for (i = 0; i < rtc->natts; i++)
7429 bruce 3166 ECB : {
7188 bruce 3167 GIC 66 : int attnum = rtc->atts[i];
7188 bruce 3168 ECB : Datum d;
3169 : bool isNull;
3170 : Datum conResult;
2058 andres 3171 GIC 66 : Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
7429 bruce 3172 ECB :
1490 andres 3173 GIC 66 : d = slot_getattr(slot, attnum, &isNull);
3174 :
7429 bruce 3175 66 : econtext->domainValue_datum = d;
3176 66 : econtext->domainValue_isNull = isNull;
3177 :
7420 tgl 3178 66 : conResult = ExecEvalExprSwitchContext(exprstate,
3179 : econtext,
3180 : &isNull);
3181 :
7423 tgl 3182 CBC 66 : if (!isNull && !DatumGetBool(conResult))
3183 : {
3184 : /*
3185 : * In principle the auxiliary information for this error
3186 : * should be errdomainconstraint(), but errtablecol()
3187 : * seems considerably more useful in practice. Since this
3188 : * code only executes in an ALTER DOMAIN command, the
3189 : * client should already know which domain is in question,
3190 : * and which constraint too.
3722 tgl 3191 ECB : */
7203 tgl 3192 GIC 18 : ereport(ERROR,
7203 tgl 3193 ECB : (errcode(ERRCODE_CHECK_VIOLATION),
7132 peter_e 3194 : errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2058 andres 3195 : NameStr(attr->attname),
3196 : RelationGetRelationName(testrel)),
3197 : errtablecol(testrel, attnum)));
3722 tgl 3198 : }
3199 : }
3200 :
7429 bruce 3201 CBC 48 : ResetExprContext(econtext);
7429 bruce 3202 ECB : }
1490 andres 3203 GIC 18 : ExecDropSingleTupleTableSlot(slot);
3204 18 : table_endscan(scan);
3568 rhaas 3205 18 : UnregisterSnapshot(snapshot);
3206 :
3207 : /* Hold relation lock till commit (XXX bad for concurrency) */
1539 andres 3208 18 : table_close(testrel, NoLock);
3209 : }
3210 :
7420 tgl 3211 39 : FreeExecutorState(estate);
7429 bruce 3212 39 : }
3213 :
3214 : /*
3215 : * get_rels_with_domain
3216 : *
3217 : * Fetch all relations / attributes which are using the domain
3218 : *
3219 : * The result is a list of RelToCheck structs, one for each distinct
3220 : * relation, each containing one or more attribute numbers that are of
3221 : * the domain type. We have opened each rel and acquired the specified lock
3222 : * type on it.
3223 : *
3224 : * We support nested domains by including attributes that are of derived
3225 : * domain types. Current callers do not need to distinguish between attributes
3226 : * that are of exactly the given domain and those that are of derived domains.
3227 : *
3228 : * XXX this is completely broken because there is no way to lock the domain
3229 : * to prevent columns from being added or dropped while our command runs.
3230 : * We can partially protect against column drops by locking relations as we
3231 : * come across them, but there is still a race condition (the window between
3232 : * seeing a pg_depend entry and acquiring lock on the relation it references).
3233 : * Also, holding locks on all these relations simultaneously creates a non-
3234 : * trivial risk of deadlock. We can minimize but not eliminate the deadlock
3235 : * risk by using the weakest suitable lock (ShareLock for most callers).
7400 tgl 3236 ECB : *
3237 : * XXX the API for this is not sufficient to support checking domain values
2069 3238 : * that are inside container types, such as composite types, arrays, or
3239 : * ranges. Currently we just error out if a container type containing the
3240 : * target domain is stored anywhere.
3241 : *
3242 : * Generally used for retrieving a list of tests when adding
3243 : * new constraints to a domain.
3244 : */
7400 3245 : static List *
7400 tgl 3246 GIC 90 : get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
3247 : {
7188 bruce 3248 CBC 90 : List *result = NIL;
2069 tgl 3249 GIC 90 : char *domainTypeName = format_type_be(domainOid);
3250 : Relation depRel;
3251 : ScanKeyData key[2];
3252 : SysScanDesc depScan;
3253 : HeapTuple depTup;
7429 bruce 3254 ECB :
6096 tgl 3255 GIC 90 : Assert(lockmode != NoLock);
6096 tgl 3256 ECB :
3257 : /* since this function recurses, it could be driven to stack overflow */
2069 tgl 3258 GIC 90 : check_stack_depth();
3259 :
7429 bruce 3260 ECB : /*
3261 : * We scan pg_depend to find those things that depend on the domain. (We
3262 : * assume we can ignore refobjsubid for a domain.)
3263 : */
1539 andres 3264 GIC 90 : depRel = table_open(DependRelationId, AccessShareLock);
7429 bruce 3265 ECB :
7088 tgl 3266 GIC 90 : ScanKeyInit(&key[0],
3267 : Anum_pg_depend_refclassid,
7088 tgl 3268 ECB : BTEqualStrategyNumber, F_OIDEQ,
3269 : ObjectIdGetDatum(TypeRelationId));
7088 tgl 3270 CBC 90 : ScanKeyInit(&key[1],
7088 tgl 3271 ECB : Anum_pg_depend_refobjid,
3272 : BTEqualStrategyNumber, F_OIDEQ,
3273 : ObjectIdGetDatum(domainOid));
3274 :
6569 tgl 3275 GIC 90 : depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3276 : NULL, 2, key);
7429 bruce 3277 ECB :
7400 tgl 3278 GIC 298 : while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
7429 bruce 3279 ECB : {
7188 bruce 3280 GIC 223 : Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
7400 tgl 3281 223 : RelToCheck *rtc = NULL;
3282 : ListCell *rellist;
3283 : Form_pg_attribute pg_att;
3284 : int ptr;
3285 :
3286 : /* Check for directly dependent types */
5812 3287 223 : if (pg_depend->classid == TypeRelationId)
5812 tgl 3288 ECB : {
2069 tgl 3289 CBC 99 : if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3290 : {
3291 : /*
3292 : * This is a sub-domain, so recursively add dependent columns
3293 : * to the output list. This is a bit inefficient since we may
3294 : * fail to combine RelToCheck entries when attributes of the
3295 : * same rel have different derived domain types, but it's
3296 : * probably not worth improving.
3297 : */
3298 6 : result = list_concat(result,
2069 tgl 3299 GIC 6 : get_rels_with_domain(pg_depend->objid,
3300 : lockmode));
3301 : }
2069 tgl 3302 ECB : else
3303 : {
3304 : /*
3305 : * Otherwise, it is some container type using the domain, so
3306 : * fail if there are any columns of this type.
3307 : */
2069 tgl 3308 CBC 93 : find_composite_type_dependencies(pg_depend->objid,
2069 tgl 3309 ECB : NULL,
3310 : domainTypeName);
3311 : }
5812 tgl 3312 CBC 96 : continue;
3313 : }
5812 tgl 3314 ECB :
3315 : /* Else, ignore dependees that aren't user columns of relations */
7400 3316 : /* (we assume system columns are never of domain types) */
6569 tgl 3317 GIC 124 : if (pg_depend->classid != RelationRelationId ||
7400 tgl 3318 CBC 84 : pg_depend->objsubid <= 0)
3319 40 : continue;
3320 :
3321 : /* See if we already have an entry for this relation */
7400 tgl 3322 GIC 84 : foreach(rellist, result)
7400 tgl 3323 ECB : {
7400 tgl 3324 GIC 9 : RelToCheck *rt = (RelToCheck *) lfirst(rellist);
3325 :
3326 9 : if (RelationGetRelid(rt->rel) == pg_depend->objid)
3327 : {
3328 9 : rtc = rt;
7400 tgl 3329 CBC 9 : break;
3330 : }
3331 : }
3332 :
7400 tgl 3333 GIC 84 : if (rtc == NULL)
3334 : {
7400 tgl 3335 ECB : /* First attribute found for this relation */
3336 : Relation rel;
3337 :
3338 : /* Acquire requested lock on relation */
6913 tgl 3339 GIC 75 : rel = relation_open(pg_depend->objid, lockmode);
3340 :
3341 : /*
3342 : * Check to see if rowtype is stored anyplace as a composite-type
3343 : * column; if so we have to fail, for now anyway.
3344 : */
5812 3345 75 : if (OidIsValid(rel->rd_rel->reltype))
3346 75 : find_composite_type_dependencies(rel->rd_rel->reltype,
3347 : NULL,
2069 tgl 3348 ECB : domainTypeName);
5812 3349 :
3350 : /*
3565 noah 3351 : * Otherwise, we can ignore relations except those with both
3352 : * storage and user-chosen column types.
3353 : *
3354 : * XXX If an index-only scan could satisfy "col::some_domain" from
3355 : * a suitable expression index, this should also check expression
3356 : * index columns.
3357 : */
3689 kgrittn 3358 CBC 63 : if (rel->rd_rel->relkind != RELKIND_RELATION &&
3359 18 : rel->rd_rel->relkind != RELKIND_MATVIEW)
6913 tgl 3360 ECB : {
6913 tgl 3361 GIC 18 : relation_close(rel, lockmode);
3362 18 : continue;
3363 : }
3364 :
3365 : /* Build the RelToCheck entry with enough space for all atts */
7400 3366 45 : rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
3367 45 : rtc->rel = rel;
3368 45 : rtc->natts = 0;
7400 tgl 3369 CBC 45 : rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
1362 tgl 3370 GBC 45 : result = lappend(result, rtc);
7400 tgl 3371 ECB : }
7429 bruce 3372 :
7400 tgl 3373 EUB : /*
3374 : * Confirm column has not been dropped, and is of the expected type.
3375 : * This defends against an ALTER DROP COLUMN occurring just before we
3376 : * acquired lock ... but if the whole table were dropped, we'd still
3377 : * have a problem.
3378 : */
7400 tgl 3379 GIC 54 : if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
7400 tgl 3380 LBC 0 : continue;
2058 andres 3381 GIC 54 : pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
7400 tgl 3382 CBC 54 : if (pg_att->attisdropped || pg_att->atttypid != domainOid)
7400 tgl 3383 LBC 0 : continue;
3384 :
7400 tgl 3385 EUB : /*
3260 bruce 3386 : * Okay, add column to result. We store the columns in column-number
3387 : * order; this is just a hack to improve predictability of regression
6385 bruce 3388 ECB : * test output ...
3389 : */
7400 tgl 3390 GIC 54 : Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
7429 bruce 3391 ECB :
7400 tgl 3392 GIC 54 : ptr = rtc->natts++;
7188 bruce 3393 CBC 54 : while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3394 : {
7188 bruce 3395 LBC 0 : rtc->atts[ptr] = rtc->atts[ptr - 1];
7400 tgl 3396 UIC 0 : ptr--;
3397 : }
7400 tgl 3398 GIC 54 : rtc->atts[ptr] = pg_depend->objsubid;
3399 : }
3400 :
3401 75 : systable_endscan(depScan);
3402 :
3403 75 : relation_close(depRel, AccessShareLock);
3404 :
7400 tgl 3405 CBC 75 : return result;
3406 : }
7429 bruce 3407 ECB :
3408 : /*
3409 : * checkDomainOwner
3410 : *
6235 tgl 3411 EUB : * Check that the type is actually a domain and that the current user
3412 : * has permission to do ALTER DOMAIN on it. Throw an error if not.
3413 : */
3414 : void
4550 tgl 3415 GIC 127 : checkDomainOwner(HeapTuple tup)
3416 : {
7188 bruce 3417 CBC 127 : Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
7429 bruce 3418 EUB :
7429 bruce 3419 ECB : /* Check that this is actually a domain */
5851 tgl 3420 GIC 127 : if (typTup->typtype != TYPTYPE_DOMAIN)
7203 tgl 3421 UIC 0 : ereport(ERROR,
3422 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3423 : errmsg("%s is not a domain",
3424 : format_type_be(typTup->oid))));
7429 bruce 3425 ECB :
3426 : /* Permission check: must own type */
147 peter 3427 GNC 127 : if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
1601 andres 3428 UIC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
7400 tgl 3429 GIC 127 : }
3430 :
3431 : /*
3432 : * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
3433 : */
3434 : static char *
7429 bruce 3435 807 : domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3436 : int typMod, Constraint *constr,
3437 : const char *domainName, ObjectAddress *constrAddr)
7429 bruce 3438 ECB : {
3439 : Node *expr;
3440 : char *ccbin;
3441 : ParseState *pstate;
7188 3442 : CoerceToDomainValue *domVal;
2959 alvherre 3443 EUB : Oid ccoid;
3444 :
3445 : /*
3446 : * Assign or validate constraint name
3447 : */
5001 tgl 3448 GIC 807 : if (constr->conname)
7429 bruce 3449 ECB : {
7429 bruce 3450 GIC 699 : if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
3451 : domainOid,
5001 tgl 3452 699 : constr->conname))
7203 tgl 3453 UIC 0 : ereport(ERROR,
3454 : (errcode(ERRCODE_DUPLICATE_OBJECT),
3455 : errmsg("constraint \"%s\" for domain \"%s\" already exists",
3456 : constr->conname, domainName)));
3457 : }
7429 bruce 3458 ECB : else
5001 tgl 3459 GIC 108 : constr->conname = ChooseConstraintName(domainName,
3460 : NULL,
3461 : "check",
3462 : domainNamespace,
3463 : NIL);
3464 :
3465 : /*
3466 : * Convert the A_EXPR in raw_expr into an EXPR
7429 bruce 3467 ECB : */
7429 bruce 3468 CBC 807 : pstate = make_parsestate(NULL);
7429 bruce 3469 ECB :
3470 : /*
6385 3471 : * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3472 : * the expression. Note that it will appear to have the type of the base
3473 : * type, not the domain. This seems correct since within the check
3474 : * expression, we should not assume the input value can be considered a
3475 : * member of the domain.
7429 3476 : */
7370 tgl 3477 GIC 807 : domVal = makeNode(CoerceToDomainValue);
7429 bruce 3478 807 : domVal->typeId = baseTypeOid;
3479 807 : domVal->typeMod = typMod;
4404 tgl 3480 807 : domVal->collation = get_typcollation(baseTypeOid);
5337 tgl 3481 CBC 807 : domVal->location = -1; /* will be set when/if used */
3482 :
2283 tgl 3483 GIC 807 : pstate->p_pre_columnref_hook = replace_domain_constraint_value;
3484 807 : pstate->p_ref_hook_state = (void *) domVal;
3485 :
3894 tgl 3486 CBC 807 : expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3487 :
3488 : /*
3489 : * Make sure it yields a boolean result.
3490 : */
7285 tgl 3491 GIC 804 : expr = coerce_to_boolean(pstate, expr, "CHECK");
7429 bruce 3492 ECB :
4404 tgl 3493 : /*
4404 tgl 3494 EUB : * Fix up collation information.
3495 : */
4404 tgl 3496 GIC 804 : assign_expr_collations(pstate, expr);
3497 :
3498 : /*
3499 : * Domains don't allow variables (this is probably dead code now that
3500 : * add_missing_from is history, but let's be sure).
7429 bruce 3501 ECB : */
235 tgl 3502 GNC 1608 : if (pstate->p_rtable != NIL ||
3894 tgl 3503 GIC 804 : contain_var_clause(expr))
7203 tgl 3504 UIC 0 : ereport(ERROR,
3505 : (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3506 : errmsg("cannot use table references in domain check constraint")));
7429 bruce 3507 ECB :
3508 : /*
3509 : * Convert to string form for storage.
3510 : */
7429 bruce 3511 GIC 804 : ccbin = nodeToString(expr);
7429 bruce 3512 ECB :
3513 : /*
3514 : * Store the constraint in pg_constraint
3515 : */
3516 : ccoid =
2959 alvherre 3517 GIC 804 : CreateConstraintEntry(constr->conname, /* Constraint Name */
3518 : domainNamespace, /* namespace */
3519 : CONSTRAINT_CHECK, /* Constraint Type */
3520 : false, /* Is Deferrable */
3521 : false, /* Is Deferred */
3522 804 : !constr->skip_validation, /* Is Validated */
3523 : InvalidOid, /* no parent constraint */
3524 : InvalidOid, /* not a relation constraint */
3525 : NULL,
3526 : 0,
3527 : 0,
3528 : domainOid, /* domain constraint */
3529 : InvalidOid, /* no associated index */
3530 : InvalidOid, /* Foreign key fields */
3531 : NULL,
3532 : NULL,
3533 : NULL,
3534 : NULL,
3535 : 0,
3536 : ' ',
2959 alvherre 3537 ECB : ' ',
487 peter 3538 : NULL,
3539 : 0,
3540 : ' ',
3541 : NULL, /* not an exclusion constraint */
3542 : expr, /* Tree form of check constraint */
3543 : ccbin, /* Binary form of check constraint */
3544 : true, /* is local */
2959 alvherre 3545 : 0, /* inhcount */
3546 : false, /* connoinherit */
2959 alvherre 3547 GIC 804 : false); /* is_internal */
3548 804 : if (constrAddr)
3549 65 : ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
7429 bruce 3550 ECB :
3551 : /*
3552 : * Return the compiled constraint expression so the calling routine can
3553 : * perform any additional required tests.
3554 : */
7429 bruce 3555 GIC 804 : return ccbin;
3556 : }
3557 :
2283 tgl 3558 ECB : /* Parser pre_columnref_hook for domain CHECK constraint parsing */
3559 : static Node *
2283 tgl 3560 CBC 853 : replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
3561 : {
3562 : /*
2283 tgl 3563 ECB : * Check for a reference to "value", and if that's what it is, replace
3564 : * with a CoerceToDomainValue as prepared for us by domainAddConstraint.
3565 : * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of
3566 : * applications that have used VALUE as a column name in the past.)
3567 : */
2283 tgl 3568 GIC 853 : if (list_length(cref->fields) == 1)
2283 tgl 3569 ECB : {
2283 tgl 3570 CBC 853 : Node *field1 = (Node *) linitial(cref->fields);
3571 : char *colname;
3572 :
2283 tgl 3573 GIC 853 : colname = strVal(field1);
3574 853 : if (strcmp(colname, "value") == 0)
3575 : {
3576 853 : CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
3577 :
3578 : /* Propagate location knowledge, if any */
3579 853 : domVal->location = cref->location;
2283 tgl 3580 CBC 853 : return (Node *) domVal;
3581 : }
2283 tgl 3582 ECB : }
2283 tgl 3583 LBC 0 : return NULL;
3584 : }
3585 :
3586 :
3587 : /*
3588 : * Execute ALTER TYPE RENAME
3589 : */
3590 : ObjectAddress
4126 peter_e 3591 GIC 16 : RenameType(RenameStmt *stmt)
5499 tgl 3592 ECB : {
2339 peter_e 3593 CBC 16 : List *names = castNode(List, stmt->object);
4126 peter_e 3594 GIC 16 : const char *newTypeName = stmt->newname;
3595 : TypeName *typename;
5499 tgl 3596 ECB : Oid typeOid;
3597 : Relation rel;
3598 : HeapTuple tup;
3599 : Form_pg_type typTup;
2959 alvherre 3600 EUB : ObjectAddress address;
5499 tgl 3601 ECB :
3602 : /* Make a TypeName so we can use standard type lookup machinery */
5499 tgl 3603 GIC 16 : typename = makeTypeNameFromNameList(names);
4549 peter_e 3604 CBC 16 : typeOid = typenameTypeId(NULL, typename);
5499 tgl 3605 EUB :
3606 : /* Look up the type in the type table */
1539 andres 3607 GIC 16 : rel = table_open(TypeRelationId, RowExclusiveLock);
5499 tgl 3608 ECB :
4802 rhaas 3609 GBC 16 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
5499 tgl 3610 GIC 16 : if (!HeapTupleIsValid(tup))
5499 tgl 3611 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
5499 tgl 3612 GIC 16 : typTup = (Form_pg_type) GETSTRUCT(tup);
3613 :
3614 : /* check permissions on type */
147 peter 3615 GNC 16 : if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3950 peter_e 3616 UIC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3617 :
3618 : /* ALTER DOMAIN used on a non-domain? */
4126 peter_e 3619 CBC 16 : if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
4126 peter_e 3620 LBC 0 : ereport(ERROR,
4126 peter_e 3621 EUB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3622 : errmsg("%s is not a domain",
3623 : format_type_be(typeOid))));
3624 :
3625 : /*
3626 : * If it's a composite type, we need to check that it really is a
3627 : * free-standing composite type, and not a table's rowtype. We want people
5050 bruce 3628 ECB : * to use ALTER TABLE not ALTER TYPE for that case.
5499 tgl 3629 EUB : */
5499 tgl 3630 GIC 17 : if (typTup->typtype == TYPTYPE_COMPOSITE &&
3631 1 : get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
5499 tgl 3632 UIC 0 : ereport(ERROR,
3633 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3634 : errmsg("%s is a table's row type",
3635 : format_type_be(typeOid)),
3636 : errhint("Use ALTER TABLE instead.")));
3637 :
3638 : /* don't allow direct alteration of array types, either */
851 tgl 3639 GIC 16 : if (IsTrueArrayType(typTup))
5499 tgl 3640 LBC 0 : ereport(ERROR,
5499 tgl 3641 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3642 : errmsg("cannot alter array type %s",
3643 : format_type_be(typeOid)),
3644 : errhint("You can alter type %s, which will alter the array type as well.",
3645 : format_type_be(typTup->typelem))));
3646 :
3647 : /*
3648 : * If type is composite we need to rename associated pg_class entry too.
3649 : * RenameRelationInternal will call RenameTypeInternal automatically.
3650 : */
5499 tgl 3651 GIC 16 : if (typTup->typtype == TYPTYPE_COMPOSITE)
1627 peter_e 3652 1 : RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3653 : else
5499 tgl 3654 15 : RenameTypeInternal(typeOid, newTypeName,
3655 : typTup->typnamespace);
3656 :
2959 alvherre 3657 CBC 16 : ObjectAddressSet(address, TypeRelationId, typeOid);
3658 : /* Clean up */
1539 andres 3659 GIC 16 : table_close(rel, RowExclusiveLock);
3660 :
2959 alvherre 3661 16 : return address;
3662 : }
3663 :
3664 : /*
3665 : * Change the owner of a type.
3666 : */
3667 : ObjectAddress
4090 peter_e 3668 CBC 48 : AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3669 : {
3670 : TypeName *typename;
7398 tgl 3671 ECB : Oid typeOid;
3672 : Relation rel;
3673 : HeapTuple tup;
5628 3674 : HeapTuple newtup;
7188 bruce 3675 : Form_pg_type typTup;
6478 tgl 3676 EUB : AclResult aclresult;
3677 : ObjectAddress address;
3678 :
1539 andres 3679 GIC 48 : rel = table_open(TypeRelationId, RowExclusiveLock);
5628 tgl 3680 ECB :
3681 : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 3682 GIC 48 : typename = makeTypeNameFromNameList(names);
7398 tgl 3683 ECB :
6235 3684 : /* Use LookupTypeName here so that shell types can be processed */
3363 alvherre 3685 CBC 48 : tup = LookupTypeName(NULL, typename, NULL, false);
5628 tgl 3686 48 : if (tup == NULL)
7203 tgl 3687 UIC 0 : ereport(ERROR,
3688 : (errcode(ERRCODE_UNDEFINED_OBJECT),
7203 tgl 3689 ECB : errmsg("type \"%s\" does not exist",
7203 tgl 3690 EUB : TypeNameToString(typename))));
5624 bruce 3691 GIC 48 : typeOid = typeTypeId(tup);
3692 :
3693 : /* Copy the syscache entry so we can scribble on it below */
5628 tgl 3694 48 : newtup = heap_copytuple(tup);
3695 48 : ReleaseSysCache(tup);
3696 48 : tup = newtup;
7398 3697 48 : typTup = (Form_pg_type) GETSTRUCT(tup);
3698 :
3699 : /* Don't allow ALTER DOMAIN on a type */
4090 peter_e 3700 CBC 48 : if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
4090 peter_e 3701 LBC 0 : ereport(ERROR,
4090 peter_e 3702 EUB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3703 : errmsg("%s is not a domain",
3704 : format_type_be(typeOid))));
3705 :
3706 : /*
3707 : * If it's a composite type, we need to check that it really is a
3708 : * free-standing composite type, and not a table's rowtype. We want people
5624 bruce 3709 ECB : * to use ALTER TABLE not ALTER TYPE for that case.
6862 tgl 3710 EUB : */
5851 tgl 3711 GIC 62 : if (typTup->typtype == TYPTYPE_COMPOSITE &&
6457 3712 14 : get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
7203 tgl 3713 UIC 0 : ereport(ERROR,
3714 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3715 : errmsg("%s is a table's row type",
3716 : format_type_be(typeOid)),
3717 : errhint("Use ALTER TABLE instead.")));
3718 :
3719 : /* don't allow direct alteration of array types, either */
851 tgl 3720 GIC 48 : if (IsTrueArrayType(typTup))
5812 tgl 3721 LBC 0 : ereport(ERROR,
3722 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3723 : errmsg("cannot alter array type %s",
5812 tgl 3724 EUB : format_type_be(typeOid)),
3725 : errhint("You can alter type %s, which will alter the array type as well.",
3726 : format_type_be(typTup->typelem))));
3727 :
6797 bruce 3728 : /*
3729 : * If the new owner is the same as the existing owner, consider the
3730 : * command to have succeeded. This is for dump restoration purposes.
6862 tgl 3731 : */
6494 tgl 3732 GIC 48 : if (typTup->typowner != newOwnerId)
3733 : {
6439 tgl 3734 EUB : /* Superusers can always do it */
6439 tgl 3735 UIC 0 : if (!superuser())
3736 : {
6439 tgl 3737 EUB : /* Otherwise, must be owner of the existing object */
147 peter 3738 UNC 0 : if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
1601 andres 3739 UBC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
3740 :
3741 : /* Must be able to become new owner */
142 rhaas 3742 UNC 0 : check_can_set_role(GetUserId(), newOwnerId);
3743 :
3744 : /* New owner must have CREATE privilege on namespace */
147 peter 3745 0 : aclresult = object_aclcheck(NamespaceRelationId, typTup->typnamespace,
3746 : newOwnerId,
3747 : ACL_CREATE);
6439 tgl 3748 LBC 0 : if (aclresult != ACLCHECK_OK)
1954 peter_e 3749 UIC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
6439 tgl 3750 LBC 0 : get_namespace_name(typTup->typnamespace));
3751 : }
3752 :
2670 alvherre 3753 UIC 0 : AlterTypeOwner_oid(typeOid, newOwnerId, true);
3754 : }
3755 :
2959 alvherre 3756 GIC 48 : ObjectAddressSet(address, TypeRelationId, typeOid);
3757 :
3758 : /* Clean up */
1539 andres 3759 48 : table_close(rel, RowExclusiveLock);
3760 :
2959 alvherre 3761 48 : return address;
3762 : }
3763 :
3764 : /*
2670 alvherre 3765 ECB : * AlterTypeOwner_oid - change type owner unconditionally
3766 : *
3767 : * This function recurses to handle a pg_class entry, if necessary. It
3768 : * invokes any necessary access object hooks. If hasDependEntry is true, this
3769 : * function modifies the pg_shdepend entry appropriately (this should be
3770 : * passed as false only for table rowtypes and array types).
6457 tgl 3771 : *
3772 : * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
2670 alvherre 3773 : * OWNED BY. It assumes the caller has done all needed check.
3774 : */
2670 alvherre 3775 EUB : void
2670 alvherre 3776 CBC 12 : AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3777 : {
3778 : Relation rel;
3779 : HeapTuple tup;
3780 : Form_pg_type typTup;
3781 :
1539 andres 3782 GIC 12 : rel = table_open(TypeRelationId, RowExclusiveLock);
2670 alvherre 3783 ECB :
2670 alvherre 3784 CBC 12 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2670 alvherre 3785 GIC 12 : if (!HeapTupleIsValid(tup))
2670 alvherre 3786 LBC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
2670 alvherre 3787 GIC 12 : typTup = (Form_pg_type) GETSTRUCT(tup);
3788 :
2670 alvherre 3789 ECB : /*
2495 rhaas 3790 : * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3791 : * the pg_class entry properly. That will call back to
3792 : * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3793 : */
2670 alvherre 3794 CBC 12 : if (typTup->typtype == TYPTYPE_COMPOSITE)
3795 3 : ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
2670 alvherre 3796 ECB : else
2670 alvherre 3797 GIC 9 : AlterTypeOwnerInternal(typeOid, newOwnerId);
3798 :
3799 : /* Update owner dependency reference */
3800 12 : if (hasDependEntry)
3801 12 : changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3802 :
3803 12 : InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3804 :
2670 alvherre 3805 CBC 12 : ReleaseSysCache(tup);
1539 andres 3806 GIC 12 : table_close(rel, RowExclusiveLock);
2670 alvherre 3807 12 : }
3808 :
3809 : /*
3810 : * AlterTypeOwnerInternal - bare-bones type owner change.
3811 : *
3812 : * This routine simply modifies the owner of a pg_type entry, and recurses
3813 : * to handle a possible array type.
3814 : */
3815 : void
3816 296 : AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
6457 tgl 3817 ECB : {
3818 : Relation rel;
3819 : HeapTuple tup;
3820 : Form_pg_type typTup;
2999 bruce 3821 EUB : Datum repl_val[Natts_pg_type];
2999 bruce 3822 ECB : bool repl_null[Natts_pg_type];
3823 : bool repl_repl[Natts_pg_type];
3824 : Acl *newAcl;
3825 : Datum aclDatum;
3826 : bool isNull;
6457 tgl 3827 :
1539 andres 3828 CBC 296 : rel = table_open(TypeRelationId, RowExclusiveLock);
3829 :
4802 rhaas 3830 296 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
6457 tgl 3831 GIC 296 : if (!HeapTupleIsValid(tup))
6457 tgl 3832 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
6457 tgl 3833 GIC 296 : typTup = (Form_pg_type) GETSTRUCT(tup);
3834 :
2999 bruce 3835 CBC 296 : memset(repl_null, false, sizeof(repl_null));
2999 bruce 3836 GIC 296 : memset(repl_repl, false, sizeof(repl_repl));
2999 bruce 3837 EUB :
2999 bruce 3838 GIC 296 : repl_repl[Anum_pg_type_typowner - 1] = true;
2999 bruce 3839 GBC 296 : repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
2999 bruce 3840 EUB :
2999 bruce 3841 GIC 296 : aclDatum = heap_getattr(tup,
3842 : Anum_pg_type_typacl,
2999 bruce 3843 ECB : RelationGetDescr(rel),
3844 : &isNull);
3845 : /* Null ACLs do not require changes */
2999 bruce 3846 CBC 296 : if (!isNull)
3847 : {
2999 bruce 3848 UIC 0 : newAcl = aclnewowner(DatumGetAclP(aclDatum),
2999 bruce 3849 ECB : typTup->typowner, newOwnerId);
2999 bruce 3850 LBC 0 : repl_repl[Anum_pg_type_typacl - 1] = true;
2999 bruce 3851 UIC 0 : repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3852 : }
2999 bruce 3853 ECB :
2999 bruce 3854 CBC 296 : tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3855 : repl_repl);
3856 :
2259 alvherre 3857 GIC 296 : CatalogTupleUpdate(rel, &tup->t_self, tup);
3858 :
3859 : /* If it has an array type, update that too */
5812 tgl 3860 CBC 296 : if (OidIsValid(typTup->typarray))
2670 alvherre 3861 GIC 148 : AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3862 :
3863 : /* Clean up */
1539 andres 3864 296 : table_close(rel, RowExclusiveLock);
6457 tgl 3865 296 : }
3866 :
3867 : /*
3868 : * Execute ALTER TYPE SET SCHEMA
3869 : */
3870 : ObjectAddress
2959 alvherre 3871 CBC 9 : AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
2959 alvherre 3872 ECB : Oid *oldschema)
3873 : {
3874 : TypeName *typename;
6385 bruce 3875 : Oid typeOid;
6385 bruce 3876 EUB : Oid nspOid;
3877 : Oid oldNspOid;
3878 : ObjectAddresses *objsMoved;
3879 : ObjectAddress myself;
3880 :
3881 : /* Make a TypeName so we can use standard type lookup machinery */
6235 tgl 3882 CBC 9 : typename = makeTypeNameFromNameList(names);
4549 peter_e 3883 GIC 9 : typeOid = typenameTypeId(NULL, typename);
6460 tgl 3884 ECB :
4090 peter_e 3885 : /* Don't allow ALTER DOMAIN on a type */
4090 peter_e 3886 CBC 9 : if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
4090 peter_e 3887 UIC 0 : ereport(ERROR,
4090 peter_e 3888 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3889 : errmsg("%s is not a domain",
3890 : format_type_be(typeOid))));
3891 :
3892 : /* get schema OID and check its permissions */
4443 tgl 3893 CBC 9 : nspOid = LookupCreationNamespace(newschema);
3894 :
3812 alvherre 3895 GIC 9 : objsMoved = new_object_addresses();
2959 3896 9 : oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3812 alvherre 3897 CBC 9 : free_object_addresses(objsMoved);
3898 :
2959 alvherre 3899 GIC 9 : if (oldschema)
3900 9 : *oldschema = oldNspOid;
3901 :
2959 alvherre 3902 CBC 9 : ObjectAddressSet(myself, TypeRelationId, typeOid);
2959 alvherre 3903 EUB :
2959 alvherre 3904 GIC 9 : return myself;
3905 : }
4443 tgl 3906 ECB :
3907 : Oid
3812 alvherre 3908 GBC 9 : AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3909 : {
3910 : Oid elemOid;
3911 :
3912 : /* check permissions on type */
147 peter 3913 GNC 9 : if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3950 peter_e 3914 UIC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3915 :
5812 tgl 3916 ECB : /* don't allow direct alteration of array types */
5812 tgl 3917 GIC 9 : elemOid = get_element_type(typeOid);
3918 9 : if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
5812 tgl 3919 UIC 0 : ereport(ERROR,
3920 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3921 : errmsg("cannot alter array type %s",
3922 : format_type_be(typeOid)),
3923 : errhint("You can alter type %s, which will alter the array type as well.",
3924 : format_type_be(elemOid))));
3925 :
3926 : /* and do the work */
3812 alvherre 3927 GIC 9 : return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3928 : }
3929 :
3930 : /*
3931 : * Move specified type to new namespace.
3932 : *
3933 : * Caller must have already checked privileges.
3934 : *
5812 tgl 3935 ECB : * The function automatically recurses to process the type's array type,
3936 : * if any. isImplicitArray should be true only when doing this internal
3937 : * recursion (outside callers must never try to move an array type directly).
3938 : *
3939 : * If errorOnTableType is true, the function errors out if the type is
3940 : * a table type. ALTER TABLE has to be used to move a table to a new
3941 : * namespace.
3942 : *
3943 : * Returns the type's old namespace OID.
3944 : */
3945 : Oid
6460 tgl 3946 GIC 100 : AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3947 : bool isImplicitArray,
3948 : bool errorOnTableType,
3949 : ObjectAddresses *objsMoved)
3950 : {
6460 tgl 3951 ECB : Relation rel;
3952 : HeapTuple tup;
3953 : Form_pg_type typform;
3954 : Oid oldNspOid;
5812 3955 : Oid arrayOid;
6460 tgl 3956 EUB : bool isCompositeType;
3957 : ObjectAddress thisobj;
3812 alvherre 3958 ECB :
3959 : /*
3960 : * Make sure we haven't moved this object previously.
3961 : */
3812 alvherre 3962 GBC 100 : thisobj.classId = TypeRelationId;
3812 alvherre 3963 CBC 100 : thisobj.objectId = typeOid;
3812 alvherre 3964 GIC 100 : thisobj.objectSubId = 0;
3812 alvherre 3965 ECB :
3812 alvherre 3966 CBC 100 : if (object_address_present(&thisobj, objsMoved))
3812 alvherre 3967 UIC 0 : return InvalidOid;
3968 :
1539 andres 3969 CBC 100 : rel = table_open(TypeRelationId, RowExclusiveLock);
3970 :
4802 rhaas 3971 GIC 100 : tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
6460 tgl 3972 CBC 100 : if (!HeapTupleIsValid(tup))
6460 tgl 3973 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
6460 tgl 3974 GIC 100 : typform = (Form_pg_type) GETSTRUCT(tup);
6460 tgl 3975 ECB :
6460 tgl 3976 GIC 100 : oldNspOid = typform->typnamespace;
5812 3977 100 : arrayOid = typform->typarray;
6460 tgl 3978 EUB :
3979 : /* If the type is already there, we scan skip these next few checks. */
2698 rhaas 3980 GIC 100 : if (oldNspOid != nspOid)
3981 : {
3982 : /* common checks on switching namespaces */
3983 82 : CheckSetNamespace(oldNspOid, nspOid);
3984 :
3985 : /* check for duplicate name (more friendly than unique-index failure) */
2698 rhaas 3986 CBC 82 : if (SearchSysCacheExists2(TYPENAMENSP,
2399 tgl 3987 ECB : NameGetDatum(&typform->typname),
2698 rhaas 3988 : ObjectIdGetDatum(nspOid)))
2698 rhaas 3989 UIC 0 : ereport(ERROR,
3990 : (errcode(ERRCODE_DUPLICATE_OBJECT),
2698 rhaas 3991 ECB : errmsg("type \"%s\" already exists in schema \"%s\"",
3992 : NameStr(typform->typname),
2698 rhaas 3993 EUB : get_namespace_name(nspOid))));
3994 : }
3995 :
3996 : /* Detect whether type is a composite type (but not a table rowtype) */
6460 tgl 3997 GIC 100 : isCompositeType =
5851 3998 147 : (typform->typtype == TYPTYPE_COMPOSITE &&
6460 tgl 3999 CBC 47 : get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
4000 :
4001 : /* Enforce not-table-type if requested */
5851 tgl 4002 GIC 100 : if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
4003 : errorOnTableType)
6460 tgl 4004 LBC 0 : ereport(ERROR,
4005 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6460 tgl 4006 ECB : errmsg("%s is a table's row type",
4007 : format_type_be(typeOid)),
4008 : errhint("Use ALTER TABLE instead.")));
4009 :
2698 rhaas 4010 GIC 100 : if (oldNspOid != nspOid)
4011 : {
4012 : /* OK, modify the pg_type row */
4013 :
4014 : /* tup is a copy, so we can scribble directly on it */
2698 rhaas 4015 CBC 82 : typform->typnamespace = nspOid;
4016 :
2259 alvherre 4017 GIC 82 : CatalogTupleUpdate(rel, &tup->t_self, tup);
4018 : }
6460 tgl 4019 ECB :
4020 : /*
4021 : * Composite types have pg_class entries.
4022 : *
4023 : * We need to modify the pg_class tuple as well to reflect the change of
4024 : * schema.
4025 : */
6460 tgl 4026 GIC 100 : if (isCompositeType)
4027 : {
4028 : Relation classRel;
4029 :
1539 andres 4030 6 : classRel = table_open(RelationRelationId, RowExclusiveLock);
6460 tgl 4031 ECB :
6460 tgl 4032 GIC 6 : AlterRelationNamespaceInternal(classRel, typform->typrelid,
4033 : oldNspOid, nspOid,
4034 : false, objsMoved);
4035 :
1539 andres 4036 6 : table_close(classRel, RowExclusiveLock);
6460 tgl 4037 ECB :
4038 : /*
4039 : * Check for constraints associated with the composite type (we don't
4040 : * currently support this, but probably will someday).
4041 : */
6460 tgl 4042 GIC 6 : AlterConstraintNamespaces(typform->typrelid, oldNspOid,
4043 : nspOid, false, objsMoved);
4044 : }
4045 : else
6460 tgl 4046 ECB : {
4047 : /* If it's a domain, it might have constraints */
5851 tgl 4048 CBC 94 : if (typform->typtype == TYPTYPE_DOMAIN)
3812 alvherre 4049 3 : AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
4050 : objsMoved);
5812 tgl 4051 EUB : }
4052 :
4053 : /*
5812 tgl 4054 ECB : * Update dependency on schema, if any --- a table rowtype has not got
4055 : * one, and neither does an implicit array.
4056 : */
2698 rhaas 4057 GIC 100 : if (oldNspOid != nspOid &&
2698 rhaas 4058 CBC 79 : (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
5812 tgl 4059 GIC 47 : !isImplicitArray)
5812 tgl 4060 CBC 6 : if (changeDependencyFor(TypeRelationId, typeOid,
4061 : NamespaceRelationId, oldNspOid, nspOid) != 1)
5812 tgl 4062 UIC 0 : elog(ERROR, "failed to change schema dependency for type %s",
5812 tgl 4063 ECB : format_type_be(typeOid));
6460 4064 :
3675 rhaas 4065 GIC 100 : InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3675 rhaas 4066 ECB :
6460 tgl 4067 GIC 100 : heap_freetuple(tup);
4068 :
1539 andres 4069 100 : table_close(rel, RowExclusiveLock);
4070 :
3812 alvherre 4071 100 : add_exact_object_address(&thisobj, objsMoved);
4072 :
4073 : /* Recursively alter the associated array type, if any */
5812 tgl 4074 100 : if (OidIsValid(arrayOid))
3812 alvherre 4075 50 : AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
4076 :
4443 tgl 4077 100 : return oldNspOid;
6460 tgl 4078 ECB : }
4079 :
4080 : /*
4081 : * AlterType
4082 : * ALTER TYPE <type> SET (option = ...)
4083 : *
4084 : * NOTE: the set of changes that can be allowed here is constrained by many
4085 : * non-obvious implementation restrictions. Tread carefully when considering
1129 4086 : * adding new flexibility.
4087 : */
4088 : ObjectAddress
1129 tgl 4089 GIC 30 : AlterType(AlterTypeStmt *stmt)
1129 tgl 4090 ECB : {
4091 : ObjectAddress address;
4092 : Relation catalog;
4093 : TypeName *typename;
4094 : HeapTuple tup;
4095 : Oid typeOid;
4096 : Form_pg_type typForm;
1129 tgl 4097 CBC 30 : bool requireSuper = false;
4098 : AlterTypeRecurseParams atparams;
4099 : ListCell *pl;
1129 tgl 4100 ECB :
1129 tgl 4101 CBC 30 : catalog = table_open(TypeRelationId, RowExclusiveLock);
4102 :
1129 tgl 4103 ECB : /* Make a TypeName so we can use standard type lookup machinery */
1129 tgl 4104 GIC 30 : typename = makeTypeNameFromNameList(stmt->typeName);
1129 tgl 4105 CBC 30 : tup = typenameType(NULL, typename, NULL);
4106 :
4107 27 : typeOid = typeTypeId(tup);
1129 tgl 4108 GIC 27 : typForm = (Form_pg_type) GETSTRUCT(tup);
1129 tgl 4109 ECB :
4110 : /* Process options */
1129 tgl 4111 CBC 27 : memset(&atparams, 0, sizeof(atparams));
1129 tgl 4112 GBC 77 : foreach(pl, stmt->options)
1129 tgl 4113 ECB : {
1129 tgl 4114 CBC 53 : DefElem *defel = (DefElem *) lfirst(pl);
1129 tgl 4115 EUB :
1129 tgl 4116 GBC 53 : if (strcmp(defel->defname, "storage") == 0)
4117 : {
4118 6 : char *a = defGetString(defel);
4119 :
1129 tgl 4120 GIC 6 : if (pg_strcasecmp(a, "plain") == 0)
4121 3 : atparams.storage = TYPSTORAGE_PLAIN;
4122 3 : else if (pg_strcasecmp(a, "external") == 0)
1129 tgl 4123 UIC 0 : atparams.storage = TYPSTORAGE_EXTERNAL;
1129 tgl 4124 GIC 3 : else if (pg_strcasecmp(a, "extended") == 0)
4125 3 : atparams.storage = TYPSTORAGE_EXTENDED;
1129 tgl 4126 LBC 0 : else if (pg_strcasecmp(a, "main") == 0)
1129 tgl 4127 UBC 0 : atparams.storage = TYPSTORAGE_MAIN;
4128 : else
1129 tgl 4129 UIC 0 : ereport(ERROR,
4130 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4131 : errmsg("storage \"%s\" not recognized", a)));
4132 :
4133 : /*
4134 : * Validate the storage request. If the type isn't varlena, it
4135 : * certainly doesn't support non-PLAIN storage.
4136 : */
1129 tgl 4137 GIC 6 : if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
1129 tgl 4138 UIC 0 : ereport(ERROR,
4139 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4140 : errmsg("fixed-size types must have storage PLAIN")));
1129 tgl 4141 ECB :
4142 : /*
1129 tgl 4143 EUB : * Switching from PLAIN to non-PLAIN is allowed, but it requires
1129 tgl 4144 ECB : * superuser, since we can't validate that the type's C functions
4145 : * will support it. Switching from non-PLAIN to PLAIN is
4146 : * disallowed outright, because it's not practical to ensure that
4147 : * no tables have toasted values of the type. Switching among
4148 : * different non-PLAIN settings is OK, since it just constitutes a
4149 : * change in the strategy requested for columns created in the
4150 : * future.
4151 : */
1129 tgl 4152 CBC 6 : if (atparams.storage != TYPSTORAGE_PLAIN &&
1129 tgl 4153 GIC 3 : typForm->typstorage == TYPSTORAGE_PLAIN)
1129 tgl 4154 LBC 0 : requireSuper = true;
1129 tgl 4155 CBC 6 : else if (atparams.storage == TYPSTORAGE_PLAIN &&
4156 3 : typForm->typstorage != TYPSTORAGE_PLAIN)
1129 tgl 4157 GIC 3 : ereport(ERROR,
4158 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1129 tgl 4159 EUB : errmsg("cannot change type's storage to PLAIN")));
1129 tgl 4160 ECB :
1129 tgl 4161 GIC 3 : atparams.updateStorage = true;
1129 tgl 4162 ECB : }
1129 tgl 4163 GIC 47 : else if (strcmp(defel->defname, "receive") == 0)
1129 tgl 4164 ECB : {
1129 tgl 4165 GIC 14 : if (defel->arg != NULL)
1129 tgl 4166 CBC 14 : atparams.receiveOid =
4167 14 : findTypeReceiveFunction(defGetQualifiedName(defel),
1129 tgl 4168 ECB : typeOid);
4169 : else
1129 tgl 4170 UIC 0 : atparams.receiveOid = InvalidOid; /* NONE, remove function */
1129 tgl 4171 GBC 14 : atparams.updateReceive = true;
1129 tgl 4172 ECB : /* Replacing an I/O function requires superuser. */
1129 tgl 4173 GIC 14 : requireSuper = true;
1129 tgl 4174 ECB : }
1129 tgl 4175 GIC 33 : else if (strcmp(defel->defname, "send") == 0)
1129 tgl 4176 ECB : {
1129 tgl 4177 GIC 14 : if (defel->arg != NULL)
1129 tgl 4178 CBC 14 : atparams.sendOid =
4179 14 : findTypeSendFunction(defGetQualifiedName(defel),
1129 tgl 4180 ECB : typeOid);
4181 : else
1129 tgl 4182 UBC 0 : atparams.sendOid = InvalidOid; /* NONE, remove function */
1129 tgl 4183 CBC 14 : atparams.updateSend = true;
4184 : /* Replacing an I/O function requires superuser. */
4185 14 : requireSuper = true;
4186 : }
4187 19 : else if (strcmp(defel->defname, "typmod_in") == 0)
4188 : {
4189 3 : if (defel->arg != NULL)
4190 3 : atparams.typmodinOid =
4191 3 : findTypeTypmodinFunction(defGetQualifiedName(defel));
4192 : else
1129 tgl 4193 UBC 0 : atparams.typmodinOid = InvalidOid; /* NONE, remove function */
1129 tgl 4194 CBC 3 : atparams.updateTypmodin = true;
4195 : /* Replacing an I/O function requires superuser. */
4196 3 : requireSuper = true;
4197 : }
4198 16 : else if (strcmp(defel->defname, "typmod_out") == 0)
4199 : {
4200 3 : if (defel->arg != NULL)
4201 3 : atparams.typmodoutOid =
4202 3 : findTypeTypmodoutFunction(defGetQualifiedName(defel));
4203 : else
1129 tgl 4204 UIC 0 : atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
1129 tgl 4205 GBC 3 : atparams.updateTypmodout = true;
1129 tgl 4206 ECB : /* Replacing an I/O function requires superuser. */
1129 tgl 4207 GIC 3 : requireSuper = true;
1129 tgl 4208 ECB : }
1129 tgl 4209 GIC 13 : else if (strcmp(defel->defname, "analyze") == 0)
1129 tgl 4210 ECB : {
1129 tgl 4211 GIC 3 : if (defel->arg != NULL)
1129 tgl 4212 CBC 3 : atparams.analyzeOid =
4213 3 : findTypeAnalyzeFunction(defGetQualifiedName(defel),
1129 tgl 4214 ECB : typeOid);
4215 : else
1129 tgl 4216 UIC 0 : atparams.analyzeOid = InvalidOid; /* NONE, remove function */
1129 tgl 4217 GBC 3 : atparams.updateAnalyze = true;
1129 tgl 4218 ECB : /* Replacing an analyze function requires superuser. */
1129 tgl 4219 GIC 3 : requireSuper = true;
1129 tgl 4220 ECB : }
849 tgl 4221 GIC 10 : else if (strcmp(defel->defname, "subscript") == 0)
4222 : {
4223 10 : if (defel->arg != NULL)
4224 10 : atparams.subscriptOid =
4225 10 : findTypeSubscriptingFunction(defGetQualifiedName(defel),
4226 : typeOid);
849 tgl 4227 EUB : else
849 tgl 4228 UBC 0 : atparams.subscriptOid = InvalidOid; /* NONE, remove function */
849 tgl 4229 GBC 10 : atparams.updateSubscript = true;
849 tgl 4230 EUB : /* Replacing a subscript function requires superuser. */
849 tgl 4231 GBC 10 : requireSuper = true;
849 tgl 4232 EUB : }
1129 4233 :
4234 : /*
4235 : * The rest of the options that CREATE accepts cannot be changed.
4236 : * Check for them so that we can give a meaningful error message.
4237 : */
1129 tgl 4238 UBC 0 : else if (strcmp(defel->defname, "input") == 0 ||
4239 0 : strcmp(defel->defname, "output") == 0 ||
1129 tgl 4240 UIC 0 : strcmp(defel->defname, "internallength") == 0 ||
4241 0 : strcmp(defel->defname, "passedbyvalue") == 0 ||
4242 0 : strcmp(defel->defname, "alignment") == 0 ||
4243 0 : strcmp(defel->defname, "like") == 0 ||
1129 tgl 4244 UBC 0 : strcmp(defel->defname, "category") == 0 ||
1129 tgl 4245 UIC 0 : strcmp(defel->defname, "preferred") == 0 ||
4246 0 : strcmp(defel->defname, "default") == 0 ||
4247 0 : strcmp(defel->defname, "element") == 0 ||
4248 0 : strcmp(defel->defname, "delimiter") == 0 ||
4249 0 : strcmp(defel->defname, "collatable") == 0)
4250 0 : ereport(ERROR,
4251 : (errcode(ERRCODE_SYNTAX_ERROR),
4252 : errmsg("type attribute \"%s\" cannot be changed",
4253 : defel->defname)));
1129 tgl 4254 ECB : else
1129 tgl 4255 UIC 0 : ereport(ERROR,
1129 tgl 4256 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
1129 tgl 4257 EUB : errmsg("type attribute \"%s\" not recognized",
4258 : defel->defname)));
4259 : }
4260 :
4261 : /*
4262 : * Permissions check. Require superuser if we decided the command
1129 tgl 4263 ECB : * requires that, else must own the type.
1129 tgl 4264 EUB : */
1129 tgl 4265 GIC 24 : if (requireSuper)
4266 : {
4267 21 : if (!superuser())
1129 tgl 4268 UIC 0 : ereport(ERROR,
4269 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4270 : errmsg("must be superuser to alter a type")));
4271 : }
4272 : else
4273 : {
147 peter 4274 GNC 3 : if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
1129 tgl 4275 UIC 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
4276 : }
1129 tgl 4277 ECB :
1129 tgl 4278 EUB : /*
4279 : * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4280 : * types. It would for example be highly unsafe, not to mention
4281 : * pointless, to change the send/receive functions for a composite type.
4282 : * Moreover, pg_dump has no support for changing these properties on
4283 : * non-base types. We might weaken this someday, but not now.
4284 : *
4285 : * Note: if you weaken this enough to allow composite types, be sure to
1129 tgl 4286 ECB : * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
1129 tgl 4287 EUB : */
1129 tgl 4288 GIC 24 : if (typForm->typtype != TYPTYPE_BASE)
1129 tgl 4289 UIC 0 : ereport(ERROR,
4290 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4291 : errmsg("%s is not a base type",
4292 : format_type_be(typeOid))));
1129 tgl 4293 ECB :
4294 : /*
4295 : * For the same reasons, don't allow direct alteration of array types.
4296 : */
851 tgl 4297 GIC 24 : if (IsTrueArrayType(typForm))
1129 tgl 4298 LBC 0 : ereport(ERROR,
4299 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1129 tgl 4300 ECB : errmsg("%s is not a base type",
4301 : format_type_be(typeOid))));
4302 :
4303 : /* OK, recursively update this type and any arrays/domains over it */
982 tgl 4304 GIC 24 : AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4305 :
4306 : /* Clean up */
1129 4307 24 : ReleaseSysCache(tup);
4308 :
4309 24 : table_close(catalog, RowExclusiveLock);
4310 :
4311 24 : ObjectAddressSet(address, TypeRelationId, typeOid);
4312 :
4313 24 : return address;
4314 : }
4315 :
4316 : /*
4317 : * AlterTypeRecurse: one recursion step for AlterType()
4318 : *
4319 : * Apply the changes specified by "atparams" to the type identified by
4320 : * "typeOid", whose existing pg_type tuple is "tup". If necessary,
4321 : * recursively update its array type as well. Then search for any domains
4322 : * over this type, and recursively apply (most of) the same changes to those
4323 : * domains.
4324 : *
4325 : * We need this because the system generally assumes that a domain inherits
4326 : * many properties from its base type. See DefineDomain() above for details
4327 : * of what is inherited. Arrays inherit a smaller number of properties,
4328 : * but not none.
1129 tgl 4329 ECB : *
4330 : * There's a race condition here, in that some other transaction could
4331 : * concurrently add another domain atop this base type; we'd miss updating
4332 : * that one. Hence, be wary of allowing ALTER TYPE to change properties for
4333 : * which it'd be really fatal for a domain to be out of sync with its base
4334 : * type (typlen, for example). In practice, races seem unlikely to be an
4335 : * issue for plausible use-cases for ALTER TYPE. If one does happen, it could
4336 : * be fixed by re-doing the same ALTER TYPE once all prior transactions have
4337 : * committed.
4338 : */
4339 : static void
982 tgl 4340 GIC 33 : AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
4341 : HeapTuple tup, Relation catalog,
1129 tgl 4342 ECB : AlterTypeRecurseParams *atparams)
4343 : {
4344 : Datum values[Natts_pg_type];
4345 : bool nulls[Natts_pg_type];
4346 : bool replaces[Natts_pg_type];
4347 : HeapTuple newtup;
4348 : SysScanDesc scan;
4349 : ScanKeyData key[1];
4350 : HeapTuple domainTup;
4351 :
4352 : /* Since this function recurses, it could be driven to stack overflow */
1129 tgl 4353 GIC 33 : check_stack_depth();
1129 tgl 4354 ECB :
4355 : /* Update the current type's tuple */
1129 tgl 4356 CBC 33 : memset(values, 0, sizeof(values));
4357 33 : memset(nulls, 0, sizeof(nulls));
1129 tgl 4358 GIC 33 : memset(replaces, 0, sizeof(replaces));
1129 tgl 4359 ECB :
1129 tgl 4360 GIC 33 : if (atparams->updateStorage)
1129 tgl 4361 ECB : {
1129 tgl 4362 CBC 6 : replaces[Anum_pg_type_typstorage - 1] = true;
1129 tgl 4363 GIC 6 : values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
1129 tgl 4364 ECB : }
1129 tgl 4365 GIC 33 : if (atparams->updateReceive)
1129 tgl 4366 ECB : {
1129 tgl 4367 CBC 14 : replaces[Anum_pg_type_typreceive - 1] = true;
1129 tgl 4368 GIC 14 : values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
1129 tgl 4369 ECB : }
1129 tgl 4370 GIC 33 : if (atparams->updateSend)
1129 tgl 4371 ECB : {
1129 tgl 4372 CBC 17 : replaces[Anum_pg_type_typsend - 1] = true;
1129 tgl 4373 GIC 17 : values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
1129 tgl 4374 ECB : }
1129 tgl 4375 GIC 33 : if (atparams->updateTypmodin)
1129 tgl 4376 ECB : {
1129 tgl 4377 CBC 6 : replaces[Anum_pg_type_typmodin - 1] = true;
1129 tgl 4378 GIC 6 : values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
1129 tgl 4379 ECB : }
1129 tgl 4380 GIC 33 : if (atparams->updateTypmodout)
1129 tgl 4381 ECB : {
1129 tgl 4382 CBC 6 : replaces[Anum_pg_type_typmodout - 1] = true;
1129 tgl 4383 GIC 6 : values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
4384 : }
1129 tgl 4385 CBC 33 : if (atparams->updateAnalyze)
4386 : {
1129 tgl 4387 GIC 6 : replaces[Anum_pg_type_typanalyze - 1] = true;
1129 tgl 4388 CBC 6 : values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
4389 : }
849 tgl 4390 GIC 33 : if (atparams->updateSubscript)
849 tgl 4391 ECB : {
849 tgl 4392 GIC 10 : replaces[Anum_pg_type_typsubscript - 1] = true;
4393 10 : values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
4394 : }
4395 :
1129 4396 33 : newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
4397 : values, nulls, replaces);
4398 :
4399 33 : CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
4400 :
1129 tgl 4401 ECB : /* Rebuild dependencies for this type */
1129 tgl 4402 GIC 33 : GenerateTypeDependencies(newtup,
4403 : catalog,
4404 : NULL, /* don't have defaultExpr handy */
4405 : NULL, /* don't have typacl handy */
4406 : 0, /* we rejected composite types above */
4407 : isImplicitArray, /* it might be an array */
982 tgl 4408 ECB : isImplicitArray, /* dependent iff it's array */
600 4409 : false, /* don't touch extension membership */
4410 : true);
1129 4411 :
1129 tgl 4412 GIC 33 : InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
1129 tgl 4413 ECB :
4414 : /*
4415 : * Arrays inherit their base type's typmodin and typmodout, but none of
4416 : * the other properties we're concerned with here. Recurse to the array
4417 : * type if needed.
982 4418 : */
982 tgl 4419 CBC 33 : if (!isImplicitArray &&
982 tgl 4420 GBC 30 : (atparams->updateTypmodin || atparams->updateTypmodout))
4421 : {
982 tgl 4422 CBC 3 : Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
982 tgl 4423 ECB :
982 tgl 4424 CBC 3 : if (OidIsValid(arrtypoid))
982 tgl 4425 ECB : {
4426 : HeapTuple arrtup;
4427 : AlterTypeRecurseParams arrparams;
4428 :
982 tgl 4429 GIC 3 : arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
982 tgl 4430 CBC 3 : if (!HeapTupleIsValid(arrtup))
982 tgl 4431 UIC 0 : elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4432 :
982 tgl 4433 GIC 3 : memset(&arrparams, 0, sizeof(arrparams));
4434 3 : arrparams.updateTypmodin = atparams->updateTypmodin;
4435 3 : arrparams.updateTypmodout = atparams->updateTypmodout;
4436 3 : arrparams.typmodinOid = atparams->typmodinOid;
4437 3 : arrparams.typmodoutOid = atparams->typmodoutOid;
982 tgl 4438 ECB :
982 tgl 4439 CBC 3 : AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
982 tgl 4440 ECB :
982 tgl 4441 CBC 3 : ReleaseSysCache(arrtup);
4442 : }
4443 : }
982 tgl 4444 ECB :
1129 4445 : /*
4446 : * Now we need to recurse to domains. However, some properties are not
4447 : * inherited by domains, so clear the update flags for those.
4448 : */
1129 tgl 4449 GIC 33 : atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
1129 tgl 4450 CBC 33 : atparams->updateTypmodin = false; /* domains don't have typmods */
1129 tgl 4451 GIC 33 : atparams->updateTypmodout = false;
849 4452 33 : atparams->updateSubscript = false; /* domains don't have subscriptors */
4453 :
4454 : /* Skip the scan if nothing remains to be done */
982 tgl 4455 CBC 33 : if (!(atparams->updateStorage ||
982 tgl 4456 GIC 27 : atparams->updateSend ||
4457 10 : atparams->updateAnalyze))
982 tgl 4458 CBC 10 : return;
4459 :
1129 tgl 4460 ECB : /* Search pg_type for possible domains over this type */
1129 tgl 4461 GIC 23 : ScanKeyInit(&key[0],
4462 : Anum_pg_type_typbasetype,
4463 : BTEqualStrategyNumber, F_OIDEQ,
4464 : ObjectIdGetDatum(typeOid));
4465 :
1129 tgl 4466 CBC 23 : scan = systable_beginscan(catalog, InvalidOid, false,
1129 tgl 4467 EUB : NULL, 1, key);
4468 :
1129 tgl 4469 CBC 29 : while ((domainTup = systable_getnext(scan)) != NULL)
4470 : {
1129 tgl 4471 GIC 6 : Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
1129 tgl 4472 ECB :
4473 : /*
4474 : * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4475 : * check
4476 : */
1129 tgl 4477 GIC 6 : if (domainForm->typtype != TYPTYPE_DOMAIN)
1129 tgl 4478 UIC 0 : continue;
4479 :
982 tgl 4480 GIC 6 : AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
4481 : }
4482 :
1129 4483 23 : systable_endscan(scan);
4484 : }
|