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