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