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