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