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