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);
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 /* Check we have creation rights in target namespace */
1501 if (aclresult != ACLCHECK_OK)
1504 }
1505 else
1506 ereport(ERROR,
1508 errmsg("type attribute \"%s\" not recognized",
1509 defel->defname)));
1510 }
1511
1512 /* Must have a subtype */
1514 ereport(ERROR,
1516 errmsg("type attribute \"subtype\" is required")));
1517 /* disallow ranges of pseudotypes */
1519 ereport(ERROR,
1521 errmsg("range subtype cannot be %s",
1523
1524 /* Identify subopclass */
1526
1527 /* Identify collation to use, if any */
1529 {
1530 if (rangeCollationName != NIL)
1532 else
1534 }
1535 else
1536 {
1537 if (rangeCollationName != NIL)
1538 ereport(ERROR,
1540 errmsg("range collation specified but subtype does not support collation")));
1542 }
1543
1544 /* Identify support functions, if provided */
1545 if (rangeCanonicalName != NIL)
1546 {
1547 if (!OidIsValid(typoid))
1548 ereport(ERROR,
1550 errmsg("cannot specify a canonical function without a pre-created shell type"),
1551 errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
1553 typoid);
1554 }
1555 else
1557
1560 rangeSubtype);
1561 else
1563
1566
1567 /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
1569
1570 /* Allocate OID for array type, its multirange, and its multirange array */
1574
1575 /* Create the pg_type entry */
1576 address =
1577 TypeCreate(InvalidOid, /* no predetermined type OID */
1578 typeName, /* type name */
1579 typeNamespace, /* namespace */
1580 InvalidOid, /* relation oid (n/a here) */
1581 0, /* relation kind (ditto) */
1582 GetUserId(), /* owner's ID */
1583 -1, /* internal size (always varlena) */
1584 TYPTYPE_RANGE, /* type-type (range type) */
1585 TYPCATEGORY_RANGE, /* type-category (range type) */
1586 false, /* range types are never preferred */
1587 DEFAULT_TYPDELIM, /* array element delimiter */
1588 F_RANGE_IN, /* input procedure */
1589 F_RANGE_OUT, /* output procedure */
1590 F_RANGE_RECV, /* receive procedure */
1591 F_RANGE_SEND, /* send procedure */
1592 InvalidOid, /* typmodin procedure - none */
1593 InvalidOid, /* typmodout procedure - none */
1594 F_RANGE_TYPANALYZE, /* analyze procedure */
1595 InvalidOid, /* subscript procedure - none */
1596 InvalidOid, /* element type ID - none */
1597 false, /* this is not an array type */
1598 rangeArrayOid, /* array type we are about to create */
1599 InvalidOid, /* base type ID (only for domains) */
1600 NULL, /* never a default type value */
1601 NULL, /* no binary form available either */
1602 false, /* never passed by value */
1603 alignment, /* alignment */
1604 TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
1605 -1, /* typMod (Domains only) */
1606 0, /* Array dimensions of typbasetype */
1607 false, /* Type NOT NULL */
1608 InvalidOid); /* type's collation (ranges never have one) */
1609 Assert(typoid == InvalidOid || typoid == address.objectId);
1610 typoid = address.objectId;
1611
1612 /* Create the multirange that goes with it */
1614 {
1616
1617 /*
1618 * Look to see if multirange type already exists.
1619 */
1623
1624 /*
1625 * If it's not a shell, see if it's an autogenerated array type, and
1626 * if so rename it out of the way.
1627 */
1629 {
1631 ereport(ERROR,
1633 errmsg("type \"%s\" already exists", multirangeTypeName)));
1634 }
1635 }
1636 else
1637 {
1638 /* Generate multirange name automatically */
1641 }
1642
1644 TypeCreate(multirangeOid, /* force assignment of this type OID */
1645 multirangeTypeName, /* type name */
1646 multirangeNamespace, /* namespace */
1647 InvalidOid, /* relation oid (n/a here) */
1648 0, /* relation kind (ditto) */
1649 GetUserId(), /* owner's ID */
1650 -1, /* internal size (always varlena) */
1651 TYPTYPE_MULTIRANGE, /* type-type (multirange type) */
1652 TYPCATEGORY_RANGE, /* type-category (range type) */
1653 false, /* multirange types are never preferred */
1654 DEFAULT_TYPDELIM, /* array element delimiter */
1655 F_MULTIRANGE_IN, /* input procedure */
1656 F_MULTIRANGE_OUT, /* output procedure */
1657 F_MULTIRANGE_RECV, /* receive procedure */
1658 F_MULTIRANGE_SEND, /* send procedure */
1659 InvalidOid, /* typmodin procedure - none */
1660 InvalidOid, /* typmodout procedure - none */
1661 F_MULTIRANGE_TYPANALYZE, /* analyze procedure */
1662 InvalidOid, /* subscript procedure - none */
1663 InvalidOid, /* element type ID - none */
1664 false, /* this is not an array type */
1665 multirangeArrayOid, /* array type we are about to create */
1666 InvalidOid, /* base type ID (only for domains) */
1667 NULL, /* never a default type value */
1668 NULL, /* no binary form available either */
1669 false, /* never passed by value */
1670 alignment, /* alignment */
1671 'x', /* TOAST strategy (always extended) */
1672 -1, /* typMod (Domains only) */
1673 0, /* Array dimensions of typbasetype */
1674 false, /* Type NOT NULL */
1675 InvalidOid); /* type's collation (ranges never have one) */
1676 Assert(multirangeOid == mltrngaddress.objectId);
1677
1678 /*
1679 * Create the array type that goes with it.
1680 */
1682
1683 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1684 rangeArrayName, /* type name */
1685 typeNamespace, /* namespace */
1686 InvalidOid, /* relation oid (n/a here) */
1687 0, /* relation kind (ditto) */
1688 GetUserId(), /* owner's ID */
1689 -1, /* internal size (always varlena) */
1690 TYPTYPE_BASE, /* type-type (base type) */
1691 TYPCATEGORY_ARRAY, /* type-category (array) */
1692 false, /* array types are never preferred */
1693 DEFAULT_TYPDELIM, /* array element delimiter */
1694 F_ARRAY_IN, /* input procedure */
1695 F_ARRAY_OUT, /* output procedure */
1696 F_ARRAY_RECV, /* receive procedure */
1697 F_ARRAY_SEND, /* send procedure */
1698 InvalidOid, /* typmodin procedure - none */
1699 InvalidOid, /* typmodout procedure - none */
1700 F_ARRAY_TYPANALYZE, /* analyze procedure */
1701 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1702 typoid, /* element type ID */
1703 true, /* yes this is an array type */
1704 InvalidOid, /* no further array type */
1705 InvalidOid, /* base type ID */
1706 NULL, /* never a default type value */
1707 NULL, /* binary default isn't sent either */
1708 false, /* never passed by value */
1709 alignment, /* alignment - same as range's */
1710 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1711 -1, /* typMod (Domains only) */
1712 0, /* Array dimensions of typbasetype */
1713 false, /* Type NOT NULL */
1714 InvalidOid); /* typcollation */
1715
1717
1718 /* Create the multirange's array type */
1719
1721
1722 TypeCreate(multirangeArrayOid, /* force assignment of this type OID */
1723 multirangeArrayName, /* type name */
1724 multirangeNamespace, /* namespace */
1725 InvalidOid, /* relation oid (n/a here) */
1726 0, /* relation kind (ditto) */
1727 GetUserId(), /* owner's ID */
1728 -1, /* internal size (always varlena) */
1729 TYPTYPE_BASE, /* type-type (base type) */
1730 TYPCATEGORY_ARRAY, /* type-category (array) */
1731 false, /* array types are never preferred */
1732 DEFAULT_TYPDELIM, /* array element delimiter */
1733 F_ARRAY_IN, /* input procedure */
1734 F_ARRAY_OUT, /* output procedure */
1735 F_ARRAY_RECV, /* receive procedure */
1736 F_ARRAY_SEND, /* send procedure */
1737 InvalidOid, /* typmodin procedure - none */
1738 InvalidOid, /* typmodout procedure - none */
1739 F_ARRAY_TYPANALYZE, /* analyze procedure */
1740 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1741 multirangeOid, /* element type ID */
1742 true, /* yes this is an array type */
1743 InvalidOid, /* no further array type */
1744 InvalidOid, /* base type ID */
1745 NULL, /* never a default type value */
1746 NULL, /* binary default isn't sent either */
1747 false, /* never passed by value */
1748 alignment, /* alignment - same as range's */
1749 'x', /* ARRAY is always toastable */
1750 -1, /* typMod (Domains only) */
1751 0, /* Array dimensions of typbasetype */
1752 false, /* Type NOT NULL */
1753 InvalidOid); /* typcollation */
1754
1755 /* Ensure these new types are visible to ProcedureCreate */
1757
1758 /* And create the constructor functions for this range type */
1765
1766 /* Create the entry in pg_range */
1771
1772 /* Create cast from the range type to its multirange type */
1776
1778
1779 return address;
1780}
1781
1782/*
1783 * Because there may exist several range types over the same subtype, the
1784 * range type can't be uniquely determined from the subtype. So it's
1785 * impossible to define a polymorphic constructor; we have to generate new
1786 * constructor functions explicitly for each range type.
1787 *
1788 * We actually define 2 functions, with 2 through 3 arguments. This is just
1789 * to offer more convenience for the user.
1790 *
1791 * The OIDs of the created functions are returned through the pointer
1792 * arguments.
1793 */
1794static void
1795makeRangeConstructors(const char *name, Oid namespace,
1796 Oid rangeOid, Oid subtype,
1798{
1799 static const char *const prosrc[2] = {"range_constructor2",
1800 "range_constructor3"};
1801 static const int pronargs[2] = {2, 3};
1802
1805 referenced;
1806 int i;
1807
1808 constructorArgTypes[0] = subtype;
1809 constructorArgTypes[1] = subtype;
1811
1813 referenced.objectId = rangeOid;
1814 referenced.objectSubId = 0;
1815
1816 for (i = 0; i < lengthof(prosrc); i++)
1817 {
1819
1821 pronargs[i]);
1822
1823 myself = ProcedureCreate(name, /* name: same as range type */
1824 namespace, /* namespace */
1825 false, /* replace */
1826 false, /* returns set */
1827 rangeOid, /* return type */
1828 BOOTSTRAP_SUPERUSERID, /* proowner */
1829 INTERNALlanguageId, /* language */
1830 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1831 prosrc[i], /* prosrc */
1832 NULL, /* probin */
1833 NULL, /* prosqlbody */
1835 false, /* security_definer */
1836 false, /* leakproof */
1837 false, /* isStrict */
1838 PROVOLATILE_IMMUTABLE, /* volatility */
1839 PROPARALLEL_SAFE, /* parallel safety */
1840 constructorArgTypesVector, /* parameterTypes */
1841 PointerGetDatum(NULL), /* allParameterTypes */
1842 PointerGetDatum(NULL), /* parameterModes */
1843 PointerGetDatum(NULL), /* parameterNames */
1844 NIL, /* parameterDefaults */
1845 PointerGetDatum(NULL), /* trftypes */
1846 NIL, /* trfoids */
1847 PointerGetDatum(NULL), /* proconfig */
1848 InvalidOid, /* prosupport */
1849 1.0, /* procost */
1850 0.0); /* prorows */
1851
1852 /*
1853 * Make the constructors internally-dependent on the range type so
1854 * that they go away silently when the type is dropped. Note that
1855 * pg_dump depends on this choice to avoid dumping the constructors.
1856 */
1858
1859 if (pronargs[i] == 2)
1860 *rangeConstruct2_p = myself.objectId;
1861 else if (pronargs[i] == 3)
1862 *rangeConstruct3_p = myself.objectId;
1863 }
1864}
1865
1866/*
1867 * We make a separate multirange constructor for each range type
1868 * so its name can include the base type, like range constructors do.
1869 * If we had an anyrangearray polymorphic type we could use it here,
1870 * but since each type has its own constructor name there's no need.
1871 *
1872 * The OIDs of the created functions are returned through the pointer
1873 * arguments.
1874 */
1875static void
1876makeMultirangeConstructors(const char *name, Oid namespace,
1879{
1881 referenced;
1882 oidvector *argtypes;
1887
1888 referenced.classId = TypeRelationId;
1889 referenced.objectId = multirangeOid;
1890 referenced.objectSubId = 0;
1891
1892 /* 0-arg constructor - for empty multiranges */
1893 argtypes = buildoidvector(NULL, 0);
1894 myself = ProcedureCreate(name, /* name: same as multirange type */
1895 namespace,
1896 false, /* replace */
1897 false, /* returns set */
1898 multirangeOid, /* return type */
1899 BOOTSTRAP_SUPERUSERID, /* proowner */
1900 INTERNALlanguageId, /* language */
1902 "multirange_constructor0", /* prosrc */
1903 NULL, /* probin */
1904 NULL, /* prosqlbody */
1906 false, /* security_definer */
1907 false, /* leakproof */
1908 true, /* isStrict */
1909 PROVOLATILE_IMMUTABLE, /* volatility */
1910 PROPARALLEL_SAFE, /* parallel safety */
1911 argtypes, /* parameterTypes */
1912 PointerGetDatum(NULL), /* allParameterTypes */
1913 PointerGetDatum(NULL), /* parameterModes */
1914 PointerGetDatum(NULL), /* parameterNames */
1915 NIL, /* parameterDefaults */
1916 PointerGetDatum(NULL), /* trftypes */
1917 NIL, /* trfoids */
1918 PointerGetDatum(NULL), /* proconfig */
1919 InvalidOid, /* prosupport */
1920 1.0, /* procost */
1921 0.0); /* prorows */
1922
1923 /*
1924 * Make the constructor internally-dependent on the multirange type so
1925 * that they go away silently when the type is dropped. Note that pg_dump
1926 * depends on this choice to avoid dumping the constructors.
1927 */
1929 *mltrngConstruct0_p = myself.objectId;
1930 pfree(argtypes);
1931
1932 /*
1933 * 1-arg constructor - for casts
1934 *
1935 * In theory we shouldn't need both this and the vararg (n-arg)
1936 * constructor, but having a separate 1-arg function lets us define casts
1937 * against it.
1938 */
1939 argtypes = buildoidvector(&rangeOid, 1);
1940 myself = ProcedureCreate(name, /* name: same as multirange type */
1941 namespace,
1942 false, /* replace */
1943 false, /* returns set */
1944 multirangeOid, /* return type */
1945 BOOTSTRAP_SUPERUSERID, /* proowner */
1946 INTERNALlanguageId, /* language */
1948 "multirange_constructor1", /* prosrc */
1949 NULL, /* probin */
1950 NULL, /* prosqlbody */
1952 false, /* security_definer */
1953 false, /* leakproof */
1954 true, /* isStrict */
1955 PROVOLATILE_IMMUTABLE, /* volatility */
1956 PROPARALLEL_SAFE, /* parallel safety */
1957 argtypes, /* parameterTypes */
1958 PointerGetDatum(NULL), /* allParameterTypes */
1959 PointerGetDatum(NULL), /* parameterModes */
1960 PointerGetDatum(NULL), /* parameterNames */
1961 NIL, /* parameterDefaults */
1962 PointerGetDatum(NULL), /* trftypes */
1963 NIL, /* trfoids */
1964 PointerGetDatum(NULL), /* proconfig */
1965 InvalidOid, /* prosupport */
1966 1.0, /* procost */
1967 0.0); /* prorows */
1968 /* ditto */
1970 *mltrngConstruct1_p = myself.objectId;
1971 pfree(argtypes);
1972
1973 /* n-arg constructor - vararg */
1974 argtypes = buildoidvector(&rangeArrayOid, 1);
1979 myself = ProcedureCreate(name, /* name: same as multirange type */
1980 namespace,
1981 false, /* replace */
1982 false, /* returns set */
1983 multirangeOid, /* return type */
1984 BOOTSTRAP_SUPERUSERID, /* proowner */
1985 INTERNALlanguageId, /* language */
1987 "multirange_constructor2", /* prosrc */
1988 NULL, /* probin */
1989 NULL, /* prosqlbody */
1991 false, /* security_definer */
1992 false, /* leakproof */
1993 true, /* isStrict */
1994 PROVOLATILE_IMMUTABLE, /* volatility */
1995 PROPARALLEL_SAFE, /* parallel safety */
1996 argtypes, /* parameterTypes */
1997 PointerGetDatum(allParameterTypes), /* allParameterTypes */
1998 PointerGetDatum(parameterModes), /* parameterModes */
1999 PointerGetDatum(NULL), /* parameterNames */
2000 NIL, /* parameterDefaults */
2001 PointerGetDatum(NULL), /* trftypes */
2002 NIL, /* trfoids */
2003 PointerGetDatum(NULL), /* proconfig */
2004 InvalidOid, /* prosupport */
2005 1.0, /* procost */
2006 0.0); /* prorows */
2007 /* ditto */
2009 *mltrngConstruct2_p = myself.objectId;
2010 pfree(argtypes);
2013}
2014
2015/*
2016 * Find suitable I/O and other support functions for a type.
2017 *
2018 * typeOid is the type's OID (which will already exist, if only as a shell
2019 * type).
2020 */
2021
2022static Oid
2023findTypeInputFunction(List *procname, Oid typeOid)
2024{
2025 Oid argList[3];
2026 Oid procOid;
2027 Oid procOid2;
2028
2029 /*
2030 * Input functions can take a single argument of type CSTRING, or three
2031 * arguments (string, typioparam OID, typmod). Whine about ambiguity if
2032 * both forms exist.
2033 */
2034 argList[0] = CSTRINGOID;
2035 argList[1] = OIDOID;
2036 argList[2] = INT4OID;
2037
2038 procOid = LookupFuncName(procname, 1, argList, true);
2039 procOid2 = LookupFuncName(procname, 3, argList, true);
2040 if (OidIsValid(procOid))
2041 {
2042 if (OidIsValid(procOid2))
2043 ereport(ERROR,
2045 errmsg("type input function %s has multiple matches",
2046 NameListToString(procname))));
2047 }
2048 else
2049 {
2050 procOid = procOid2;
2051 /* If not found, reference the 1-argument signature in error msg */
2052 if (!OidIsValid(procOid))
2053 ereport(ERROR,
2055 errmsg("function %s does not exist",
2056 func_signature_string(procname, 1, NIL, argList))));
2057 }
2058
2059 /* Input functions must return the target type. */
2060 if (get_func_rettype(procOid) != typeOid)
2061 ereport(ERROR,
2063 errmsg("type input function %s must return type %s",
2064 NameListToString(procname), format_type_be(typeOid))));
2065
2066 /*
2067 * Print warnings if any of the type's I/O functions are marked volatile.
2068 * There is a general assumption that I/O functions are stable or
2069 * immutable; this allows us for example to mark record_in/record_out
2070 * stable rather than volatile. Ideally we would throw errors not just
2071 * warnings here; but since this check is new as of 9.5, and since the
2072 * volatility marking might be just an error-of-omission and not a true
2073 * indication of how the function behaves, we'll let it pass as a warning
2074 * for now.
2075 */
2079 errmsg("type input function %s should not be volatile",
2080 NameListToString(procname))));
2081
2082 return procOid;
2083}
2084
2085static Oid
2087{
2088 Oid argList[1];
2089 Oid procOid;
2090
2091 /*
2092 * Output functions always take a single argument of the type and return
2093 * cstring.
2094 */
2095 argList[0] = typeOid;
2096
2097 procOid = LookupFuncName(procname, 1, argList, true);
2098 if (!OidIsValid(procOid))
2099 ereport(ERROR,
2101 errmsg("function %s does not exist",
2102 func_signature_string(procname, 1, NIL, argList))));
2103
2105 ereport(ERROR,
2107 errmsg("type output function %s must return type %s",
2108 NameListToString(procname), "cstring")));
2109
2110 /* Just a warning for now, per comments in findTypeInputFunction */
2114 errmsg("type output function %s should not be volatile",
2115 NameListToString(procname))));
2116
2117 return procOid;
2118}
2119
2120static Oid
2122{
2123 Oid argList[3];
2124 Oid procOid;
2125 Oid procOid2;
2126
2127 /*
2128 * Receive functions can take a single argument of type INTERNAL, or three
2129 * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2130 * both forms exist.
2131 */
2132 argList[0] = INTERNALOID;
2133 argList[1] = OIDOID;
2134 argList[2] = INT4OID;
2135
2136 procOid = LookupFuncName(procname, 1, argList, true);
2137 procOid2 = LookupFuncName(procname, 3, argList, true);
2138 if (OidIsValid(procOid))
2139 {
2140 if (OidIsValid(procOid2))
2141 ereport(ERROR,
2143 errmsg("type receive function %s has multiple matches",
2144 NameListToString(procname))));
2145 }
2146 else
2147 {
2148 procOid = procOid2;
2149 /* If not found, reference the 1-argument signature in error msg */
2150 if (!OidIsValid(procOid))
2151 ereport(ERROR,
2153 errmsg("function %s does not exist",
2154 func_signature_string(procname, 1, NIL, argList))));
2155 }
2156
2157 /* Receive functions must return the target type. */
2158 if (get_func_rettype(procOid) != typeOid)
2159 ereport(ERROR,
2161 errmsg("type receive function %s must return type %s",
2162 NameListToString(procname), format_type_be(typeOid))));
2163
2164 /* Just a warning for now, per comments in findTypeInputFunction */
2168 errmsg("type receive function %s should not be volatile",
2169 NameListToString(procname))));
2170
2171 return procOid;
2172}
2173
2174static Oid
2175findTypeSendFunction(List *procname, Oid typeOid)
2176{
2177 Oid argList[1];
2178 Oid procOid;
2179
2180 /*
2181 * Send functions always take a single argument of the type and return
2182 * bytea.
2183 */
2184 argList[0] = typeOid;
2185
2186 procOid = LookupFuncName(procname, 1, argList, true);
2187 if (!OidIsValid(procOid))
2188 ereport(ERROR,
2190 errmsg("function %s does not exist",
2191 func_signature_string(procname, 1, NIL, argList))));
2192
2194 ereport(ERROR,
2196 errmsg("type send function %s must return type %s",
2197 NameListToString(procname), "bytea")));
2198
2199 /* Just a warning for now, per comments in findTypeInputFunction */
2203 errmsg("type send function %s should not be volatile",
2204 NameListToString(procname))));
2205
2206 return procOid;
2207}
2208
2209static Oid
2211{
2212 Oid argList[1];
2213 Oid procOid;
2214
2215 /*
2216 * typmodin functions always take one cstring[] argument and return int4.
2217 */
2219
2220 procOid = LookupFuncName(procname, 1, argList, true);
2221 if (!OidIsValid(procOid))
2222 ereport(ERROR,
2224 errmsg("function %s does not exist",
2225 func_signature_string(procname, 1, NIL, argList))));
2226
2228 ereport(ERROR,
2230 errmsg("typmod_in function %s must return type %s",
2231 NameListToString(procname), "integer")));
2232
2233 /* Just a warning for now, per comments in findTypeInputFunction */
2237 errmsg("type modifier input function %s should not be volatile",
2238 NameListToString(procname))));
2239
2240 return procOid;
2241}
2242
2243static Oid
2245{
2246 Oid argList[1];
2247 Oid procOid;
2248
2249 /*
2250 * typmodout functions always take one int4 argument and return cstring.
2251 */
2252 argList[0] = INT4OID;
2253
2254 procOid = LookupFuncName(procname, 1, argList, true);
2255 if (!OidIsValid(procOid))
2256 ereport(ERROR,
2258 errmsg("function %s does not exist",
2259 func_signature_string(procname, 1, NIL, argList))));
2260
2262 ereport(ERROR,
2264 errmsg("typmod_out function %s must return type %s",
2265 NameListToString(procname), "cstring")));
2266
2267 /* Just a warning for now, per comments in findTypeInputFunction */
2271 errmsg("type modifier output function %s should not be volatile",
2272 NameListToString(procname))));
2273
2274 return procOid;
2275}
2276
2277static Oid
2279{
2280 Oid argList[1];
2281 Oid procOid;
2282
2283 /*
2284 * Analyze functions always take one INTERNAL argument and return bool.
2285 */
2286 argList[0] = INTERNALOID;
2287
2288 procOid = LookupFuncName(procname, 1, argList, true);
2289 if (!OidIsValid(procOid))
2290 ereport(ERROR,
2292 errmsg("function %s does not exist",
2293 func_signature_string(procname, 1, NIL, argList))));
2294
2296 ereport(ERROR,
2298 errmsg("type analyze function %s must return type %s",
2299 NameListToString(procname), "boolean")));
2300
2301 return procOid;
2302}
2303
2304static Oid
2306{
2307 Oid argList[1];
2308 Oid procOid;
2309
2310 /*
2311 * Subscripting support functions always take one INTERNAL argument and
2312 * return INTERNAL. (The argument is not used, but we must have it to
2313 * maintain type safety.)
2314 */
2315 argList[0] = INTERNALOID;
2316
2317 procOid = LookupFuncName(procname, 1, argList, true);
2318 if (!OidIsValid(procOid))
2319 ereport(ERROR,
2321 errmsg("function %s does not exist",
2322 func_signature_string(procname, 1, NIL, argList))));
2323
2325 ereport(ERROR,
2327 errmsg("type subscripting function %s must return type %s",
2328 NameListToString(procname), "internal")));
2329
2330 /*
2331 * We disallow array_subscript_handler() from being selected explicitly,
2332 * since that must only be applied to autogenerated array types.
2333 */
2335 ereport(ERROR,
2337 errmsg("user-defined types cannot use subscripting function %s",
2338 NameListToString(procname))));
2339
2340 return procOid;
2341}
2342
2343/*
2344 * Find suitable support functions and opclasses for a range type.
2345 */
2346
2347/*
2348 * Find named btree opclass for subtype, or default btree opclass if
2349 * opcname is NIL.
2350 */
2351static Oid
2353{
2354 Oid opcid;
2356
2357 if (opcname != NIL)
2358 {
2360
2361 /*
2362 * Verify that the operator class accepts this datatype. Note we will
2363 * accept binary compatibility.
2364 */
2366 if (!IsBinaryCoercible(subtype, opInputType))
2367 ereport(ERROR,
2369 errmsg("operator class \"%s\" does not accept data type %s",
2371 format_type_be(subtype))));
2372 }
2373 else
2374 {
2376 if (!OidIsValid(opcid))
2377 {
2378 /* We spell the error message identically to ResolveOpClass */
2379 ereport(ERROR,
2381 errmsg("data type %s has no default operator class for access method \"%s\"",
2382 format_type_be(subtype), "btree"),
2383 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2384 }
2385 }
2386
2387 return opcid;
2388}
2389
2390static Oid
2392{
2393 Oid argList[1];
2394 Oid procOid;
2396
2397 /*
2398 * Range canonical functions must take and return the range type, and must
2399 * be immutable.
2400 */
2401 argList[0] = typeOid;
2402
2403 procOid = LookupFuncName(procname, 1, argList, true);
2404
2405 if (!OidIsValid(procOid))
2406 ereport(ERROR,
2408 errmsg("function %s does not exist",
2409 func_signature_string(procname, 1, NIL, argList))));
2410
2411 if (get_func_rettype(procOid) != typeOid)
2412 ereport(ERROR,
2414 errmsg("range canonical function %s must return range type",
2415 func_signature_string(procname, 1, NIL, argList))));
2416
2418 ereport(ERROR,
2420 errmsg("range canonical function %s must be immutable",
2421 func_signature_string(procname, 1, NIL, argList))));
2422
2423 /* Also, range type's creator must have permission to call function */
2425 if (aclresult != ACLCHECK_OK)
2427
2428 return procOid;
2429}
2430
2431static Oid
2433{
2434 Oid argList[2];
2435 Oid procOid;
2437
2438 /*
2439 * Range subtype diff functions must take two arguments of the subtype,
2440 * must return float8, and must be immutable.
2441 */
2442 argList[0] = subtype;
2443 argList[1] = subtype;
2444
2445 procOid = LookupFuncName(procname, 2, argList, true);
2446
2447 if (!OidIsValid(procOid))
2448 ereport(ERROR,
2450 errmsg("function %s does not exist",
2451 func_signature_string(procname, 2, NIL, argList))));
2452
2454 ereport(ERROR,
2456 errmsg("range subtype diff function %s must return type %s",
2457 func_signature_string(procname, 2, NIL, argList),
2458 "double precision")));
2459
2461 ereport(ERROR,
2463 errmsg("range subtype diff function %s must be immutable",
2464 func_signature_string(procname, 2, NIL, argList))));
2465
2466 /* Also, range type's creator must have permission to call function */
2468 if (aclresult != ACLCHECK_OK)
2470
2471 return procOid;
2472}
2473
2474/*
2475 * AssignTypeArrayOid
2476 *
2477 * Pre-assign the type's array OID for use in pg_type.typarray
2478 */
2479Oid
2481{
2483
2484 /* Use binary-upgrade override for pg_type.typarray? */
2485 if (IsBinaryUpgrade)
2486 {
2488 ereport(ERROR,
2490 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2491
2494 }
2495 else
2496 {
2498
2502 }
2503
2504 return type_array_oid;
2505}
2506
2507/*
2508 * AssignTypeMultirangeOid
2509 *
2510 * Pre-assign the range type's multirange OID for use in pg_type.oid
2511 */
2512Oid
2514{
2516
2517 /* Use binary-upgrade override for pg_type.oid? */
2518 if (IsBinaryUpgrade)
2519 {
2521 ereport(ERROR,
2523 errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2524
2527 }
2528 else
2529 {
2531
2535 }
2536
2537 return type_multirange_oid;
2538}
2539
2540/*
2541 * AssignTypeMultirangeArrayOid
2542 *
2543 * Pre-assign the range type's multirange array OID for use in pg_type.typarray
2544 */
2545Oid
2547{
2549
2550 /* Use binary-upgrade override for pg_type.oid? */
2551 if (IsBinaryUpgrade)
2552 {
2554 ereport(ERROR,
2556 errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2557
2560 }
2561 else
2562 {
2564
2568 }
2569
2571}
2572
2573
2574/*-------------------------------------------------------------------
2575 * DefineCompositeType
2576 *
2577 * Create a Composite Type relation.
2578 * `DefineRelation' does all the work, we just provide the correct
2579 * arguments!
2580 *
2581 * If the relation already exists, then 'DefineRelation' will abort
2582 * the xact...
2583 *
2584 * Return type is the new type's object address.
2585 *-------------------------------------------------------------------
2586 */
2588DefineCompositeType(RangeVar *typevar, List *coldeflist)
2589{
2590 CreateStmt *createStmt = makeNode(CreateStmt);
2593 ObjectAddress address;
2594
2595 /*
2596 * now set the parameters for keys/inheritance etc. All of these are
2597 * uninteresting for composite types...
2598 */
2599 createStmt->relation = typevar;
2600 createStmt->tableElts = coldeflist;
2601 createStmt->inhRelations = NIL;
2602 createStmt->constraints = NIL;
2603 createStmt->options = NIL;
2604 createStmt->oncommit = ONCOMMIT_NOOP;
2605 createStmt->tablespacename = NULL;
2606 createStmt->if_not_exists = false;
2607
2608 /*
2609 * Check for collision with an existing type name. If there is one and
2610 * it's an autogenerated array, we can rename it out of the way. This
2611 * check is here mainly to get a better error message about a "type"
2612 * instead of below about a "relation".
2613 */
2615 NoLock, NULL);
2617 old_type_oid =
2619 CStringGetDatum(createStmt->relation->relname),
2622 {
2624 ereport(ERROR,
2626 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2627 }
2628
2629 /*
2630 * Finally create the relation. This also creates the type.
2631 */
2632 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2633 NULL);
2634
2635 return address;
2636}
2637
2638/*
2639 * AlterDomainDefault
2640 *
2641 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2642 *
2643 * Returns ObjectAddress of the modified domain.
2644 */
2647{
2648 TypeName *typename;
2649 Oid domainoid;
2650 HeapTuple tup;
2651 ParseState *pstate;
2652 Relation rel;
2653 char *defaultValue;
2654 Node *defaultExpr = NULL; /* NULL if no default specified */
2656 bool new_record_nulls[Natts_pg_type] = {0};
2657 bool new_record_repl[Natts_pg_type] = {0};
2658 HeapTuple newtuple;
2660 ObjectAddress address;
2661
2662 /* Make a TypeName so we can use standard type lookup machinery */
2663 typename = makeTypeNameFromNameList(names);
2664 domainoid = typenameTypeId(NULL, typename);
2665
2666 /* Look up the domain in the type table */
2668
2670 if (!HeapTupleIsValid(tup))
2671 elog(ERROR, "cache lookup failed for type %u", domainoid);
2673
2674 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2676
2677 /* Setup new tuple */
2678
2679 /* Store the new default into the tuple */
2680 if (defaultRaw)
2681 {
2682 /* Create a dummy ParseState for transformExpr */
2683 pstate = make_parsestate(NULL);
2684
2685 /*
2686 * Cook the colDef->raw_expr into an expression. Note: Name is
2687 * strictly for error message
2688 */
2690 typTup->typbasetype,
2691 typTup->typtypmod,
2692 NameStr(typTup->typname),
2693 0);
2694
2695 /*
2696 * If the expression is just a NULL constant, we treat the command
2697 * like ALTER ... DROP DEFAULT. (But see note for same test in
2698 * DefineDomain.)
2699 */
2700 if (defaultExpr == NULL ||
2702 {
2703 /* Default is NULL, drop it */
2704 defaultExpr = NULL;
2709 }
2710 else
2711 {
2712 /*
2713 * Expression must be stored as a nodeToString result, but we also
2714 * require a valid textual representation (mainly to make life
2715 * easier for pg_dump).
2716 */
2718 NIL, false, false);
2719
2720 /*
2721 * Form an updated tuple with the new default and write it back.
2722 */
2724
2728 }
2729 }
2730 else
2731 {
2732 /* ALTER ... DROP DEFAULT */
2737 }
2738
2739 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2742
2743 CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2744
2745 /* Rebuild dependencies */
2746 GenerateTypeDependencies(newtuple,
2747 rel,
2749 NULL, /* don't have typacl handy */
2750 0, /* relation kind is n/a */
2751 false, /* a domain isn't an implicit array */
2752 false, /* nor is it any kind of dependent type */
2753 false, /* don't touch extension membership */
2754 true); /* We do need to rebuild dependencies */
2755
2757
2759
2760 /* Clean up */
2762 heap_freetuple(newtuple);
2763
2764 return address;
2765}
2766
2767/*
2768 * AlterDomainNotNull
2769 *
2770 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2771 *
2772 * Returns ObjectAddress of the modified domain.
2773 */
2776{
2777 TypeName *typename;
2778 Oid domainoid;
2780 HeapTuple tup;
2783
2784 /* Make a TypeName so we can use standard type lookup machinery */
2785 typename = makeTypeNameFromNameList(names);
2786 domainoid = typenameTypeId(NULL, typename);
2787
2788 /* Look up the domain in the type table */
2790
2792 if (!HeapTupleIsValid(tup))
2793 elog(ERROR, "cache lookup failed for type %u", domainoid);
2795
2796 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2798
2799 /* Is the domain already set to the desired constraint? */
2800 if (typTup->typnotnull == notNull)
2801 {
2803 return address;
2804 }
2805
2806 if (notNull)
2807 {
2808 Constraint *constr;
2809
2810 constr = makeNode(Constraint);
2811 constr->contype = CONSTR_NOTNULL;
2812 constr->initially_valid = true;
2813 constr->location = -1;
2814
2816 typTup->typbasetype, typTup->typtypmod,
2817 constr, NameStr(typTup->typname), NULL);
2818
2820 }
2821 else
2822 {
2825
2827 if (conTup == NULL)
2828 elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
2829
2832 }
2833
2834 /*
2835 * Okay to update pg_type row. We can scribble on typTup because it's a
2836 * copy.
2837 */
2838 typTup->typnotnull = notNull;
2839
2840 CatalogTupleUpdate(typrel, &tup->t_self, tup);
2841
2843
2845
2846 /* Clean up */
2849
2850 return address;
2851}
2852
2853/*
2854 * AlterDomainDropConstraint
2855 *
2856 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2857 *
2858 * Returns ObjectAddress of the modified domain.
2859 */
2862 DropBehavior behavior, bool missing_ok)
2863{
2864 TypeName *typename;
2865 Oid domainoid;
2866 HeapTuple tup;
2867 Relation rel;
2870 ScanKeyData skey[3];
2872 bool found = false;
2873 ObjectAddress address;
2874
2875 /* Make a TypeName so we can use standard type lookup machinery */
2876 typename = makeTypeNameFromNameList(names);
2877 domainoid = typenameTypeId(NULL, typename);
2878
2879 /* Look up the domain in the type table */
2881
2883 if (!HeapTupleIsValid(tup))
2884 elog(ERROR, "cache lookup failed for type %u", domainoid);
2885
2886 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2888
2889 /* Grab an appropriate lock on the pg_constraint relation */
2891
2892 /* Find and remove the target constraint */
2893 ScanKeyInit(&skey[0],
2897 ScanKeyInit(&skey[1],
2901 ScanKeyInit(&skey[2],
2905
2907 NULL, 3, skey);
2908
2909 /* There can be at most one matching row */
2910 if ((contup = systable_getnext(conscan)) != NULL)
2911 {
2914
2915 if (construct->contype == CONSTRAINT_NOTNULL)
2916 {
2917 ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2918 CatalogTupleUpdate(rel, &tup->t_self, tup);
2919 }
2920
2921 conobj.classId = ConstraintRelationId;
2922 conobj.objectId = construct->oid;
2923 conobj.objectSubId = 0;
2924
2925 performDeletion(&conobj, behavior, 0);
2926 found = true;
2927 }
2928
2929 /* Clean up after the scan */
2932
2933 if (!found)
2934 {
2935 if (!missing_ok)
2936 ereport(ERROR,
2938 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2939 constrName, TypeNameToString(typename))));
2940 else
2942 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2943 constrName, TypeNameToString(typename))));
2944 }
2945
2946 /*
2947 * We must send out an sinval message for the domain, to ensure that any
2948 * dependent plans get rebuilt. Since this command doesn't change the
2949 * domain's pg_type row, that won't happen automatically; do it manually.
2950 */
2952
2954
2955 /* Clean up */
2957
2958 return address;
2959}
2960
2961/*
2962 * AlterDomainAddConstraint
2963 *
2964 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2965 */
2969{
2970 TypeName *typename;
2971 Oid domainoid;
2973 HeapTuple tup;
2975 Constraint *constr;
2976 char *ccbin;
2978
2979 /* Make a TypeName so we can use standard type lookup machinery */
2980 typename = makeTypeNameFromNameList(names);
2981 domainoid = typenameTypeId(NULL, typename);
2982
2983 /* Look up the domain in the type table */
2985
2987 if (!HeapTupleIsValid(tup))
2988 elog(ERROR, "cache lookup failed for type %u", domainoid);
2990
2991 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2993
2995 elog(ERROR, "unrecognized node type: %d",
2996 (int) nodeTag(newConstraint));
2997
2998 constr = (Constraint *) newConstraint;
2999
3000 /* enforced by parser */
3001 Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
3002
3003 if (constr->contype == CONSTR_CHECK)
3004 {
3005 /*
3006 * First, process the constraint expression and add an entry to
3007 * pg_constraint.
3008 */
3009
3010 ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
3011 typTup->typbasetype, typTup->typtypmod,
3012 constr, NameStr(typTup->typname), constrAddr);
3013
3014
3015 /*
3016 * If requested to validate the constraint, test all values stored in
3017 * the attributes based on the domain the constraint is being added
3018 * to.
3019 */
3020 if (!constr->skip_validation)
3022
3023 /*
3024 * We must send out an sinval message for the domain, to ensure that
3025 * any dependent plans get rebuilt. Since this command doesn't change
3026 * the domain's pg_type row, that won't happen automatically; do it
3027 * manually.
3028 */
3030 }
3031 else if (constr->contype == CONSTR_NOTNULL)
3032 {
3033 /* Is the domain already set NOT NULL? */
3034 if (typTup->typnotnull)
3035 {
3037 return address;
3038 }
3040 typTup->typbasetype, typTup->typtypmod,
3041 constr, NameStr(typTup->typname), constrAddr);
3042
3043 if (!constr->skip_validation)
3045
3046 typTup->typnotnull = true;
3047 CatalogTupleUpdate(typrel, &tup->t_self, tup);
3048 }
3049
3051
3052 /* Clean up */
3054
3055 return address;
3056}
3057
3058/*
3059 * AlterDomainValidateConstraint
3060 *
3061 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
3062 *
3063 * Return value is the address of the validated constraint. If the constraint
3064 * was already validated, InvalidObjectAddress is returned.
3065 */
3068{
3069 TypeName *typename;
3070 Oid domainoid;
3073 HeapTuple tup;
3076 char *conbin;
3077 SysScanDesc scan;
3078 Datum val;
3079 HeapTuple tuple;
3081 ScanKeyData skey[3];
3083
3084 /* Make a TypeName so we can use standard type lookup machinery */
3085 typename = makeTypeNameFromNameList(names);
3086 domainoid = typenameTypeId(NULL, typename);
3087
3088 /* Look up the domain in the type table */
3090
3092 if (!HeapTupleIsValid(tup))
3093 elog(ERROR, "cache lookup failed for type %u", domainoid);
3094
3095 /* Check it's a domain and check user has permission for ALTER DOMAIN */
3097
3098 /*
3099 * Find and check the target constraint
3100 */
3102
3103 ScanKeyInit(&skey[0],
3107 ScanKeyInit(&skey[1],
3111 ScanKeyInit(&skey[2],
3115
3117 NULL, 3, skey);
3118
3119 /* There can be at most one matching row */
3120 if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
3121 ereport(ERROR,
3123 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3124 constrName, TypeNameToString(typename))));
3125
3126 con = (Form_pg_constraint) GETSTRUCT(tuple);
3127 if (con->contype != CONSTRAINT_CHECK)
3128 ereport(ERROR,
3130 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
3131 constrName, TypeNameToString(typename))));
3132
3133 if (!con->convalidated)
3134 {
3137
3139
3140 /*
3141 * Now update the catalog, while we have the door open.
3142 */
3143 copyTuple = heap_copytuple(tuple);
3145 copy_con->convalidated = true;
3147
3149
3151
3153 }
3154
3155 systable_endscan(scan);
3156
3159
3161
3162 return address;
3163}
3164
3165/*
3166 * Verify that all columns currently using the domain are not null.
3167 */
3168static void
3170{
3171 List *rels;
3172 ListCell *rt;
3173
3174 /* Fetch relation list with attributes based on this domain */
3175 /* ShareLock is sufficient to prevent concurrent data changes */
3176
3178
3179 foreach(rt, rels)
3180 {
3182 Relation testrel = rtc->rel;
3184 TupleTableSlot *slot;
3185 TableScanDesc scan;
3186 Snapshot snapshot;
3187
3188 /* Scan all tuples in this relation */
3189 snapshot = RegisterSnapshot(GetLatestSnapshot());
3190 scan = table_beginscan(testrel, snapshot, 0, NULL,
3191 SO_NONE);
3193 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3194 {
3195 int i;
3196
3197 /* Test attributes that are of the domain */
3198 for (i = 0; i < rtc->natts; i++)
3199 {
3200 int attnum = rtc->atts[i];
3201 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3202
3203 if (slot_attisnull(slot, attnum))
3204 {
3205 /*
3206 * In principle the auxiliary information for this error
3207 * should be errdatatype(), but errtablecol() seems
3208 * considerably more useful in practice. Since this code
3209 * only executes in an ALTER DOMAIN command, the client
3210 * should already know which domain is in question.
3211 */
3212 ereport(ERROR,
3214 errmsg("column \"%s\" of table \"%s\" contains null values",
3215 NameStr(attr->attname),
3218 }
3219 }
3220 }
3222 table_endscan(scan);
3223 UnregisterSnapshot(snapshot);
3224
3225 /* Close each rel after processing, but keep lock */
3227 }
3228}
3229
3230/*
3231 * Verify that all columns currently using the domain satisfy the given check
3232 * constraint expression.
3233 */
3234static void
3236{
3237 Expr *expr = (Expr *) stringToNode(ccbin);
3238 List *rels;
3239 ListCell *rt;
3240 EState *estate;
3241 ExprContext *econtext;
3242 ExprState *exprstate;
3243
3244 /* Need an EState to run ExecEvalExpr */
3245 estate = CreateExecutorState();
3246 econtext = GetPerTupleExprContext(estate);
3247
3248 /* build execution state for expr */
3249 exprstate = ExecPrepareExpr(expr, estate);
3250
3251 /* Fetch relation list with attributes based on this domain */
3252 /* ShareLock is sufficient to prevent concurrent data changes */
3253
3255
3256 foreach(rt, rels)
3257 {
3259 Relation testrel = rtc->rel;
3261 TupleTableSlot *slot;
3262 TableScanDesc scan;
3263 Snapshot snapshot;
3264
3265 /* Scan all tuples in this relation */
3266 snapshot = RegisterSnapshot(GetLatestSnapshot());
3267 scan = table_beginscan(testrel, snapshot, 0, NULL,
3268 SO_NONE);
3270 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3271 {
3272 int i;
3273
3274 /* Test attributes that are of the domain */
3275 for (i = 0; i < rtc->natts; i++)
3276 {
3277 int attnum = rtc->atts[i];
3278 Datum d;
3279 bool isNull;
3281
3282 d = slot_getattr(slot, attnum, &isNull);
3283
3284 econtext->domainValue_datum = d;
3285 econtext->domainValue_isNull = isNull;
3286
3288 econtext,
3289 &isNull);
3290
3291 if (!isNull && !DatumGetBool(conResult))
3292 {
3293 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3294
3295 /*
3296 * In principle the auxiliary information for this error
3297 * should be errdomainconstraint(), but errtablecol()
3298 * seems considerably more useful in practice. Since this
3299 * code only executes in an ALTER DOMAIN command, the
3300 * client should already know which domain is in question,
3301 * and which constraint too.
3302 */
3303 ereport(ERROR,
3305 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3306 NameStr(attr->attname),
3309 }
3310 }
3311
3312 ResetExprContext(econtext);
3313 }
3315 table_endscan(scan);
3316 UnregisterSnapshot(snapshot);
3317
3318 /* Hold relation lock till commit (XXX bad for concurrency) */
3320 }
3321
3322 FreeExecutorState(estate);
3323}
3324
3325/*
3326 * get_rels_with_domain
3327 *
3328 * Fetch all relations / attributes which are using the domain
3329 *
3330 * The result is a list of RelToCheck structs, one for each distinct
3331 * relation, each containing one or more attribute numbers that are of
3332 * the domain type. We have opened each rel and acquired the specified lock
3333 * type on it.
3334 *
3335 * We support nested domains by including attributes that are of derived
3336 * domain types. Current callers do not need to distinguish between attributes
3337 * that are of exactly the given domain and those that are of derived domains.
3338 *
3339 * XXX this is completely broken because there is no way to lock the domain
3340 * to prevent columns from being added or dropped while our command runs.
3341 * We can partially protect against column drops by locking relations as we
3342 * come across them, but there is still a race condition (the window between
3343 * seeing a pg_depend entry and acquiring lock on the relation it references).
3344 * Also, holding locks on all these relations simultaneously creates a non-
3345 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
3346 * risk by using the weakest suitable lock (ShareLock for most callers).
3347 *
3348 * XXX the API for this is not sufficient to support checking domain values
3349 * that are inside container types, such as composite types, arrays, or
3350 * ranges. Currently we just error out if a container type containing the
3351 * target domain is stored anywhere.
3352 *
3353 * Generally used for retrieving a list of tests when adding
3354 * new constraints to a domain.
3355 */
3356static List *
3358{
3359 List *result = NIL;
3362 ScanKeyData key[2];
3365
3366 Assert(lockmode != NoLock);
3367
3368 /* since this function recurses, it could be driven to stack overflow */
3370
3371 /*
3372 * We scan pg_depend to find those things that depend on the domain. (We
3373 * assume we can ignore refobjsubid for a domain.)
3374 */
3376
3377 ScanKeyInit(&key[0],
3381 ScanKeyInit(&key[1],
3385
3387 NULL, 2, key);
3388
3390 {
3392 RelToCheck *rtc = NULL;
3395 int ptr;
3396
3397 /* Check for directly dependent types */
3398 if (pg_depend->classid == TypeRelationId)
3399 {
3400 if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3401 {
3402 /*
3403 * This is a sub-domain, so recursively add dependent columns
3404 * to the output list. This is a bit inefficient since we may
3405 * fail to combine RelToCheck entries when attributes of the
3406 * same rel have different derived domain types, but it's
3407 * probably not worth improving.
3408 */
3411 lockmode));
3412 }
3413 else
3414 {
3415 /*
3416 * Otherwise, it is some container type using the domain, so
3417 * fail if there are any columns of this type.
3418 */
3420 NULL,
3422 }
3423 continue;
3424 }
3425
3426 /* Else, ignore dependees that aren't user columns of relations */
3427 /* (we assume system columns are never of domain types) */
3428 if (pg_depend->classid != RelationRelationId ||
3429 pg_depend->objsubid <= 0)
3430 continue;
3431
3432 /* See if we already have an entry for this relation */
3433 foreach(rellist, result)
3434 {
3436
3437 if (RelationGetRelid(rt->rel) == pg_depend->objid)
3438 {
3439 rtc = rt;
3440 break;
3441 }
3442 }
3443
3444 if (rtc == NULL)
3445 {
3446 /* First attribute found for this relation */
3447 Relation rel;
3448
3449 /* Acquire requested lock on relation */
3450 rel = relation_open(pg_depend->objid, lockmode);
3451
3452 /*
3453 * Check to see if rowtype is stored anyplace as a composite-type
3454 * column; if so we have to fail, for now anyway.
3455 */
3456 if (OidIsValid(rel->rd_rel->reltype))
3458 NULL,
3460
3461 /*
3462 * Otherwise, we can ignore relations except those with both
3463 * storage and user-chosen column types.
3464 *
3465 * XXX If an index-only scan could satisfy "col::some_domain" from
3466 * a suitable expression index, this should also check expression
3467 * index columns.
3468 */
3469 if (rel->rd_rel->relkind != RELKIND_RELATION &&
3470 rel->rd_rel->relkind != RELKIND_MATVIEW)
3471 {
3472 relation_close(rel, lockmode);
3473 continue;
3474 }
3475
3476 /* Build the RelToCheck entry with enough space for all atts */
3478 rtc->rel = rel;
3479 rtc->natts = 0;
3482 }
3483
3484 /*
3485 * Confirm column has not been dropped, and is of the expected type.
3486 * This defends against an ALTER DROP COLUMN occurring just before we
3487 * acquired lock ... but if the whole table were dropped, we'd still
3488 * have a problem.
3489 */
3490 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3491 continue;
3492 pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3493 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3494 continue;
3495
3496 /*
3497 * Okay, add column to result. We store the columns in column-number
3498 * order; this is just a hack to improve predictability of regression
3499 * test output ...
3500 */
3502
3503 ptr = rtc->natts++;
3504 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3505 {
3506 rtc->atts[ptr] = rtc->atts[ptr - 1];
3507 ptr--;
3508 }
3509 rtc->atts[ptr] = pg_depend->objsubid;
3510 }
3511
3513
3515
3516 return result;
3517}
3518
3519/*
3520 * checkDomainOwner
3521 *
3522 * Check that the type is actually a domain and that the current user
3523 * has permission to do ALTER DOMAIN on it. Throw an error if not.
3524 */
3525void
3527{
3529
3530 /* Check that this is actually a domain */
3531 if (typTup->typtype != TYPTYPE_DOMAIN)
3532 ereport(ERROR,
3534 errmsg("%s is not a domain",
3535 format_type_be(typTup->oid))));
3536
3537 /* Permission check: must own type */
3540}
3541
3542/*
3543 * domainAddCheckConstraint - code shared between CREATE and ALTER DOMAIN
3544 */
3545static char *
3547 int typMod, Constraint *constr,
3548 const char *domainName, ObjectAddress *constrAddr)
3549{
3550 Node *expr;
3551 char *ccbin;
3552 ParseState *pstate;
3554 Oid ccoid;
3555
3556 Assert(constr->contype == CONSTR_CHECK);
3557
3558 /*
3559 * Assign or validate constraint name
3560 */
3561 if (constr->conname)
3562 {
3564 domainOid,
3565 constr->conname))
3566 ereport(ERROR,
3568 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3569 constr->conname, domainName)));
3570 }
3571 else
3573 NULL,
3574 "check",
3576 NIL);
3577
3578 /*
3579 * Convert the A_EXPR in raw_expr into an EXPR
3580 */
3581 pstate = make_parsestate(NULL);
3582
3583 /*
3584 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3585 * the expression. Note that it will appear to have the type of the base
3586 * type, not the domain. This seems correct since within the check
3587 * expression, we should not assume the input value can be considered a
3588 * member of the domain.
3589 */
3591 domVal->typeId = baseTypeOid;
3592 domVal->typeMod = typMod;
3593 domVal->collation = get_typcollation(baseTypeOid);
3594 domVal->location = -1; /* will be set when/if used */
3595
3597 pstate->p_ref_hook_state = domVal;
3598
3599 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3600
3601 /*
3602 * Make sure it yields a boolean result.
3603 */
3604 expr = coerce_to_boolean(pstate, expr, "CHECK");
3605
3606 /*
3607 * Fix up collation information.
3608 */
3609 assign_expr_collations(pstate, expr);
3610
3611 /*
3612 * Domains don't allow variables (this is probably dead code now that
3613 * add_missing_from is history, but let's be sure).
3614 */
3615 if (pstate->p_rtable != NIL ||
3616 contain_var_clause(expr))
3617 ereport(ERROR,
3619 errmsg("cannot use table references in domain check constraint")));
3620
3621 /*
3622 * Convert to string form for storage.
3623 */
3624 ccbin = nodeToString(expr);
3625
3626 /*
3627 * Store the constraint in pg_constraint
3628 */
3629 ccoid =
3630 CreateConstraintEntry(constr->conname, /* Constraint Name */
3631 domainNamespace, /* namespace */
3632 CONSTRAINT_CHECK, /* Constraint Type */
3633 false, /* Is Deferrable */
3634 false, /* Is Deferred */
3635 true, /* Is Enforced */
3636 !constr->skip_validation, /* Is Validated */
3637 InvalidOid, /* no parent constraint */
3638 InvalidOid, /* not a relation constraint */
3639 NULL,
3640 0,
3641 0,
3642 domainOid, /* domain constraint */
3643 InvalidOid, /* no associated index */
3644 InvalidOid, /* Foreign key fields */
3645 NULL,
3646 NULL,
3647 NULL,
3648 NULL,
3649 0,
3650 ' ',
3651 ' ',
3652 NULL,
3653 0,
3654 ' ',
3655 NULL, /* not an exclusion constraint */
3656 expr, /* Tree form of check constraint */
3657 ccbin, /* Binary form of check constraint */
3658 true, /* is local */
3659 0, /* inhcount */
3660 false, /* connoinherit */
3661 false, /* conperiod */
3662 false); /* is_internal */
3663 if (constrAddr)
3665
3666 /*
3667 * Return the compiled constraint expression so the calling routine can
3668 * perform any additional required tests.
3669 */
3670 return ccbin;
3671}
3672
3673/* Parser pre_columnref_hook for domain CHECK constraint parsing */
3674static Node *
3676{
3677 /*
3678 * Check for a reference to "value", and if that's what it is, replace
3679 * with a CoerceToDomainValue as prepared for us by
3680 * domainAddCheckConstraint. (We handle VALUE as a name, not a keyword, to
3681 * avoid breaking a lot of applications that have used VALUE as a column
3682 * name in the past.)
3683 */
3684 if (list_length(cref->fields) == 1)
3685 {
3686 Node *field1 = (Node *) linitial(cref->fields);
3687 char *colname;
3688
3689 colname = strVal(field1);
3690 if (strcmp(colname, "value") == 0)
3691 {
3693
3694 /* Propagate location knowledge, if any */
3695 domVal->location = cref->location;
3696 return (Node *) domVal;
3697 }
3698 }
3699 return NULL;
3700}
3701
3702/*
3703 * domainAddNotNullConstraint - code shared between CREATE and ALTER DOMAIN
3704 */
3705static void
3707 int typMod, Constraint *constr,
3708 const char *domainName, ObjectAddress *constrAddr)
3709{
3710 Oid ccoid;
3711
3712 Assert(constr->contype == CONSTR_NOTNULL);
3713
3714 /*
3715 * Assign or validate constraint name
3716 */
3717 if (constr->conname)
3718 {
3720 domainOid,
3721 constr->conname))
3722 ereport(ERROR,
3724 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3725 constr->conname, domainName)));
3726 }
3727 else
3729 NULL,
3730 "not_null",
3732 NIL);
3733
3734 /*
3735 * Store the constraint in pg_constraint
3736 */
3737 ccoid =
3738 CreateConstraintEntry(constr->conname, /* Constraint Name */
3739 domainNamespace, /* namespace */
3740 CONSTRAINT_NOTNULL, /* Constraint Type */
3741 false, /* Is Deferrable */
3742 false, /* Is Deferred */
3743 true, /* Is Enforced */
3744 !constr->skip_validation, /* Is Validated */
3745 InvalidOid, /* no parent constraint */
3746 InvalidOid, /* not a relation constraint */
3747 NULL,
3748 0,
3749 0,
3750 domainOid, /* domain constraint */
3751 InvalidOid, /* no associated index */
3752 InvalidOid, /* Foreign key fields */
3753 NULL,
3754 NULL,
3755 NULL,
3756 NULL,
3757 0,
3758 ' ',
3759 ' ',
3760 NULL,
3761 0,
3762 ' ',
3763 NULL, /* not an exclusion constraint */
3764 NULL,
3765 NULL,
3766 true, /* is local */
3767 0, /* inhcount */
3768 false, /* connoinherit */
3769 false, /* conperiod */
3770 false); /* is_internal */
3771
3772 if (constrAddr)
3774}
3775
3776
3777/*
3778 * Execute ALTER TYPE RENAME
3779 */
3782{
3783 List *names = castNode(List, stmt->object);
3784 const char *newTypeName = stmt->newname;
3785 TypeName *typename;
3786 Oid typeOid;
3787 Relation rel;
3788 HeapTuple tup;
3790 ObjectAddress address;
3791
3792 /* Make a TypeName so we can use standard type lookup machinery */
3793 typename = makeTypeNameFromNameList(names);
3794 typeOid = typenameTypeId(NULL, typename);
3795
3796 /* Look up the type in the type table */
3798
3800 if (!HeapTupleIsValid(tup))
3801 elog(ERROR, "cache lookup failed for type %u", typeOid);
3803
3804 /* check permissions on type */
3805 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3807
3808 /* ALTER DOMAIN used on a non-domain? */
3809 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3810 ereport(ERROR,
3812 errmsg("%s is not a domain",
3813 format_type_be(typeOid))));
3814
3815 /*
3816 * If it's a composite type, we need to check that it really is a
3817 * free-standing composite type, and not a table's rowtype. We want people
3818 * to use ALTER TABLE not ALTER TYPE for that case.
3819 */
3820 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3822 ereport(ERROR,
3824 errmsg("%s is a table's row type",
3825 format_type_be(typeOid)),
3826 /* translator: %s is an SQL ALTER command */
3827 errhint("Use %s instead.",
3828 "ALTER TABLE")));
3829
3830 /* don't allow direct alteration of array types, either */
3832 ereport(ERROR,
3834 errmsg("cannot alter array type %s",
3835 format_type_be(typeOid)),
3836 errhint("You can alter type %s, which will alter the array type as well.",
3837 format_type_be(typTup->typelem))));
3838
3839 /* we do allow separate renaming of multirange types, though */
3840
3841 /*
3842 * If type is composite we need to rename associated pg_class entry too.
3843 * RenameRelationInternal will call RenameTypeInternal automatically.
3844 */
3845 if (typTup->typtype == TYPTYPE_COMPOSITE)
3846 RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3847 else
3849 typTup->typnamespace);
3850
3851 ObjectAddressSet(address, TypeRelationId, typeOid);
3852 /* Clean up */
3854
3855 return address;
3856}
3857
3858/*
3859 * Change the owner of a type.
3860 */
3863{
3864 TypeName *typename;
3865 Oid typeOid;
3866 Relation rel;
3867 HeapTuple tup;
3871 ObjectAddress address;
3872
3874
3875 /* Make a TypeName so we can use standard type lookup machinery */
3876 typename = makeTypeNameFromNameList(names);
3877
3878 /* Use LookupTypeName here so that shell types can be processed */
3879 tup = LookupTypeName(NULL, typename, NULL, false);
3880 if (tup == NULL)
3881 ereport(ERROR,
3883 errmsg("type \"%s\" does not exist",
3884 TypeNameToString(typename))));
3885 typeOid = typeTypeId(tup);
3886
3887 /* Copy the syscache entry so we can scribble on it below */
3890 tup = newtup;
3892
3893 /* Don't allow ALTER DOMAIN on a type */
3894 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3895 ereport(ERROR,
3897 errmsg("%s is not a domain",
3898 format_type_be(typeOid))));
3899
3900 /*
3901 * If it's a composite type, we need to check that it really is a
3902 * free-standing composite type, and not a table's rowtype. We want people
3903 * to use ALTER TABLE not ALTER TYPE for that case.
3904 */
3905 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3907 ereport(ERROR,
3909 errmsg("%s is a table's row type",
3910 format_type_be(typeOid)),
3911 /* translator: %s is an SQL ALTER command */
3912 errhint("Use %s instead.",
3913 "ALTER TABLE")));
3914
3915 /* don't allow direct alteration of array types, either */
3917 ereport(ERROR,
3919 errmsg("cannot alter array type %s",
3920 format_type_be(typeOid)),
3921 errhint("You can alter type %s, which will alter the array type as well.",
3922 format_type_be(typTup->typelem))));
3923
3924 /* don't allow direct alteration of multirange types, either */
3925 if (typTup->typtype == TYPTYPE_MULTIRANGE)
3926 {
3928
3929 /* We don't expect get_multirange_range to fail, but cope if so */
3930 ereport(ERROR,
3932 errmsg("cannot alter multirange type %s",
3933 format_type_be(typeOid)),
3935 errhint("You can alter type %s, which will alter the multirange type as well.",
3936 format_type_be(rangetype)) : 0));
3937 }
3938
3939 /*
3940 * If the new owner is the same as the existing owner, consider the
3941 * command to have succeeded. This is for dump restoration purposes.
3942 */
3943 if (typTup->typowner != newOwnerId)
3944 {
3945 /* Superusers can always do it */
3946 if (!superuser())
3947 {
3948 /* Otherwise, must be owner of the existing object */
3951
3952 /* Must be able to become new owner */
3954
3955 /* New owner must have CREATE privilege on namespace */
3957 newOwnerId,
3958 ACL_CREATE);
3959 if (aclresult != ACLCHECK_OK)
3961 get_namespace_name(typTup->typnamespace));
3962 }
3963
3964 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3965 }
3966
3967 ObjectAddressSet(address, TypeRelationId, typeOid);
3968
3969 /* Clean up */
3971
3972 return address;
3973}
3974
3975/*
3976 * AlterTypeOwner_oid - change type owner unconditionally
3977 *
3978 * This function recurses to handle dependent types (arrays and multiranges).
3979 * It invokes any necessary access object hooks. If hasDependEntry is true,
3980 * this function modifies the pg_shdepend entry appropriately (this should be
3981 * passed as false only for table rowtypes and dependent types).
3982 *
3983 * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3984 * OWNED BY. It assumes the caller has done all needed checks.
3985 */
3986void
3988{
3989 Relation rel;
3990 HeapTuple tup;
3992
3994
3996 if (!HeapTupleIsValid(tup))
3997 elog(ERROR, "cache lookup failed for type %u", typeOid);
3999
4000 /*
4001 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
4002 * the pg_class entry properly. That will call back to
4003 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
4004 */
4005 if (typTup->typtype == TYPTYPE_COMPOSITE)
4007 else
4009
4010 /* Update owner dependency reference */
4011 if (hasDependEntry)
4013
4015
4018}
4019
4020/*
4021 * AlterTypeOwnerInternal - bare-bones type owner change.
4022 *
4023 * This routine simply modifies the owner of a pg_type entry, and recurses
4024 * to handle any dependent types.
4025 */
4026void
4028{
4029 Relation rel;
4030 HeapTuple tup;
4035 Acl *newAcl;
4037 bool isNull;
4038
4040
4042 if (!HeapTupleIsValid(tup))
4043 elog(ERROR, "cache lookup failed for type %u", typeOid);
4045
4046 memset(repl_null, false, sizeof(repl_null));
4047 memset(repl_repl, false, sizeof(repl_repl));
4048
4049 repl_repl[Anum_pg_type_typowner - 1] = true;
4051
4054 RelationGetDescr(rel),
4055 &isNull);
4056 /* Null ACLs do not require changes */
4057 if (!isNull)
4058 {
4060 typTup->typowner, newOwnerId);
4061 repl_repl[Anum_pg_type_typacl - 1] = true;
4063 }
4064
4066 repl_repl);
4067
4068 CatalogTupleUpdate(rel, &tup->t_self, tup);
4069
4070 /* If it has an array type, update that too */
4071 if (OidIsValid(typTup->typarray))
4073
4074 /* If it is a range type, update the associated multirange too */
4075 if (typTup->typtype == TYPTYPE_RANGE)
4076 {
4078
4080 ereport(ERROR,
4082 errmsg("could not find multirange type for data type %s",
4083 format_type_be(typeOid))));
4085 }
4086
4087 /* Clean up */
4089}
4090
4091/*
4092 * Execute ALTER TYPE SET SCHEMA
4093 */
4095AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
4096 Oid *oldschema)
4097{
4098 TypeName *typename;
4099 Oid typeOid;
4100 Oid nspOid;
4101 Oid oldNspOid;
4104
4105 /* Make a TypeName so we can use standard type lookup machinery */
4106 typename = makeTypeNameFromNameList(names);
4107 typeOid = typenameTypeId(NULL, typename);
4108
4109 /* Don't allow ALTER DOMAIN on a non-domain type */
4110 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
4111 ereport(ERROR,
4113 errmsg("%s is not a domain",
4114 format_type_be(typeOid))));
4115
4116 /* get schema OID and check its permissions */
4117 nspOid = LookupCreationNamespace(newschema);
4118
4122
4123 if (oldschema)
4125
4127
4128 return myself;
4129}
4130
4131/*
4132 * ALTER TYPE SET SCHEMA, where the caller has already looked up the OIDs
4133 * of the type and the target schema and checked the schema's privileges.
4134 *
4135 * If ignoreDependent is true, we silently ignore dependent types
4136 * (array types and table rowtypes) rather than raising errors.
4137 *
4138 * This entry point is exported for use by AlterObjectNamespace_oid,
4139 * which doesn't want errors when it passes OIDs of dependent types.
4140 *
4141 * Returns the type's old namespace OID, or InvalidOid if we did nothing.
4142 */
4143Oid
4146{
4147 Oid elemOid;
4148
4149 /* check permissions on type */
4150 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4152
4153 /* don't allow direct alteration of array types */
4154 elemOid = get_element_type(typeOid);
4155 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4156 {
4157 if (ignoreDependent)
4158 return InvalidOid;
4159 ereport(ERROR,
4161 errmsg("cannot alter array type %s",
4162 format_type_be(typeOid)),
4163 errhint("You can alter type %s, which will alter the array type as well.",
4165 }
4166
4167 /* and do the work */
4168 return AlterTypeNamespaceInternal(typeOid, nspOid,
4169 false, /* isImplicitArray */
4170 ignoreDependent, /* ignoreDependent */
4171 true, /* errorOnTableType */
4172 objsMoved);
4173}
4174
4175/*
4176 * Move specified type to new namespace.
4177 *
4178 * Caller must have already checked privileges.
4179 *
4180 * The function automatically recurses to process the type's array type,
4181 * if any. isImplicitArray should be true only when doing this internal
4182 * recursion (outside callers must never try to move an array type directly).
4183 *
4184 * If ignoreDependent is true, we silently don't process table types.
4185 *
4186 * If errorOnTableType is true, the function errors out if the type is
4187 * a table type. ALTER TABLE has to be used to move a table to a new
4188 * namespace. (This flag is ignored if ignoreDependent is true.)
4189 *
4190 * We also do nothing if the type is already listed in *objsMoved.
4191 * After a successful move, we add the type to *objsMoved.
4192 *
4193 * Returns the type's old namespace OID, or InvalidOid if we did nothing.
4194 */
4195Oid
4197 bool isImplicitArray,
4198 bool ignoreDependent,
4199 bool errorOnTableType,
4201{
4202 Relation rel;
4203 HeapTuple tup;
4205 Oid oldNspOid;
4206 Oid arrayOid;
4207 bool isCompositeType;
4209
4210 /*
4211 * Make sure we haven't moved this object previously.
4212 */
4214 thisobj.objectId = typeOid;
4215 thisobj.objectSubId = 0;
4216
4218 return InvalidOid;
4219
4221
4223 if (!HeapTupleIsValid(tup))
4224 elog(ERROR, "cache lookup failed for type %u", typeOid);
4226
4227 oldNspOid = typform->typnamespace;
4228 arrayOid = typform->typarray;
4229
4230 /* If the type is already there, we scan skip these next few checks. */
4231 if (oldNspOid != nspOid)
4232 {
4233 /* common checks on switching namespaces */
4235
4236 /* check for duplicate name (more friendly than unique-index failure) */
4238 NameGetDatum(&typform->typname),
4240 ereport(ERROR,
4242 errmsg("type \"%s\" already exists in schema \"%s\"",
4243 NameStr(typform->typname),
4245 }
4246
4247 /* Detect whether type is a composite type (but not a table rowtype) */
4249 (typform->typtype == TYPTYPE_COMPOSITE &&
4251
4252 /* Enforce not-table-type if requested */
4253 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType)
4254 {
4255 if (ignoreDependent)
4256 {
4258 return InvalidOid;
4259 }
4260 if (errorOnTableType)
4261 ereport(ERROR,
4263 errmsg("%s is a table's row type",
4264 format_type_be(typeOid)),
4265 /* translator: %s is an SQL ALTER command */
4266 errhint("Use %s instead.", "ALTER TABLE")));
4267 }
4268
4269 if (oldNspOid != nspOid)
4270 {
4271 /* OK, modify the pg_type row */
4272
4273 /* tup is a copy, so we can scribble directly on it */
4274 typform->typnamespace = nspOid;
4275
4276 CatalogTupleUpdate(rel, &tup->t_self, tup);
4277 }
4278
4279 /*
4280 * Composite types have pg_class entries.
4281 *
4282 * We need to modify the pg_class tuple as well to reflect the change of
4283 * schema.
4284 */
4285 if (isCompositeType)
4286 {
4288
4290
4293 false, objsMoved);
4294
4296
4297 /*
4298 * Check for constraints associated with the composite type (we don't
4299 * currently support this, but probably will someday).
4300 */
4302 nspOid, false, objsMoved);
4303 }
4304 else
4305 {
4306 /* If it's a domain, it might have constraints */
4307 if (typform->typtype == TYPTYPE_DOMAIN)
4309 objsMoved);
4310 }
4311
4312 /*
4313 * Update dependency on schema, if any --- a table rowtype has not got
4314 * one, and neither does an implicit array.
4315 */
4316 if (oldNspOid != nspOid &&
4317 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4321 elog(ERROR, "could not change schema dependency for type \"%s\"",
4322 format_type_be(typeOid));
4323
4325
4327
4329
4331
4332 /* Recursively alter the associated array type, if any */
4333 if (OidIsValid(arrayOid))
4335 true, /* isImplicitArray */
4336 false, /* ignoreDependent */
4337 true, /* errorOnTableType */
4338 objsMoved);
4339
4340 return oldNspOid;
4341}
4342
4343/*
4344 * AlterType
4345 * ALTER TYPE <type> SET (option = ...)
4346 *
4347 * NOTE: the set of changes that can be allowed here is constrained by many
4348 * non-obvious implementation restrictions. Tread carefully when considering
4349 * adding new flexibility.
4350 */
4353{
4354 ObjectAddress address;
4356 TypeName *typename;
4357 HeapTuple tup;
4358 Oid typeOid;
4360 bool requireSuper = false;
4362 ListCell *pl;
4363
4365
4366 /* Make a TypeName so we can use standard type lookup machinery */
4367 typename = makeTypeNameFromNameList(stmt->typeName);
4368 tup = typenameType(NULL, typename, NULL);
4369
4370 typeOid = typeTypeId(tup);
4372
4373 /* Process options */
4374 memset(&atparams, 0, sizeof(atparams));
4375 foreach(pl, stmt->options)
4376 {
4377 DefElem *defel = (DefElem *) lfirst(pl);
4378
4379 if (strcmp(defel->defname, "storage") == 0)
4380 {
4381 char *a = defGetString(defel);
4382
4383 if (pg_strcasecmp(a, "plain") == 0)
4384 atparams.storage = TYPSTORAGE_PLAIN;
4385 else if (pg_strcasecmp(a, "external") == 0)
4386 atparams.storage = TYPSTORAGE_EXTERNAL;
4387 else if (pg_strcasecmp(a, "extended") == 0)
4388 atparams.storage = TYPSTORAGE_EXTENDED;
4389 else if (pg_strcasecmp(a, "main") == 0)
4390 atparams.storage = TYPSTORAGE_MAIN;
4391 else
4392 ereport(ERROR,
4394 errmsg("storage \"%s\" not recognized", a)));
4395
4396 /*
4397 * Validate the storage request. If the type isn't varlena, it
4398 * certainly doesn't support non-PLAIN storage.
4399 */
4400 if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4401 ereport(ERROR,
4403 errmsg("fixed-size types must have storage PLAIN")));
4404
4405 /*
4406 * Switching from PLAIN to non-PLAIN is allowed, but it requires
4407 * superuser, since we can't validate that the type's C functions
4408 * will support it. Switching from non-PLAIN to PLAIN is
4409 * disallowed outright, because it's not practical to ensure that
4410 * no tables have toasted values of the type. Switching among
4411 * different non-PLAIN settings is OK, since it just constitutes a
4412 * change in the strategy requested for columns created in the
4413 * future.
4414 */
4415 if (atparams.storage != TYPSTORAGE_PLAIN &&
4416 typForm->typstorage == TYPSTORAGE_PLAIN)
4417 requireSuper = true;
4418 else if (atparams.storage == TYPSTORAGE_PLAIN &&
4419 typForm->typstorage != TYPSTORAGE_PLAIN)
4420 ereport(ERROR,
4422 errmsg("cannot change type's storage to PLAIN")));
4423
4424 atparams.updateStorage = true;
4425 }
4426 else if (strcmp(defel->defname, "receive") == 0)
4427 {
4428 if (defel->arg != NULL)
4429 atparams.receiveOid =
4431 typeOid);
4432 else
4433 atparams.receiveOid = InvalidOid; /* NONE, remove function */
4434 atparams.updateReceive = true;
4435 /* Replacing an I/O function requires superuser. */
4436 requireSuper = true;
4437 }
4438 else if (strcmp(defel->defname, "send") == 0)
4439 {
4440 if (defel->arg != NULL)
4441 atparams.sendOid =
4443 typeOid);
4444 else
4445 atparams.sendOid = InvalidOid; /* NONE, remove function */
4446 atparams.updateSend = true;
4447 /* Replacing an I/O function requires superuser. */
4448 requireSuper = true;
4449 }
4450 else if (strcmp(defel->defname, "typmod_in") == 0)
4451 {
4452 if (defel->arg != NULL)
4453 atparams.typmodinOid =
4455 else
4456 atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4457 atparams.updateTypmodin = true;
4458 /* Replacing an I/O function requires superuser. */
4459 requireSuper = true;
4460 }
4461 else if (strcmp(defel->defname, "typmod_out") == 0)
4462 {
4463 if (defel->arg != NULL)
4464 atparams.typmodoutOid =
4466 else
4467 atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4468 atparams.updateTypmodout = true;
4469 /* Replacing an I/O function requires superuser. */
4470 requireSuper = true;
4471 }
4472 else if (strcmp(defel->defname, "analyze") == 0)
4473 {
4474 if (defel->arg != NULL)
4475 atparams.analyzeOid =
4477 typeOid);
4478 else
4479 atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4480 atparams.updateAnalyze = true;
4481 /* Replacing an analyze function requires superuser. */
4482 requireSuper = true;
4483 }
4484 else if (strcmp(defel->defname, "subscript") == 0)
4485 {
4486 if (defel->arg != NULL)
4487 atparams.subscriptOid =
4489 typeOid);
4490 else
4491 atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4492 atparams.updateSubscript = true;
4493 /* Replacing a subscript function requires superuser. */
4494 requireSuper = true;
4495 }
4496
4497 /*
4498 * The rest of the options that CREATE accepts cannot be changed.
4499 * Check for them so that we can give a meaningful error message.
4500 */
4501 else if (strcmp(defel->defname, "input") == 0 ||
4502 strcmp(defel->defname, "output") == 0 ||
4503 strcmp(defel->defname, "internallength") == 0 ||
4504 strcmp(defel->defname, "passedbyvalue") == 0 ||
4505 strcmp(defel->defname, "alignment") == 0 ||
4506 strcmp(defel->defname, "like") == 0 ||
4507 strcmp(defel->defname, "category") == 0 ||
4508 strcmp(defel->defname, "preferred") == 0 ||
4509 strcmp(defel->defname, "default") == 0 ||
4510 strcmp(defel->defname, "element") == 0 ||
4511 strcmp(defel->defname, "delimiter") == 0 ||
4512 strcmp(defel->defname, "collatable") == 0)
4513 ereport(ERROR,
4515 errmsg("type attribute \"%s\" cannot be changed",
4516 defel->defname)));
4517 else
4518 ereport(ERROR,
4520 errmsg("type attribute \"%s\" not recognized",
4521 defel->defname)));
4522 }
4523
4524 /*
4525 * Permissions check. Require superuser if we decided the command
4526 * requires that, else must own the type.
4527 */
4528 if (requireSuper)
4529 {
4530 if (!superuser())
4531 ereport(ERROR,
4533 errmsg("must be superuser to alter a type")));
4534 }
4535 else
4536 {
4537 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4539 }
4540
4541 /*
4542 * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4543 * types. It would for example be highly unsafe, not to mention
4544 * pointless, to change the send/receive functions for a composite type.
4545 * Moreover, pg_dump has no support for changing these properties on
4546 * non-base types. We might weaken this someday, but not now.
4547 *
4548 * Note: if you weaken this enough to allow composite types, be sure to
4549 * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4550 */
4551 if (typForm->typtype != TYPTYPE_BASE)
4552 ereport(ERROR,
4554 errmsg("%s is not a base type",
4555 format_type_be(typeOid))));
4556
4557 /*
4558 * For the same reasons, don't allow direct alteration of array types.
4559 */
4561 ereport(ERROR,
4563 errmsg("%s is not a base type",
4564 format_type_be(typeOid))));
4565
4566 /* OK, recursively update this type and any arrays/domains over it */
4567 AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4568
4569 /* Clean up */
4571
4573
4574 ObjectAddressSet(address, TypeRelationId, typeOid);
4575
4576 return address;
4577}
4578
4579/*
4580 * AlterTypeRecurse: one recursion step for AlterType()
4581 *
4582 * Apply the changes specified by "atparams" to the type identified by
4583 * "typeOid", whose existing pg_type tuple is "tup". If necessary,
4584 * recursively update its array type as well. Then search for any domains
4585 * over this type, and recursively apply (most of) the same changes to those
4586 * domains.
4587 *
4588 * We need this because the system generally assumes that a domain inherits
4589 * many properties from its base type. See DefineDomain() above for details
4590 * of what is inherited. Arrays inherit a smaller number of properties,
4591 * but not none.
4592 *
4593 * There's a race condition here, in that some other transaction could
4594 * concurrently add another domain atop this base type; we'd miss updating
4595 * that one. Hence, be wary of allowing ALTER TYPE to change properties for
4596 * which it'd be really fatal for a domain to be out of sync with its base
4597 * type (typlen, for example). In practice, races seem unlikely to be an
4598 * issue for plausible use-cases for ALTER TYPE. If one does happen, it could
4599 * be fixed by re-doing the same ALTER TYPE once all prior transactions have
4600 * committed.
4601 */
4602static void
4606{
4608 bool nulls[Natts_pg_type];
4609 bool replaces[Natts_pg_type];
4611 SysScanDesc scan;
4612 ScanKeyData key[1];
4614
4615 /* Since this function recurses, it could be driven to stack overflow */
4617
4618 /* Update the current type's tuple */
4619 memset(values, 0, sizeof(values));
4620 memset(nulls, 0, sizeof(nulls));
4621 memset(replaces, 0, sizeof(replaces));
4622
4623 if (atparams->updateStorage)
4624 {
4627 }
4628 if (atparams->updateReceive)
4629 {
4632 }
4633 if (atparams->updateSend)
4634 {
4635 replaces[Anum_pg_type_typsend - 1] = true;
4637 }
4638 if (atparams->updateTypmodin)
4639 {
4640 replaces[Anum_pg_type_typmodin - 1] = true;
4642 }
4643 if (atparams->updateTypmodout)
4644 {
4645 replaces[Anum_pg_type_typmodout - 1] = true;
4647 }
4648 if (atparams->updateAnalyze)
4649 {
4652 }
4653 if (atparams->updateSubscript)
4654 {
4657 }
4658
4660 values, nulls, replaces);
4661
4663
4664 /* Rebuild dependencies for this type */
4666 catalog,
4667 NULL, /* don't have defaultExpr handy */
4668 NULL, /* don't have typacl handy */
4669 0, /* we rejected composite types above */
4670 isImplicitArray, /* it might be an array */
4671 isImplicitArray, /* dependent iff it's array */
4672 false, /* don't touch extension membership */
4673 true);
4674
4676
4677 /*
4678 * Arrays inherit their base type's typmodin and typmodout, but none of
4679 * the other properties we're concerned with here. Recurse to the array
4680 * type if needed.
4681 */
4682 if (!isImplicitArray &&
4683 (atparams->updateTypmodin || atparams->updateTypmodout))
4684 {
4685 Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4686
4687 if (OidIsValid(arrtypoid))
4688 {
4691
4694 elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4695
4696 memset(&arrparams, 0, sizeof(arrparams));
4697 arrparams.updateTypmodin = atparams->updateTypmodin;
4698 arrparams.updateTypmodout = atparams->updateTypmodout;
4699 arrparams.typmodinOid = atparams->typmodinOid;
4700 arrparams.typmodoutOid = atparams->typmodoutOid;
4701
4703
4705 }
4706 }
4707
4708 /*
4709 * Now we need to recurse to domains. However, some properties are not
4710 * inherited by domains, so clear the update flags for those.
4711 */
4712 atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4713 atparams->updateTypmodin = false; /* domains don't have typmods */
4714 atparams->updateTypmodout = false;
4715 atparams->updateSubscript = false; /* domains don't have subscriptors */
4716
4717 /* Skip the scan if nothing remains to be done */
4718 if (!(atparams->updateStorage ||
4719 atparams->updateSend ||
4720 atparams->updateAnalyze))
4721 return;
4722
4723 /* Search pg_type for possible domains over this type */
4724 ScanKeyInit(&key[0],
4727 ObjectIdGetDatum(typeOid));
4728
4729 scan = systable_beginscan(catalog, InvalidOid, false,
4730 NULL, 1, key);
4731
4732 while ((domainTup = systable_getnext(scan)) != NULL)
4733 {
4735
4736 /*
4737 * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4738 * check
4739 */
4740 if (domainForm->typtype != TYPTYPE_DOMAIN)
4741 continue;
4742
4744 }
4745
4746 systable_endscan(scan);
4747}
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:3880
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4134
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:875
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:765
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:665
#define ResetExprContext(econtext)
Definition executor.h:659
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:444
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
char * format_type_be(Oid type_oid)
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
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:3343
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:1568
int a
Definition isn.c:73
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_concat(List *list1, const List *list2)
Definition list.c:561
int LOCKMODE
Definition lockdefs.h:26
#define NoLock
Definition lockdefs.h:34
#define AccessExclusiveLock
Definition lockdefs.h:43
#define AccessShareLock
Definition lockdefs.h:36
#define ShareLock
Definition lockdefs.h:40
#define RowExclusiveLock
Definition lockdefs.h:38
Oid get_element_type(Oid typid)
Definition lsyscache.c:3067
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1456
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3836
bool get_typisdefined(Oid typid)
Definition lsyscache.c:2479
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2577
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2309
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3364
char func_volatile(Oid funcid)
Definition lsyscache.c:2086
char * get_func_name(Oid funcid)
Definition lsyscache.c:1914
Oid get_range_multirange(Oid rangeOid)
Definition lsyscache.c:3811
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3389
int16 get_typlen(Oid typid)
Definition lsyscache.c:2503
char get_typtype(Oid typid)
Definition lsyscache.c:2937
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3674
Oid get_array_type(Oid typid)
Definition lsyscache.c:3095
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1961
TypeName * makeTypeNameFromNameList(List *names)
Definition makefuncs.c:531
void pfree(void *pointer)
Definition mcxt.c:1619
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:162
#define copyObject(obj)
Definition nodes.h:230
#define nodeTag(nodeptr)
Definition nodes.h:137
#define makeNode(_type_)
Definition nodes.h:159
#define castNode(_type_, nodeptr)
Definition nodes.h:180
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:51
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:470
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 ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
#define PointerGetDatum(X)
Definition postgres.h:354
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:6099
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:96
#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:133
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:7033
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition tablecmds.c:817
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition tablecmds.c:4334
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:2775
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition typecmds.c:2121
Oid AssignTypeMultirangeOid(void)
Definition typecmds.c:2513
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:4603
static void checkEnumOwner(HeapTuple tup)
Definition typecmds.c:1355
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin)
Definition typecmds.c:3235
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition typecmds.c:2278
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition typecmds.c:2352
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent, ObjectAddresses *objsMoved)
Definition typecmds.c:4144
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:1876
ObjectAddress DefineType(ParseState *pstate, List *names, List *parameters)
Definition typecmds.c:154
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition typecmds.c:2432
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition typecmds.c:2086
ObjectAddress DefineEnum(CreateEnumStmt *stmt)
Definition typecmds.c:1183
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition typecmds.c:2175
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition typecmds.c:3546
ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
Definition typecmds.c:3862
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition typecmds.c:2391
ObjectAddress AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
Definition typecmds.c:2861
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition typecmds.c:4027
ObjectAddress AlterEnum(AlterEnumStmt *stmt)
Definition typecmds.c:1307
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition typecmds.c:2967
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:1795
ObjectAddress AlterDomainValidateConstraint(List *names, const char *constrName)
Definition typecmds.c:3067
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition typecmds.c:2305
static Oid findTypeTypmodoutFunction(List *procname)
Definition typecmds.c:2244
static Oid findTypeTypmodinFunction(List *procname)
Definition typecmds.c:2210
ObjectAddress AlterDomainDefault(List *names, Node *defaultRaw)
Definition typecmds.c:2646
Oid binary_upgrade_next_array_pg_type_oid
Definition typecmds.c:109
ObjectAddress RenameType(RenameStmt *stmt)
Definition typecmds.c:3781
Oid AssignTypeArrayOid(void)
Definition typecmds.c:2480
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition typecmds.c:2023
void checkDomainOwner(HeapTuple tup)
Definition typecmds.c:3526
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition typecmds.c:3987
ObjectAddress AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
Definition typecmds.c:4095
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition typecmds.c:3357
ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist)
Definition typecmds.c:2588
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition typecmds.c:3706
Oid AssignTypeMultirangeArrayOid(void)
Definition typecmds.c:2546
ObjectAddress AlterType(AlterTypeStmt *stmt)
Definition typecmds.c:4352
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition typecmds.c:4196
static void validateDomainNotNullConstraint(Oid domainoid)
Definition typecmds.c:3169
ObjectAddress DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
Definition typecmds.c:1382
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition typecmds.c:3675
#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