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