PostgreSQL Source Code git master
typecmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * typecmds.c
4 * Routines for SQL commands that manipulate types (and domains).
5 *
6 * Portions Copyright (c) 1996-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 /* Ensure these new types are visible to ProcedureCreate */
1747
1748 /* And create the constructor functions for this range type */
1749 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1750 makeMultirangeConstructors(multirangeTypeName, typeNamespace,
1751 multirangeOid, typoid, rangeArrayOid,
1752 &castFuncOid);
1753
1754 /* Create cast from the range type to its multirange type */
1755 CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
1756 COERCION_CODE_EXPLICIT, COERCION_METHOD_FUNCTION,
1758
1759 pfree(multirangeArrayName);
1760
1761 return address;
1762}
1763
1764/*
1765 * Because there may exist several range types over the same subtype, the
1766 * range type can't be uniquely determined from the subtype. So it's
1767 * impossible to define a polymorphic constructor; we have to generate new
1768 * constructor functions explicitly for each range type.
1769 *
1770 * We actually define 4 functions, with 0 through 3 arguments. This is just
1771 * to offer more convenience for the user.
1772 */
1773static void
1774makeRangeConstructors(const char *name, Oid namespace,
1775 Oid rangeOid, Oid subtype)
1776{
1777 static const char *const prosrc[2] = {"range_constructor2",
1778 "range_constructor3"};
1779 static const int pronargs[2] = {2, 3};
1780
1781 Oid constructorArgTypes[3];
1782 ObjectAddress myself,
1783 referenced;
1784 int i;
1785
1786 constructorArgTypes[0] = subtype;
1787 constructorArgTypes[1] = subtype;
1788 constructorArgTypes[2] = TEXTOID;
1789
1790 referenced.classId = TypeRelationId;
1791 referenced.objectId = rangeOid;
1792 referenced.objectSubId = 0;
1793
1794 for (i = 0; i < lengthof(prosrc); i++)
1795 {
1796 oidvector *constructorArgTypesVector;
1797
1798 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1799 pronargs[i]);
1800
1801 myself = ProcedureCreate(name, /* name: same as range type */
1802 namespace, /* namespace */
1803 false, /* replace */
1804 false, /* returns set */
1805 rangeOid, /* return type */
1806 BOOTSTRAP_SUPERUSERID, /* proowner */
1807 INTERNALlanguageId, /* language */
1808 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1809 prosrc[i], /* prosrc */
1810 NULL, /* probin */
1811 NULL, /* prosqlbody */
1812 PROKIND_FUNCTION,
1813 false, /* security_definer */
1814 false, /* leakproof */
1815 false, /* isStrict */
1816 PROVOLATILE_IMMUTABLE, /* volatility */
1817 PROPARALLEL_SAFE, /* parallel safety */
1818 constructorArgTypesVector, /* parameterTypes */
1819 PointerGetDatum(NULL), /* allParameterTypes */
1820 PointerGetDatum(NULL), /* parameterModes */
1821 PointerGetDatum(NULL), /* parameterNames */
1822 NIL, /* parameterDefaults */
1823 PointerGetDatum(NULL), /* trftypes */
1824 NIL, /* trfoids */
1825 PointerGetDatum(NULL), /* proconfig */
1826 InvalidOid, /* prosupport */
1827 1.0, /* procost */
1828 0.0); /* prorows */
1829
1830 /*
1831 * Make the constructors internally-dependent on the range type so
1832 * that they go away silently when the type is dropped. Note that
1833 * pg_dump depends on this choice to avoid dumping the constructors.
1834 */
1835 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1836 }
1837}
1838
1839/*
1840 * We make a separate multirange constructor for each range type
1841 * so its name can include the base type, like range constructors do.
1842 * If we had an anyrangearray polymorphic type we could use it here,
1843 * but since each type has its own constructor name there's no need.
1844 *
1845 * Sets castFuncOid to the oid of the new constructor that can be used
1846 * to cast from a range to a multirange.
1847 */
1848static void
1849makeMultirangeConstructors(const char *name, Oid namespace,
1850 Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid,
1851 Oid *castFuncOid)
1852{
1853 ObjectAddress myself,
1854 referenced;
1855 oidvector *argtypes;
1856 Datum allParamTypes;
1857 ArrayType *allParameterTypes;
1858 Datum paramModes;
1859 ArrayType *parameterModes;
1860
1861 referenced.classId = TypeRelationId;
1862 referenced.objectId = multirangeOid;
1863 referenced.objectSubId = 0;
1864
1865 /* 0-arg constructor - for empty multiranges */
1866 argtypes = buildoidvector(NULL, 0);
1867 myself = ProcedureCreate(name, /* name: same as multirange type */
1868 namespace,
1869 false, /* replace */
1870 false, /* returns set */
1871 multirangeOid, /* return type */
1872 BOOTSTRAP_SUPERUSERID, /* proowner */
1873 INTERNALlanguageId, /* language */
1874 F_FMGR_INTERNAL_VALIDATOR,
1875 "multirange_constructor0", /* prosrc */
1876 NULL, /* probin */
1877 NULL, /* prosqlbody */
1878 PROKIND_FUNCTION,
1879 false, /* security_definer */
1880 false, /* leakproof */
1881 true, /* isStrict */
1882 PROVOLATILE_IMMUTABLE, /* volatility */
1883 PROPARALLEL_SAFE, /* parallel safety */
1884 argtypes, /* parameterTypes */
1885 PointerGetDatum(NULL), /* allParameterTypes */
1886 PointerGetDatum(NULL), /* parameterModes */
1887 PointerGetDatum(NULL), /* parameterNames */
1888 NIL, /* parameterDefaults */
1889 PointerGetDatum(NULL), /* trftypes */
1890 NIL, /* trfoids */
1891 PointerGetDatum(NULL), /* proconfig */
1892 InvalidOid, /* prosupport */
1893 1.0, /* procost */
1894 0.0); /* prorows */
1895
1896 /*
1897 * Make the constructor internally-dependent on the multirange type so
1898 * that they go away silently when the type is dropped. Note that pg_dump
1899 * depends on this choice to avoid dumping the constructors.
1900 */
1901 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1902 pfree(argtypes);
1903
1904 /*
1905 * 1-arg constructor - for casts
1906 *
1907 * In theory we shouldn't need both this and the vararg (n-arg)
1908 * constructor, but having a separate 1-arg function lets us define casts
1909 * against it.
1910 */
1911 argtypes = buildoidvector(&rangeOid, 1);
1912 myself = ProcedureCreate(name, /* name: same as multirange type */
1913 namespace,
1914 false, /* replace */
1915 false, /* returns set */
1916 multirangeOid, /* return type */
1917 BOOTSTRAP_SUPERUSERID, /* proowner */
1918 INTERNALlanguageId, /* language */
1919 F_FMGR_INTERNAL_VALIDATOR,
1920 "multirange_constructor1", /* prosrc */
1921 NULL, /* probin */
1922 NULL, /* prosqlbody */
1923 PROKIND_FUNCTION,
1924 false, /* security_definer */
1925 false, /* leakproof */
1926 true, /* isStrict */
1927 PROVOLATILE_IMMUTABLE, /* volatility */
1928 PROPARALLEL_SAFE, /* parallel safety */
1929 argtypes, /* parameterTypes */
1930 PointerGetDatum(NULL), /* allParameterTypes */
1931 PointerGetDatum(NULL), /* parameterModes */
1932 PointerGetDatum(NULL), /* parameterNames */
1933 NIL, /* parameterDefaults */
1934 PointerGetDatum(NULL), /* trftypes */
1935 NIL, /* trfoids */
1936 PointerGetDatum(NULL), /* proconfig */
1937 InvalidOid, /* prosupport */
1938 1.0, /* procost */
1939 0.0); /* prorows */
1940 /* ditto */
1941 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1942 pfree(argtypes);
1943 *castFuncOid = myself.objectId;
1944
1945 /* n-arg constructor - vararg */
1946 argtypes = buildoidvector(&rangeArrayOid, 1);
1947 allParamTypes = ObjectIdGetDatum(rangeArrayOid);
1948 allParameterTypes = construct_array_builtin(&allParamTypes, 1, OIDOID);
1949 paramModes = CharGetDatum(FUNC_PARAM_VARIADIC);
1950 parameterModes = construct_array_builtin(&paramModes, 1, CHAROID);
1951 myself = ProcedureCreate(name, /* name: same as multirange type */
1952 namespace,
1953 false, /* replace */
1954 false, /* returns set */
1955 multirangeOid, /* return type */
1956 BOOTSTRAP_SUPERUSERID, /* proowner */
1957 INTERNALlanguageId, /* language */
1958 F_FMGR_INTERNAL_VALIDATOR,
1959 "multirange_constructor2", /* prosrc */
1960 NULL, /* probin */
1961 NULL, /* prosqlbody */
1962 PROKIND_FUNCTION,
1963 false, /* security_definer */
1964 false, /* leakproof */
1965 true, /* isStrict */
1966 PROVOLATILE_IMMUTABLE, /* volatility */
1967 PROPARALLEL_SAFE, /* parallel safety */
1968 argtypes, /* parameterTypes */
1969 PointerGetDatum(allParameterTypes), /* allParameterTypes */
1970 PointerGetDatum(parameterModes), /* parameterModes */
1971 PointerGetDatum(NULL), /* parameterNames */
1972 NIL, /* parameterDefaults */
1973 PointerGetDatum(NULL), /* trftypes */
1974 NIL, /* trfoids */
1975 PointerGetDatum(NULL), /* proconfig */
1976 InvalidOid, /* prosupport */
1977 1.0, /* procost */
1978 0.0); /* prorows */
1979 /* ditto */
1980 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1981 pfree(argtypes);
1982 pfree(allParameterTypes);
1983 pfree(parameterModes);
1984}
1985
1986/*
1987 * Find suitable I/O and other support functions for a type.
1988 *
1989 * typeOid is the type's OID (which will already exist, if only as a shell
1990 * type).
1991 */
1992
1993static Oid
1994findTypeInputFunction(List *procname, Oid typeOid)
1995{
1996 Oid argList[3];
1997 Oid procOid;
1998 Oid procOid2;
1999
2000 /*
2001 * Input functions can take a single argument of type CSTRING, or three
2002 * arguments (string, typioparam OID, typmod). Whine about ambiguity if
2003 * both forms exist.
2004 */
2005 argList[0] = CSTRINGOID;
2006 argList[1] = OIDOID;
2007 argList[2] = INT4OID;
2008
2009 procOid = LookupFuncName(procname, 1, argList, true);
2010 procOid2 = LookupFuncName(procname, 3, argList, true);
2011 if (OidIsValid(procOid))
2012 {
2013 if (OidIsValid(procOid2))
2014 ereport(ERROR,
2015 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
2016 errmsg("type input function %s has multiple matches",
2017 NameListToString(procname))));
2018 }
2019 else
2020 {
2021 procOid = procOid2;
2022 /* If not found, reference the 1-argument signature in error msg */
2023 if (!OidIsValid(procOid))
2024 ereport(ERROR,
2025 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2026 errmsg("function %s does not exist",
2027 func_signature_string(procname, 1, NIL, argList))));
2028 }
2029
2030 /* Input functions must return the target type. */
2031 if (get_func_rettype(procOid) != typeOid)
2032 ereport(ERROR,
2033 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2034 errmsg("type input function %s must return type %s",
2035 NameListToString(procname), format_type_be(typeOid))));
2036
2037 /*
2038 * Print warnings if any of the type's I/O functions are marked volatile.
2039 * There is a general assumption that I/O functions are stable or
2040 * immutable; this allows us for example to mark record_in/record_out
2041 * stable rather than volatile. Ideally we would throw errors not just
2042 * warnings here; but since this check is new as of 9.5, and since the
2043 * volatility marking might be just an error-of-omission and not a true
2044 * indication of how the function behaves, we'll let it pass as a warning
2045 * for now.
2046 */
2047 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2049 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2050 errmsg("type input function %s should not be volatile",
2051 NameListToString(procname))));
2052
2053 return procOid;
2054}
2055
2056static Oid
2058{
2059 Oid argList[1];
2060 Oid procOid;
2061
2062 /*
2063 * Output functions always take a single argument of the type and return
2064 * cstring.
2065 */
2066 argList[0] = typeOid;
2067
2068 procOid = LookupFuncName(procname, 1, argList, true);
2069 if (!OidIsValid(procOid))
2070 ereport(ERROR,
2071 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2072 errmsg("function %s does not exist",
2073 func_signature_string(procname, 1, NIL, argList))));
2074
2075 if (get_func_rettype(procOid) != CSTRINGOID)
2076 ereport(ERROR,
2077 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2078 errmsg("type output function %s must return type %s",
2079 NameListToString(procname), "cstring")));
2080
2081 /* Just a warning for now, per comments in findTypeInputFunction */
2082 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2084 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2085 errmsg("type output function %s should not be volatile",
2086 NameListToString(procname))));
2087
2088 return procOid;
2089}
2090
2091static Oid
2093{
2094 Oid argList[3];
2095 Oid procOid;
2096 Oid procOid2;
2097
2098 /*
2099 * Receive functions can take a single argument of type INTERNAL, or three
2100 * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2101 * both forms exist.
2102 */
2103 argList[0] = INTERNALOID;
2104 argList[1] = OIDOID;
2105 argList[2] = INT4OID;
2106
2107 procOid = LookupFuncName(procname, 1, argList, true);
2108 procOid2 = LookupFuncName(procname, 3, argList, true);
2109 if (OidIsValid(procOid))
2110 {
2111 if (OidIsValid(procOid2))
2112 ereport(ERROR,
2113 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
2114 errmsg("type receive function %s has multiple matches",
2115 NameListToString(procname))));
2116 }
2117 else
2118 {
2119 procOid = procOid2;
2120 /* If not found, reference the 1-argument signature in error msg */
2121 if (!OidIsValid(procOid))
2122 ereport(ERROR,
2123 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2124 errmsg("function %s does not exist",
2125 func_signature_string(procname, 1, NIL, argList))));
2126 }
2127
2128 /* Receive functions must return the target type. */
2129 if (get_func_rettype(procOid) != typeOid)
2130 ereport(ERROR,
2131 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2132 errmsg("type receive function %s must return type %s",
2133 NameListToString(procname), format_type_be(typeOid))));
2134
2135 /* Just a warning for now, per comments in findTypeInputFunction */
2136 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2138 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2139 errmsg("type receive function %s should not be volatile",
2140 NameListToString(procname))));
2141
2142 return procOid;
2143}
2144
2145static Oid
2146findTypeSendFunction(List *procname, Oid typeOid)
2147{
2148 Oid argList[1];
2149 Oid procOid;
2150
2151 /*
2152 * Send functions always take a single argument of the type and return
2153 * bytea.
2154 */
2155 argList[0] = typeOid;
2156
2157 procOid = LookupFuncName(procname, 1, argList, true);
2158 if (!OidIsValid(procOid))
2159 ereport(ERROR,
2160 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2161 errmsg("function %s does not exist",
2162 func_signature_string(procname, 1, NIL, argList))));
2163
2164 if (get_func_rettype(procOid) != BYTEAOID)
2165 ereport(ERROR,
2166 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2167 errmsg("type send function %s must return type %s",
2168 NameListToString(procname), "bytea")));
2169
2170 /* Just a warning for now, per comments in findTypeInputFunction */
2171 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2173 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2174 errmsg("type send function %s should not be volatile",
2175 NameListToString(procname))));
2176
2177 return procOid;
2178}
2179
2180static Oid
2182{
2183 Oid argList[1];
2184 Oid procOid;
2185
2186 /*
2187 * typmodin functions always take one cstring[] argument and return int4.
2188 */
2189 argList[0] = CSTRINGARRAYOID;
2190
2191 procOid = LookupFuncName(procname, 1, argList, true);
2192 if (!OidIsValid(procOid))
2193 ereport(ERROR,
2194 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2195 errmsg("function %s does not exist",
2196 func_signature_string(procname, 1, NIL, argList))));
2197
2198 if (get_func_rettype(procOid) != INT4OID)
2199 ereport(ERROR,
2200 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2201 errmsg("typmod_in function %s must return type %s",
2202 NameListToString(procname), "integer")));
2203
2204 /* Just a warning for now, per comments in findTypeInputFunction */
2205 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2207 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2208 errmsg("type modifier input function %s should not be volatile",
2209 NameListToString(procname))));
2210
2211 return procOid;
2212}
2213
2214static Oid
2216{
2217 Oid argList[1];
2218 Oid procOid;
2219
2220 /*
2221 * typmodout functions always take one int4 argument and return cstring.
2222 */
2223 argList[0] = INT4OID;
2224
2225 procOid = LookupFuncName(procname, 1, argList, true);
2226 if (!OidIsValid(procOid))
2227 ereport(ERROR,
2228 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2229 errmsg("function %s does not exist",
2230 func_signature_string(procname, 1, NIL, argList))));
2231
2232 if (get_func_rettype(procOid) != CSTRINGOID)
2233 ereport(ERROR,
2234 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2235 errmsg("typmod_out function %s must return type %s",
2236 NameListToString(procname), "cstring")));
2237
2238 /* Just a warning for now, per comments in findTypeInputFunction */
2239 if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2241 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2242 errmsg("type modifier output function %s should not be volatile",
2243 NameListToString(procname))));
2244
2245 return procOid;
2246}
2247
2248static Oid
2250{
2251 Oid argList[1];
2252 Oid procOid;
2253
2254 /*
2255 * Analyze functions always take one INTERNAL argument and return bool.
2256 */
2257 argList[0] = INTERNALOID;
2258
2259 procOid = LookupFuncName(procname, 1, argList, true);
2260 if (!OidIsValid(procOid))
2261 ereport(ERROR,
2262 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2263 errmsg("function %s does not exist",
2264 func_signature_string(procname, 1, NIL, argList))));
2265
2266 if (get_func_rettype(procOid) != BOOLOID)
2267 ereport(ERROR,
2268 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2269 errmsg("type analyze function %s must return type %s",
2270 NameListToString(procname), "boolean")));
2271
2272 return procOid;
2273}
2274
2275static Oid
2277{
2278 Oid argList[1];
2279 Oid procOid;
2280
2281 /*
2282 * Subscripting support functions always take one INTERNAL argument and
2283 * return INTERNAL. (The argument is not used, but we must have it to
2284 * maintain type safety.)
2285 */
2286 argList[0] = INTERNALOID;
2287
2288 procOid = LookupFuncName(procname, 1, argList, true);
2289 if (!OidIsValid(procOid))
2290 ereport(ERROR,
2291 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2292 errmsg("function %s does not exist",
2293 func_signature_string(procname, 1, NIL, argList))));
2294
2295 if (get_func_rettype(procOid) != INTERNALOID)
2296 ereport(ERROR,
2297 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2298 errmsg("type subscripting function %s must return type %s",
2299 NameListToString(procname), "internal")));
2300
2301 /*
2302 * We disallow array_subscript_handler() from being selected explicitly,
2303 * since that must only be applied to autogenerated array types.
2304 */
2305 if (procOid == F_ARRAY_SUBSCRIPT_HANDLER)
2306 ereport(ERROR,
2307 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2308 errmsg("user-defined types cannot use subscripting function %s",
2309 NameListToString(procname))));
2310
2311 return procOid;
2312}
2313
2314/*
2315 * Find suitable support functions and opclasses for a range type.
2316 */
2317
2318/*
2319 * Find named btree opclass for subtype, or default btree opclass if
2320 * opcname is NIL.
2321 */
2322static Oid
2323findRangeSubOpclass(List *opcname, Oid subtype)
2324{
2325 Oid opcid;
2326 Oid opInputType;
2327
2328 if (opcname != NIL)
2329 {
2330 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
2331
2332 /*
2333 * Verify that the operator class accepts this datatype. Note we will
2334 * accept binary compatibility.
2335 */
2336 opInputType = get_opclass_input_type(opcid);
2337 if (!IsBinaryCoercible(subtype, opInputType))
2338 ereport(ERROR,
2339 (errcode(ERRCODE_DATATYPE_MISMATCH),
2340 errmsg("operator class \"%s\" does not accept data type %s",
2341 NameListToString(opcname),
2342 format_type_be(subtype))));
2343 }
2344 else
2345 {
2346 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
2347 if (!OidIsValid(opcid))
2348 {
2349 /* We spell the error message identically to ResolveOpClass */
2350 ereport(ERROR,
2351 (errcode(ERRCODE_UNDEFINED_OBJECT),
2352 errmsg("data type %s has no default operator class for access method \"%s\"",
2353 format_type_be(subtype), "btree"),
2354 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2355 }
2356 }
2357
2358 return opcid;
2359}
2360
2361static Oid
2363{
2364 Oid argList[1];
2365 Oid procOid;
2366 AclResult aclresult;
2367
2368 /*
2369 * Range canonical functions must take and return the range type, and must
2370 * be immutable.
2371 */
2372 argList[0] = typeOid;
2373
2374 procOid = LookupFuncName(procname, 1, argList, true);
2375
2376 if (!OidIsValid(procOid))
2377 ereport(ERROR,
2378 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2379 errmsg("function %s does not exist",
2380 func_signature_string(procname, 1, NIL, argList))));
2381
2382 if (get_func_rettype(procOid) != typeOid)
2383 ereport(ERROR,
2384 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2385 errmsg("range canonical function %s must return range type",
2386 func_signature_string(procname, 1, NIL, argList))));
2387
2388 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2389 ereport(ERROR,
2390 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2391 errmsg("range canonical function %s must be immutable",
2392 func_signature_string(procname, 1, NIL, argList))));
2393
2394 /* Also, range type's creator must have permission to call function */
2395 aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
2396 if (aclresult != ACLCHECK_OK)
2397 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2398
2399 return procOid;
2400}
2401
2402static Oid
2404{
2405 Oid argList[2];
2406 Oid procOid;
2407 AclResult aclresult;
2408
2409 /*
2410 * Range subtype diff functions must take two arguments of the subtype,
2411 * must return float8, and must be immutable.
2412 */
2413 argList[0] = subtype;
2414 argList[1] = subtype;
2415
2416 procOid = LookupFuncName(procname, 2, argList, true);
2417
2418 if (!OidIsValid(procOid))
2419 ereport(ERROR,
2420 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2421 errmsg("function %s does not exist",
2422 func_signature_string(procname, 2, NIL, argList))));
2423
2424 if (get_func_rettype(procOid) != FLOAT8OID)
2425 ereport(ERROR,
2426 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2427 errmsg("range subtype diff function %s must return type %s",
2428 func_signature_string(procname, 2, NIL, argList),
2429 "double precision")));
2430
2431 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2432 ereport(ERROR,
2433 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2434 errmsg("range subtype diff function %s must be immutable",
2435 func_signature_string(procname, 2, NIL, argList))));
2436
2437 /* Also, range type's creator must have permission to call function */
2438 aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
2439 if (aclresult != ACLCHECK_OK)
2440 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2441
2442 return procOid;
2443}
2444
2445/*
2446 * AssignTypeArrayOid
2447 *
2448 * Pre-assign the type's array OID for use in pg_type.typarray
2449 */
2450Oid
2452{
2453 Oid type_array_oid;
2454
2455 /* Use binary-upgrade override for pg_type.typarray? */
2456 if (IsBinaryUpgrade)
2457 {
2459 ereport(ERROR,
2460 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2461 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2462
2465 }
2466 else
2467 {
2468 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2469
2470 type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2471 Anum_pg_type_oid);
2472 table_close(pg_type, AccessShareLock);
2473 }
2474
2475 return type_array_oid;
2476}
2477
2478/*
2479 * AssignTypeMultirangeOid
2480 *
2481 * Pre-assign the range type's multirange OID for use in pg_type.oid
2482 */
2483Oid
2485{
2486 Oid type_multirange_oid;
2487
2488 /* Use binary-upgrade override for pg_type.oid? */
2489 if (IsBinaryUpgrade)
2490 {
2492 ereport(ERROR,
2493 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2494 errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2495
2496 type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2498 }
2499 else
2500 {
2501 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2502
2503 type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2504 Anum_pg_type_oid);
2505 table_close(pg_type, AccessShareLock);
2506 }
2507
2508 return type_multirange_oid;
2509}
2510
2511/*
2512 * AssignTypeMultirangeArrayOid
2513 *
2514 * Pre-assign the range type's multirange array OID for use in pg_type.typarray
2515 */
2516Oid
2518{
2519 Oid type_multirange_array_oid;
2520
2521 /* Use binary-upgrade override for pg_type.oid? */
2522 if (IsBinaryUpgrade)
2523 {
2525 ereport(ERROR,
2526 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2527 errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2528
2529 type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2531 }
2532 else
2533 {
2534 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2535
2536 type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2537 Anum_pg_type_oid);
2538 table_close(pg_type, AccessShareLock);
2539 }
2540
2541 return type_multirange_array_oid;
2542}
2543
2544
2545/*-------------------------------------------------------------------
2546 * DefineCompositeType
2547 *
2548 * Create a Composite Type relation.
2549 * `DefineRelation' does all the work, we just provide the correct
2550 * arguments!
2551 *
2552 * If the relation already exists, then 'DefineRelation' will abort
2553 * the xact...
2554 *
2555 * Return type is the new type's object address.
2556 *-------------------------------------------------------------------
2557 */
2559DefineCompositeType(RangeVar *typevar, List *coldeflist)
2560{
2561 CreateStmt *createStmt = makeNode(CreateStmt);
2562 Oid old_type_oid;
2563 Oid typeNamespace;
2564 ObjectAddress address;
2565
2566 /*
2567 * now set the parameters for keys/inheritance etc. All of these are
2568 * uninteresting for composite types...
2569 */
2570 createStmt->relation = typevar;
2571 createStmt->tableElts = coldeflist;
2572 createStmt->inhRelations = NIL;
2573 createStmt->constraints = NIL;
2574 createStmt->options = NIL;
2575 createStmt->oncommit = ONCOMMIT_NOOP;
2576 createStmt->tablespacename = NULL;
2577 createStmt->if_not_exists = false;
2578
2579 /*
2580 * Check for collision with an existing type name. If there is one and
2581 * it's an autogenerated array, we can rename it out of the way. This
2582 * check is here mainly to get a better error message about a "type"
2583 * instead of below about a "relation".
2584 */
2585 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2586 NoLock, NULL);
2587 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2588 old_type_oid =
2589 GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2590 CStringGetDatum(createStmt->relation->relname),
2591 ObjectIdGetDatum(typeNamespace));
2592 if (OidIsValid(old_type_oid))
2593 {
2594 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2595 ereport(ERROR,
2597 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2598 }
2599
2600 /*
2601 * Finally create the relation. This also creates the type.
2602 */
2603 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2604 NULL);
2605
2606 return address;
2607}
2608
2609/*
2610 * AlterDomainDefault
2611 *
2612 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2613 *
2614 * Returns ObjectAddress of the modified domain.
2615 */
2617AlterDomainDefault(List *names, Node *defaultRaw)
2618{
2619 TypeName *typename;
2620 Oid domainoid;
2621 HeapTuple tup;
2622 ParseState *pstate;
2623 Relation rel;
2624 char *defaultValue;
2625 Node *defaultExpr = NULL; /* NULL if no default specified */
2626 Datum new_record[Natts_pg_type] = {0};
2627 bool new_record_nulls[Natts_pg_type] = {0};
2628 bool new_record_repl[Natts_pg_type] = {0};
2629 HeapTuple newtuple;
2630 Form_pg_type typTup;
2631 ObjectAddress address;
2632
2633 /* Make a TypeName so we can use standard type lookup machinery */
2634 typename = makeTypeNameFromNameList(names);
2635 domainoid = typenameTypeId(NULL, typename);
2636
2637 /* Look up the domain in the type table */
2638 rel = table_open(TypeRelationId, RowExclusiveLock);
2639
2640 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2641 if (!HeapTupleIsValid(tup))
2642 elog(ERROR, "cache lookup failed for type %u", domainoid);
2643 typTup = (Form_pg_type) GETSTRUCT(tup);
2644
2645 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2646 checkDomainOwner(tup);
2647
2648 /* Setup new tuple */
2649
2650 /* Store the new default into the tuple */
2651 if (defaultRaw)
2652 {
2653 /* Create a dummy ParseState for transformExpr */
2654 pstate = make_parsestate(NULL);
2655
2656 /*
2657 * Cook the colDef->raw_expr into an expression. Note: Name is
2658 * strictly for error message
2659 */
2660 defaultExpr = cookDefault(pstate, defaultRaw,
2661 typTup->typbasetype,
2662 typTup->typtypmod,
2663 NameStr(typTup->typname),
2664 0);
2665
2666 /*
2667 * If the expression is just a NULL constant, we treat the command
2668 * like ALTER ... DROP DEFAULT. (But see note for same test in
2669 * DefineDomain.)
2670 */
2671 if (defaultExpr == NULL ||
2672 (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
2673 {
2674 /* Default is NULL, drop it */
2675 defaultExpr = NULL;
2676 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2677 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2678 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2679 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2680 }
2681 else
2682 {
2683 /*
2684 * Expression must be stored as a nodeToString result, but we also
2685 * require a valid textual representation (mainly to make life
2686 * easier for pg_dump).
2687 */
2688 defaultValue = deparse_expression(defaultExpr,
2689 NIL, false, false);
2690
2691 /*
2692 * Form an updated tuple with the new default and write it back.
2693 */
2694 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2695
2696 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2697 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2698 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2699 }
2700 }
2701 else
2702 {
2703 /* ALTER ... DROP DEFAULT */
2704 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2705 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2706 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2707 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2708 }
2709
2710 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2711 new_record, new_record_nulls,
2712 new_record_repl);
2713
2714 CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2715
2716 /* Rebuild dependencies */
2717 GenerateTypeDependencies(newtuple,
2718 rel,
2719 defaultExpr,
2720 NULL, /* don't have typacl handy */
2721 0, /* relation kind is n/a */
2722 false, /* a domain isn't an implicit array */
2723 false, /* nor is it any kind of dependent type */
2724 false, /* don't touch extension membership */
2725 true); /* We do need to rebuild dependencies */
2726
2727 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2728
2729 ObjectAddressSet(address, TypeRelationId, domainoid);
2730
2731 /* Clean up */
2733 heap_freetuple(newtuple);
2734
2735 return address;
2736}
2737
2738/*
2739 * AlterDomainNotNull
2740 *
2741 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2742 *
2743 * Returns ObjectAddress of the modified domain.
2744 */
2746AlterDomainNotNull(List *names, bool notNull)
2747{
2748 TypeName *typename;
2749 Oid domainoid;
2750 Relation typrel;
2751 HeapTuple tup;
2752 Form_pg_type typTup;
2754
2755 /* Make a TypeName so we can use standard type lookup machinery */
2756 typename = makeTypeNameFromNameList(names);
2757 domainoid = typenameTypeId(NULL, typename);
2758
2759 /* Look up the domain in the type table */
2760 typrel = table_open(TypeRelationId, RowExclusiveLock);
2761
2762 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2763 if (!HeapTupleIsValid(tup))
2764 elog(ERROR, "cache lookup failed for type %u", domainoid);
2765 typTup = (Form_pg_type) GETSTRUCT(tup);
2766
2767 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2768 checkDomainOwner(tup);
2769
2770 /* Is the domain already set to the desired constraint? */
2771 if (typTup->typnotnull == notNull)
2772 {
2774 return address;
2775 }
2776
2777 if (notNull)
2778 {
2779 Constraint *constr;
2780
2781 constr = makeNode(Constraint);
2782 constr->contype = CONSTR_NOTNULL;
2783 constr->initially_valid = true;
2784 constr->location = -1;
2785
2786 domainAddNotNullConstraint(domainoid, typTup->typnamespace,
2787 typTup->typbasetype, typTup->typtypmod,
2788 constr, NameStr(typTup->typname), NULL);
2789
2791 }
2792 else
2793 {
2794 HeapTuple conTup;
2795 ObjectAddress conobj;
2796
2797 conTup = findDomainNotNullConstraint(domainoid);
2798 if (conTup == NULL)
2799 elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
2800
2801 ObjectAddressSet(conobj, ConstraintRelationId, ((Form_pg_constraint) GETSTRUCT(conTup))->oid);
2802 performDeletion(&conobj, DROP_RESTRICT, 0);
2803 }
2804
2805 /*
2806 * Okay to update pg_type row. We can scribble on typTup because it's a
2807 * copy.
2808 */
2809 typTup->typnotnull = notNull;
2810
2811 CatalogTupleUpdate(typrel, &tup->t_self, tup);
2812
2813 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2814
2815 ObjectAddressSet(address, TypeRelationId, domainoid);
2816
2817 /* Clean up */
2818 heap_freetuple(tup);
2820
2821 return address;
2822}
2823
2824/*
2825 * AlterDomainDropConstraint
2826 *
2827 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2828 *
2829 * Returns ObjectAddress of the modified domain.
2830 */
2832AlterDomainDropConstraint(List *names, const char *constrName,
2833 DropBehavior behavior, bool missing_ok)
2834{
2835 TypeName *typename;
2836 Oid domainoid;
2837 HeapTuple tup;
2838 Relation rel;
2839 Relation conrel;
2840 SysScanDesc conscan;
2841 ScanKeyData skey[3];
2842 HeapTuple contup;
2843 bool found = false;
2844 ObjectAddress address;
2845
2846 /* Make a TypeName so we can use standard type lookup machinery */
2847 typename = makeTypeNameFromNameList(names);
2848 domainoid = typenameTypeId(NULL, typename);
2849
2850 /* Look up the domain in the type table */
2851 rel = table_open(TypeRelationId, RowExclusiveLock);
2852
2853 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2854 if (!HeapTupleIsValid(tup))
2855 elog(ERROR, "cache lookup failed for type %u", domainoid);
2856
2857 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2858 checkDomainOwner(tup);
2859
2860 /* Grab an appropriate lock on the pg_constraint relation */
2861 conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2862
2863 /* Find and remove the target constraint */
2864 ScanKeyInit(&skey[0],
2865 Anum_pg_constraint_conrelid,
2866 BTEqualStrategyNumber, F_OIDEQ,
2868 ScanKeyInit(&skey[1],
2869 Anum_pg_constraint_contypid,
2870 BTEqualStrategyNumber, F_OIDEQ,
2871 ObjectIdGetDatum(domainoid));
2872 ScanKeyInit(&skey[2],
2873 Anum_pg_constraint_conname,
2874 BTEqualStrategyNumber, F_NAMEEQ,
2875 CStringGetDatum(constrName));
2876
2877 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2878 NULL, 3, skey);
2879
2880 /* There can be at most one matching row */
2881 if ((contup = systable_getnext(conscan)) != NULL)
2882 {
2883 Form_pg_constraint construct = (Form_pg_constraint) GETSTRUCT(contup);
2884 ObjectAddress conobj;
2885
2886 if (construct->contype == CONSTRAINT_NOTNULL)
2887 {
2888 ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2889 CatalogTupleUpdate(rel, &tup->t_self, tup);
2890 }
2891
2892 conobj.classId = ConstraintRelationId;
2893 conobj.objectId = construct->oid;
2894 conobj.objectSubId = 0;
2895
2896 performDeletion(&conobj, behavior, 0);
2897 found = true;
2898 }
2899
2900 /* Clean up after the scan */
2901 systable_endscan(conscan);
2903
2904 if (!found)
2905 {
2906 if (!missing_ok)
2907 ereport(ERROR,
2908 (errcode(ERRCODE_UNDEFINED_OBJECT),
2909 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2910 constrName, TypeNameToString(typename))));
2911 else
2913 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2914 constrName, TypeNameToString(typename))));
2915 }
2916
2917 /*
2918 * We must send out an sinval message for the domain, to ensure that any
2919 * dependent plans get rebuilt. Since this command doesn't change the
2920 * domain's pg_type row, that won't happen automatically; do it manually.
2921 */
2922 CacheInvalidateHeapTuple(rel, tup, NULL);
2923
2924 ObjectAddressSet(address, TypeRelationId, domainoid);
2925
2926 /* Clean up */
2928
2929 return address;
2930}
2931
2932/*
2933 * AlterDomainAddConstraint
2934 *
2935 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2936 */
2938AlterDomainAddConstraint(List *names, Node *newConstraint,
2939 ObjectAddress *constrAddr)
2940{
2941 TypeName *typename;
2942 Oid domainoid;
2943 Relation typrel;
2944 HeapTuple tup;
2945 Form_pg_type typTup;
2946 Constraint *constr;
2947 char *ccbin;
2949
2950 /* Make a TypeName so we can use standard type lookup machinery */
2951 typename = makeTypeNameFromNameList(names);
2952 domainoid = typenameTypeId(NULL, typename);
2953
2954 /* Look up the domain in the type table */
2955 typrel = table_open(TypeRelationId, RowExclusiveLock);
2956
2957 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2958 if (!HeapTupleIsValid(tup))
2959 elog(ERROR, "cache lookup failed for type %u", domainoid);
2960 typTup = (Form_pg_type) GETSTRUCT(tup);
2961
2962 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2963 checkDomainOwner(tup);
2964
2965 if (!IsA(newConstraint, Constraint))
2966 elog(ERROR, "unrecognized node type: %d",
2967 (int) nodeTag(newConstraint));
2968
2969 constr = (Constraint *) newConstraint;
2970
2971 /* enforced by parser */
2972 Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
2973
2974 if (constr->contype == CONSTR_CHECK)
2975 {
2976 /*
2977 * First, process the constraint expression and add an entry to
2978 * pg_constraint.
2979 */
2980
2981 ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
2982 typTup->typbasetype, typTup->typtypmod,
2983 constr, NameStr(typTup->typname), constrAddr);
2984
2985
2986 /*
2987 * If requested to validate the constraint, test all values stored in
2988 * the attributes based on the domain the constraint is being added
2989 * to.
2990 */
2991 if (!constr->skip_validation)
2992 validateDomainCheckConstraint(domainoid, ccbin, ShareLock);
2993
2994 /*
2995 * We must send out an sinval message for the domain, to ensure that
2996 * any dependent plans get rebuilt. Since this command doesn't change
2997 * the domain's pg_type row, that won't happen automatically; do it
2998 * manually.
2999 */
3000 CacheInvalidateHeapTuple(typrel, tup, NULL);
3001 }
3002 else if (constr->contype == CONSTR_NOTNULL)
3003 {
3004 /* Is the domain already set NOT NULL? */
3005 if (typTup->typnotnull)
3006 {
3008 return address;
3009 }
3010 domainAddNotNullConstraint(domainoid, typTup->typnamespace,
3011 typTup->typbasetype, typTup->typtypmod,
3012 constr, NameStr(typTup->typname), constrAddr);
3013
3014 if (!constr->skip_validation)
3016
3017 typTup->typnotnull = true;
3018 CatalogTupleUpdate(typrel, &tup->t_self, tup);
3019 }
3020
3021 ObjectAddressSet(address, TypeRelationId, domainoid);
3022
3023 /* Clean up */
3025
3026 return address;
3027}
3028
3029/*
3030 * AlterDomainValidateConstraint
3031 *
3032 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
3033 */
3035AlterDomainValidateConstraint(List *names, const char *constrName)
3036{
3037 TypeName *typename;
3038 Oid domainoid;
3039 Relation typrel;
3040 Relation conrel;
3041 HeapTuple tup;
3043 Form_pg_constraint copy_con;
3044 char *conbin;
3045 SysScanDesc scan;
3046 Datum val;
3047 HeapTuple tuple;
3048 HeapTuple copyTuple;
3049 ScanKeyData skey[3];
3050 ObjectAddress address;
3051
3052 /* Make a TypeName so we can use standard type lookup machinery */
3053 typename = makeTypeNameFromNameList(names);
3054 domainoid = typenameTypeId(NULL, typename);
3055
3056 /* Look up the domain in the type table */
3057 typrel = table_open(TypeRelationId, AccessShareLock);
3058
3059 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
3060 if (!HeapTupleIsValid(tup))
3061 elog(ERROR, "cache lookup failed for type %u", domainoid);
3062
3063 /* Check it's a domain and check user has permission for ALTER DOMAIN */
3064 checkDomainOwner(tup);
3065
3066 /*
3067 * Find and check the target constraint
3068 */
3069 conrel = table_open(ConstraintRelationId, RowExclusiveLock);
3070
3071 ScanKeyInit(&skey[0],
3072 Anum_pg_constraint_conrelid,
3073 BTEqualStrategyNumber, F_OIDEQ,
3075 ScanKeyInit(&skey[1],
3076 Anum_pg_constraint_contypid,
3077 BTEqualStrategyNumber, F_OIDEQ,
3078 ObjectIdGetDatum(domainoid));
3079 ScanKeyInit(&skey[2],
3080 Anum_pg_constraint_conname,
3081 BTEqualStrategyNumber, F_NAMEEQ,
3082 CStringGetDatum(constrName));
3083
3084 scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
3085 NULL, 3, skey);
3086
3087 /* There can be at most one matching row */
3088 if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
3089 ereport(ERROR,
3090 (errcode(ERRCODE_UNDEFINED_OBJECT),
3091 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3092 constrName, TypeNameToString(typename))));
3093
3094 con = (Form_pg_constraint) GETSTRUCT(tuple);
3095 if (con->contype != CONSTRAINT_CHECK)
3096 ereport(ERROR,
3097 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3098 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
3099 constrName, TypeNameToString(typename))));
3100
3101 val = SysCacheGetAttrNotNull(CONSTROID, tuple, Anum_pg_constraint_conbin);
3102 conbin = TextDatumGetCString(val);
3103
3104 /*
3105 * Locking related relations with ShareUpdateExclusiveLock is ok because
3106 * not-yet-valid constraints are still enforced against concurrent inserts
3107 * or updates.
3108 */
3110
3111 /*
3112 * Now update the catalog, while we have the door open.
3113 */
3114 copyTuple = heap_copytuple(tuple);
3115 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
3116 copy_con->convalidated = true;
3117 CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
3118
3119 InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
3120
3121 ObjectAddressSet(address, TypeRelationId, domainoid);
3122
3123 heap_freetuple(copyTuple);
3124
3125 systable_endscan(scan);
3126
3129
3130 ReleaseSysCache(tup);
3131
3132 return address;
3133}
3134
3135/*
3136 * Verify that all columns currently using the domain are not null.
3137 */
3138static void
3140{
3141 List *rels;
3142 ListCell *rt;
3143
3144 /* Fetch relation list with attributes based on this domain */
3145 /* ShareLock is sufficient to prevent concurrent data changes */
3146
3147 rels = get_rels_with_domain(domainoid, ShareLock);
3148
3149 foreach(rt, rels)
3150 {
3151 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3152 Relation testrel = rtc->rel;
3153 TupleDesc tupdesc = RelationGetDescr(testrel);
3154 TupleTableSlot *slot;
3155 TableScanDesc scan;
3156 Snapshot snapshot;
3157
3158 /* Scan all tuples in this relation */
3159 snapshot = RegisterSnapshot(GetLatestSnapshot());
3160 scan = table_beginscan(testrel, snapshot, 0, NULL);
3161 slot = table_slot_create(testrel, NULL);
3162 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3163 {
3164 int i;
3165
3166 /* Test attributes that are of the domain */
3167 for (i = 0; i < rtc->natts; i++)
3168 {
3169 int attnum = rtc->atts[i];
3170 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3171
3172 if (slot_attisnull(slot, attnum))
3173 {
3174 /*
3175 * In principle the auxiliary information for this error
3176 * should be errdatatype(), but errtablecol() seems
3177 * considerably more useful in practice. Since this code
3178 * only executes in an ALTER DOMAIN command, the client
3179 * should already know which domain is in question.
3180 */
3181 ereport(ERROR,
3182 (errcode(ERRCODE_NOT_NULL_VIOLATION),
3183 errmsg("column \"%s\" of table \"%s\" contains null values",
3184 NameStr(attr->attname),
3185 RelationGetRelationName(testrel)),
3186 errtablecol(testrel, attnum)));
3187 }
3188 }
3189 }
3191 table_endscan(scan);
3192 UnregisterSnapshot(snapshot);
3193
3194 /* Close each rel after processing, but keep lock */
3195 table_close(testrel, NoLock);
3196 }
3197}
3198
3199/*
3200 * Verify that all columns currently using the domain satisfy the given check
3201 * constraint expression.
3202 *
3203 * It is used to validate existing constraints and to add newly created check
3204 * constraints to a domain.
3205 *
3206 * The lockmode is used for relations using the domain. It should be
3207 * ShareLock when adding a new constraint to domain. It can be
3208 * ShareUpdateExclusiveLock when validating an existing constraint.
3209 */
3210static void
3211validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
3212{
3213 Expr *expr = (Expr *) stringToNode(ccbin);
3214 List *rels;
3215 ListCell *rt;
3216 EState *estate;
3217 ExprContext *econtext;
3218 ExprState *exprstate;
3219
3220 /* Need an EState to run ExecEvalExpr */
3221 estate = CreateExecutorState();
3222 econtext = GetPerTupleExprContext(estate);
3223
3224 /* build execution state for expr */
3225 exprstate = ExecPrepareExpr(expr, estate);
3226
3227 /* Fetch relation list with attributes based on this domain */
3228 rels = get_rels_with_domain(domainoid, lockmode);
3229
3230 foreach(rt, rels)
3231 {
3232 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3233 Relation testrel = rtc->rel;
3234 TupleDesc tupdesc = RelationGetDescr(testrel);
3235 TupleTableSlot *slot;
3236 TableScanDesc scan;
3237 Snapshot snapshot;
3238
3239 /* Scan all tuples in this relation */
3240 snapshot = RegisterSnapshot(GetLatestSnapshot());
3241 scan = table_beginscan(testrel, snapshot, 0, NULL);
3242 slot = table_slot_create(testrel, NULL);
3243 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3244 {
3245 int i;
3246
3247 /* Test attributes that are of the domain */
3248 for (i = 0; i < rtc->natts; i++)
3249 {
3250 int attnum = rtc->atts[i];
3251 Datum d;
3252 bool isNull;
3253 Datum conResult;
3254
3255 d = slot_getattr(slot, attnum, &isNull);
3256
3257 econtext->domainValue_datum = d;
3258 econtext->domainValue_isNull = isNull;
3259
3260 conResult = ExecEvalExprSwitchContext(exprstate,
3261 econtext,
3262 &isNull);
3263
3264 if (!isNull && !DatumGetBool(conResult))
3265 {
3266 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3267
3268 /*
3269 * In principle the auxiliary information for this error
3270 * should be errdomainconstraint(), but errtablecol()
3271 * seems considerably more useful in practice. Since this
3272 * code only executes in an ALTER DOMAIN command, the
3273 * client should already know which domain is in question,
3274 * and which constraint too.
3275 */
3276 ereport(ERROR,
3277 (errcode(ERRCODE_CHECK_VIOLATION),
3278 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3279 NameStr(attr->attname),
3280 RelationGetRelationName(testrel)),
3281 errtablecol(testrel, attnum)));
3282 }
3283 }
3284
3285 ResetExprContext(econtext);
3286 }
3288 table_endscan(scan);
3289 UnregisterSnapshot(snapshot);
3290
3291 /* Hold relation lock till commit (XXX bad for concurrency) */
3292 table_close(testrel, NoLock);
3293 }
3294
3295 FreeExecutorState(estate);
3296}
3297
3298/*
3299 * get_rels_with_domain
3300 *
3301 * Fetch all relations / attributes which are using the domain
3302 *
3303 * The result is a list of RelToCheck structs, one for each distinct
3304 * relation, each containing one or more attribute numbers that are of
3305 * the domain type. We have opened each rel and acquired the specified lock
3306 * type on it.
3307 *
3308 * We support nested domains by including attributes that are of derived
3309 * domain types. Current callers do not need to distinguish between attributes
3310 * that are of exactly the given domain and those that are of derived domains.
3311 *
3312 * XXX this is completely broken because there is no way to lock the domain
3313 * to prevent columns from being added or dropped while our command runs.
3314 * We can partially protect against column drops by locking relations as we
3315 * come across them, but there is still a race condition (the window between
3316 * seeing a pg_depend entry and acquiring lock on the relation it references).
3317 * Also, holding locks on all these relations simultaneously creates a non-
3318 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
3319 * risk by using the weakest suitable lock (ShareLock for most callers).
3320 *
3321 * XXX the API for this is not sufficient to support checking domain values
3322 * that are inside container types, such as composite types, arrays, or
3323 * ranges. Currently we just error out if a container type containing the
3324 * target domain is stored anywhere.
3325 *
3326 * Generally used for retrieving a list of tests when adding
3327 * new constraints to a domain.
3328 */
3329static List *
3331{
3332 List *result = NIL;
3333 char *domainTypeName = format_type_be(domainOid);
3334 Relation depRel;
3335 ScanKeyData key[2];
3336 SysScanDesc depScan;
3337 HeapTuple depTup;
3338
3339 Assert(lockmode != NoLock);
3340
3341 /* since this function recurses, it could be driven to stack overflow */
3343
3344 /*
3345 * We scan pg_depend to find those things that depend on the domain. (We
3346 * assume we can ignore refobjsubid for a domain.)
3347 */
3348 depRel = table_open(DependRelationId, AccessShareLock);
3349
3350 ScanKeyInit(&key[0],
3351 Anum_pg_depend_refclassid,
3352 BTEqualStrategyNumber, F_OIDEQ,
3353 ObjectIdGetDatum(TypeRelationId));
3354 ScanKeyInit(&key[1],
3355 Anum_pg_depend_refobjid,
3356 BTEqualStrategyNumber, F_OIDEQ,
3357 ObjectIdGetDatum(domainOid));
3358
3359 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3360 NULL, 2, key);
3361
3362 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
3363 {
3364 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
3365 RelToCheck *rtc = NULL;
3366 ListCell *rellist;
3367 Form_pg_attribute pg_att;
3368 int ptr;
3369
3370 /* Check for directly dependent types */
3371 if (pg_depend->classid == TypeRelationId)
3372 {
3373 if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3374 {
3375 /*
3376 * This is a sub-domain, so recursively add dependent columns
3377 * to the output list. This is a bit inefficient since we may
3378 * fail to combine RelToCheck entries when attributes of the
3379 * same rel have different derived domain types, but it's
3380 * probably not worth improving.
3381 */
3382 result = list_concat(result,
3383 get_rels_with_domain(pg_depend->objid,
3384 lockmode));
3385 }
3386 else
3387 {
3388 /*
3389 * Otherwise, it is some container type using the domain, so
3390 * fail if there are any columns of this type.
3391 */
3392 find_composite_type_dependencies(pg_depend->objid,
3393 NULL,
3394 domainTypeName);
3395 }
3396 continue;
3397 }
3398
3399 /* Else, ignore dependees that aren't user columns of relations */
3400 /* (we assume system columns are never of domain types) */
3401 if (pg_depend->classid != RelationRelationId ||
3402 pg_depend->objsubid <= 0)
3403 continue;
3404
3405 /* See if we already have an entry for this relation */
3406 foreach(rellist, result)
3407 {
3408 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
3409
3410 if (RelationGetRelid(rt->rel) == pg_depend->objid)
3411 {
3412 rtc = rt;
3413 break;
3414 }
3415 }
3416
3417 if (rtc == NULL)
3418 {
3419 /* First attribute found for this relation */
3420 Relation rel;
3421
3422 /* Acquire requested lock on relation */
3423 rel = relation_open(pg_depend->objid, lockmode);
3424
3425 /*
3426 * Check to see if rowtype is stored anyplace as a composite-type
3427 * column; if so we have to fail, for now anyway.
3428 */
3429 if (OidIsValid(rel->rd_rel->reltype))
3431 NULL,
3432 domainTypeName);
3433
3434 /*
3435 * Otherwise, we can ignore relations except those with both
3436 * storage and user-chosen column types.
3437 *
3438 * XXX If an index-only scan could satisfy "col::some_domain" from
3439 * a suitable expression index, this should also check expression
3440 * index columns.
3441 */
3442 if (rel->rd_rel->relkind != RELKIND_RELATION &&
3443 rel->rd_rel->relkind != RELKIND_MATVIEW)
3444 {
3445 relation_close(rel, lockmode);
3446 continue;
3447 }
3448
3449 /* Build the RelToCheck entry with enough space for all atts */
3450 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
3451 rtc->rel = rel;
3452 rtc->natts = 0;
3453 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
3454 result = lappend(result, rtc);
3455 }
3456
3457 /*
3458 * Confirm column has not been dropped, and is of the expected type.
3459 * This defends against an ALTER DROP COLUMN occurring just before we
3460 * acquired lock ... but if the whole table were dropped, we'd still
3461 * have a problem.
3462 */
3463 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3464 continue;
3465 pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3466 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3467 continue;
3468
3469 /*
3470 * Okay, add column to result. We store the columns in column-number
3471 * order; this is just a hack to improve predictability of regression
3472 * test output ...
3473 */
3475
3476 ptr = rtc->natts++;
3477 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3478 {
3479 rtc->atts[ptr] = rtc->atts[ptr - 1];
3480 ptr--;
3481 }
3482 rtc->atts[ptr] = pg_depend->objsubid;
3483 }
3484
3485 systable_endscan(depScan);
3486
3488
3489 return result;
3490}
3491
3492/*
3493 * checkDomainOwner
3494 *
3495 * Check that the type is actually a domain and that the current user
3496 * has permission to do ALTER DOMAIN on it. Throw an error if not.
3497 */
3498void
3500{
3501 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3502
3503 /* Check that this is actually a domain */
3504 if (typTup->typtype != TYPTYPE_DOMAIN)
3505 ereport(ERROR,
3506 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3507 errmsg("%s is not a domain",
3508 format_type_be(typTup->oid))));
3509
3510 /* Permission check: must own type */
3511 if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
3513}
3514
3515/*
3516 * domainAddCheckConstraint - code shared between CREATE and ALTER DOMAIN
3517 */
3518static char *
3519domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3520 int typMod, Constraint *constr,
3521 const char *domainName, ObjectAddress *constrAddr)
3522{
3523 Node *expr;
3524 char *ccbin;
3525 ParseState *pstate;
3526 CoerceToDomainValue *domVal;
3527 Oid ccoid;
3528
3529 Assert(constr->contype == CONSTR_CHECK);
3530
3531 /*
3532 * Assign or validate constraint name
3533 */
3534 if (constr->conname)
3535 {
3537 domainOid,
3538 constr->conname))
3539 ereport(ERROR,
3541 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3542 constr->conname, domainName)));
3543 }
3544 else
3545 constr->conname = ChooseConstraintName(domainName,
3546 NULL,
3547 "check",
3548 domainNamespace,
3549 NIL);
3550
3551 /*
3552 * Convert the A_EXPR in raw_expr into an EXPR
3553 */
3554 pstate = make_parsestate(NULL);
3555
3556 /*
3557 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3558 * the expression. Note that it will appear to have the type of the base
3559 * type, not the domain. This seems correct since within the check
3560 * expression, we should not assume the input value can be considered a
3561 * member of the domain.
3562 */
3563 domVal = makeNode(CoerceToDomainValue);
3564 domVal->typeId = baseTypeOid;
3565 domVal->typeMod = typMod;
3566 domVal->collation = get_typcollation(baseTypeOid);
3567 domVal->location = -1; /* will be set when/if used */
3568
3570 pstate->p_ref_hook_state = domVal;
3571
3572 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3573
3574 /*
3575 * Make sure it yields a boolean result.
3576 */
3577 expr = coerce_to_boolean(pstate, expr, "CHECK");
3578
3579 /*
3580 * Fix up collation information.
3581 */
3582 assign_expr_collations(pstate, expr);
3583
3584 /*
3585 * Domains don't allow variables (this is probably dead code now that
3586 * add_missing_from is history, but let's be sure).
3587 */
3588 if (pstate->p_rtable != NIL ||
3589 contain_var_clause(expr))
3590 ereport(ERROR,
3591 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3592 errmsg("cannot use table references in domain check constraint")));
3593
3594 /*
3595 * Convert to string form for storage.
3596 */
3597 ccbin = nodeToString(expr);
3598
3599 /*
3600 * Store the constraint in pg_constraint
3601 */
3602 ccoid =
3603 CreateConstraintEntry(constr->conname, /* Constraint Name */
3604 domainNamespace, /* namespace */
3605 CONSTRAINT_CHECK, /* Constraint Type */
3606 false, /* Is Deferrable */
3607 false, /* Is Deferred */
3608 true, /* Is Enforced */
3609 !constr->skip_validation, /* Is Validated */
3610 InvalidOid, /* no parent constraint */
3611 InvalidOid, /* not a relation constraint */
3612 NULL,
3613 0,
3614 0,
3615 domainOid, /* domain constraint */
3616 InvalidOid, /* no associated index */
3617 InvalidOid, /* Foreign key fields */
3618 NULL,
3619 NULL,
3620 NULL,
3621 NULL,
3622 0,
3623 ' ',
3624 ' ',
3625 NULL,
3626 0,
3627 ' ',
3628 NULL, /* not an exclusion constraint */
3629 expr, /* Tree form of check constraint */
3630 ccbin, /* Binary form of check constraint */
3631 true, /* is local */
3632 0, /* inhcount */
3633 false, /* connoinherit */
3634 false, /* conperiod */
3635 false); /* is_internal */
3636 if (constrAddr)
3637 ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3638
3639 /*
3640 * Return the compiled constraint expression so the calling routine can
3641 * perform any additional required tests.
3642 */
3643 return ccbin;
3644}
3645
3646/* Parser pre_columnref_hook for domain CHECK constraint parsing */
3647static Node *
3649{
3650 /*
3651 * Check for a reference to "value", and if that's what it is, replace
3652 * with a CoerceToDomainValue as prepared for us by
3653 * domainAddCheckConstraint. (We handle VALUE as a name, not a keyword, to
3654 * avoid breaking a lot of applications that have used VALUE as a column
3655 * name in the past.)
3656 */
3657 if (list_length(cref->fields) == 1)
3658 {
3659 Node *field1 = (Node *) linitial(cref->fields);
3660 char *colname;
3661
3662 colname = strVal(field1);
3663 if (strcmp(colname, "value") == 0)
3664 {
3666
3667 /* Propagate location knowledge, if any */
3668 domVal->location = cref->location;
3669 return (Node *) domVal;
3670 }
3671 }
3672 return NULL;
3673}
3674
3675/*
3676 * domainAddNotNullConstraint - code shared between CREATE and ALTER DOMAIN
3677 */
3678static void
3679domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3680 int typMod, Constraint *constr,
3681 const char *domainName, ObjectAddress *constrAddr)
3682{
3683 Oid ccoid;
3684
3685 Assert(constr->contype == CONSTR_NOTNULL);
3686
3687 /*
3688 * Assign or validate constraint name
3689 */
3690 if (constr->conname)
3691 {
3693 domainOid,
3694 constr->conname))
3695 ereport(ERROR,
3697 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3698 constr->conname, domainName)));
3699 }
3700 else
3701 constr->conname = ChooseConstraintName(domainName,
3702 NULL,
3703 "not_null",
3704 domainNamespace,
3705 NIL);
3706
3707 /*
3708 * Store the constraint in pg_constraint
3709 */
3710 ccoid =
3711 CreateConstraintEntry(constr->conname, /* Constraint Name */
3712 domainNamespace, /* namespace */
3713 CONSTRAINT_NOTNULL, /* Constraint Type */
3714 false, /* Is Deferrable */
3715 false, /* Is Deferred */
3716 true, /* Is Enforced */
3717 !constr->skip_validation, /* Is Validated */
3718 InvalidOid, /* no parent constraint */
3719 InvalidOid, /* not a relation constraint */
3720 NULL,
3721 0,
3722 0,
3723 domainOid, /* domain constraint */
3724 InvalidOid, /* no associated index */
3725 InvalidOid, /* Foreign key fields */
3726 NULL,
3727 NULL,
3728 NULL,
3729 NULL,
3730 0,
3731 ' ',
3732 ' ',
3733 NULL,
3734 0,
3735 ' ',
3736 NULL, /* not an exclusion constraint */
3737 NULL,
3738 NULL,
3739 true, /* is local */
3740 0, /* inhcount */
3741 false, /* connoinherit */
3742 false, /* conperiod */
3743 false); /* is_internal */
3744
3745 if (constrAddr)
3746 ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3747}
3748
3749
3750/*
3751 * Execute ALTER TYPE RENAME
3752 */
3755{
3756 List *names = castNode(List, stmt->object);
3757 const char *newTypeName = stmt->newname;
3758 TypeName *typename;
3759 Oid typeOid;
3760 Relation rel;
3761 HeapTuple tup;
3762 Form_pg_type typTup;
3763 ObjectAddress address;
3764
3765 /* Make a TypeName so we can use standard type lookup machinery */
3766 typename = makeTypeNameFromNameList(names);
3767 typeOid = typenameTypeId(NULL, typename);
3768
3769 /* Look up the type in the type table */
3770 rel = table_open(TypeRelationId, RowExclusiveLock);
3771
3772 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3773 if (!HeapTupleIsValid(tup))
3774 elog(ERROR, "cache lookup failed for type %u", typeOid);
3775 typTup = (Form_pg_type) GETSTRUCT(tup);
3776
3777 /* check permissions on type */
3778 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3780
3781 /* ALTER DOMAIN used on a non-domain? */
3782 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3783 ereport(ERROR,
3784 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3785 errmsg("%s is not a domain",
3786 format_type_be(typeOid))));
3787
3788 /*
3789 * If it's a composite type, we need to check that it really is a
3790 * free-standing composite type, and not a table's rowtype. We want people
3791 * to use ALTER TABLE not ALTER TYPE for that case.
3792 */
3793 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3794 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3795 ereport(ERROR,
3796 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3797 errmsg("%s is a table's row type",
3798 format_type_be(typeOid)),
3799 /* translator: %s is an SQL ALTER command */
3800 errhint("Use %s instead.",
3801 "ALTER TABLE")));
3802
3803 /* don't allow direct alteration of array types, either */
3804 if (IsTrueArrayType(typTup))
3805 ereport(ERROR,
3806 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3807 errmsg("cannot alter array type %s",
3808 format_type_be(typeOid)),
3809 errhint("You can alter type %s, which will alter the array type as well.",
3810 format_type_be(typTup->typelem))));
3811
3812 /* we do allow separate renaming of multirange types, though */
3813
3814 /*
3815 * If type is composite we need to rename associated pg_class entry too.
3816 * RenameRelationInternal will call RenameTypeInternal automatically.
3817 */
3818 if (typTup->typtype == TYPTYPE_COMPOSITE)
3819 RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3820 else
3821 RenameTypeInternal(typeOid, newTypeName,
3822 typTup->typnamespace);
3823
3824 ObjectAddressSet(address, TypeRelationId, typeOid);
3825 /* Clean up */
3827
3828 return address;
3829}
3830
3831/*
3832 * Change the owner of a type.
3833 */
3835AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3836{
3837 TypeName *typename;
3838 Oid typeOid;
3839 Relation rel;
3840 HeapTuple tup;
3841 HeapTuple newtup;
3842 Form_pg_type typTup;
3843 AclResult aclresult;
3844 ObjectAddress address;
3845
3846 rel = table_open(TypeRelationId, RowExclusiveLock);
3847
3848 /* Make a TypeName so we can use standard type lookup machinery */
3849 typename = makeTypeNameFromNameList(names);
3850
3851 /* Use LookupTypeName here so that shell types can be processed */
3852 tup = LookupTypeName(NULL, typename, NULL, false);
3853 if (tup == NULL)
3854 ereport(ERROR,
3855 (errcode(ERRCODE_UNDEFINED_OBJECT),
3856 errmsg("type \"%s\" does not exist",
3857 TypeNameToString(typename))));
3858 typeOid = typeTypeId(tup);
3859
3860 /* Copy the syscache entry so we can scribble on it below */
3861 newtup = heap_copytuple(tup);
3862 ReleaseSysCache(tup);
3863 tup = newtup;
3864 typTup = (Form_pg_type) GETSTRUCT(tup);
3865
3866 /* Don't allow ALTER DOMAIN on a type */
3867 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3868 ereport(ERROR,
3869 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3870 errmsg("%s is not a domain",
3871 format_type_be(typeOid))));
3872
3873 /*
3874 * If it's a composite type, we need to check that it really is a
3875 * free-standing composite type, and not a table's rowtype. We want people
3876 * to use ALTER TABLE not ALTER TYPE for that case.
3877 */
3878 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3879 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3880 ereport(ERROR,
3881 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3882 errmsg("%s is a table's row type",
3883 format_type_be(typeOid)),
3884 /* translator: %s is an SQL ALTER command */
3885 errhint("Use %s instead.",
3886 "ALTER TABLE")));
3887
3888 /* don't allow direct alteration of array types, either */
3889 if (IsTrueArrayType(typTup))
3890 ereport(ERROR,
3891 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3892 errmsg("cannot alter array type %s",
3893 format_type_be(typeOid)),
3894 errhint("You can alter type %s, which will alter the array type as well.",
3895 format_type_be(typTup->typelem))));
3896
3897 /* don't allow direct alteration of multirange types, either */
3898 if (typTup->typtype == TYPTYPE_MULTIRANGE)
3899 {
3900 Oid rangetype = get_multirange_range(typeOid);
3901
3902 /* We don't expect get_multirange_range to fail, but cope if so */
3903 ereport(ERROR,
3904 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3905 errmsg("cannot alter multirange type %s",
3906 format_type_be(typeOid)),
3907 OidIsValid(rangetype) ?
3908 errhint("You can alter type %s, which will alter the multirange type as well.",
3909 format_type_be(rangetype)) : 0));
3910 }
3911
3912 /*
3913 * If the new owner is the same as the existing owner, consider the
3914 * command to have succeeded. This is for dump restoration purposes.
3915 */
3916 if (typTup->typowner != newOwnerId)
3917 {
3918 /* Superusers can always do it */
3919 if (!superuser())
3920 {
3921 /* Otherwise, must be owner of the existing object */
3922 if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
3924
3925 /* Must be able to become new owner */
3926 check_can_set_role(GetUserId(), newOwnerId);
3927
3928 /* New owner must have CREATE privilege on namespace */
3929 aclresult = object_aclcheck(NamespaceRelationId, typTup->typnamespace,
3930 newOwnerId,
3931 ACL_CREATE);
3932 if (aclresult != ACLCHECK_OK)
3933 aclcheck_error(aclresult, OBJECT_SCHEMA,
3934 get_namespace_name(typTup->typnamespace));
3935 }
3936
3937 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3938 }
3939
3940 ObjectAddressSet(address, TypeRelationId, typeOid);
3941
3942 /* Clean up */
3944
3945 return address;
3946}
3947
3948/*
3949 * AlterTypeOwner_oid - change type owner unconditionally
3950 *
3951 * This function recurses to handle dependent types (arrays and multiranges).
3952 * It invokes any necessary access object hooks. If hasDependEntry is true,
3953 * this function modifies the pg_shdepend entry appropriately (this should be
3954 * passed as false only for table rowtypes and dependent types).
3955 *
3956 * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3957 * OWNED BY. It assumes the caller has done all needed checks.
3958 */
3959void
3960AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3961{
3962 Relation rel;
3963 HeapTuple tup;
3964 Form_pg_type typTup;
3965
3966 rel = table_open(TypeRelationId, RowExclusiveLock);
3967
3968 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3969 if (!HeapTupleIsValid(tup))
3970 elog(ERROR, "cache lookup failed for type %u", typeOid);
3971 typTup = (Form_pg_type) GETSTRUCT(tup);
3972
3973 /*
3974 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3975 * the pg_class entry properly. That will call back to
3976 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3977 */
3978 if (typTup->typtype == TYPTYPE_COMPOSITE)
3979 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3980 else
3981 AlterTypeOwnerInternal(typeOid, newOwnerId);
3982
3983 /* Update owner dependency reference */
3984 if (hasDependEntry)
3985 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3986
3987 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3988
3989 ReleaseSysCache(tup);
3991}
3992
3993/*
3994 * AlterTypeOwnerInternal - bare-bones type owner change.
3995 *
3996 * This routine simply modifies the owner of a pg_type entry, and recurses
3997 * to handle any dependent types.
3998 */
3999void
4000AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
4001{
4002 Relation rel;
4003 HeapTuple tup;
4004 Form_pg_type typTup;
4005 Datum repl_val[Natts_pg_type];
4006 bool repl_null[Natts_pg_type];
4007 bool repl_repl[Natts_pg_type];
4008 Acl *newAcl;
4009 Datum aclDatum;
4010 bool isNull;
4011
4012 rel = table_open(TypeRelationId, RowExclusiveLock);
4013
4014 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
4015 if (!HeapTupleIsValid(tup))
4016 elog(ERROR, "cache lookup failed for type %u", typeOid);
4017 typTup = (Form_pg_type) GETSTRUCT(tup);
4018
4019 memset(repl_null, false, sizeof(repl_null));
4020 memset(repl_repl, false, sizeof(repl_repl));
4021
4022 repl_repl[Anum_pg_type_typowner - 1] = true;
4023 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
4024
4025 aclDatum = heap_getattr(tup,
4026 Anum_pg_type_typacl,
4027 RelationGetDescr(rel),
4028 &isNull);
4029 /* Null ACLs do not require changes */
4030 if (!isNull)
4031 {
4032 newAcl = aclnewowner(DatumGetAclP(aclDatum),
4033 typTup->typowner, newOwnerId);
4034 repl_repl[Anum_pg_type_typacl - 1] = true;
4035 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
4036 }
4037
4038 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
4039 repl_repl);
4040
4041 CatalogTupleUpdate(rel, &tup->t_self, tup);
4042
4043 /* If it has an array type, update that too */
4044 if (OidIsValid(typTup->typarray))
4045 AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
4046
4047 /* If it is a range type, update the associated multirange too */
4048 if (typTup->typtype == TYPTYPE_RANGE)
4049 {
4050 Oid multirange_typeid = get_range_multirange(typeOid);
4051
4052 if (!OidIsValid(multirange_typeid))
4053 ereport(ERROR,
4054 (errcode(ERRCODE_UNDEFINED_OBJECT),
4055 errmsg("could not find multirange type for data type %s",
4056 format_type_be(typeOid))));
4057 AlterTypeOwnerInternal(multirange_typeid, newOwnerId);
4058 }
4059
4060 /* Clean up */
4062}
4063
4064/*
4065 * Execute ALTER TYPE SET SCHEMA
4066 */
4068AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
4069 Oid *oldschema)
4070{
4071 TypeName *typename;
4072 Oid typeOid;
4073 Oid nspOid;
4074 Oid oldNspOid;
4075 ObjectAddresses *objsMoved;
4076 ObjectAddress myself;
4077
4078 /* Make a TypeName so we can use standard type lookup machinery */
4079 typename = makeTypeNameFromNameList(names);
4080 typeOid = typenameTypeId(NULL, typename);
4081
4082 /* Don't allow ALTER DOMAIN on a non-domain type */
4083 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
4084 ereport(ERROR,
4085 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4086 errmsg("%s is not a domain",
4087 format_type_be(typeOid))));
4088
4089 /* get schema OID and check its permissions */
4090 nspOid = LookupCreationNamespace(newschema);
4091
4092 objsMoved = new_object_addresses();
4093 oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, false, objsMoved);
4094 free_object_addresses(objsMoved);
4095
4096 if (oldschema)
4097 *oldschema = oldNspOid;
4098
4099 ObjectAddressSet(myself, TypeRelationId, typeOid);
4100
4101 return myself;
4102}
4103
4104/*
4105 * ALTER TYPE SET SCHEMA, where the caller has already looked up the OIDs
4106 * of the type and the target schema and checked the schema's privileges.
4107 *
4108 * If ignoreDependent is true, we silently ignore dependent types
4109 * (array types and table rowtypes) rather than raising errors.
4110 *
4111 * This entry point is exported for use by AlterObjectNamespace_oid,
4112 * which doesn't want errors when it passes OIDs of dependent types.
4113 *
4114 * Returns the type's old namespace OID, or InvalidOid if we did nothing.
4115 */
4116Oid
4117AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent,
4118 ObjectAddresses *objsMoved)
4119{
4120 Oid elemOid;
4121
4122 /* check permissions on type */
4123 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4125
4126 /* don't allow direct alteration of array types */
4127 elemOid = get_element_type(typeOid);
4128 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4129 {
4130 if (ignoreDependent)
4131 return InvalidOid;
4132 ereport(ERROR,
4133 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4134 errmsg("cannot alter array type %s",
4135 format_type_be(typeOid)),
4136 errhint("You can alter type %s, which will alter the array type as well.",
4137 format_type_be(elemOid))));
4138 }
4139
4140 /* and do the work */
4141 return AlterTypeNamespaceInternal(typeOid, nspOid,
4142 false, /* isImplicitArray */
4143 ignoreDependent, /* ignoreDependent */
4144 true, /* errorOnTableType */
4145 objsMoved);
4146}
4147
4148/*
4149 * Move specified type to new namespace.
4150 *
4151 * Caller must have already checked privileges.
4152 *
4153 * The function automatically recurses to process the type's array type,
4154 * if any. isImplicitArray should be true only when doing this internal
4155 * recursion (outside callers must never try to move an array type directly).
4156 *
4157 * If ignoreDependent is true, we silently don't process table types.
4158 *
4159 * If errorOnTableType is true, the function errors out if the type is
4160 * a table type. ALTER TABLE has to be used to move a table to a new
4161 * namespace. (This flag is ignored if ignoreDependent is true.)
4162 *
4163 * We also do nothing if the type is already listed in *objsMoved.
4164 * After a successful move, we add the type to *objsMoved.
4165 *
4166 * Returns the type's old namespace OID, or InvalidOid if we did nothing.
4167 */
4168Oid
4170 bool isImplicitArray,
4171 bool ignoreDependent,
4172 bool errorOnTableType,
4173 ObjectAddresses *objsMoved)
4174{
4175 Relation rel;
4176 HeapTuple tup;
4177 Form_pg_type typform;
4178 Oid oldNspOid;
4179 Oid arrayOid;
4180 bool isCompositeType;
4181 ObjectAddress thisobj;
4182
4183 /*
4184 * Make sure we haven't moved this object previously.
4185 */
4186 thisobj.classId = TypeRelationId;
4187 thisobj.objectId = typeOid;
4188 thisobj.objectSubId = 0;
4189
4190 if (object_address_present(&thisobj, objsMoved))
4191 return InvalidOid;
4192
4193 rel = table_open(TypeRelationId, RowExclusiveLock);
4194
4195 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
4196 if (!HeapTupleIsValid(tup))
4197 elog(ERROR, "cache lookup failed for type %u", typeOid);
4198 typform = (Form_pg_type) GETSTRUCT(tup);
4199
4200 oldNspOid = typform->typnamespace;
4201 arrayOid = typform->typarray;
4202
4203 /* If the type is already there, we scan skip these next few checks. */
4204 if (oldNspOid != nspOid)
4205 {
4206 /* common checks on switching namespaces */
4207 CheckSetNamespace(oldNspOid, nspOid);
4208
4209 /* check for duplicate name (more friendly than unique-index failure) */
4210 if (SearchSysCacheExists2(TYPENAMENSP,
4211 NameGetDatum(&typform->typname),
4212 ObjectIdGetDatum(nspOid)))
4213 ereport(ERROR,
4215 errmsg("type \"%s\" already exists in schema \"%s\"",
4216 NameStr(typform->typname),
4217 get_namespace_name(nspOid))));
4218 }
4219
4220 /* Detect whether type is a composite type (but not a table rowtype) */
4222 (typform->typtype == TYPTYPE_COMPOSITE &&
4223 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
4224
4225 /* Enforce not-table-type if requested */
4226 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType)
4227 {
4228 if (ignoreDependent)
4229 {
4231 return InvalidOid;
4232 }
4233 if (errorOnTableType)
4234 ereport(ERROR,
4235 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4236 errmsg("%s is a table's row type",
4237 format_type_be(typeOid)),
4238 /* translator: %s is an SQL ALTER command */
4239 errhint("Use %s instead.", "ALTER TABLE")));
4240 }
4241
4242 if (oldNspOid != nspOid)
4243 {
4244 /* OK, modify the pg_type row */
4245
4246 /* tup is a copy, so we can scribble directly on it */
4247 typform->typnamespace = nspOid;
4248
4249 CatalogTupleUpdate(rel, &tup->t_self, tup);
4250 }
4251
4252 /*
4253 * Composite types have pg_class entries.
4254 *
4255 * We need to modify the pg_class tuple as well to reflect the change of
4256 * schema.
4257 */
4258 if (isCompositeType)
4259 {
4260 Relation classRel;
4261
4262 classRel = table_open(RelationRelationId, RowExclusiveLock);
4263
4264 AlterRelationNamespaceInternal(classRel, typform->typrelid,
4265 oldNspOid, nspOid,
4266 false, objsMoved);
4267
4268 table_close(classRel, RowExclusiveLock);
4269
4270 /*
4271 * Check for constraints associated with the composite type (we don't
4272 * currently support this, but probably will someday).
4273 */
4274 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
4275 nspOid, false, objsMoved);
4276 }
4277 else
4278 {
4279 /* If it's a domain, it might have constraints */
4280 if (typform->typtype == TYPTYPE_DOMAIN)
4281 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
4282 objsMoved);
4283 }
4284
4285 /*
4286 * Update dependency on schema, if any --- a table rowtype has not got
4287 * one, and neither does an implicit array.
4288 */
4289 if (oldNspOid != nspOid &&
4290 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4291 !isImplicitArray)
4292 if (changeDependencyFor(TypeRelationId, typeOid,
4293 NamespaceRelationId, oldNspOid, nspOid) != 1)
4294 elog(ERROR, "could not change schema dependency for type \"%s\"",
4295 format_type_be(typeOid));
4296
4297 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4298
4299 heap_freetuple(tup);
4300
4302
4303 add_exact_object_address(&thisobj, objsMoved);
4304
4305 /* Recursively alter the associated array type, if any */
4306 if (OidIsValid(arrayOid))
4307 AlterTypeNamespaceInternal(arrayOid, nspOid,
4308 true, /* isImplicitArray */
4309 false, /* ignoreDependent */
4310 true, /* errorOnTableType */
4311 objsMoved);
4312
4313 return oldNspOid;
4314}
4315
4316/*
4317 * AlterType
4318 * ALTER TYPE <type> SET (option = ...)
4319 *
4320 * NOTE: the set of changes that can be allowed here is constrained by many
4321 * non-obvious implementation restrictions. Tread carefully when considering
4322 * adding new flexibility.
4323 */
4326{
4327 ObjectAddress address;
4328 Relation catalog;
4329 TypeName *typename;
4330 HeapTuple tup;
4331 Oid typeOid;
4332 Form_pg_type typForm;
4333 bool requireSuper = false;
4334 AlterTypeRecurseParams atparams;
4335 ListCell *pl;
4336
4337 catalog = table_open(TypeRelationId, RowExclusiveLock);
4338
4339 /* Make a TypeName so we can use standard type lookup machinery */
4340 typename = makeTypeNameFromNameList(stmt->typeName);
4341 tup = typenameType(NULL, typename, NULL);
4342
4343 typeOid = typeTypeId(tup);
4344 typForm = (Form_pg_type) GETSTRUCT(tup);
4345
4346 /* Process options */
4347 memset(&atparams, 0, sizeof(atparams));
4348 foreach(pl, stmt->options)
4349 {
4350 DefElem *defel = (DefElem *) lfirst(pl);
4351
4352 if (strcmp(defel->defname, "storage") == 0)
4353 {
4354 char *a = defGetString(defel);
4355
4356 if (pg_strcasecmp(a, "plain") == 0)
4357 atparams.storage = TYPSTORAGE_PLAIN;
4358 else if (pg_strcasecmp(a, "external") == 0)
4359 atparams.storage = TYPSTORAGE_EXTERNAL;
4360 else if (pg_strcasecmp(a, "extended") == 0)
4361 atparams.storage = TYPSTORAGE_EXTENDED;
4362 else if (pg_strcasecmp(a, "main") == 0)
4363 atparams.storage = TYPSTORAGE_MAIN;
4364 else
4365 ereport(ERROR,
4366 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4367 errmsg("storage \"%s\" not recognized", a)));
4368
4369 /*
4370 * Validate the storage request. If the type isn't varlena, it
4371 * certainly doesn't support non-PLAIN storage.
4372 */
4373 if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4374 ereport(ERROR,
4375 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4376 errmsg("fixed-size types must have storage PLAIN")));
4377
4378 /*
4379 * Switching from PLAIN to non-PLAIN is allowed, but it requires
4380 * superuser, since we can't validate that the type's C functions
4381 * will support it. Switching from non-PLAIN to PLAIN is
4382 * disallowed outright, because it's not practical to ensure that
4383 * no tables have toasted values of the type. Switching among
4384 * different non-PLAIN settings is OK, since it just constitutes a
4385 * change in the strategy requested for columns created in the
4386 * future.
4387 */
4388 if (atparams.storage != TYPSTORAGE_PLAIN &&
4389 typForm->typstorage == TYPSTORAGE_PLAIN)
4390 requireSuper = true;
4391 else if (atparams.storage == TYPSTORAGE_PLAIN &&
4392 typForm->typstorage != TYPSTORAGE_PLAIN)
4393 ereport(ERROR,
4394 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4395 errmsg("cannot change type's storage to PLAIN")));
4396
4397 atparams.updateStorage = true;
4398 }
4399 else if (strcmp(defel->defname, "receive") == 0)
4400 {
4401 if (defel->arg != NULL)
4402 atparams.receiveOid =
4404 typeOid);
4405 else
4406 atparams.receiveOid = InvalidOid; /* NONE, remove function */
4407 atparams.updateReceive = true;
4408 /* Replacing an I/O function requires superuser. */
4409 requireSuper = true;
4410 }
4411 else if (strcmp(defel->defname, "send") == 0)
4412 {
4413 if (defel->arg != NULL)
4414 atparams.sendOid =
4416 typeOid);
4417 else
4418 atparams.sendOid = InvalidOid; /* NONE, remove function */
4419 atparams.updateSend = true;
4420 /* Replacing an I/O function requires superuser. */
4421 requireSuper = true;
4422 }
4423 else if (strcmp(defel->defname, "typmod_in") == 0)
4424 {
4425 if (defel->arg != NULL)
4426 atparams.typmodinOid =
4428 else
4429 atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4430 atparams.updateTypmodin = true;
4431 /* Replacing an I/O function requires superuser. */
4432 requireSuper = true;
4433 }
4434 else if (strcmp(defel->defname, "typmod_out") == 0)
4435 {
4436 if (defel->arg != NULL)
4437 atparams.typmodoutOid =
4439 else
4440 atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4441 atparams.updateTypmodout = true;
4442 /* Replacing an I/O function requires superuser. */
4443 requireSuper = true;
4444 }
4445 else if (strcmp(defel->defname, "analyze") == 0)
4446 {
4447 if (defel->arg != NULL)
4448 atparams.analyzeOid =
4450 typeOid);
4451 else
4452 atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4453 atparams.updateAnalyze = true;
4454 /* Replacing an analyze function requires superuser. */
4455 requireSuper = true;
4456 }
4457 else if (strcmp(defel->defname, "subscript") == 0)
4458 {
4459 if (defel->arg != NULL)
4460 atparams.subscriptOid =
4462 typeOid);
4463 else
4464 atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4465 atparams.updateSubscript = true;
4466 /* Replacing a subscript function requires superuser. */
4467 requireSuper = true;
4468 }
4469
4470 /*
4471 * The rest of the options that CREATE accepts cannot be changed.
4472 * Check for them so that we can give a meaningful error message.
4473 */
4474 else if (strcmp(defel->defname, "input") == 0 ||
4475 strcmp(defel->defname, "output") == 0 ||
4476 strcmp(defel->defname, "internallength") == 0 ||
4477 strcmp(defel->defname, "passedbyvalue") == 0 ||
4478 strcmp(defel->defname, "alignment") == 0 ||
4479 strcmp(defel->defname, "like") == 0 ||
4480 strcmp(defel->defname, "category") == 0 ||
4481 strcmp(defel->defname, "preferred") == 0 ||
4482 strcmp(defel->defname, "default") == 0 ||
4483 strcmp(defel->defname, "element") == 0 ||
4484 strcmp(defel->defname, "delimiter") == 0 ||
4485 strcmp(defel->defname, "collatable") == 0)
4486 ereport(ERROR,
4487 (errcode(ERRCODE_SYNTAX_ERROR),
4488 errmsg("type attribute \"%s\" cannot be changed",
4489 defel->defname)));
4490 else
4491 ereport(ERROR,
4492 (errcode(ERRCODE_SYNTAX_ERROR),
4493 errmsg("type attribute \"%s\" not recognized",
4494 defel->defname)));
4495 }
4496
4497 /*
4498 * Permissions check. Require superuser if we decided the command
4499 * requires that, else must own the type.
4500 */
4501 if (requireSuper)
4502 {
4503 if (!superuser())
4504 ereport(ERROR,
4505 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4506 errmsg("must be superuser to alter a type")));
4507 }
4508 else
4509 {
4510 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4512 }
4513
4514 /*
4515 * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4516 * types. It would for example be highly unsafe, not to mention
4517 * pointless, to change the send/receive functions for a composite type.
4518 * Moreover, pg_dump has no support for changing these properties on
4519 * non-base types. We might weaken this someday, but not now.
4520 *
4521 * Note: if you weaken this enough to allow composite types, be sure to
4522 * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4523 */
4524 if (typForm->typtype != TYPTYPE_BASE)
4525 ereport(ERROR,
4526 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4527 errmsg("%s is not a base type",
4528 format_type_be(typeOid))));
4529
4530 /*
4531 * For the same reasons, don't allow direct alteration of array types.
4532 */
4533 if (IsTrueArrayType(typForm))
4534 ereport(ERROR,
4535 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4536 errmsg("%s is not a base type",
4537 format_type_be(typeOid))));
4538
4539 /* OK, recursively update this type and any arrays/domains over it */
4540 AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4541
4542 /* Clean up */
4543 ReleaseSysCache(tup);
4544
4545 table_close(catalog, RowExclusiveLock);
4546
4547 ObjectAddressSet(address, TypeRelationId, typeOid);
4548
4549 return address;
4550}
4551
4552/*
4553 * AlterTypeRecurse: one recursion step for AlterType()
4554 *
4555 * Apply the changes specified by "atparams" to the type identified by
4556 * "typeOid", whose existing pg_type tuple is "tup". If necessary,
4557 * recursively update its array type as well. Then search for any domains
4558 * over this type, and recursively apply (most of) the same changes to those
4559 * domains.
4560 *
4561 * We need this because the system generally assumes that a domain inherits
4562 * many properties from its base type. See DefineDomain() above for details
4563 * of what is inherited. Arrays inherit a smaller number of properties,
4564 * but not none.
4565 *
4566 * There's a race condition here, in that some other transaction could
4567 * concurrently add another domain atop this base type; we'd miss updating
4568 * that one. Hence, be wary of allowing ALTER TYPE to change properties for
4569 * which it'd be really fatal for a domain to be out of sync with its base
4570 * type (typlen, for example). In practice, races seem unlikely to be an
4571 * issue for plausible use-cases for ALTER TYPE. If one does happen, it could
4572 * be fixed by re-doing the same ALTER TYPE once all prior transactions have
4573 * committed.
4574 */
4575static void
4576AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
4577 HeapTuple tup, Relation catalog,
4578 AlterTypeRecurseParams *atparams)
4579{
4580 Datum values[Natts_pg_type];
4581 bool nulls[Natts_pg_type];
4582 bool replaces[Natts_pg_type];
4583 HeapTuple newtup;
4584 SysScanDesc scan;
4585 ScanKeyData key[1];
4586 HeapTuple domainTup;
4587
4588 /* Since this function recurses, it could be driven to stack overflow */
4590
4591 /* Update the current type's tuple */
4592 memset(values, 0, sizeof(values));
4593 memset(nulls, 0, sizeof(nulls));
4594 memset(replaces, 0, sizeof(replaces));
4595
4596 if (atparams->updateStorage)
4597 {
4598 replaces[Anum_pg_type_typstorage - 1] = true;
4599 values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
4600 }
4601 if (atparams->updateReceive)
4602 {
4603 replaces[Anum_pg_type_typreceive - 1] = true;
4604 values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
4605 }
4606 if (atparams->updateSend)
4607 {
4608 replaces[Anum_pg_type_typsend - 1] = true;
4609 values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
4610 }
4611 if (atparams->updateTypmodin)
4612 {
4613 replaces[Anum_pg_type_typmodin - 1] = true;
4614 values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
4615 }
4616 if (atparams->updateTypmodout)
4617 {
4618 replaces[Anum_pg_type_typmodout - 1] = true;
4619 values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
4620 }
4621 if (atparams->updateAnalyze)
4622 {
4623 replaces[Anum_pg_type_typanalyze - 1] = true;
4624 values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
4625 }
4626 if (atparams->updateSubscript)
4627 {
4628 replaces[Anum_pg_type_typsubscript - 1] = true;
4629 values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
4630 }
4631
4632 newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
4633 values, nulls, replaces);
4634
4635 CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
4636
4637 /* Rebuild dependencies for this type */
4639 catalog,
4640 NULL, /* don't have defaultExpr handy */
4641 NULL, /* don't have typacl handy */
4642 0, /* we rejected composite types above */
4643 isImplicitArray, /* it might be an array */
4644 isImplicitArray, /* dependent iff it's array */
4645 false, /* don't touch extension membership */
4646 true);
4647
4648 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4649
4650 /*
4651 * Arrays inherit their base type's typmodin and typmodout, but none of
4652 * the other properties we're concerned with here. Recurse to the array
4653 * type if needed.
4654 */
4655 if (!isImplicitArray &&
4656 (atparams->updateTypmodin || atparams->updateTypmodout))
4657 {
4658 Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4659
4660 if (OidIsValid(arrtypoid))
4661 {
4662 HeapTuple arrtup;
4663 AlterTypeRecurseParams arrparams;
4664
4665 arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
4666 if (!HeapTupleIsValid(arrtup))
4667 elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4668
4669 memset(&arrparams, 0, sizeof(arrparams));
4670 arrparams.updateTypmodin = atparams->updateTypmodin;
4671 arrparams.updateTypmodout = atparams->updateTypmodout;
4672 arrparams.typmodinOid = atparams->typmodinOid;
4673 arrparams.typmodoutOid = atparams->typmodoutOid;
4674
4675 AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
4676
4677 ReleaseSysCache(arrtup);
4678 }
4679 }
4680
4681 /*
4682 * Now we need to recurse to domains. However, some properties are not
4683 * inherited by domains, so clear the update flags for those.
4684 */
4685 atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4686 atparams->updateTypmodin = false; /* domains don't have typmods */
4687 atparams->updateTypmodout = false;
4688 atparams->updateSubscript = false; /* domains don't have subscriptors */
4689
4690 /* Skip the scan if nothing remains to be done */
4691 if (!(atparams->updateStorage ||
4692 atparams->updateSend ||
4693 atparams->updateAnalyze))
4694 return;
4695
4696 /* Search pg_type for possible domains over this type */
4697 ScanKeyInit(&key[0],
4698 Anum_pg_type_typbasetype,
4699 BTEqualStrategyNumber, F_OIDEQ,
4700 ObjectIdGetDatum(typeOid));
4701
4702 scan = systable_beginscan(catalog, InvalidOid, false,
4703 NULL, 1, key);
4704
4705 while ((domainTup = systable_getnext(scan)) != NULL)
4706 {
4707 Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
4708
4709 /*
4710 * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4711 * check
4712 */
4713 if (domainForm->typtype != TYPTYPE_DOMAIN)
4714 continue;
4715
4716 AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
4717 }
4718
4719 systable_endscan(scan);
4720}
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:756
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
Oid regproc
Definition: c.h:659
int16_t int16
Definition: c.h:538
int32_t int32
Definition: c.h:539
#define lengthof(array)
Definition: c.h:792
#define OidIsValid(objectId)
Definition: c.h:779
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:274
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2696
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2636
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2590
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2876
@ 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:99
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:736
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:2746
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2092
Oid AssignTypeMultirangeOid(void)
Definition: typecmds.c:2484
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:4576
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1353
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2249
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:2323
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent, ObjectAddresses *objsMoved)
Definition: typecmds.c:4117
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:2403
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2057
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:1849
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2146
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3519
ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
Definition: typecmds.c:3835
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2362
ObjectAddress AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
Definition: typecmds.c:2832
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:4000
ObjectAddress AlterEnum(AlterEnumStmt *stmt)
Definition: typecmds.c:1305
ObjectAddress AlterDomainAddConstraint(List *names, Node *newConstraint, ObjectAddress *constrAddr)
Definition: typecmds.c:2938
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:3035
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2276
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:2215
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:2181
ObjectAddress AlterDomainDefault(List *names, Node *defaultRaw)
Definition: typecmds.c:2617
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:109
ObjectAddress RenameType(RenameStmt *stmt)
Definition: typecmds.c:3754
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2451
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1994
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3499
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3960
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1774
ObjectAddress AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
Definition: typecmds.c:4068
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:3330
ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist)
Definition: typecmds.c:2559
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3679
Oid AssignTypeMultirangeArrayOid(void)
Definition: typecmds.c:2517
ObjectAddress AlterType(AlterTypeStmt *stmt)
Definition: typecmds.c:4325
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4169
static void validateDomainNotNullConstraint(Oid domainoid)
Definition: typecmds.c:3139
ObjectAddress DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
Definition: typecmds.c:1380
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
Definition: typecmds.c:3211
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3648
#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