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