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