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