Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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