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
1583  * if so 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  NULL, /* prosqlbody */
1779  PROKIND_FUNCTION,
1780  false, /* security_definer */
1781  false, /* leakproof */
1782  false, /* isStrict */
1783  PROVOLATILE_IMMUTABLE, /* volatility */
1784  PROPARALLEL_SAFE, /* parallel safety */
1785  constructorArgTypesVector, /* parameterTypes */
1786  PointerGetDatum(NULL), /* allParameterTypes */
1787  PointerGetDatum(NULL), /* parameterModes */
1788  PointerGetDatum(NULL), /* parameterNames */
1789  NIL, /* parameterDefaults */
1790  PointerGetDatum(NULL), /* trftypes */
1791  PointerGetDatum(NULL), /* proconfig */
1792  InvalidOid, /* prosupport */
1793  1.0, /* procost */
1794  0.0); /* prorows */
1795 
1796  /*
1797  * Make the constructors internally-dependent on the range type so
1798  * that they go away silently when the type is dropped. Note that
1799  * pg_dump depends on this choice to avoid dumping the constructors.
1800  */
1801  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1802  }
1803 }
1804 
1805 /*
1806  * We make a separate multirange constructor for each range type
1807  * so its name can include the base type, like range constructors do.
1808  * If we had an anyrangearray polymorphic type we could use it here,
1809  * but since each type has its own constructor name there's no need.
1810  *
1811  * Sets castFuncOid to the oid of the new constructor that can be used
1812  * to cast from a range to a multirange.
1813  */
1814 static void
1815 makeMultirangeConstructors(const char *name, Oid namespace,
1816  Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid,
1817  Oid *castFuncOid)
1818 {
1819  ObjectAddress myself,
1820  referenced;
1821  oidvector *argtypes;
1822  Datum allParamTypes;
1823  ArrayType *allParameterTypes;
1824  Datum paramModes;
1825  ArrayType *parameterModes;
1826 
1827  referenced.classId = TypeRelationId;
1828  referenced.objectId = multirangeOid;
1829  referenced.objectSubId = 0;
1830 
1831  /* 0-arg constructor - for empty multiranges */
1832  argtypes = buildoidvector(NULL, 0);
1833  myself = ProcedureCreate(name, /* name: same as multirange type */
1834  namespace,
1835  false, /* replace */
1836  false, /* returns set */
1837  multirangeOid, /* return type */
1838  BOOTSTRAP_SUPERUSERID, /* proowner */
1839  INTERNALlanguageId, /* language */
1840  F_FMGR_INTERNAL_VALIDATOR,
1841  "multirange_constructor0", /* prosrc */
1842  NULL, /* probin */
1843  NULL, /* prosqlbody */
1844  PROKIND_FUNCTION,
1845  false, /* security_definer */
1846  false, /* leakproof */
1847  true, /* isStrict */
1848  PROVOLATILE_IMMUTABLE, /* volatility */
1849  PROPARALLEL_SAFE, /* parallel safety */
1850  argtypes, /* parameterTypes */
1851  PointerGetDatum(NULL), /* allParameterTypes */
1852  PointerGetDatum(NULL), /* parameterModes */
1853  PointerGetDatum(NULL), /* parameterNames */
1854  NIL, /* parameterDefaults */
1855  PointerGetDatum(NULL), /* trftypes */
1856  PointerGetDatum(NULL), /* proconfig */
1857  InvalidOid, /* prosupport */
1858  1.0, /* procost */
1859  0.0); /* prorows */
1860 
1861  /*
1862  * Make the constructor internally-dependent on the multirange type so
1863  * that they go away silently when the type is dropped. Note that pg_dump
1864  * depends on this choice to avoid dumping the constructors.
1865  */
1866  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1867  pfree(argtypes);
1868 
1869  /*
1870  * 1-arg constructor - for casts
1871  *
1872  * In theory we shouldn't need both this and the vararg (n-arg)
1873  * constructor, but having a separate 1-arg function lets us define casts
1874  * against it.
1875  */
1876  argtypes = buildoidvector(&rangeOid, 1);
1877  myself = ProcedureCreate(name, /* name: same as multirange type */
1878  namespace,
1879  false, /* replace */
1880  false, /* returns set */
1881  multirangeOid, /* return type */
1882  BOOTSTRAP_SUPERUSERID, /* proowner */
1883  INTERNALlanguageId, /* language */
1884  F_FMGR_INTERNAL_VALIDATOR,
1885  "multirange_constructor1", /* prosrc */
1886  NULL, /* probin */
1887  NULL, /* prosqlbody */
1888  PROKIND_FUNCTION,
1889  false, /* security_definer */
1890  false, /* leakproof */
1891  true, /* isStrict */
1892  PROVOLATILE_IMMUTABLE, /* volatility */
1893  PROPARALLEL_SAFE, /* parallel safety */
1894  argtypes, /* parameterTypes */
1895  PointerGetDatum(NULL), /* allParameterTypes */
1896  PointerGetDatum(NULL), /* parameterModes */
1897  PointerGetDatum(NULL), /* parameterNames */
1898  NIL, /* parameterDefaults */
1899  PointerGetDatum(NULL), /* trftypes */
1900  PointerGetDatum(NULL), /* proconfig */
1901  InvalidOid, /* prosupport */
1902  1.0, /* procost */
1903  0.0); /* prorows */
1904  /* ditto */
1905  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1906  pfree(argtypes);
1907  *castFuncOid = myself.objectId;
1908 
1909  /* n-arg constructor - vararg */
1910  argtypes = buildoidvector(&rangeArrayOid, 1);
1911  allParamTypes = ObjectIdGetDatum(rangeArrayOid);
1912  allParameterTypes = construct_array(&allParamTypes,
1913  1, OIDOID,
1914  sizeof(Oid), true, 'i');
1915  paramModes = CharGetDatum(FUNC_PARAM_VARIADIC);
1916  parameterModes = construct_array(&paramModes, 1, CHAROID,
1917  1, true, 'c');
1918  myself = ProcedureCreate(name, /* name: same as multirange type */
1919  namespace,
1920  false, /* replace */
1921  false, /* returns set */
1922  multirangeOid, /* return type */
1923  BOOTSTRAP_SUPERUSERID, /* proowner */
1924  INTERNALlanguageId, /* language */
1925  F_FMGR_INTERNAL_VALIDATOR,
1926  "multirange_constructor2", /* prosrc */
1927  NULL, /* probin */
1928  NULL, /* prosqlbody */
1929  PROKIND_FUNCTION,
1930  false, /* security_definer */
1931  false, /* leakproof */
1932  true, /* isStrict */
1933  PROVOLATILE_IMMUTABLE, /* volatility */
1934  PROPARALLEL_SAFE, /* parallel safety */
1935  argtypes, /* parameterTypes */
1936  PointerGetDatum(allParameterTypes), /* allParameterTypes */
1937  PointerGetDatum(parameterModes), /* parameterModes */
1938  PointerGetDatum(NULL), /* parameterNames */
1939  NIL, /* parameterDefaults */
1940  PointerGetDatum(NULL), /* trftypes */
1941  PointerGetDatum(NULL), /* proconfig */
1942  InvalidOid, /* prosupport */
1943  1.0, /* procost */
1944  0.0); /* prorows */
1945  /* ditto */
1946  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1947  pfree(argtypes);
1948  pfree(allParameterTypes);
1949  pfree(parameterModes);
1950 }
1951 
1952 /*
1953  * Find suitable I/O and other support functions for a type.
1954  *
1955  * typeOid is the type's OID (which will already exist, if only as a shell
1956  * type).
1957  */
1958 
1959 static Oid
1960 findTypeInputFunction(List *procname, Oid typeOid)
1961 {
1962  Oid argList[3];
1963  Oid procOid;
1964  Oid procOid2;
1965 
1966  /*
1967  * Input functions can take a single argument of type CSTRING, or three
1968  * arguments (string, typioparam OID, typmod). Whine about ambiguity if
1969  * both forms exist.
1970  */
1971  argList[0] = CSTRINGOID;
1972  argList[1] = OIDOID;
1973  argList[2] = INT4OID;
1974 
1975  procOid = LookupFuncName(procname, 1, argList, true);
1976  procOid2 = LookupFuncName(procname, 3, argList, true);
1977  if (OidIsValid(procOid))
1978  {
1979  if (OidIsValid(procOid2))
1980  ereport(ERROR,
1981  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1982  errmsg("type input function %s has multiple matches",
1983  NameListToString(procname))));
1984  }
1985  else
1986  {
1987  procOid = procOid2;
1988  /* If not found, reference the 1-argument signature in error msg */
1989  if (!OidIsValid(procOid))
1990  ereport(ERROR,
1991  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1992  errmsg("function %s does not exist",
1993  func_signature_string(procname, 1, NIL, argList))));
1994  }
1995 
1996  /* Input functions must return the target type. */
1997  if (get_func_rettype(procOid) != typeOid)
1998  ereport(ERROR,
1999  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2000  errmsg("type input function %s must return type %s",
2001  NameListToString(procname), format_type_be(typeOid))));
2002 
2003  /*
2004  * Print warnings if any of the type's I/O functions are marked volatile.
2005  * There is a general assumption that I/O functions are stable or
2006  * immutable; this allows us for example to mark record_in/record_out
2007  * stable rather than volatile. Ideally we would throw errors not just
2008  * warnings here; but since this check is new as of 9.5, and since the
2009  * volatility marking might be just an error-of-omission and not a true
2010  * indication of how the function behaves, we'll let it pass as a warning
2011  * for now.
2012  */
2013  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2014  ereport(WARNING,
2015  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2016  errmsg("type input function %s should not be volatile",
2017  NameListToString(procname))));
2018 
2019  return procOid;
2020 }
2021 
2022 static Oid
2023 findTypeOutputFunction(List *procname, Oid typeOid)
2024 {
2025  Oid argList[1];
2026  Oid procOid;
2027 
2028  /*
2029  * Output functions always take a single argument of the type and return
2030  * cstring.
2031  */
2032  argList[0] = typeOid;
2033 
2034  procOid = LookupFuncName(procname, 1, argList, true);
2035  if (!OidIsValid(procOid))
2036  ereport(ERROR,
2037  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2038  errmsg("function %s does not exist",
2039  func_signature_string(procname, 1, NIL, argList))));
2040 
2041  if (get_func_rettype(procOid) != CSTRINGOID)
2042  ereport(ERROR,
2043  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2044  errmsg("type output function %s must return type %s",
2045  NameListToString(procname), "cstring")));
2046 
2047  /* Just a warning for now, per comments in findTypeInputFunction */
2048  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2049  ereport(WARNING,
2050  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2051  errmsg("type output function %s should not be volatile",
2052  NameListToString(procname))));
2053 
2054  return procOid;
2055 }
2056 
2057 static Oid
2058 findTypeReceiveFunction(List *procname, Oid typeOid)
2059 {
2060  Oid argList[3];
2061  Oid procOid;
2062  Oid procOid2;
2063 
2064  /*
2065  * Receive functions can take a single argument of type INTERNAL, or three
2066  * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2067  * both forms exist.
2068  */
2069  argList[0] = INTERNALOID;
2070  argList[1] = OIDOID;
2071  argList[2] = INT4OID;
2072 
2073  procOid = LookupFuncName(procname, 1, argList, true);
2074  procOid2 = LookupFuncName(procname, 3, argList, true);
2075  if (OidIsValid(procOid))
2076  {
2077  if (OidIsValid(procOid2))
2078  ereport(ERROR,
2079  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
2080  errmsg("type receive function %s has multiple matches",
2081  NameListToString(procname))));
2082  }
2083  else
2084  {
2085  procOid = procOid2;
2086  /* If not found, reference the 1-argument signature in error msg */
2087  if (!OidIsValid(procOid))
2088  ereport(ERROR,
2089  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2090  errmsg("function %s does not exist",
2091  func_signature_string(procname, 1, NIL, argList))));
2092  }
2093 
2094  /* Receive functions must return the target type. */
2095  if (get_func_rettype(procOid) != typeOid)
2096  ereport(ERROR,
2097  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2098  errmsg("type receive function %s must return type %s",
2099  NameListToString(procname), format_type_be(typeOid))));
2100 
2101  /* Just a warning for now, per comments in findTypeInputFunction */
2102  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2103  ereport(WARNING,
2104  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2105  errmsg("type receive function %s should not be volatile",
2106  NameListToString(procname))));
2107 
2108  return procOid;
2109 }
2110 
2111 static Oid
2112 findTypeSendFunction(List *procname, Oid typeOid)
2113 {
2114  Oid argList[1];
2115  Oid procOid;
2116 
2117  /*
2118  * Send functions always take a single argument of the type and return
2119  * bytea.
2120  */
2121  argList[0] = typeOid;
2122 
2123  procOid = LookupFuncName(procname, 1, argList, true);
2124  if (!OidIsValid(procOid))
2125  ereport(ERROR,
2126  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2127  errmsg("function %s does not exist",
2128  func_signature_string(procname, 1, NIL, argList))));
2129 
2130  if (get_func_rettype(procOid) != BYTEAOID)
2131  ereport(ERROR,
2132  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2133  errmsg("type send function %s must return type %s",
2134  NameListToString(procname), "bytea")));
2135 
2136  /* Just a warning for now, per comments in findTypeInputFunction */
2137  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2138  ereport(WARNING,
2139  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2140  errmsg("type send function %s should not be volatile",
2141  NameListToString(procname))));
2142 
2143  return procOid;
2144 }
2145 
2146 static Oid
2148 {
2149  Oid argList[1];
2150  Oid procOid;
2151 
2152  /*
2153  * typmodin functions always take one cstring[] argument and return int4.
2154  */
2155  argList[0] = CSTRINGARRAYOID;
2156 
2157  procOid = LookupFuncName(procname, 1, argList, true);
2158  if (!OidIsValid(procOid))
2159  ereport(ERROR,
2160  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2161  errmsg("function %s does not exist",
2162  func_signature_string(procname, 1, NIL, argList))));
2163 
2164  if (get_func_rettype(procOid) != INT4OID)
2165  ereport(ERROR,
2166  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2167  errmsg("typmod_in function %s must return type %s",
2168  NameListToString(procname), "integer")));
2169 
2170  /* Just a warning for now, per comments in findTypeInputFunction */
2171  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2172  ereport(WARNING,
2173  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2174  errmsg("type modifier input function %s should not be volatile",
2175  NameListToString(procname))));
2176 
2177  return procOid;
2178 }
2179 
2180 static Oid
2182 {
2183  Oid argList[1];
2184  Oid procOid;
2185 
2186  /*
2187  * typmodout functions always take one int4 argument and return cstring.
2188  */
2189  argList[0] = INT4OID;
2190 
2191  procOid = LookupFuncName(procname, 1, argList, true);
2192  if (!OidIsValid(procOid))
2193  ereport(ERROR,
2194  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2195  errmsg("function %s does not exist",
2196  func_signature_string(procname, 1, NIL, argList))));
2197 
2198  if (get_func_rettype(procOid) != CSTRINGOID)
2199  ereport(ERROR,
2200  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2201  errmsg("typmod_out function %s must return type %s",
2202  NameListToString(procname), "cstring")));
2203 
2204  /* Just a warning for now, per comments in findTypeInputFunction */
2205  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2206  ereport(WARNING,
2207  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2208  errmsg("type modifier output function %s should not be volatile",
2209  NameListToString(procname))));
2210 
2211  return procOid;
2212 }
2213 
2214 static Oid
2215 findTypeAnalyzeFunction(List *procname, Oid typeOid)
2216 {
2217  Oid argList[1];
2218  Oid procOid;
2219 
2220  /*
2221  * Analyze functions always take one INTERNAL argument and return bool.
2222  */
2223  argList[0] = INTERNALOID;
2224 
2225  procOid = LookupFuncName(procname, 1, argList, true);
2226  if (!OidIsValid(procOid))
2227  ereport(ERROR,
2228  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2229  errmsg("function %s does not exist",
2230  func_signature_string(procname, 1, NIL, argList))));
2231 
2232  if (get_func_rettype(procOid) != BOOLOID)
2233  ereport(ERROR,
2234  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2235  errmsg("type analyze function %s must return type %s",
2236  NameListToString(procname), "boolean")));
2237 
2238  return procOid;
2239 }
2240 
2241 static Oid
2243 {
2244  Oid argList[1];
2245  Oid procOid;
2246 
2247  /*
2248  * Subscripting support functions always take one INTERNAL argument and
2249  * return INTERNAL. (The argument is not used, but we must have it to
2250  * maintain type safety.)
2251  */
2252  argList[0] = INTERNALOID;
2253 
2254  procOid = LookupFuncName(procname, 1, argList, true);
2255  if (!OidIsValid(procOid))
2256  ereport(ERROR,
2257  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2258  errmsg("function %s does not exist",
2259  func_signature_string(procname, 1, NIL, argList))));
2260 
2261  if (get_func_rettype(procOid) != INTERNALOID)
2262  ereport(ERROR,
2263  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2264  errmsg("type subscripting function %s must return type %s",
2265  NameListToString(procname), "internal")));
2266 
2267  /*
2268  * We disallow array_subscript_handler() from being selected explicitly,
2269  * since that must only be applied to autogenerated array types.
2270  */
2271  if (procOid == F_ARRAY_SUBSCRIPT_HANDLER)
2272  ereport(ERROR,
2273  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2274  errmsg("user-defined types cannot use subscripting function %s",
2275  NameListToString(procname))));
2276 
2277  return procOid;
2278 }
2279 
2280 /*
2281  * Find suitable support functions and opclasses for a range type.
2282  */
2283 
2284 /*
2285  * Find named btree opclass for subtype, or default btree opclass if
2286  * opcname is NIL.
2287  */
2288 static Oid
2289 findRangeSubOpclass(List *opcname, Oid subtype)
2290 {
2291  Oid opcid;
2292  Oid opInputType;
2293 
2294  if (opcname != NIL)
2295  {
2296  opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
2297 
2298  /*
2299  * Verify that the operator class accepts this datatype. Note we will
2300  * accept binary compatibility.
2301  */
2302  opInputType = get_opclass_input_type(opcid);
2303  if (!IsBinaryCoercible(subtype, opInputType))
2304  ereport(ERROR,
2305  (errcode(ERRCODE_DATATYPE_MISMATCH),
2306  errmsg("operator class \"%s\" does not accept data type %s",
2307  NameListToString(opcname),
2308  format_type_be(subtype))));
2309  }
2310  else
2311  {
2312  opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
2313  if (!OidIsValid(opcid))
2314  {
2315  /* We spell the error message identically to ResolveOpClass */
2316  ereport(ERROR,
2317  (errcode(ERRCODE_UNDEFINED_OBJECT),
2318  errmsg("data type %s has no default operator class for access method \"%s\"",
2319  format_type_be(subtype), "btree"),
2320  errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2321  }
2322  }
2323 
2324  return opcid;
2325 }
2326 
2327 static Oid
2329 {
2330  Oid argList[1];
2331  Oid procOid;
2332  AclResult aclresult;
2333 
2334  /*
2335  * Range canonical functions must take and return the range type, and must
2336  * be immutable.
2337  */
2338  argList[0] = typeOid;
2339 
2340  procOid = LookupFuncName(procname, 1, argList, true);
2341 
2342  if (!OidIsValid(procOid))
2343  ereport(ERROR,
2344  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2345  errmsg("function %s does not exist",
2346  func_signature_string(procname, 1, NIL, argList))));
2347 
2348  if (get_func_rettype(procOid) != typeOid)
2349  ereport(ERROR,
2350  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2351  errmsg("range canonical function %s must return range type",
2352  func_signature_string(procname, 1, NIL, argList))));
2353 
2354  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2355  ereport(ERROR,
2356  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2357  errmsg("range canonical function %s must be immutable",
2358  func_signature_string(procname, 1, NIL, argList))));
2359 
2360  /* Also, range type's creator must have permission to call function */
2361  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2362  if (aclresult != ACLCHECK_OK)
2363  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2364 
2365  return procOid;
2366 }
2367 
2368 static Oid
2370 {
2371  Oid argList[2];
2372  Oid procOid;
2373  AclResult aclresult;
2374 
2375  /*
2376  * Range subtype diff functions must take two arguments of the subtype,
2377  * must return float8, and must be immutable.
2378  */
2379  argList[0] = subtype;
2380  argList[1] = subtype;
2381 
2382  procOid = LookupFuncName(procname, 2, argList, true);
2383 
2384  if (!OidIsValid(procOid))
2385  ereport(ERROR,
2386  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2387  errmsg("function %s does not exist",
2388  func_signature_string(procname, 2, NIL, argList))));
2389 
2390  if (get_func_rettype(procOid) != FLOAT8OID)
2391  ereport(ERROR,
2392  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2393  errmsg("range subtype diff function %s must return type %s",
2394  func_signature_string(procname, 2, NIL, argList),
2395  "double precision")));
2396 
2397  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2398  ereport(ERROR,
2399  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2400  errmsg("range subtype diff function %s must be immutable",
2401  func_signature_string(procname, 2, NIL, argList))));
2402 
2403  /* Also, range type's creator must have permission to call function */
2404  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2405  if (aclresult != ACLCHECK_OK)
2406  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2407 
2408  return procOid;
2409 }
2410 
2411 /*
2412  * AssignTypeArrayOid
2413  *
2414  * Pre-assign the type's array OID for use in pg_type.typarray
2415  */
2416 Oid
2418 {
2419  Oid type_array_oid;
2420 
2421  /* Use binary-upgrade override for pg_type.typarray? */
2422  if (IsBinaryUpgrade)
2423  {
2425  ereport(ERROR,
2426  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2427  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2428 
2429  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2431  }
2432  else
2433  {
2434  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2435 
2436  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2437  Anum_pg_type_oid);
2438  table_close(pg_type, AccessShareLock);
2439  }
2440 
2441  return type_array_oid;
2442 }
2443 
2444 /*
2445  * AssignTypeMultirangeOid
2446  *
2447  * Pre-assign the range type's multirange OID for use in pg_type.oid
2448  */
2449 Oid
2451 {
2452  Oid type_multirange_oid;
2453 
2454  /* Use binary-upgrade override for pg_type.oid? */
2455  if (IsBinaryUpgrade)
2456  {
2458  ereport(ERROR,
2459  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2460  errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2461 
2462  type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2464  }
2465  else
2466  {
2467  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2468 
2469  type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2470  Anum_pg_type_oid);
2471  table_close(pg_type, AccessShareLock);
2472  }
2473 
2474  return type_multirange_oid;
2475 }
2476 
2477 /*
2478  * AssignTypeMultirangeArrayOid
2479  *
2480  * Pre-assign the range type's multirange array OID for use in pg_type.typarray
2481  */
2482 Oid
2484 {
2485  Oid type_multirange_array_oid;
2486 
2487  /* Use binary-upgrade override for pg_type.oid? */
2488  if (IsBinaryUpgrade)
2489  {
2491  ereport(ERROR,
2492  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2493  errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2494 
2495  type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2497  }
2498  else
2499  {
2500  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2501 
2502  type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2503  Anum_pg_type_oid);
2504  table_close(pg_type, AccessShareLock);
2505  }
2506 
2507  return type_multirange_array_oid;
2508 }
2509 
2510 
2511 /*-------------------------------------------------------------------
2512  * DefineCompositeType
2513  *
2514  * Create a Composite Type relation.
2515  * `DefineRelation' does all the work, we just provide the correct
2516  * arguments!
2517  *
2518  * If the relation already exists, then 'DefineRelation' will abort
2519  * the xact...
2520  *
2521  * Return type is the new type's object address.
2522  *-------------------------------------------------------------------
2523  */
2525 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2526 {
2527  CreateStmt *createStmt = makeNode(CreateStmt);
2528  Oid old_type_oid;
2529  Oid typeNamespace;
2530  ObjectAddress address;
2531 
2532  /*
2533  * now set the parameters for keys/inheritance etc. All of these are
2534  * uninteresting for composite types...
2535  */
2536  createStmt->relation = typevar;
2537  createStmt->tableElts = coldeflist;
2538  createStmt->inhRelations = NIL;
2539  createStmt->constraints = NIL;
2540  createStmt->options = NIL;
2541  createStmt->oncommit = ONCOMMIT_NOOP;
2542  createStmt->tablespacename = NULL;
2543  createStmt->if_not_exists = false;
2544 
2545  /*
2546  * Check for collision with an existing type name. If there is one and
2547  * it's an autogenerated array, we can rename it out of the way. This
2548  * check is here mainly to get a better error message about a "type"
2549  * instead of below about a "relation".
2550  */
2551  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2552  NoLock, NULL);
2553  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2554  old_type_oid =
2555  GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2556  CStringGetDatum(createStmt->relation->relname),
2557  ObjectIdGetDatum(typeNamespace));
2558  if (OidIsValid(old_type_oid))
2559  {
2560  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2561  ereport(ERROR,
2563  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2564  }
2565 
2566  /*
2567  * Finally create the relation. This also creates the type.
2568  */
2569  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2570  NULL);
2571 
2572  return address;
2573 }
2574 
2575 /*
2576  * AlterDomainDefault
2577  *
2578  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2579  *
2580  * Returns ObjectAddress of the modified domain.
2581  */
2583 AlterDomainDefault(List *names, Node *defaultRaw)
2584 {
2585  TypeName *typename;
2586  Oid domainoid;
2587  HeapTuple tup;
2588  ParseState *pstate;
2589  Relation rel;
2590  char *defaultValue;
2591  Node *defaultExpr = NULL; /* NULL if no default specified */
2592  Datum new_record[Natts_pg_type];
2593  bool new_record_nulls[Natts_pg_type];
2594  bool new_record_repl[Natts_pg_type];
2595  HeapTuple newtuple;
2596  Form_pg_type typTup;
2597  ObjectAddress address;
2598 
2599  /* Make a TypeName so we can use standard type lookup machinery */
2600  typename = makeTypeNameFromNameList(names);
2601  domainoid = typenameTypeId(NULL, typename);
2602 
2603  /* Look up the domain in the type table */
2604  rel = table_open(TypeRelationId, RowExclusiveLock);
2605 
2606  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2607  if (!HeapTupleIsValid(tup))
2608  elog(ERROR, "cache lookup failed for type %u", domainoid);
2609  typTup = (Form_pg_type) GETSTRUCT(tup);
2610 
2611  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2612  checkDomainOwner(tup);
2613 
2614  /* Setup new tuple */
2615  MemSet(new_record, (Datum) 0, sizeof(new_record));
2616  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2617  MemSet(new_record_repl, false, sizeof(new_record_repl));
2618 
2619  /* Store the new default into the tuple */
2620  if (defaultRaw)
2621  {
2622  /* Create a dummy ParseState for transformExpr */
2623  pstate = make_parsestate(NULL);
2624 
2625  /*
2626  * Cook the colDef->raw_expr into an expression. Note: Name is
2627  * strictly for error message
2628  */
2629  defaultExpr = cookDefault(pstate, defaultRaw,
2630  typTup->typbasetype,
2631  typTup->typtypmod,
2632  NameStr(typTup->typname),
2633  0);
2634 
2635  /*
2636  * If the expression is just a NULL constant, we treat the command
2637  * like ALTER ... DROP DEFAULT. (But see note for same test in
2638  * DefineDomain.)
2639  */
2640  if (defaultExpr == NULL ||
2641  (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
2642  {
2643  /* Default is NULL, drop it */
2644  defaultExpr = NULL;
2645  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2646  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2647  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2648  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2649  }
2650  else
2651  {
2652  /*
2653  * Expression must be stored as a nodeToString result, but we also
2654  * require a valid textual representation (mainly to make life
2655  * easier for pg_dump).
2656  */
2657  defaultValue = deparse_expression(defaultExpr,
2658  NIL, false, false);
2659 
2660  /*
2661  * Form an updated tuple with the new default and write it back.
2662  */
2663  new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2664 
2665  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2666  new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2667  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2668  }
2669  }
2670  else
2671  {
2672  /* ALTER ... DROP DEFAULT */
2673  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2674  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2675  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2676  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2677  }
2678 
2679  newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2680  new_record, new_record_nulls,
2681  new_record_repl);
2682 
2683  CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2684 
2685  /* Rebuild dependencies */
2686  GenerateTypeDependencies(newtuple,
2687  rel,
2688  defaultExpr,
2689  NULL, /* don't have typacl handy */
2690  0, /* relation kind is n/a */
2691  false, /* a domain isn't an implicit array */
2692  false, /* nor is it any kind of dependent type */
2693  true); /* We do need to rebuild dependencies */
2694 
2695  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2696 
2697  ObjectAddressSet(address, TypeRelationId, domainoid);
2698 
2699  /* Clean up */
2701  heap_freetuple(newtuple);
2702 
2703  return address;
2704 }
2705 
2706 /*
2707  * AlterDomainNotNull
2708  *
2709  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2710  *
2711  * Returns ObjectAddress of the modified domain.
2712  */
2714 AlterDomainNotNull(List *names, bool notNull)
2715 {
2716  TypeName *typename;
2717  Oid domainoid;
2718  Relation typrel;
2719  HeapTuple tup;
2720  Form_pg_type typTup;
2722 
2723  /* Make a TypeName so we can use standard type lookup machinery */
2724  typename = makeTypeNameFromNameList(names);
2725  domainoid = typenameTypeId(NULL, typename);
2726 
2727  /* Look up the domain in the type table */
2728  typrel = table_open(TypeRelationId, RowExclusiveLock);
2729 
2730  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2731  if (!HeapTupleIsValid(tup))
2732  elog(ERROR, "cache lookup failed for type %u", domainoid);
2733  typTup = (Form_pg_type) GETSTRUCT(tup);
2734 
2735  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2736  checkDomainOwner(tup);
2737 
2738  /* Is the domain already set to the desired constraint? */
2739  if (typTup->typnotnull == notNull)
2740  {
2741  table_close(typrel, RowExclusiveLock);
2742  return address;
2743  }
2744 
2745  /* Adding a NOT NULL constraint requires checking existing columns */
2746  if (notNull)
2747  {
2748  List *rels;
2749  ListCell *rt;
2750 
2751  /* Fetch relation list with attributes based on this domain */
2752  /* ShareLock is sufficient to prevent concurrent data changes */
2753 
2754  rels = get_rels_with_domain(domainoid, ShareLock);
2755 
2756  foreach(rt, rels)
2757  {
2758  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2759  Relation testrel = rtc->rel;
2760  TupleDesc tupdesc = RelationGetDescr(testrel);
2761  TupleTableSlot *slot;
2762  TableScanDesc scan;
2763  Snapshot snapshot;
2764 
2765  /* Scan all tuples in this relation */
2766  snapshot = RegisterSnapshot(GetLatestSnapshot());
2767  scan = table_beginscan(testrel, snapshot, 0, NULL);
2768  slot = table_slot_create(testrel, NULL);
2769  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
2770  {
2771  int i;
2772 
2773  /* Test attributes that are of the domain */
2774  for (i = 0; i < rtc->natts; i++)
2775  {
2776  int attnum = rtc->atts[i];
2777  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2778 
2779  if (slot_attisnull(slot, attnum))
2780  {
2781  /*
2782  * In principle the auxiliary information for this
2783  * error should be errdatatype(), but errtablecol()
2784  * seems considerably more useful in practice. Since
2785  * this code only executes in an ALTER DOMAIN command,
2786  * the client should already know which domain is in
2787  * question.
2788  */
2789  ereport(ERROR,
2790  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2791  errmsg("column \"%s\" of table \"%s\" contains null values",
2792  NameStr(attr->attname),
2793  RelationGetRelationName(testrel)),
2794  errtablecol(testrel, attnum)));
2795  }
2796  }
2797  }
2799  table_endscan(scan);
2800  UnregisterSnapshot(snapshot);
2801 
2802  /* Close each rel after processing, but keep lock */
2803  table_close(testrel, NoLock);
2804  }
2805  }
2806 
2807  /*
2808  * Okay to update pg_type row. We can scribble on typTup because it's a
2809  * copy.
2810  */
2811  typTup->typnotnull = notNull;
2812 
2813  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2814 
2815  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2816 
2817  ObjectAddressSet(address, TypeRelationId, domainoid);
2818 
2819  /* Clean up */
2820  heap_freetuple(tup);
2821  table_close(typrel, RowExclusiveLock);
2822 
2823  return address;
2824 }
2825 
2826 /*
2827  * AlterDomainDropConstraint
2828  *
2829  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2830  *
2831  * Returns ObjectAddress of the modified domain.
2832  */
2834 AlterDomainDropConstraint(List *names, const char *constrName,
2835  DropBehavior behavior, bool missing_ok)
2836 {
2837  TypeName *typename;
2838  Oid domainoid;
2839  HeapTuple tup;
2840  Relation rel;
2841  Relation conrel;
2842  SysScanDesc conscan;
2843  ScanKeyData skey[3];
2844  HeapTuple contup;
2845  bool found = false;
2846  ObjectAddress address;
2847 
2848  /* Make a TypeName so we can use standard type lookup machinery */
2849  typename = makeTypeNameFromNameList(names);
2850  domainoid = typenameTypeId(NULL, typename);
2851 
2852  /* Look up the domain in the type table */
2853  rel = table_open(TypeRelationId, RowExclusiveLock);
2854 
2855  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2856  if (!HeapTupleIsValid(tup))
2857  elog(ERROR, "cache lookup failed for type %u", domainoid);
2858 
2859  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2860  checkDomainOwner(tup);
2861 
2862  /* Grab an appropriate lock on the pg_constraint relation */
2863  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2864 
2865  /* Find and remove the target constraint */
2866  ScanKeyInit(&skey[0],
2867  Anum_pg_constraint_conrelid,
2868  BTEqualStrategyNumber, F_OIDEQ,
2870  ScanKeyInit(&skey[1],
2871  Anum_pg_constraint_contypid,
2872  BTEqualStrategyNumber, F_OIDEQ,
2873  ObjectIdGetDatum(domainoid));
2874  ScanKeyInit(&skey[2],
2875  Anum_pg_constraint_conname,
2876  BTEqualStrategyNumber, F_NAMEEQ,
2877  CStringGetDatum(constrName));
2878 
2879  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2880  NULL, 3, skey);
2881 
2882  /* There can be at most one matching row */
2883  if ((contup = systable_getnext(conscan)) != NULL)
2884  {
2885  ObjectAddress conobj;
2886 
2887  conobj.classId = ConstraintRelationId;
2888  conobj.objectId = ((Form_pg_constraint) GETSTRUCT(contup))->oid;
2889  conobj.objectSubId = 0;
2890 
2891  performDeletion(&conobj, behavior, 0);
2892  found = true;
2893  }
2894 
2895  /* Clean up after the scan */
2896  systable_endscan(conscan);
2897  table_close(conrel, RowExclusiveLock);
2898 
2899  if (!found)
2900  {
2901  if (!missing_ok)
2902  ereport(ERROR,
2903  (errcode(ERRCODE_UNDEFINED_OBJECT),
2904  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2905  constrName, TypeNameToString(typename))));
2906  else
2907  ereport(NOTICE,
2908  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2909  constrName, TypeNameToString(typename))));
2910  }
2911 
2912  /*
2913  * We must send out an sinval message for the domain, to ensure that any
2914  * dependent plans get rebuilt. Since this command doesn't change the
2915  * domain's pg_type row, that won't happen automatically; do it manually.
2916  */
2917  CacheInvalidateHeapTuple(rel, tup, NULL);
2918 
2919  ObjectAddressSet(address, TypeRelationId, domainoid);
2920 
2921  /* Clean up */
2923 
2924  return address;
2925 }
2926 
2927 /*
2928  * AlterDomainAddConstraint
2929  *
2930  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2931  */
2933 AlterDomainAddConstraint(List *names, Node *newConstraint,
2934  ObjectAddress *constrAddr)
2935 {
2936  TypeName *typename;
2937  Oid domainoid;
2938  Relation typrel;
2939  HeapTuple tup;
2940  Form_pg_type typTup;
2941  Constraint *constr;
2942  char *ccbin;
2943  ObjectAddress address;
2944 
2945  /* Make a TypeName so we can use standard type lookup machinery */
2946  typename = makeTypeNameFromNameList(names);
2947  domainoid = typenameTypeId(NULL, typename);
2948 
2949  /* Look up the domain in the type table */
2950  typrel = table_open(TypeRelationId, RowExclusiveLock);
2951 
2952  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2953  if (!HeapTupleIsValid(tup))
2954  elog(ERROR, "cache lookup failed for type %u", domainoid);
2955  typTup = (Form_pg_type) GETSTRUCT(tup);
2956 
2957  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2958  checkDomainOwner(tup);
2959 
2960  if (!IsA(newConstraint, Constraint))
2961  elog(ERROR, "unrecognized node type: %d",
2962  (int) nodeTag(newConstraint));
2963 
2964  constr = (Constraint *) newConstraint;
2965 
2966  switch (constr->contype)
2967  {
2968  case CONSTR_CHECK:
2969  /* processed below */
2970  break;
2971 
2972  case CONSTR_UNIQUE:
2973  ereport(ERROR,
2974  (errcode(ERRCODE_SYNTAX_ERROR),
2975  errmsg("unique constraints not possible for domains")));
2976  break;
2977 
2978  case CONSTR_PRIMARY:
2979  ereport(ERROR,
2980  (errcode(ERRCODE_SYNTAX_ERROR),
2981  errmsg("primary key constraints not possible for domains")));
2982  break;
2983 
2984  case CONSTR_EXCLUSION:
2985  ereport(ERROR,
2986  (errcode(ERRCODE_SYNTAX_ERROR),
2987  errmsg("exclusion constraints not possible for domains")));
2988  break;
2989 
2990  case CONSTR_FOREIGN:
2991  ereport(ERROR,
2992  (errcode(ERRCODE_SYNTAX_ERROR),
2993  errmsg("foreign key constraints not possible for domains")));
2994  break;
2995 
2998  case CONSTR_ATTR_DEFERRED:
2999  case CONSTR_ATTR_IMMEDIATE:
3000  ereport(ERROR,
3001  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3002  errmsg("specifying constraint deferrability not supported for domains")));
3003  break;
3004 
3005  default:
3006  elog(ERROR, "unrecognized constraint subtype: %d",
3007  (int) constr->contype);
3008  break;
3009  }
3010 
3011  /*
3012  * Since all other constraint types throw errors, this must be a check
3013  * constraint. First, process the constraint expression and add an entry
3014  * to pg_constraint.
3015  */
3016 
3017  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
3018  typTup->typbasetype, typTup->typtypmod,
3019  constr, NameStr(typTup->typname), constrAddr);
3020 
3021  /*
3022  * If requested to validate the constraint, test all values stored in the
3023  * attributes based on the domain the constraint is being added to.
3024  */
3025  if (!constr->skip_validation)
3026  validateDomainConstraint(domainoid, ccbin);
3027 
3028  /*
3029  * We must send out an sinval message for the domain, to ensure that any
3030  * dependent plans get rebuilt. Since this command doesn't change the
3031  * domain's pg_type row, that won't happen automatically; do it manually.
3032  */
3033  CacheInvalidateHeapTuple(typrel, tup, NULL);
3034 
3035  ObjectAddressSet(address, TypeRelationId, domainoid);
3036 
3037  /* Clean up */
3038  table_close(typrel, RowExclusiveLock);
3039 
3040  return address;
3041 }
3042 
3043 /*
3044  * AlterDomainValidateConstraint
3045  *
3046  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
3047  */
3049 AlterDomainValidateConstraint(List *names, const char *constrName)
3050 {
3051  TypeName *typename;
3052  Oid domainoid;
3053  Relation typrel;
3054  Relation conrel;
3055  HeapTuple tup;
3056  Form_pg_constraint con;
3057  Form_pg_constraint copy_con;
3058  char *conbin;
3059  SysScanDesc scan;
3060  Datum val;
3061  bool isnull;
3062  HeapTuple tuple;
3063  HeapTuple copyTuple;
3064  ScanKeyData skey[3];
3065  ObjectAddress address;
3066 
3067  /* Make a TypeName so we can use standard type lookup machinery */
3068  typename = makeTypeNameFromNameList(names);
3069  domainoid = typenameTypeId(NULL, typename);
3070 
3071  /* Look up the domain in the type table */
3072  typrel = table_open(TypeRelationId, AccessShareLock);
3073 
3074  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
3075  if (!HeapTupleIsValid(tup))
3076  elog(ERROR, "cache lookup failed for type %u", domainoid);
3077 
3078  /* Check it's a domain and check user has permission for ALTER DOMAIN */
3079  checkDomainOwner(tup);
3080 
3081  /*
3082  * Find and check the target constraint
3083  */
3084  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
3085 
3086  ScanKeyInit(&skey[0],
3087  Anum_pg_constraint_conrelid,
3088  BTEqualStrategyNumber, F_OIDEQ,
3090  ScanKeyInit(&skey[1],
3091  Anum_pg_constraint_contypid,
3092  BTEqualStrategyNumber, F_OIDEQ,
3093  ObjectIdGetDatum(domainoid));
3094  ScanKeyInit(&skey[2],
3095  Anum_pg_constraint_conname,
3096  BTEqualStrategyNumber, F_NAMEEQ,
3097  CStringGetDatum(constrName));
3098 
3100  NULL, 3, skey);
3101 
3102  /* There can be at most one matching row */
3103  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
3104  ereport(ERROR,
3105  (errcode(ERRCODE_UNDEFINED_OBJECT),
3106  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3107  constrName, TypeNameToString(typename))));
3108 
3109  con = (Form_pg_constraint) GETSTRUCT(tuple);
3110  if (con->contype != CONSTRAINT_CHECK)
3111  ereport(ERROR,
3112  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3113  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
3114  constrName, TypeNameToString(typename))));
3115 
3116  val = SysCacheGetAttr(CONSTROID, tuple,
3117  Anum_pg_constraint_conbin,
3118  &isnull);
3119  if (isnull)
3120  elog(ERROR, "null conbin for constraint %u",
3121  con->oid);
3122  conbin = TextDatumGetCString(val);
3123 
3124  validateDomainConstraint(domainoid, conbin);
3125 
3126  /*
3127  * Now update the catalog, while we have the door open.
3128  */
3129  copyTuple = heap_copytuple(tuple);
3130  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
3131  copy_con->convalidated = true;
3132  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
3133 
3134  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
3135 
3136  ObjectAddressSet(address, TypeRelationId, domainoid);
3137 
3138  heap_freetuple(copyTuple);
3139 
3140  systable_endscan(scan);
3141 
3142  table_close(typrel, AccessShareLock);
3143  table_close(conrel, RowExclusiveLock);
3144 
3145  ReleaseSysCache(tup);
3146 
3147  return address;
3148 }
3149 
3150 static void
3151 validateDomainConstraint(Oid domainoid, char *ccbin)
3152 {
3153  Expr *expr = (Expr *) stringToNode(ccbin);
3154  List *rels;
3155  ListCell *rt;
3156  EState *estate;
3157  ExprContext *econtext;
3158  ExprState *exprstate;
3159 
3160  /* Need an EState to run ExecEvalExpr */
3161  estate = CreateExecutorState();
3162  econtext = GetPerTupleExprContext(estate);
3163 
3164  /* build execution state for expr */
3165  exprstate = ExecPrepareExpr(expr, estate);
3166 
3167  /* Fetch relation list with attributes based on this domain */
3168  /* ShareLock is sufficient to prevent concurrent data changes */
3169 
3170  rels = get_rels_with_domain(domainoid, ShareLock);
3171 
3172  foreach(rt, rels)
3173  {
3174  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3175  Relation testrel = rtc->rel;
3176  TupleDesc tupdesc = RelationGetDescr(testrel);
3177  TupleTableSlot *slot;
3178  TableScanDesc scan;
3179  Snapshot snapshot;
3180 
3181  /* Scan all tuples in this relation */
3182  snapshot = RegisterSnapshot(GetLatestSnapshot());
3183  scan = table_beginscan(testrel, snapshot, 0, NULL);
3184  slot = table_slot_create(testrel, NULL);
3185  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3186  {
3187  int i;
3188 
3189  /* Test attributes that are of the domain */
3190  for (i = 0; i < rtc->natts; i++)
3191  {
3192  int attnum = rtc->atts[i];
3193  Datum d;
3194  bool isNull;
3195  Datum conResult;
3196  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3197 
3198  d = slot_getattr(slot, attnum, &isNull);
3199 
3200  econtext->domainValue_datum = d;
3201  econtext->domainValue_isNull = isNull;
3202 
3203  conResult = ExecEvalExprSwitchContext(exprstate,
3204  econtext,
3205  &isNull);
3206 
3207  if (!isNull && !DatumGetBool(conResult))
3208  {
3209  /*
3210  * In principle the auxiliary information for this error
3211  * should be errdomainconstraint(), but errtablecol()
3212  * seems considerably more useful in practice. Since this
3213  * code only executes in an ALTER DOMAIN command, the
3214  * client should already know which domain is in question,
3215  * and which constraint too.
3216  */
3217  ereport(ERROR,
3218  (errcode(ERRCODE_CHECK_VIOLATION),
3219  errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3220  NameStr(attr->attname),
3221  RelationGetRelationName(testrel)),
3222  errtablecol(testrel, attnum)));
3223  }
3224  }
3225 
3226  ResetExprContext(econtext);
3227  }
3229  table_endscan(scan);
3230  UnregisterSnapshot(snapshot);
3231 
3232  /* Hold relation lock till commit (XXX bad for concurrency) */
3233  table_close(testrel, NoLock);
3234  }
3235 
3236  FreeExecutorState(estate);
3237 }
3238 
3239 /*
3240  * get_rels_with_domain
3241  *
3242  * Fetch all relations / attributes which are using the domain
3243  *
3244  * The result is a list of RelToCheck structs, one for each distinct
3245  * relation, each containing one or more attribute numbers that are of
3246  * the domain type. We have opened each rel and acquired the specified lock
3247  * type on it.
3248  *
3249  * We support nested domains by including attributes that are of derived
3250  * domain types. Current callers do not need to distinguish between attributes
3251  * that are of exactly the given domain and those that are of derived domains.
3252  *
3253  * XXX this is completely broken because there is no way to lock the domain
3254  * to prevent columns from being added or dropped while our command runs.
3255  * We can partially protect against column drops by locking relations as we
3256  * come across them, but there is still a race condition (the window between
3257  * seeing a pg_depend entry and acquiring lock on the relation it references).
3258  * Also, holding locks on all these relations simultaneously creates a non-
3259  * trivial risk of deadlock. We can minimize but not eliminate the deadlock
3260  * risk by using the weakest suitable lock (ShareLock for most callers).
3261  *
3262  * XXX the API for this is not sufficient to support checking domain values
3263  * that are inside container types, such as composite types, arrays, or
3264  * ranges. Currently we just error out if a container type containing the
3265  * target domain is stored anywhere.
3266  *
3267  * Generally used for retrieving a list of tests when adding
3268  * new constraints to a domain.
3269  */
3270 static List *
3271 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
3272 {
3273  List *result = NIL;
3274  char *domainTypeName = format_type_be(domainOid);
3275  Relation depRel;
3276  ScanKeyData key[2];
3277  SysScanDesc depScan;
3278  HeapTuple depTup;
3279 
3280  Assert(lockmode != NoLock);
3281 
3282  /* since this function recurses, it could be driven to stack overflow */
3284 
3285  /*
3286  * We scan pg_depend to find those things that depend on the domain. (We
3287  * assume we can ignore refobjsubid for a domain.)
3288  */
3289  depRel = table_open(DependRelationId, AccessShareLock);
3290 
3291  ScanKeyInit(&key[0],
3292  Anum_pg_depend_refclassid,
3293  BTEqualStrategyNumber, F_OIDEQ,
3294  ObjectIdGetDatum(TypeRelationId));
3295  ScanKeyInit(&key[1],
3296  Anum_pg_depend_refobjid,
3297  BTEqualStrategyNumber, F_OIDEQ,
3298  ObjectIdGetDatum(domainOid));
3299 
3300  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3301  NULL, 2, key);
3302 
3303  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
3304  {
3305  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
3306  RelToCheck *rtc = NULL;
3307  ListCell *rellist;
3308  Form_pg_attribute pg_att;
3309  int ptr;
3310 
3311  /* Check for directly dependent types */
3312  if (pg_depend->classid == TypeRelationId)
3313  {
3314  if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3315  {
3316  /*
3317  * This is a sub-domain, so recursively add dependent columns
3318  * to the output list. This is a bit inefficient since we may
3319  * fail to combine RelToCheck entries when attributes of the
3320  * same rel have different derived domain types, but it's
3321  * probably not worth improving.
3322  */
3323  result = list_concat(result,
3324  get_rels_with_domain(pg_depend->objid,
3325  lockmode));
3326  }
3327  else
3328  {
3329  /*
3330  * Otherwise, it is some container type using the domain, so
3331  * fail if there are any columns of this type.
3332  */
3333  find_composite_type_dependencies(pg_depend->objid,
3334  NULL,
3335  domainTypeName);
3336  }
3337  continue;
3338  }
3339 
3340  /* Else, ignore dependees that aren't user columns of relations */
3341  /* (we assume system columns are never of domain types) */
3342  if (pg_depend->classid != RelationRelationId ||
3343  pg_depend->objsubid <= 0)
3344  continue;
3345 
3346  /* See if we already have an entry for this relation */
3347  foreach(rellist, result)
3348  {
3349  RelToCheck *rt = (RelToCheck *) lfirst(rellist);
3350 
3351  if (RelationGetRelid(rt->rel) == pg_depend->objid)
3352  {
3353  rtc = rt;
3354  break;
3355  }
3356  }
3357 
3358  if (rtc == NULL)
3359  {
3360  /* First attribute found for this relation */
3361  Relation rel;
3362 
3363  /* Acquire requested lock on relation */
3364  rel = relation_open(pg_depend->objid, lockmode);
3365 
3366  /*
3367  * Check to see if rowtype is stored anyplace as a composite-type
3368  * column; if so we have to fail, for now anyway.
3369  */
3370  if (OidIsValid(rel->rd_rel->reltype))
3372  NULL,
3373  domainTypeName);
3374 
3375  /*
3376  * Otherwise, we can ignore relations except those with both
3377  * storage and user-chosen column types.
3378  *
3379  * XXX If an index-only scan could satisfy "col::some_domain" from
3380  * a suitable expression index, this should also check expression
3381  * index columns.
3382  */
3383  if (rel->rd_rel->relkind != RELKIND_RELATION &&
3384  rel->rd_rel->relkind != RELKIND_MATVIEW)
3385  {
3386  relation_close(rel, lockmode);
3387  continue;
3388  }
3389 
3390  /* Build the RelToCheck entry with enough space for all atts */
3391  rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
3392  rtc->rel = rel;
3393  rtc->natts = 0;
3394  rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
3395  result = lappend(result, rtc);
3396  }
3397 
3398  /*
3399  * Confirm column has not been dropped, and is of the expected type.
3400  * This defends against an ALTER DROP COLUMN occurring just before we
3401  * acquired lock ... but if the whole table were dropped, we'd still
3402  * have a problem.
3403  */
3404  if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3405  continue;
3406  pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3407  if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3408  continue;
3409 
3410  /*
3411  * Okay, add column to result. We store the columns in column-number
3412  * order; this is just a hack to improve predictability of regression
3413  * test output ...
3414  */
3416 
3417  ptr = rtc->natts++;
3418  while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3419  {
3420  rtc->atts[ptr] = rtc->atts[ptr - 1];
3421  ptr--;
3422  }
3423  rtc->atts[ptr] = pg_depend->objsubid;
3424  }
3425 
3426  systable_endscan(depScan);
3427 
3429 
3430  return result;
3431 }
3432 
3433 /*
3434  * checkDomainOwner
3435  *
3436  * Check that the type is actually a domain and that the current user
3437  * has permission to do ALTER DOMAIN on it. Throw an error if not.
3438  */
3439 void
3441 {
3442  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3443 
3444  /* Check that this is actually a domain */
3445  if (typTup->typtype != TYPTYPE_DOMAIN)
3446  ereport(ERROR,
3447  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3448  errmsg("%s is not a domain",
3449  format_type_be(typTup->oid))));
3450 
3451  /* Permission check: must own type */
3452  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
3454 }
3455 
3456 /*
3457  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
3458  */
3459 static char *
3460 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3461  int typMod, Constraint *constr,
3462  const char *domainName, ObjectAddress *constrAddr)
3463 {
3464  Node *expr;
3465  char *ccbin;
3466  ParseState *pstate;
3467  CoerceToDomainValue *domVal;
3468  Oid ccoid;
3469 
3470  /*
3471  * Assign or validate constraint name
3472  */
3473  if (constr->conname)
3474  {
3476  domainOid,
3477  constr->conname))
3478  ereport(ERROR,
3480  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3481  constr->conname, domainName)));
3482  }
3483  else
3484  constr->conname = ChooseConstraintName(domainName,
3485  NULL,
3486  "check",
3487  domainNamespace,
3488  NIL);
3489 
3490  /*
3491  * Convert the A_EXPR in raw_expr into an EXPR
3492  */
3493  pstate = make_parsestate(NULL);
3494 
3495  /*
3496  * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3497  * the expression. Note that it will appear to have the type of the base
3498  * type, not the domain. This seems correct since within the check
3499  * expression, we should not assume the input value can be considered a
3500  * member of the domain.
3501  */
3502  domVal = makeNode(CoerceToDomainValue);
3503  domVal->typeId = baseTypeOid;
3504  domVal->typeMod = typMod;
3505  domVal->collation = get_typcollation(baseTypeOid);
3506  domVal->location = -1; /* will be set when/if used */
3507 
3509  pstate->p_ref_hook_state = (void *) domVal;
3510 
3511  expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3512 
3513  /*
3514  * Make sure it yields a boolean result.
3515  */
3516  expr = coerce_to_boolean(pstate, expr, "CHECK");
3517 
3518  /*
3519  * Fix up collation information.
3520  */
3521  assign_expr_collations(pstate, expr);
3522 
3523  /*
3524  * Domains don't allow variables (this is probably dead code now that
3525  * add_missing_from is history, but let's be sure).
3526  */
3527  if (list_length(pstate->p_rtable) != 0 ||
3528  contain_var_clause(expr))
3529  ereport(ERROR,
3530  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3531  errmsg("cannot use table references in domain check constraint")));
3532 
3533  /*
3534  * Convert to string form for storage.
3535  */
3536  ccbin = nodeToString(expr);
3537 
3538  /*
3539  * Store the constraint in pg_constraint
3540  */
3541  ccoid =
3542  CreateConstraintEntry(constr->conname, /* Constraint Name */
3543  domainNamespace, /* namespace */
3544  CONSTRAINT_CHECK, /* Constraint Type */
3545  false, /* Is Deferrable */
3546  false, /* Is Deferred */
3547  !constr->skip_validation, /* Is Validated */
3548  InvalidOid, /* no parent constraint */
3549  InvalidOid, /* not a relation constraint */
3550  NULL,
3551  0,
3552  0,
3553  domainOid, /* domain constraint */
3554  InvalidOid, /* no associated index */
3555  InvalidOid, /* Foreign key fields */
3556  NULL,
3557  NULL,
3558  NULL,
3559  NULL,
3560  0,
3561  ' ',
3562  ' ',
3563  ' ',
3564  NULL, /* not an exclusion constraint */
3565  expr, /* Tree form of check constraint */
3566  ccbin, /* Binary form of check constraint */
3567  true, /* is local */
3568  0, /* inhcount */
3569  false, /* connoinherit */
3570  false); /* is_internal */
3571  if (constrAddr)
3572  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3573 
3574  /*
3575  * Return the compiled constraint expression so the calling routine can
3576  * perform any additional required tests.
3577  */
3578  return ccbin;
3579 }
3580 
3581 /* Parser pre_columnref_hook for domain CHECK constraint parsing */
3582 static Node *
3584 {
3585  /*
3586  * Check for a reference to "value", and if that's what it is, replace
3587  * with a CoerceToDomainValue as prepared for us by domainAddConstraint.
3588  * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of
3589  * applications that have used VALUE as a column name in the past.)
3590  */
3591  if (list_length(cref->fields) == 1)
3592  {
3593  Node *field1 = (Node *) linitial(cref->fields);
3594  char *colname;
3595 
3596  Assert(IsA(field1, String));
3597  colname = strVal(field1);
3598  if (strcmp(colname, "value") == 0)
3599  {
3600  CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
3601 
3602  /* Propagate location knowledge, if any */
3603  domVal->location = cref->location;
3604  return (Node *) domVal;
3605  }
3606  }
3607  return NULL;
3608 }
3609 
3610 
3611 /*
3612  * Execute ALTER TYPE RENAME
3613  */
3616 {
3617  List *names = castNode(List, stmt->object);
3618  const char *newTypeName = stmt->newname;
3619  TypeName *typename;
3620  Oid typeOid;
3621  Relation rel;
3622  HeapTuple tup;
3623  Form_pg_type typTup;
3624  ObjectAddress address;
3625 
3626  /* Make a TypeName so we can use standard type lookup machinery */
3627  typename = makeTypeNameFromNameList(names);
3628  typeOid = typenameTypeId(NULL, typename);
3629 
3630  /* Look up the type in the type table */
3631  rel = table_open(TypeRelationId, RowExclusiveLock);
3632 
3633  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3634  if (!HeapTupleIsValid(tup))
3635  elog(ERROR, "cache lookup failed for type %u", typeOid);
3636  typTup = (Form_pg_type) GETSTRUCT(tup);
3637 
3638  /* check permissions on type */
3639  if (!pg_type_ownercheck(typeOid, GetUserId()))
3641 
3642  /* ALTER DOMAIN used on a non-domain? */
3643  if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3644  ereport(ERROR,
3645  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3646  errmsg("%s is not a domain",
3647  format_type_be(typeOid))));
3648 
3649  /*
3650  * If it's a composite type, we need to check that it really is a
3651  * free-standing composite type, and not a table's rowtype. We want people
3652  * to use ALTER TABLE not ALTER TYPE for that case.
3653  */
3654  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3655  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3656  ereport(ERROR,
3657  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3658  errmsg("%s is a table's row type",
3659  format_type_be(typeOid)),
3660  errhint("Use ALTER TABLE instead.")));
3661 
3662  /* don't allow direct alteration of array types, either */
3663  if (IsTrueArrayType(typTup))
3664  ereport(ERROR,
3665  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3666  errmsg("cannot alter array type %s",
3667  format_type_be(typeOid)),
3668  errhint("You can alter type %s, which will alter the array type as well.",
3669  format_type_be(typTup->typelem))));
3670 
3671  /*
3672  * If type is composite we need to rename associated pg_class entry too.
3673  * RenameRelationInternal will call RenameTypeInternal automatically.
3674  */
3675  if (typTup->typtype == TYPTYPE_COMPOSITE)
3676  RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3677  else
3678  RenameTypeInternal(typeOid, newTypeName,
3679  typTup->typnamespace);
3680 
3681  ObjectAddressSet(address, TypeRelationId, typeOid);
3682  /* Clean up */
3684 
3685  return address;
3686 }
3687 
3688 /*
3689  * Change the owner of a type.
3690  */
3692 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3693 {
3694  TypeName *typename;
3695  Oid typeOid;
3696  Relation rel;
3697  HeapTuple tup;
3698  HeapTuple newtup;
3699  Form_pg_type typTup;
3700  AclResult aclresult;
3701  ObjectAddress address;
3702 
3703  rel = table_open(TypeRelationId, RowExclusiveLock);
3704 
3705  /* Make a TypeName so we can use standard type lookup machinery */
3706  typename = makeTypeNameFromNameList(names);
3707 
3708  /* Use LookupTypeName here so that shell types can be processed */
3709  tup = LookupTypeName(NULL, typename, NULL, false);
3710  if (tup == NULL)
3711  ereport(ERROR,
3712  (errcode(ERRCODE_UNDEFINED_OBJECT),
3713  errmsg("type \"%s\" does not exist",
3714  TypeNameToString(typename))));
3715  typeOid = typeTypeId(tup);
3716 
3717  /* Copy the syscache entry so we can scribble on it below */
3718  newtup = heap_copytuple(tup);
3719  ReleaseSysCache(tup);
3720  tup = newtup;
3721  typTup = (Form_pg_type) GETSTRUCT(tup);
3722 
3723  /* Don't allow ALTER DOMAIN on a type */
3724  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3725  ereport(ERROR,
3726  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3727  errmsg("%s is not a domain",
3728  format_type_be(typeOid))));
3729 
3730  /*
3731  * If it's a composite type, we need to check that it really is a
3732  * free-standing composite type, and not a table's rowtype. We want people
3733  * to use ALTER TABLE not ALTER TYPE for that case.
3734  */
3735  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3736  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3737  ereport(ERROR,
3738  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3739  errmsg("%s is a table's row type",
3740  format_type_be(typeOid)),
3741  errhint("Use ALTER TABLE instead.")));
3742 
3743  /* don't allow direct alteration of array types, either */
3744  if (IsTrueArrayType(typTup))
3745  ereport(ERROR,
3746  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3747  errmsg("cannot alter array type %s",
3748  format_type_be(typeOid)),
3749  errhint("You can alter type %s, which will alter the array type as well.",
3750  format_type_be(typTup->typelem))));
3751 
3752  /*
3753  * If the new owner is the same as the existing owner, consider the
3754  * command to have succeeded. This is for dump restoration purposes.
3755  */
3756  if (typTup->typowner != newOwnerId)
3757  {
3758  /* Superusers can always do it */
3759  if (!superuser())
3760  {
3761  /* Otherwise, must be owner of the existing object */
3762  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
3764 
3765  /* Must be able to become new owner */
3766  check_is_member_of_role(GetUserId(), newOwnerId);
3767 
3768  /* New owner must have CREATE privilege on namespace */
3769  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3770  newOwnerId,
3771  ACL_CREATE);
3772  if (aclresult != ACLCHECK_OK)
3773  aclcheck_error(aclresult, OBJECT_SCHEMA,
3774  get_namespace_name(typTup->typnamespace));
3775  }
3776 
3777  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3778  }
3779 
3780  ObjectAddressSet(address, TypeRelationId, typeOid);
3781 
3782  /* Clean up */
3784 
3785  return address;
3786 }
3787 
3788 /*
3789  * AlterTypeOwner_oid - change type owner unconditionally
3790  *
3791  * This function recurses to handle a pg_class entry, if necessary. It
3792  * invokes any necessary access object hooks. If hasDependEntry is true, this
3793  * function modifies the pg_shdepend entry appropriately (this should be
3794  * passed as false only for table rowtypes and array types).
3795  *
3796  * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3797  * OWNED BY. It assumes the caller has done all needed check.
3798  */
3799 void
3800 AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3801 {
3802  Relation rel;
3803  HeapTuple tup;
3804  Form_pg_type typTup;
3805 
3806  rel = table_open(TypeRelationId, RowExclusiveLock);
3807 
3808  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3809  if (!HeapTupleIsValid(tup))
3810  elog(ERROR, "cache lookup failed for type %u", typeOid);
3811  typTup = (Form_pg_type) GETSTRUCT(tup);
3812 
3813  /*
3814  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3815  * the pg_class entry properly. That will call back to
3816  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3817  */
3818  if (typTup->typtype == TYPTYPE_COMPOSITE)
3819  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3820  else
3821  AlterTypeOwnerInternal(typeOid, newOwnerId);
3822 
3823  /* Update owner dependency reference */
3824  if (hasDependEntry)
3825  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3826 
3827  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3828 
3829  ReleaseSysCache(tup);
3831 }
3832 
3833 /*
3834  * AlterTypeOwnerInternal - bare-bones type owner change.
3835  *
3836  * This routine simply modifies the owner of a pg_type entry, and recurses
3837  * to handle a possible array type.
3838  */
3839 void
3840 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
3841 {
3842  Relation rel;
3843  HeapTuple tup;
3844  Form_pg_type typTup;
3845  Datum repl_val[Natts_pg_type];
3846  bool repl_null[Natts_pg_type];
3847  bool repl_repl[Natts_pg_type];
3848  Acl *newAcl;
3849  Datum aclDatum;
3850  bool isNull;
3851 
3852  rel = table_open(TypeRelationId, RowExclusiveLock);
3853 
3854  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3855  if (!HeapTupleIsValid(tup))
3856  elog(ERROR, "cache lookup failed for type %u", typeOid);
3857  typTup = (Form_pg_type) GETSTRUCT(tup);
3858 
3859  memset(repl_null, false, sizeof(repl_null));
3860  memset(repl_repl, false, sizeof(repl_repl));
3861 
3862  repl_repl[Anum_pg_type_typowner - 1] = true;
3863  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3864 
3865  aclDatum = heap_getattr(tup,
3866  Anum_pg_type_typacl,
3867  RelationGetDescr(rel),
3868  &isNull);
3869  /* Null ACLs do not require changes */
3870  if (!isNull)
3871  {
3872  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3873  typTup->typowner, newOwnerId);
3874  repl_repl[Anum_pg_type_typacl - 1] = true;
3875  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3876  }
3877 
3878  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3879  repl_repl);
3880 
3881  CatalogTupleUpdate(rel, &tup->t_self, tup);
3882 
3883  /* If it has an array type, update that too */
3884  if (OidIsValid(typTup->typarray))
3885  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3886 
3887  /* Clean up */
3889 }
3890 
3891 /*
3892  * Execute ALTER TYPE SET SCHEMA
3893  */
3895 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
3896  Oid *oldschema)
3897 {
3898  TypeName *typename;
3899  Oid typeOid;
3900  Oid nspOid;
3901  Oid oldNspOid;
3902  ObjectAddresses *objsMoved;
3903  ObjectAddress myself;
3904 
3905  /* Make a TypeName so we can use standard type lookup machinery */
3906  typename = makeTypeNameFromNameList(names);
3907  typeOid = typenameTypeId(NULL, typename);
3908 
3909  /* Don't allow ALTER DOMAIN on a type */
3910  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3911  ereport(ERROR,
3912  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3913  errmsg("%s is not a domain",
3914  format_type_be(typeOid))));
3915 
3916  /* get schema OID and check its permissions */
3917  nspOid = LookupCreationNamespace(newschema);
3918 
3919  objsMoved = new_object_addresses();
3920  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3921  free_object_addresses(objsMoved);
3922 
3923  if (oldschema)
3924  *oldschema = oldNspOid;
3925 
3926  ObjectAddressSet(myself, TypeRelationId, typeOid);
3927 
3928  return myself;
3929 }
3930 
3931 Oid
3932 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3933 {
3934  Oid elemOid;
3935 
3936  /* check permissions on type */
3937  if (!pg_type_ownercheck(typeOid, GetUserId()))
3939 
3940  /* don't allow direct alteration of array types */
3941  elemOid = get_element_type(typeOid);
3942  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3943  ereport(ERROR,
3944  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3945  errmsg("cannot alter array type %s",
3946  format_type_be(typeOid)),
3947  errhint("You can alter type %s, which will alter the array type as well.",
3948  format_type_be(elemOid))));
3949 
3950  /* and do the work */
3951  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3952 }
3953 
3954 /*
3955  * Move specified type to new namespace.
3956  *
3957  * Caller must have already checked privileges.
3958  *
3959  * The function automatically recurses to process the type's array type,
3960  * if any. isImplicitArray should be true only when doing this internal
3961  * recursion (outside callers must never try to move an array type directly).
3962  *
3963  * If errorOnTableType is true, the function errors out if the type is
3964  * a table type. ALTER TABLE has to be used to move a table to a new
3965  * namespace.
3966  *
3967  * Returns the type's old namespace OID.
3968  */
3969 Oid
3971  bool isImplicitArray,
3972  bool errorOnTableType,
3973  ObjectAddresses *objsMoved)
3974 {
3975  Relation rel;
3976  HeapTuple tup;
3977  Form_pg_type typform;
3978  Oid oldNspOid;
3979  Oid arrayOid;
3980  bool isCompositeType;
3981  ObjectAddress thisobj;
3982 
3983  /*
3984  * Make sure we haven't moved this object previously.
3985  */
3986  thisobj.classId = TypeRelationId;
3987  thisobj.objectId = typeOid;
3988  thisobj.objectSubId = 0;
3989 
3990  if (object_address_present(&thisobj, objsMoved))
3991  return InvalidOid;
3992 
3993  rel = table_open(TypeRelationId, RowExclusiveLock);
3994 
3995  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3996  if (!HeapTupleIsValid(tup))
3997  elog(ERROR, "cache lookup failed for type %u", typeOid);
3998  typform = (Form_pg_type) GETSTRUCT(tup);
3999 
4000  oldNspOid = typform->typnamespace;
4001  arrayOid = typform->typarray;
4002 
4003  /* If the type is already there, we scan skip these next few checks. */
4004  if (oldNspOid != nspOid)
4005  {
4006  /* common checks on switching namespaces */
4007  CheckSetNamespace(oldNspOid, nspOid);
4008 
4009  /* check for duplicate name (more friendly than unique-index failure) */
4011  NameGetDatum(&typform->typname),
4012  ObjectIdGetDatum(nspOid)))
4013  ereport(ERROR,
4015  errmsg("type \"%s\" already exists in schema \"%s\"",
4016  NameStr(typform->typname),
4017  get_namespace_name(nspOid))));
4018  }
4019 
4020  /* Detect whether type is a composite type (but not a table rowtype) */
4021  isCompositeType =
4022  (typform->typtype == TYPTYPE_COMPOSITE &&
4023  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
4024 
4025  /* Enforce not-table-type if requested */
4026  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
4027  errorOnTableType)
4028  ereport(ERROR,
4029  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4030  errmsg("%s is a table's row type",
4031  format_type_be(typeOid)),
4032  errhint("Use ALTER TABLE instead.")));
4033 
4034  if (oldNspOid != nspOid)
4035  {
4036  /* OK, modify the pg_type row */
4037 
4038  /* tup is a copy, so we can scribble directly on it */
4039  typform->typnamespace = nspOid;
4040 
4041  CatalogTupleUpdate(rel, &tup->t_self, tup);
4042  }
4043 
4044  /*
4045  * Composite types have pg_class entries.
4046  *
4047  * We need to modify the pg_class tuple as well to reflect the change of
4048  * schema.
4049  */
4050  if (isCompositeType)
4051  {
4052  Relation classRel;
4053 
4054  classRel = table_open(RelationRelationId, RowExclusiveLock);
4055 
4056  AlterRelationNamespaceInternal(classRel, typform->typrelid,
4057  oldNspOid, nspOid,
4058  false, objsMoved);
4059 
4060  table_close(classRel, RowExclusiveLock);
4061 
4062  /*
4063  * Check for constraints associated with the composite type (we don't
4064  * currently support this, but probably will someday).
4065  */
4066  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
4067  nspOid, false, objsMoved);
4068  }
4069  else
4070  {
4071  /* If it's a domain, it might have constraints */
4072  if (typform->typtype == TYPTYPE_DOMAIN)
4073  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
4074  objsMoved);
4075  }
4076 
4077  /*
4078  * Update dependency on schema, if any --- a table rowtype has not got
4079  * one, and neither does an implicit array.
4080  */
4081  if (oldNspOid != nspOid &&
4082  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4083  !isImplicitArray)
4084  if (changeDependencyFor(TypeRelationId, typeOid,
4085  NamespaceRelationId, oldNspOid, nspOid) != 1)
4086  elog(ERROR, "failed to change schema dependency for type %s",
4087  format_type_be(typeOid));
4088 
4089  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4090 
4091  heap_freetuple(tup);
4092 
4094 
4095  add_exact_object_address(&thisobj, objsMoved);
4096 
4097  /* Recursively alter the associated array type, if any */
4098  if (OidIsValid(arrayOid))
4099  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
4100 
4101  return oldNspOid;
4102 }
4103 
4104 /*
4105  * AlterType
4106  * ALTER TYPE <type> SET (option = ...)
4107  *
4108  * NOTE: the set of changes that can be allowed here is constrained by many
4109  * non-obvious implementation restrictions. Tread carefully when considering
4110  * adding new flexibility.
4111  */
4114 {
4115  ObjectAddress address;
4116  Relation catalog;
4117  TypeName *typename;
4118  HeapTuple tup;
4119  Oid typeOid;
4120  Form_pg_type typForm;
4121  bool requireSuper = false;
4122  AlterTypeRecurseParams atparams;
4123  ListCell *pl;
4124 
4125  catalog = table_open(TypeRelationId, RowExclusiveLock);
4126 
4127  /* Make a TypeName so we can use standard type lookup machinery */
4128  typename = makeTypeNameFromNameList(stmt->typeName);
4129  tup = typenameType(NULL, typename, NULL);
4130 
4131  typeOid = typeTypeId(tup);
4132  typForm = (Form_pg_type) GETSTRUCT(tup);
4133 
4134  /* Process options */
4135  memset(&atparams, 0, sizeof(atparams));
4136  foreach(pl, stmt->options)
4137  {
4138  DefElem *defel = (DefElem *) lfirst(pl);
4139 
4140  if (strcmp(defel->defname, "storage") == 0)
4141  {
4142  char *a = defGetString(defel);
4143 
4144  if (pg_strcasecmp(a, "plain") == 0)
4145  atparams.storage = TYPSTORAGE_PLAIN;
4146  else if (pg_strcasecmp(a, "external") == 0)
4147  atparams.storage = TYPSTORAGE_EXTERNAL;
4148  else if (pg_strcasecmp(a, "extended") == 0)
4149  atparams.storage = TYPSTORAGE_EXTENDED;
4150  else if (pg_strcasecmp(a, "main") == 0)
4151  atparams.storage = TYPSTORAGE_MAIN;
4152  else
4153  ereport(ERROR,
4154  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4155  errmsg("storage \"%s\" not recognized", a)));
4156 
4157  /*
4158  * Validate the storage request. If the type isn't varlena, it
4159  * certainly doesn't support non-PLAIN storage.
4160  */
4161  if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4162  ereport(ERROR,
4163  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4164  errmsg("fixed-size types must have storage PLAIN")));
4165 
4166  /*
4167  * Switching from PLAIN to non-PLAIN is allowed, but it requires
4168  * superuser, since we can't validate that the type's C functions
4169  * will support it. Switching from non-PLAIN to PLAIN is
4170  * disallowed outright, because it's not practical to ensure that
4171  * no tables have toasted values of the type. Switching among
4172  * different non-PLAIN settings is OK, since it just constitutes a
4173  * change in the strategy requested for columns created in the
4174  * future.
4175  */
4176  if (atparams.storage != TYPSTORAGE_PLAIN &&
4177  typForm->typstorage == TYPSTORAGE_PLAIN)
4178  requireSuper = true;
4179  else if (atparams.storage == TYPSTORAGE_PLAIN &&
4180  typForm->typstorage != TYPSTORAGE_PLAIN)
4181  ereport(ERROR,
4182  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4183  errmsg("cannot change type's storage to PLAIN")));
4184 
4185  atparams.updateStorage = true;
4186  }
4187  else if (strcmp(defel->defname, "receive") == 0)
4188  {
4189  if (defel->arg != NULL)
4190  atparams.receiveOid =
4192  typeOid);
4193  else
4194  atparams.receiveOid = InvalidOid; /* NONE, remove function */
4195  atparams.updateReceive = true;
4196  /* Replacing an I/O function requires superuser. */
4197  requireSuper = true;
4198  }
4199  else if (strcmp(defel->defname, "send") == 0)
4200  {
4201  if (defel->arg != NULL)
4202  atparams.sendOid =
4204  typeOid);
4205  else
4206  atparams.sendOid = InvalidOid; /* NONE, remove function */
4207  atparams.updateSend = true;
4208  /* Replacing an I/O function requires superuser. */
4209  requireSuper = true;
4210  }
4211  else if (strcmp(defel->defname, "typmod_in") == 0)
4212  {
4213  if (defel->arg != NULL)
4214  atparams.typmodinOid =
4216  else
4217  atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4218  atparams.updateTypmodin = true;
4219  /* Replacing an I/O function requires superuser. */
4220  requireSuper = true;
4221  }
4222  else if (strcmp(defel->defname, "typmod_out") == 0)
4223  {
4224  if (defel->arg != NULL)
4225  atparams.typmodoutOid =
4227  else
4228  atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4229  atparams.updateTypmodout = true;
4230  /* Replacing an I/O function requires superuser. */
4231  requireSuper = true;
4232  }
4233  else if (strcmp(defel->defname, "analyze") == 0)
4234  {
4235  if (defel->arg != NULL)
4236  atparams.analyzeOid =
4238  typeOid);
4239  else
4240  atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4241  atparams.updateAnalyze = true;
4242  /* Replacing an analyze function requires superuser. */
4243  requireSuper = true;
4244  }
4245  else if (strcmp(defel->defname, "subscript") == 0)
4246  {
4247  if (defel->arg != NULL)
4248  atparams.subscriptOid =
4250  typeOid);
4251  else
4252  atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4253  atparams.updateSubscript = true;
4254  /* Replacing a subscript function requires superuser. */
4255  requireSuper = true;
4256  }
4257 
4258  /*
4259  * The rest of the options that CREATE accepts cannot be changed.
4260  * Check for them so that we can give a meaningful error message.
4261  */
4262  else if (strcmp(defel->defname, "input") == 0 ||
4263  strcmp(defel->defname, "output") == 0 ||
4264  strcmp(defel->defname, "internallength") == 0 ||
4265  strcmp(defel->defname, "passedbyvalue") == 0 ||
4266  strcmp(defel->defname, "alignment") == 0 ||
4267  strcmp(defel->defname, "like") == 0 ||
4268  strcmp(defel->defname, "category") == 0 ||
4269  strcmp(defel->defname, "preferred") == 0 ||
4270  strcmp(defel->defname, "default") == 0 ||
4271  strcmp(defel->defname, "element") == 0 ||
4272  strcmp(defel->defname, "delimiter") == 0 ||
4273  strcmp(defel->defname, "collatable") == 0)
4274  ereport(ERROR,
4275  (errcode(ERRCODE_SYNTAX_ERROR),
4276  errmsg("type attribute \"%s\" cannot be changed",
4277  defel->defname)));
4278  else
4279  ereport(ERROR,
4280  (errcode(ERRCODE_SYNTAX_ERROR),
4281  errmsg("type attribute \"%s\" not recognized",
4282  defel->defname)));
4283  }
4284 
4285  /*
4286  * Permissions check. Require superuser if we decided the command
4287  * requires that, else must own the type.
4288  */
4289  if (requireSuper)
4290  {
4291  if (!superuser())
4292  ereport(ERROR,
4293  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4294  errmsg("must be superuser to alter a type")));
4295  }
4296  else
4297  {
4298  if (!pg_type_ownercheck(typeOid, GetUserId()))
4300  }
4301 
4302  /*
4303  * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4304  * types. It would for example be highly unsafe, not to mention
4305  * pointless, to change the send/receive functions for a composite type.
4306  * Moreover, pg_dump has no support for changing these properties on
4307  * non-base types. We might weaken this someday, but not now.
4308  *
4309  * Note: if you weaken this enough to allow composite types, be sure to
4310  * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4311  */
4312  if (typForm->typtype != TYPTYPE_BASE)
4313  ereport(ERROR,
4314  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4315  errmsg("%s is not a base type",
4316  format_type_be(typeOid))));
4317 
4318  /*
4319  * For the same reasons, don't allow direct alteration of array types.
4320  */
4321  if (IsTrueArrayType(typForm))
4322  ereport(ERROR,
4323  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4324  errmsg("%s is not a base type",
4325  format_type_be(typeOid))));
4326 
4327  /* OK, recursively update this type and any arrays/domains over it */
4328  AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4329 
4330  /* Clean up */
4331  ReleaseSysCache(tup);
4332 
4333  table_close(catalog, RowExclusiveLock);
4334 
4335  ObjectAddressSet(address, TypeRelationId, typeOid);
4336 
4337  return address;
4338 }
4339 
4340 /*
4341  * AlterTypeRecurse: one recursion step for AlterType()
4342  *
4343  * Apply the changes specified by "atparams" to the type identified by
4344  * "typeOid", whose existing pg_type tuple is "tup". If necessary,
4345  * recursively update its array type as well. Then search for any domains
4346  * over this type, and recursively apply (most of) the same changes to those
4347  * domains.
4348  *
4349  * We need this because the system generally assumes that a domain inherits
4350  * many properties from its base type. See DefineDomain() above for details
4351  * of what is inherited. Arrays inherit a smaller number of properties,
4352  * but not none.
4353  *
4354  * There's a race condition here, in that some other transaction could
4355  * concurrently add another domain atop this base type; we'd miss updating
4356  * that one. Hence, be wary of allowing ALTER TYPE to change properties for
4357  * which it'd be really fatal for a domain to be out of sync with its base
4358  * type (typlen, for example). In practice, races seem unlikely to be an
4359  * issue for plausible use-cases for ALTER TYPE. If one does happen, it could
4360  * be fixed by re-doing the same ALTER TYPE once all prior transactions have
4361  * committed.
4362  */
4363 static void
4364 AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
4365  HeapTuple tup, Relation catalog,
4366  AlterTypeRecurseParams *atparams)
4367 {
4368  Datum values[Natts_pg_type];
4369  bool nulls[Natts_pg_type];
4370  bool replaces[Natts_pg_type];
4371  HeapTuple newtup;
4372  SysScanDesc scan;
4373  ScanKeyData key[1];
4374  HeapTuple domainTup;
4375 
4376  /* Since this function recurses, it could be driven to stack overflow */
4378 
4379  /* Update the current type's tuple */
4380  memset(values, 0, sizeof(values));
4381  memset(nulls, 0, sizeof(nulls));
4382  memset(replaces, 0, sizeof(replaces));
4383 
4384  if (atparams->updateStorage)
4385  {
4386  replaces[Anum_pg_type_typstorage - 1] = true;
4387  values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
4388  }
4389  if (atparams->updateReceive)
4390  {
4391  replaces[Anum_pg_type_typreceive - 1] = true;
4392  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
4393  }
4394  if (atparams->updateSend)
4395  {
4396  replaces[Anum_pg_type_typsend - 1] = true;
4397  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
4398  }
4399  if (atparams->updateTypmodin)
4400  {
4401  replaces[Anum_pg_type_typmodin - 1] = true;
4402  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
4403  }
4404  if (atparams->updateTypmodout)
4405  {
4406  replaces[Anum_pg_type_typmodout - 1] = true;
4407  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
4408  }
4409  if (atparams->updateAnalyze)
4410  {
4411  replaces[Anum_pg_type_typanalyze - 1] = true;
4412  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
4413  }
4414  if (atparams->updateSubscript)
4415  {
4416  replaces[Anum_pg_type_typsubscript - 1] = true;
4417  values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
4418  }
4419 
4420  newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
4421  values, nulls, replaces);
4422 
4423  CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
4424 
4425  /* Rebuild dependencies for this type */
4426  GenerateTypeDependencies(newtup,
4427  catalog,
4428  NULL, /* don't have defaultExpr handy */
4429  NULL, /* don't have typacl handy */
4430  0, /* we rejected composite types above */
4431  isImplicitArray, /* it might be an array */
4432  isImplicitArray, /* dependent iff it's array */
4433  true);
4434 
4435  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4436 
4437  /*
4438  * Arrays inherit their base type's typmodin and typmodout, but none of
4439  * the other properties we're concerned with here. Recurse to the array
4440  * type if needed.
4441  */
4442  if (!isImplicitArray &&
4443  (atparams->updateTypmodin || atparams->updateTypmodout))
4444  {
4445  Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4446 
4447  if (OidIsValid(arrtypoid))
4448  {
4449  HeapTuple arrtup;
4450  AlterTypeRecurseParams arrparams;
4451 
4452  arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
4453  if (!HeapTupleIsValid(arrtup))
4454  elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4455 
4456  memset(&arrparams, 0, sizeof(arrparams));
4457  arrparams.updateTypmodin = atparams->updateTypmodin;
4458  arrparams.updateTypmodout = atparams->updateTypmodout;
4459  arrparams.typmodinOid = atparams->typmodinOid;
4460  arrparams.typmodoutOid = atparams->typmodoutOid;
4461 
4462  AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
4463 
4464  ReleaseSysCache(arrtup);
4465  }
4466  }
4467 
4468  /*
4469  * Now we need to recurse to domains. However, some properties are not
4470  * inherited by domains, so clear the update flags for those.
4471  */
4472  atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4473  atparams->updateTypmodin = false; /* domains don't have typmods */
4474  atparams->updateTypmodout = false;
4475  atparams->updateSubscript = false; /* domains don't have subscriptors */
4476 
4477  /* Skip the scan if nothing remains to be done */
4478  if (!(atparams->updateStorage ||
4479  atparams->updateSend ||
4480  atparams->updateAnalyze))
4481  return;
4482 
4483  /* Search pg_type for possible domains over this type */
4484  ScanKeyInit(&key[0],
4485  Anum_pg_type_typbasetype,
4486  BTEqualStrategyNumber, F_OIDEQ,
4487  ObjectIdGetDatum(typeOid));
4488 
4489  scan = systable_beginscan(catalog, InvalidOid, false,
4490  NULL, 1, key);
4491 
4492  while ((domainTup = systable_getnext(scan)) != NULL)
4493  {
4494  Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
4495 
4496  /*
4497  * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4498  * check
4499  */
4500  if (domainForm->typtype != TYPTYPE_DOMAIN)
4501  continue;
4502 
4503  AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
4504  }
4505 
4506  systable_endscan(scan);
4507 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
RangeVar * relation
Definition: parsenodes.h:2159
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:38
signed short int16
Definition: c.h:428
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2242
#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:660
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:322
OnCommitAction oncommit
Definition: parsenodes.h:2168
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
List * inhRelations
Definition: parsenodes.h:2161
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
#define NameGetDatum(X)
Definition: postgres.h:639
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:808
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2023
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2933
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1123
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2099
ObjectAddress RenameType(RenameStmt *stmt)
Definition: typecmds.c:3615
int * atts
Definition: typecmds.c:83
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
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:2058
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:810
ObjectType renameType
Definition: parsenodes.h:3023
#define RelationGetDescr(relation)
Definition: rel.h:495
int LOCKMODE
Definition: lockdefs.h:26
Relation rel
Definition: typecmds.c:81
Oid GetUserId(void)
Definition: miscinit.c:478
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:608
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:475
#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:2706
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3583
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2218
#define PointerGetDatum(X)
Definition: postgres.h:600
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:2734
ObjectAddress AlterDomainValidateConstraint(List *names, const char *constrName)
Definition: typecmds.c:3049
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:1974
Node * raw_expr
Definition: parsenodes.h:2249
ObjectAddress AlterEnum(AlterEnumStmt *stmt)
Definition: typecmds.c:1264
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2552
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:2147
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6196
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
#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:539
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2120
ObjectAddress AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
Definition: typecmds.c:3895
#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:698
void * stringToNode(const char *str)
Definition: read.c:89
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3970
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:2576
#define MemSet(start, val, len)
Definition: c.h:1008
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:3059
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist)
Definition: typecmds.c:2525
List * typeName
Definition: parsenodes.h:3093
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2492
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3840
bool contain_var_clause(Node *node)
Definition: var.c:358
char * conname
Definition: parsenodes.h:2242
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:734
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2437
int16 pronargs
Definition: pg_proc.h:81
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1032
char * newname
Definition: parsenodes.h:3029
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2732
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
Datum domainValue_datum
Definition: execnodes.h:257
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:60
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4849
void RemoveTypeById(Oid typeOid)
Definition: typecmds.c:656
#define OidIsValid(objectId)
Definition: c.h:710
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:746
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4761
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:641
Oid AssignTypeMultirangeArrayOid(void)
Definition: typecmds.c:2483
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
bool IsBinaryUpgrade
Definition: globals.c:113
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3626
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1626
signed int int32
Definition: c.h:429
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
int location
Definition: parsenodes.h:248
int defGetTypeLength(DefElem *def)
Definition: define.c:283
List * constraints
Definition: parsenodes.h:2166
bool if_not_exists
Definition: parsenodes.h:2171
void assign_expr_collations(ParseState *pstate, Node *expr)
char * relname
Definition: primnodes.h:68
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
char * newValNeighbor
Definition: parsenodes.h:3215
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:2369
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:3313
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:3460
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
Definition: typecmds.c:3692
void pfree(void *pointer)
Definition: mcxt.c:1169
#define linitial(l)
Definition: pg_list.h:174
CollateClause * collClause
Definition: parsenodes.h:2674
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ObjectAddress AlterDomainDefault(List *names, Node *defaultRaw)
Definition: typecmds.c:2583
#define ACL_CREATE
Definition: parsenodes.h:92
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:883
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
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:2117
ItemPointerData t_self
Definition: htup.h:65
#define ConstraintRelidTypidNameIndexId
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2215
List * typeName
Definition: parsenodes.h:3212
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3800
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:4113
ObjectAddress AlterDomainNotNull(List *names, bool notNull)
Definition: typecmds.c:2714
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
Oid AssignTypeMultirangeOid(void)
Definition: typecmds.c:2450
#define NoLock
Definition: lockdefs.h:34
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:848
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
void check_stack_depth(void)
Definition: postgres.c:3469
int location
Definition: parsenodes.h:749
#define RowExclusiveLock
Definition: lockdefs.h:38
void EnumValuesDelete(Oid enumTypeOid)
Definition: pg_enum.c:157
#define CStringGetDatum(X)
Definition: postgres.h:622
#define DatumGetBool(X)
Definition: postgres.h:437
ObjectAddress DefineRange(CreateRangeStmt *stmt)
Definition: typecmds.c:1339
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:312
#define RelationGetRelationName(relation)
Definition: rel.h:503
List * options
Definition: parsenodes.h:2167
Node * object
Definition: parsenodes.h:3026
ObjectAddress DefineEnum(CreateEnumStmt *stmt)
Definition: typecmds.c:1140
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
#define ACL_USAGE
Definition: parsenodes.h:90
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:73
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:2181
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4893
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:627
#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:90
ObjectAddress DefineType(ParseState *pstate, List *names, List *parameters)
Definition: typecmds.c:148
#define DependReferenceIndexId
Definition: pg_depend.h:78
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2029
Node * arg
Definition: parsenodes.h:747
ObjectType
Definition: parsenodes.h:1775
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:2169
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:13142
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3932
#define WARNING
Definition: elog.h:40
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:3271
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:733
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
bool domainValue_isNull
Definition: execnodes.h:259
char * NameListToString(List *names)
Definition: namespace.c:3101
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define TextDatumGetCString(d)
Definition: builtins.h:83
bool skipIfNewValExists
Definition: parsenodes.h:3217
DropBehavior
Definition: parsenodes.h:1846
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
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:3216
TupleDesc rd_att
Definition: rel.h:110
List * options
Definition: parsenodes.h:3094
#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:2248
int16 attnum
Definition: pg_attribute.h:83
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:2289
#define ereport(elevel,...)
Definition: elog.h:157
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3003
#define NOTICE
Definition: elog.h:37
List * tableElts
Definition: parsenodes.h:2160
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define makeNode(_type_)
Definition: nodes.h:587
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:804
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:5645
void GenerateTypeDependencies(HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:549
void * p_ref_hook_state
Definition: parse_node.h:224
#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:3483
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
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:197
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:893
#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:15921
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:544
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2417
#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:2673
#define CharGetDatum(X)
Definition: postgres.h:460
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3440
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:3151
Oid regproc
Definition: c.h:584
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1960
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
static Datum values[MAXATTR]
Definition: bootstrap.c:166
ObjectAddress AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
Definition: typecmds.c:2834
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * collname
Definition: parsenodes.h:320
List * arrayBounds
Definition: parsenodes.h:227
char func_volatile(Oid funcid)
Definition: lsyscache.c:1751
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2144
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:388
#define ACL_EXECUTE
Definition: parsenodes.h:89
#define elog(elevel,...)
Definition: elog.h:232
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4723
#define ShareLock
Definition: lockdefs.h:41
int i
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
#define NameStr(name)
Definition: c.h:681
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:4527
ConstrType contype
Definition: parsenodes.h:2239
char * defname
Definition: parsenodes.h:746
static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition: typecmds.c:4364
PreParseColumnRefHook p_pre_columnref_hook
Definition: parse_node.h:220
#define copyObject(obj)
Definition: nodes.h:655
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:4811
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:3028
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:70
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3827
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:1037
bool skip_validation
Definition: parsenodes.h:2284
void RangeDelete(Oid rangeTypeOid)
Definition: pg_range.c:113
#define RelationGetRelid(relation)
Definition: rel.h:469
static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *castFuncOid)
Definition: typecmds.c:1815
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4901
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2328
List * fields
Definition: parsenodes.h:247
#define ResetExprContext(econtext)
Definition: executor.h:527
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155
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:2112
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1205
List * p_rtable
Definition: parse_node.h:182
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)