PostgreSQL Source Code git master
Loading...
Searching...
No Matches
parse_utilcmd.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * parse_utilcmd.c
4 * Perform parse analysis work for various utility commands
5 *
6 * Formerly we did this work during parse_analyze_*() in analyze.c. However
7 * that is fairly unsafe in the presence of querytree caching, since any
8 * database state that we depend on in making the transformations might be
9 * obsolete by the time the utility command is executed; and utility commands
10 * have no infrastructure for holding locks or rechecking plan validity.
11 * Hence these functions are now called at the start of execution of their
12 * respective utility commands.
13 *
14 *
15 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
17 *
18 * src/backend/parser/parse_utilcmd.c
19 *
20 *-------------------------------------------------------------------------
21 */
22
23#include "postgres.h"
24
25#include "access/amapi.h"
26#include "access/attmap.h"
27#include "access/htup_details.h"
28#include "access/relation.h"
29#include "access/reloptions.h"
30#include "access/table.h"
32#include "catalog/dependency.h"
33#include "catalog/heap.h"
34#include "catalog/index.h"
35#include "catalog/namespace.h"
36#include "catalog/partition.h"
37#include "catalog/pg_am.h"
40#include "catalog/pg_opclass.h"
41#include "catalog/pg_operator.h"
43#include "catalog/pg_type.h"
44#include "commands/comment.h"
45#include "commands/defrem.h"
46#include "commands/sequence.h"
47#include "commands/tablecmds.h"
48#include "commands/tablespace.h"
49#include "miscadmin.h"
50#include "nodes/makefuncs.h"
51#include "nodes/nodeFuncs.h"
52#include "optimizer/optimizer.h"
53#include "parser/analyze.h"
54#include "parser/parse_clause.h"
55#include "parser/parse_coerce.h"
57#include "parser/parse_expr.h"
59#include "parser/parse_target.h"
60#include "parser/parse_type.h"
62#include "parser/parser.h"
66#include "utils/acl.h"
67#include "utils/builtins.h"
68#include "utils/lsyscache.h"
69#include "utils/partcache.h"
70#include "utils/rel.h"
71#include "utils/ruleutils.h"
72#include "utils/syscache.h"
73#include "utils/typcache.h"
74
75
76/* State shared by transformCreateStmt and its subroutines */
77typedef struct
78{
79 ParseState *pstate; /* overall parser state */
80 const char *stmtType; /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
81 RangeVar *relation; /* relation to create */
82 Relation rel; /* opened/locked rel, if ALTER */
83 List *inhRelations; /* relations to inherit from */
84 bool isforeign; /* true if CREATE/ALTER FOREIGN TABLE */
85 bool isalter; /* true if altering existing table */
86 List *columns; /* ColumnDef items */
87 List *ckconstraints; /* CHECK constraints */
88 List *nnconstraints; /* NOT NULL constraints */
89 List *fkconstraints; /* FOREIGN KEY constraints */
90 List *ixconstraints; /* index-creating constraints */
91 List *likeclauses; /* LIKE clauses that need post-processing */
92 List *blist; /* "before list" of things to do before
93 * creating the table */
94 List *alist; /* "after list" of things to do after creating
95 * the table */
96 IndexStmt *pkey; /* PRIMARY KEY index, if any */
97 bool ispartitioned; /* true if table is partitioned */
98 PartitionBoundSpec *partbound; /* transformed FOR VALUES */
99 bool ofType; /* true if statement contains OF typename */
101
102/* State shared by transformCreateSchemaStmtElements and its subroutines */
103typedef struct
104{
105 const char *schemaname; /* name of schema */
106 List *sequences; /* CREATE SEQUENCE items */
107 List *tables; /* CREATE TABLE items */
108 List *views; /* CREATE VIEW items */
109 List *indexes; /* CREATE INDEX items */
110 List *triggers; /* CREATE TRIGGER items */
111 List *grants; /* GRANT items */
113
114
118 Constraint *constraint);
121static void transformOfType(CreateStmtContext *cxt,
122 TypeName *ofTypename);
126 const AttrMap *attmap);
127static List *get_collation(Oid collation, Oid actual_datatype);
128static List *get_opclass(Oid opclass, Oid actual_datatype);
131 CreateStmtContext *cxt);
133 bool skipValidation,
134 bool isAddConstraint);
136 bool skipValidation);
140static void setSchemaName(const char *context_schema, char **stmt_schema_name);
142static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
143 Relation parent);
144static void validateInfiniteBounds(ParseState *pstate, List *blist);
146 const char *colName, Oid colType, int32 colTypmod,
148
149
150/*
151 * transformCreateStmt -
152 * parse analysis for CREATE TABLE
153 *
154 * Returns a List of utility commands to be done in sequence. One of these
155 * will be the transformed CreateStmt, but there may be additional actions
156 * to be done before and after the actual DefineRelation() call.
157 * In addition to normal utility commands such as AlterTableStmt and
158 * IndexStmt, the result list may contain TableLikeClause(s), representing
159 * the need to perform additional parse analysis after DefineRelation().
160 *
161 * SQL allows constraints to be scattered all over, so thumb through
162 * the columns and collect all constraints into one place.
163 * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
164 * then expand those into multiple IndexStmt blocks.
165 * - thomas 1997-12-02
166 */
167List *
168transformCreateStmt(CreateStmt *stmt, const char *queryString)
169{
170 ParseState *pstate;
172 List *result;
174 ListCell *elements;
178
179 /* Set up pstate */
180 pstate = make_parsestate(NULL);
181 pstate->p_sourcetext = queryString;
182
183 /*
184 * Look up the creation namespace. This also checks permissions on the
185 * target namespace, locks it against concurrent drops, checks for a
186 * preexisting relation in that namespace with the same name, and updates
187 * stmt->relation->relpersistence if the selected namespace is temporary.
188 */
190 stmt->relation->location);
195
196 /*
197 * If the relation already exists and the user specified "IF NOT EXISTS",
198 * bail out with a NOTICE.
199 */
200 if (stmt->if_not_exists && OidIsValid(existing_relid))
201 {
202 /*
203 * If we are in an extension script, insist that the pre-existing
204 * object be a member of the extension, to avoid security risks.
205 */
206 ObjectAddress address;
207
210
211 /* OK to skip */
214 errmsg("relation \"%s\" already exists, skipping",
215 stmt->relation->relname)));
216 return NIL;
217 }
218
219 /*
220 * If the target relation name isn't schema-qualified, make it so. This
221 * prevents some corner cases in which added-on rewritten commands might
222 * think they should apply to other relations that have the same name and
223 * are earlier in the search path. But a local temp table is effectively
224 * specified to be in pg_temp, so no need for anything extra in that case.
225 */
226 if (stmt->relation->schemaname == NULL
227 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
228 stmt->relation->schemaname = get_namespace_name(namespaceid);
229
230 /* Set up CreateStmtContext */
231 cxt.pstate = pstate;
233 {
234 cxt.stmtType = "CREATE FOREIGN TABLE";
235 cxt.isforeign = true;
236 }
237 else
238 {
239 cxt.stmtType = "CREATE TABLE";
240 cxt.isforeign = false;
241 }
242 cxt.relation = stmt->relation;
243 cxt.rel = NULL;
244 cxt.inhRelations = stmt->inhRelations;
245 cxt.isalter = false;
246 cxt.columns = NIL;
247 cxt.ckconstraints = NIL;
248 cxt.nnconstraints = NIL;
249 cxt.fkconstraints = NIL;
250 cxt.ixconstraints = NIL;
251 cxt.likeclauses = NIL;
252 cxt.blist = NIL;
253 cxt.alist = NIL;
254 cxt.pkey = NULL;
255 cxt.ispartitioned = stmt->partspec != NULL;
256 cxt.partbound = stmt->partbound;
257 cxt.ofType = (stmt->ofTypename != NULL);
258
259 Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
260
261 if (stmt->ofTypename)
262 transformOfType(&cxt, stmt->ofTypename);
263
264 if (stmt->partspec)
265 {
266 if (stmt->inhRelations && !stmt->partbound)
269 errmsg("cannot create partitioned table as inheritance child")));
270 }
271
272 /*
273 * Run through each primary element in the table creation clause. Separate
274 * column defs from constraints, and do preliminary analysis.
275 */
276 foreach(elements, stmt->tableElts)
277 {
278 Node *element = lfirst(elements);
279
280 switch (nodeTag(element))
281 {
282 case T_ColumnDef:
284 break;
285
286 case T_Constraint:
288 break;
289
292 break;
293
294 default:
295 elog(ERROR, "unrecognized node type: %d",
296 (int) nodeTag(element));
297 break;
298 }
299 }
300
301 /*
302 * Transfer anything we already have in cxt.alist into save_alist, to keep
303 * it separate from the output of transformIndexConstraints. (This may
304 * not be necessary anymore, but we'll keep doing it to preserve the
305 * historical order of execution of the alist commands.)
306 */
307 save_alist = cxt.alist;
308 cxt.alist = NIL;
309
310 Assert(stmt->constraints == NIL);
311
312 /*
313 * Before processing index constraints, which could include a primary key,
314 * we must scan all not-null constraints to propagate the is_not_null flag
315 * to each corresponding ColumnDef. This is necessary because table-level
316 * not-null constraints have not been marked in each ColumnDef, and the PK
317 * processing code needs to know whether one constraint has already been
318 * declared in order not to declare a redundant one.
319 */
321 {
322 char *colname = strVal(linitial(nn->keys));
323
325 {
326 /* not our column? */
327 if (strcmp(cd->colname, colname) != 0)
328 continue;
329 /* Already marked not-null? Nothing to do */
330 if (cd->is_not_null)
331 break;
332 /* Bingo, we're done for this constraint */
333 cd->is_not_null = true;
334 break;
335 }
336 }
337
338 /*
339 * Postprocess constraints that give rise to index definitions.
340 */
342
343 /*
344 * Re-consideration of LIKE clauses should happen after creation of
345 * indexes, but before creation of foreign keys. This order is critical
346 * because a LIKE clause may attempt to create a primary key. If there's
347 * also a pkey in the main CREATE TABLE list, creation of that will not
348 * check for a duplicate at runtime (since index_check_primary_key()
349 * expects that we rejected dups here). Creation of the LIKE-generated
350 * pkey behaves like ALTER TABLE ADD, so it will check, but obviously that
351 * only works if it happens second. On the other hand, we want to make
352 * pkeys before foreign key constraints, in case the user tries to make a
353 * self-referential FK.
354 */
355 cxt.alist = list_concat(cxt.alist, cxt.likeclauses);
356
357 /*
358 * Postprocess foreign-key constraints.
359 */
360 transformFKConstraints(&cxt, true, false);
361
362 /*
363 * Postprocess check constraints.
364 *
365 * For regular tables all constraints can be marked valid immediately,
366 * because the table is new therefore empty. Not so for foreign tables.
367 */
369
370 /*
371 * Output results.
372 */
373 stmt->tableElts = cxt.columns;
374 stmt->constraints = cxt.ckconstraints;
375 stmt->nnconstraints = cxt.nnconstraints;
376
377 result = lappend(cxt.blist, stmt);
378 result = list_concat(result, cxt.alist);
379 result = list_concat(result, save_alist);
380
381 return result;
382}
383
384/*
385 * generateSerialExtraStmts
386 * Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
387 * to create the sequence for a serial or identity column.
388 *
389 * This includes determining the name the sequence will have. The caller
390 * can ask to get back the name components by passing non-null pointers
391 * for snamespace_p and sname_p.
392 */
393static void
395 Oid seqtypid, List *seqoptions,
396 bool for_identity, bool col_exists,
397 char **snamespace_p, char **sname_p)
398{
403 char *snamespace;
404 char *sname;
405 char seqpersistence;
409
410 /* Make a copy of this as we may end up modifying it in the code below */
412
413 /*
414 * Check for non-SQL-standard options (not supported within CREATE
415 * SEQUENCE, because they'd be redundant), and remove them from the
416 * seqoptions list if found.
417 */
418 foreach(option, seqoptions)
419 {
421
422 if (strcmp(defel->defname, "sequence_name") == 0)
423 {
424 if (nameEl)
426 nameEl = defel;
428 }
429 else if (strcmp(defel->defname, "logged") == 0 ||
430 strcmp(defel->defname, "unlogged") == 0)
431 {
432 if (loggedEl)
434 loggedEl = defel;
436 }
437 }
438
439 /*
440 * Determine namespace and name to use for the sequence.
441 */
442 if (nameEl)
443 {
444 /* Use specified name */
446
448 if (!snamespace)
449 {
450 /* Given unqualified SEQUENCE NAME, select namespace */
451 if (cxt->rel)
453 else
456 }
457 sname = rv->relname;
458 }
459 else
460 {
461 /*
462 * Generate a name.
463 *
464 * Although we use ChooseRelationName, it's not guaranteed that the
465 * selected sequence name won't conflict; given sufficiently long
466 * field names, two different serial columns in the same table could
467 * be assigned the same sequence name, and we'd not notice since we
468 * aren't creating the sequence quite yet. In practice this seems
469 * quite unlikely to be a problem, especially since few people would
470 * need two serial columns in one table.
471 */
472 if (cxt->rel)
474 else
475 {
478 }
481 column->colname,
482 "seq",
484 false);
485 }
486
488 (errmsg_internal("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
489 cxt->stmtType, sname,
490 cxt->relation->relname, column->colname)));
491
492 /*
493 * Determine the persistence of the sequence. By default we copy the
494 * persistence of the table, but if LOGGED or UNLOGGED was specified, use
495 * that (as long as the table isn't TEMP).
496 *
497 * For CREATE TABLE, we get the persistence from cxt->relation, which
498 * comes from the CreateStmt in progress. For ALTER TABLE, the parser
499 * won't set cxt->relation->relpersistence, but we have cxt->rel as the
500 * existing table, so we copy the persistence from there.
501 */
502 seqpersistence = cxt->rel ? cxt->rel->rd_rel->relpersistence : cxt->relation->relpersistence;
503 if (loggedEl)
504 {
508 errmsg("cannot set logged status of a temporary sequence"),
509 parser_errposition(cxt->pstate, loggedEl->location)));
510 else if (strcmp(loggedEl->defname, "logged") == 0)
512 else
514 }
515
516 /*
517 * Build a CREATE SEQUENCE command to create the sequence object, and add
518 * it to the list of things to be done before this CREATE/ALTER TABLE.
519 */
521 seqstmt->for_identity = for_identity;
522 seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
523 seqstmt->sequence->relpersistence = seqpersistence;
524 seqstmt->options = seqoptions;
525
526 /*
527 * If a sequence data type was specified, add it to the options. Prepend
528 * to the list rather than append; in case a user supplied their own AS
529 * clause, the "redundant options" error will point to their occurrence,
530 * not our synthetic one.
531 */
532 if (seqtypid)
533 seqstmt->options = lcons(makeDefElem("as",
534 (Node *) makeTypeNameFromOid(seqtypid, -1),
535 -1),
536 seqstmt->options);
537
538 /*
539 * If this is ALTER ADD COLUMN, make sure the sequence will be owned by
540 * the table's owner. The current user might be someone else (perhaps a
541 * superuser, or someone who's only a member of the owning role), but the
542 * SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
543 * exactly the same owning role.
544 */
545 if (cxt->rel)
546 seqstmt->ownerId = cxt->rel->rd_rel->relowner;
547 else
548 seqstmt->ownerId = InvalidOid;
549
550 cxt->blist = lappend(cxt->blist, seqstmt);
551
552 /*
553 * Store the identity sequence name that we decided on. ALTER TABLE ...
554 * ADD COLUMN ... IDENTITY needs this so that it can fill the new column
555 * with values from the sequence, while the association of the sequence
556 * with the table is not set until after the ALTER TABLE.
557 */
558 column->identitySequence = seqstmt->sequence;
559
560 /*
561 * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
562 * owned by this column, and add it to the appropriate list of things to
563 * be done along with this CREATE/ALTER TABLE. In a CREATE or ALTER ADD
564 * COLUMN, it must be done after the statement because we don't know the
565 * column's attnum yet. But if we do have the attnum (in AT_AddIdentity),
566 * we can do the marking immediately, which improves some ALTER TABLE
567 * behaviors.
568 */
570 altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
573 makeString(column->colname));
574 altseqstmt->options = list_make1(makeDefElem("owned_by",
575 (Node *) attnamelist, -1));
576 altseqstmt->for_identity = for_identity;
577
578 if (col_exists)
579 cxt->blist = lappend(cxt->blist, altseqstmt);
580 else
581 cxt->alist = lappend(cxt->alist, altseqstmt);
582
583 if (snamespace_p)
585 if (sname_p)
586 *sname_p = sname;
587}
588
589/*
590 * transformColumnDefinition -
591 * transform a single ColumnDef within CREATE TABLE
592 * Also used in ALTER TABLE ADD COLUMN
593 */
594static void
596{
597 bool is_serial;
598 bool saw_nullable;
599 bool saw_default;
600 bool saw_identity;
601 bool saw_generated;
602 bool need_notnull = false;
603 bool disallow_noinherit_notnull = false;
605
606 cxt->columns = lappend(cxt->columns, column);
607
608 /* Check for SERIAL pseudo-types */
609 is_serial = false;
610 if (column->typeName
611 && list_length(column->typeName->names) == 1
612 && !column->typeName->pct_type)
613 {
614 char *typname = strVal(linitial(column->typeName->names));
615
616 if (strcmp(typname, "smallserial") == 0 ||
617 strcmp(typname, "serial2") == 0)
618 {
619 is_serial = true;
620 column->typeName->names = NIL;
621 column->typeName->typeOid = INT2OID;
622 }
623 else if (strcmp(typname, "serial") == 0 ||
624 strcmp(typname, "serial4") == 0)
625 {
626 is_serial = true;
627 column->typeName->names = NIL;
628 column->typeName->typeOid = INT4OID;
629 }
630 else if (strcmp(typname, "bigserial") == 0 ||
631 strcmp(typname, "serial8") == 0)
632 {
633 is_serial = true;
634 column->typeName->names = NIL;
635 column->typeName->typeOid = INT8OID;
636 }
637
638 /*
639 * We have to reject "serial[]" explicitly, because once we've set
640 * typeid, LookupTypeName won't notice arrayBounds. We don't need any
641 * special coding for serial(typmod) though.
642 */
643 if (is_serial && column->typeName->arrayBounds != NIL)
646 errmsg("array of serial is not implemented"),
648 column->typeName->location)));
649 }
650
651 /* Do necessary work on the column type declaration */
652 if (column->typeName)
654
655 /* Special actions for SERIAL pseudo-types */
656 if (is_serial)
657 {
658 char *snamespace;
659 char *sname;
660 char *qstring;
664 Constraint *constraint;
665
667 column->typeName->typeOid, NIL,
668 false, false,
669 &snamespace, &sname);
670
671 /*
672 * Create appropriate constraints for SERIAL. We do this in full,
673 * rather than shortcutting, so that we will detect any conflicting
674 * constraints the user wrote (like a different DEFAULT).
675 *
676 * Create an expression tree representing the function call
677 * nextval('sequencename'). We cannot reduce the raw tree to cooked
678 * form until after the sequence is created, but there's no need to do
679 * so.
680 */
683 snamenode->val.node.type = T_String;
684 snamenode->val.sval.sval = qstring;
685 snamenode->location = -1;
687 castnode->typeName = SystemTypeName("regclass");
688 castnode->arg = (Node *) snamenode;
689 castnode->location = -1;
693 -1);
694 constraint = makeNode(Constraint);
695 constraint->contype = CONSTR_DEFAULT;
696 constraint->location = -1;
697 constraint->raw_expr = (Node *) funccallnode;
698 constraint->cooked_expr = NULL;
699 column->constraints = lappend(column->constraints, constraint);
700
701 /* have a not-null constraint added later */
702 need_notnull = true;
704 }
705
706 /* Process column constraints, if any... */
707 transformConstraintAttrs(cxt, column->constraints);
708
709 /*
710 * First, scan the column's constraints to see if a not-null constraint
711 * that we add must be prevented from being NO INHERIT. This should be
712 * enforced only for PRIMARY KEY, not IDENTITY or SERIAL. However, if the
713 * not-null constraint is specified as a table constraint rather than as a
714 * column constraint, AddRelationNotNullConstraints would raise an error
715 * if a NO INHERIT mismatch is found. To avoid inconsistently disallowing
716 * it in the table constraint case but not the column constraint case, we
717 * disallow it here as well. Maybe AddRelationNotNullConstraints can be
718 * improved someday, so that it doesn't complain, and then we can remove
719 * the restriction for SERIAL and IDENTITY here as well.
720 */
722 {
723 foreach_node(Constraint, constraint, column->constraints)
724 {
725 switch (constraint->contype)
726 {
727 case CONSTR_IDENTITY:
728 case CONSTR_PRIMARY:
730 break;
731 default:
732 break;
733 }
734 }
735 }
736
737 /* Now scan them again to do full processing */
738 saw_nullable = false;
739 saw_default = false;
740 saw_identity = false;
741 saw_generated = false;
742
743 foreach_node(Constraint, constraint, column->constraints)
744 {
745 switch (constraint->contype)
746 {
747 case CONSTR_NULL:
748 if ((saw_nullable && column->is_not_null) || need_notnull)
751 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
752 column->colname, cxt->relation->relname),
754 constraint->location)));
755 column->is_not_null = false;
756 saw_nullable = true;
757 break;
758
759 case CONSTR_NOTNULL:
760 if (cxt->ispartitioned && constraint->is_no_inherit)
763 errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
764
765 /* Disallow conflicting [NOT] NULL markings */
766 if (saw_nullable && !column->is_not_null)
769 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
770 column->colname, cxt->relation->relname),
772 constraint->location)));
773
774 if (disallow_noinherit_notnull && constraint->is_no_inherit)
777 errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
778 column->colname));
779
780 /*
781 * If this is the first time we see this column being marked
782 * not-null, add the constraint entry and keep track of it.
783 * Also, remove previous markings that we need one.
784 *
785 * If this is a redundant not-null specification, just check
786 * that it doesn't conflict with what was specified earlier.
787 *
788 * Any conflicts with table constraints will be further
789 * checked in AddRelationNotNullConstraints().
790 */
791 if (!column->is_not_null)
792 {
793 column->is_not_null = true;
794 saw_nullable = true;
795 need_notnull = false;
796
797 constraint->keys = list_make1(makeString(column->colname));
798 notnull_constraint = constraint;
799 cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
800 }
801 else if (notnull_constraint)
802 {
803 if (constraint->conname &&
804 notnull_constraint->conname &&
805 strcmp(notnull_constraint->conname, constraint->conname) != 0)
806 elog(ERROR, "conflicting not-null constraint names \"%s\" and \"%s\"",
807 notnull_constraint->conname, constraint->conname);
808
809 if (notnull_constraint->is_no_inherit != constraint->is_no_inherit)
812 errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
813 column->colname));
814
815 if (!notnull_constraint->conname && constraint->conname)
816 notnull_constraint->conname = constraint->conname;
817 }
818
819 break;
820
821 case CONSTR_DEFAULT:
822 if (saw_default)
825 errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
826 column->colname, cxt->relation->relname),
828 constraint->location)));
829 column->raw_default = constraint->raw_expr;
830 Assert(constraint->cooked_expr == NULL);
831 saw_default = true;
832 break;
833
834 case CONSTR_IDENTITY:
835 {
836 Type ctype;
837 Oid typeOid;
838
839 if (cxt->ofType)
842 errmsg("identity columns are not supported on typed tables")));
843 if (cxt->partbound)
846 errmsg("identity columns are not supported on partitions")));
847
848 ctype = typenameType(cxt->pstate, column->typeName, NULL);
849 typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid;
850 ReleaseSysCache(ctype);
851
852 if (saw_identity)
855 errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
856 column->colname, cxt->relation->relname),
858 constraint->location)));
859
861 typeOid, constraint->options,
862 true, false,
863 NULL, NULL);
864
865 column->identity = constraint->generated_when;
866 saw_identity = true;
867
868 /*
869 * Identity columns are always NOT NULL, but we may have a
870 * constraint already.
871 */
872 if (!saw_nullable)
873 need_notnull = true;
874 else if (!column->is_not_null)
877 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
878 column->colname, cxt->relation->relname),
880 constraint->location)));
881 break;
882 }
883
884 case CONSTR_GENERATED:
885 if (cxt->ofType)
888 errmsg("generated columns are not supported on typed tables")));
889 if (saw_generated)
892 errmsg("multiple generation clauses specified for column \"%s\" of table \"%s\"",
893 column->colname, cxt->relation->relname),
895 constraint->location)));
896 column->generated = constraint->generated_kind;
897 column->raw_default = constraint->raw_expr;
898 Assert(constraint->cooked_expr == NULL);
899 saw_generated = true;
900 break;
901
902 case CONSTR_CHECK:
903 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
904 break;
905
906 case CONSTR_PRIMARY:
907 if (saw_nullable && !column->is_not_null)
910 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
911 column->colname, cxt->relation->relname),
913 constraint->location)));
914 need_notnull = true;
915
916 if (cxt->isforeign)
919 errmsg("primary key constraints are not supported on foreign tables"),
921 constraint->location)));
923
924 case CONSTR_UNIQUE:
925 if (cxt->isforeign)
928 errmsg("unique constraints are not supported on foreign tables"),
930 constraint->location)));
931 if (constraint->keys == NIL)
932 constraint->keys = list_make1(makeString(column->colname));
933 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
934 break;
935
936 case CONSTR_EXCLUSION:
937 /* grammar does not allow EXCLUDE as a column constraint */
938 elog(ERROR, "column exclusion constraints are not supported");
939 break;
940
941 case CONSTR_FOREIGN:
942 if (cxt->isforeign)
945 errmsg("foreign key constraints are not supported on foreign tables"),
947 constraint->location)));
948
949 /*
950 * Fill in the current attribute's name and throw it into the
951 * list of FK constraints to be processed later.
952 */
953 constraint->fk_attrs = list_make1(makeString(column->colname));
954 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
955 break;
956
963 /* transformConstraintAttrs took care of these */
964 break;
965
966 default:
967 elog(ERROR, "unrecognized constraint type: %d",
968 constraint->contype);
969 break;
970 }
971
975 errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
976 column->colname, cxt->relation->relname),
978 constraint->location)));
979
983 errmsg("both default and generation expression specified for column \"%s\" of table \"%s\"",
984 column->colname, cxt->relation->relname),
986 constraint->location)));
987
991 errmsg("both identity and generation expression specified for column \"%s\" of table \"%s\"",
992 column->colname, cxt->relation->relname),
994 constraint->location)));
995 }
996
997 /*
998 * If we need a not-null constraint for PRIMARY KEY, SERIAL or IDENTITY,
999 * and one was not explicitly specified, add one now.
1000 */
1001 if (need_notnull && !(saw_nullable && column->is_not_null))
1002 {
1003 column->is_not_null = true;
1006 }
1007
1008 /*
1009 * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
1010 * per-column foreign data wrapper options to this column after creation.
1011 */
1012 if (column->fdwoptions != NIL)
1013 {
1015 AlterTableCmd *cmd;
1016
1017 cmd = makeNode(AlterTableCmd);
1019 cmd->name = column->colname;
1020 cmd->def = (Node *) column->fdwoptions;
1021 cmd->behavior = DROP_RESTRICT;
1022 cmd->missing_ok = false;
1023
1025 stmt->relation = cxt->relation;
1026 stmt->cmds = NIL;
1027 stmt->objtype = OBJECT_FOREIGN_TABLE;
1028 stmt->cmds = lappend(stmt->cmds, cmd);
1029
1030 cxt->alist = lappend(cxt->alist, stmt);
1031 }
1032}
1033
1034/*
1035 * transformTableConstraint
1036 * transform a Constraint node within CREATE TABLE or ALTER TABLE
1037 */
1038static void
1040{
1041 switch (constraint->contype)
1042 {
1043 case CONSTR_PRIMARY:
1044 if (cxt->isforeign)
1045 ereport(ERROR,
1047 errmsg("primary key constraints are not supported on foreign tables"),
1049 constraint->location)));
1050 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1051 break;
1052
1053 case CONSTR_UNIQUE:
1054 if (cxt->isforeign)
1055 ereport(ERROR,
1057 errmsg("unique constraints are not supported on foreign tables"),
1059 constraint->location)));
1060 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1061 break;
1062
1063 case CONSTR_EXCLUSION:
1064 if (cxt->isforeign)
1065 ereport(ERROR,
1067 errmsg("exclusion constraints are not supported on foreign tables"),
1069 constraint->location)));
1070 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1071 break;
1072
1073 case CONSTR_CHECK:
1074 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
1075 break;
1076
1077 case CONSTR_NOTNULL:
1078 if (cxt->ispartitioned && constraint->is_no_inherit)
1079 ereport(ERROR,
1081 errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
1082
1083 cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
1084 break;
1085
1086 case CONSTR_FOREIGN:
1087 if (cxt->isforeign)
1088 ereport(ERROR,
1090 errmsg("foreign key constraints are not supported on foreign tables"),
1092 constraint->location)));
1093 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
1094 break;
1095
1096 case CONSTR_NULL:
1097 case CONSTR_DEFAULT:
1104 elog(ERROR, "invalid context for constraint type %d",
1105 constraint->contype);
1106 break;
1107
1108 default:
1109 elog(ERROR, "unrecognized constraint type: %d",
1110 constraint->contype);
1111 break;
1112 }
1113}
1114
1115/*
1116 * transformTableLikeClause
1117 *
1118 * Change the LIKE <srctable> portion of a CREATE TABLE statement into
1119 * column definitions that recreate the user defined column portions of
1120 * <srctable>. Also, if there are any LIKE options that we can't fully
1121 * process at this point, add the TableLikeClause to cxt->likeclauses, which
1122 * will cause utility.c to call expandTableLikeClause() after the new
1123 * table has been created.
1124 *
1125 * Some options are ignored. For example, as foreign tables have no storage,
1126 * these INCLUDING options have no effect: STORAGE, COMPRESSION, IDENTITY
1127 * and INDEXES. Similarly, INCLUDING INDEXES is ignored from a view.
1128 */
1129static void
1131{
1133 Relation relation;
1136 char *comment;
1138
1140 table_like_clause->relation->location);
1141
1142 /* Open the relation referenced by the LIKE clause */
1143 relation = relation_openrv(table_like_clause->relation, AccessShareLock);
1144
1145 if (relation->rd_rel->relkind != RELKIND_RELATION &&
1146 relation->rd_rel->relkind != RELKIND_VIEW &&
1147 relation->rd_rel->relkind != RELKIND_MATVIEW &&
1148 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
1149 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
1150 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1151 ereport(ERROR,
1153 errmsg("relation \"%s\" is invalid in LIKE clause",
1154 RelationGetRelationName(relation)),
1155 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
1156
1158
1159 /*
1160 * Check for privileges
1161 */
1162 if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
1163 {
1164 aclresult = object_aclcheck(TypeRelationId, relation->rd_rel->reltype, GetUserId(),
1165 ACL_USAGE);
1166 if (aclresult != ACLCHECK_OK)
1168 RelationGetRelationName(relation));
1169 }
1170 else
1171 {
1173 ACL_SELECT);
1174 if (aclresult != ACLCHECK_OK)
1176 RelationGetRelationName(relation));
1177 }
1178
1179 tupleDesc = RelationGetDescr(relation);
1180
1181 /*
1182 * Insert the copied attributes into the cxt for the new table definition.
1183 * We must do this now so that they appear in the table in the relative
1184 * position where the LIKE clause is, as required by SQL99.
1185 */
1186 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1187 parent_attno++)
1188 {
1190 parent_attno - 1);
1191 ColumnDef *def;
1192
1193 /*
1194 * Ignore dropped columns in the parent.
1195 */
1196 if (attribute->attisdropped)
1197 continue;
1198
1199 /*
1200 * Create a new column definition
1201 */
1202 def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid,
1203 attribute->atttypmod, attribute->attcollation);
1204
1205 /*
1206 * Add to column list
1207 */
1208 cxt->columns = lappend(cxt->columns, def);
1209
1210 /*
1211 * Although we don't transfer the column's default/generation
1212 * expression now, we need to mark it GENERATED if appropriate.
1213 */
1214 if (attribute->atthasdef && attribute->attgenerated &&
1216 def->generated = attribute->attgenerated;
1217
1218 /*
1219 * Copy identity if requested
1220 */
1221 if (attribute->attidentity &&
1223 !cxt->isforeign)
1224 {
1225 Oid seq_relid;
1227
1228 /*
1229 * find sequence owned by old column; extract sequence parameters;
1230 * build new create sequence command
1231 */
1232 seq_relid = getIdentitySequence(relation, attribute->attnum, false);
1234 generateSerialExtraStmts(cxt, def,
1236 true, false,
1237 NULL, NULL);
1238 def->identity = attribute->attidentity;
1239 }
1240
1241 /* Likewise, copy storage if requested */
1243 !cxt->isforeign)
1244 def->storage = attribute->attstorage;
1245 else
1246 def->storage = 0;
1247
1248 /* Likewise, copy compression if requested */
1249 if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0 &&
1250 CompressionMethodIsValid(attribute->attcompression) &&
1251 !cxt->isforeign)
1252 def->compression =
1253 pstrdup(GetCompressionMethodName(attribute->attcompression));
1254 else
1255 def->compression = NULL;
1256
1257 /* Likewise, copy comment if requested */
1259 (comment = GetComment(attribute->attrelid,
1261 attribute->attnum)) != NULL)
1262 {
1264
1265 stmt->objtype = OBJECT_COLUMN;
1266 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1268 makeString(def->colname));
1269 stmt->comment = comment;
1270
1271 cxt->alist = lappend(cxt->alist, stmt);
1272 }
1273 }
1274
1275 /*
1276 * Reproduce not-null constraints, if any, by copying them. We do this
1277 * regardless of options given.
1278 */
1279 if (tupleDesc->constr && tupleDesc->constr->has_not_null)
1280 {
1281 List *lst;
1282
1284 true);
1286
1287 /* Copy comments on not-null constraints */
1289 {
1291 {
1293 nnconstr->conname, false),
1295 0)) != NULL)
1296 {
1298
1299 stmt->objtype = OBJECT_TABCONSTRAINT;
1300 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1302 makeString(nnconstr->conname));
1303 stmt->comment = comment;
1304 cxt->alist = lappend(cxt->alist, stmt);
1305 }
1306 }
1307 }
1308 }
1309
1310 /*
1311 * We cannot yet deal with defaults, CHECK constraints, indexes, or
1312 * statistics, since we don't yet know what column numbers the copied
1313 * columns will have in the finished table. If any of those options are
1314 * specified, add the LIKE clause to cxt->likeclauses so that
1315 * expandTableLikeClause will be called after we do know that.
1316 *
1317 * In order for this to work, we remember the relation OID so that
1318 * expandTableLikeClause is certain to open the same table.
1319 */
1320 if (table_like_clause->options &
1326 {
1327 table_like_clause->relationOid = RelationGetRelid(relation);
1329 }
1330
1331 /*
1332 * Close the parent rel, but keep our AccessShareLock on it until xact
1333 * commit. That will prevent someone else from deleting or ALTERing the
1334 * parent before we can run expandTableLikeClause.
1335 */
1336 table_close(relation, NoLock);
1337}
1338
1339/*
1340 * expandTableLikeClause
1341 *
1342 * Process LIKE options that require knowing the final column numbers
1343 * assigned to the new table's columns. This executes after we have
1344 * run DefineRelation for the new table. It returns a list of utility
1345 * commands that should be run to generate indexes etc.
1346 */
1347List *
1349{
1350 List *result = NIL;
1351 List *atsubcmds = NIL;
1353 Relation relation;
1356 TupleConstr *constr;
1357 AttrMap *attmap;
1358 char *comment;
1359
1360 /*
1361 * Open the relation referenced by the LIKE clause. We should still have
1362 * the table lock obtained by transformTableLikeClause (and this'll throw
1363 * an assertion failure if not). Hence, no need to recheck privileges
1364 * etc. We must open the rel by OID not name, to be sure we get the same
1365 * table.
1366 */
1367 if (!OidIsValid(table_like_clause->relationOid))
1368 elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause");
1369
1370 relation = relation_open(table_like_clause->relationOid, NoLock);
1371
1372 tupleDesc = RelationGetDescr(relation);
1373 constr = tupleDesc->constr;
1374
1375 /*
1376 * Open the newly-created child relation; we have lock on that too.
1377 */
1378 childrel = relation_openrv(heapRel, NoLock);
1379
1380 /*
1381 * Construct a map from the LIKE relation's attnos to the child rel's.
1382 * This re-checks type match etc, although it shouldn't be possible to
1383 * have a failure since both tables are locked.
1384 */
1386 tupleDesc,
1387 false);
1388
1389 /*
1390 * Process defaults, if required.
1391 */
1392 if ((table_like_clause->options &
1394 constr != NULL)
1395 {
1396 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1397 parent_attno++)
1398 {
1400 parent_attno - 1);
1401
1402 /*
1403 * Ignore dropped columns in the parent.
1404 */
1405 if (attribute->attisdropped)
1406 continue;
1407
1408 /*
1409 * Copy default, if present and it should be copied. We have
1410 * separate options for plain default expressions and GENERATED
1411 * defaults.
1412 */
1413 if (attribute->atthasdef &&
1414 (attribute->attgenerated ?
1417 {
1420 bool found_whole_row;
1421
1423 if (this_default == NULL)
1424 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1426
1429 atsubcmd->num = attmap->attnums[parent_attno - 1];
1431 1, 0,
1432 attmap,
1433 InvalidOid,
1434 &found_whole_row);
1435
1436 /*
1437 * Prevent this for the same reason as for constraints below.
1438 * Note that defaults cannot contain any vars, so it's OK that
1439 * the error message refers to generated columns.
1440 */
1441 if (found_whole_row)
1442 ereport(ERROR,
1444 errmsg("cannot convert whole-row table reference"),
1445 errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
1446 NameStr(attribute->attname),
1447 RelationGetRelationName(relation))));
1448
1450 }
1451 }
1452 }
1453
1454 /*
1455 * Copy CHECK constraints if requested, being careful to adjust attribute
1456 * numbers so they match the child.
1457 */
1459 constr != NULL)
1460 {
1461 int ccnum;
1462
1463 for (ccnum = 0; ccnum < constr->num_check; ccnum++)
1464 {
1465 char *ccname = constr->check[ccnum].ccname;
1466 char *ccbin = constr->check[ccnum].ccbin;
1467 bool ccenforced = constr->check[ccnum].ccenforced;
1468 bool ccnoinherit = constr->check[ccnum].ccnoinherit;
1470 bool found_whole_row;
1471 Constraint *n;
1473
1475 1, 0,
1476 attmap,
1477 InvalidOid, &found_whole_row);
1478
1479 /*
1480 * We reject whole-row variables because the whole point of LIKE
1481 * is that the new table's rowtype might later diverge from the
1482 * parent's. So, while translation might be possible right now,
1483 * it wouldn't be possible to guarantee it would work in future.
1484 */
1485 if (found_whole_row)
1486 ereport(ERROR,
1488 errmsg("cannot convert whole-row table reference"),
1489 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1490 ccname,
1491 RelationGetRelationName(relation))));
1492
1493 n = makeNode(Constraint);
1494 n->contype = CONSTR_CHECK;
1495 n->conname = pstrdup(ccname);
1496 n->location = -1;
1497 n->is_enforced = ccenforced;
1498 n->initially_valid = ccenforced; /* sic */
1499 n->is_no_inherit = ccnoinherit;
1500 n->raw_expr = NULL;
1502
1503 /* We can skip validation, since the new table should be empty. */
1504 n->skip_validation = true;
1505
1507 atsubcmd->subtype = AT_AddConstraint;
1508 atsubcmd->def = (Node *) n;
1510
1511 /* Copy comment on constraint */
1514 n->conname, false),
1516 0)) != NULL)
1517 {
1519
1520 stmt->objtype = OBJECT_TABCONSTRAINT;
1521 stmt->object = (Node *) list_make3(makeString(heapRel->schemaname),
1522 makeString(heapRel->relname),
1523 makeString(n->conname));
1524 stmt->comment = comment;
1525
1526 result = lappend(result, stmt);
1527 }
1528 }
1529 }
1530
1531 /*
1532 * If we generated any ALTER TABLE actions above, wrap them into a single
1533 * ALTER TABLE command. Stick it at the front of the result, so it runs
1534 * before any CommentStmts we made above.
1535 */
1536 if (atsubcmds)
1537 {
1539
1540 atcmd->relation = copyObject(heapRel);
1541 atcmd->cmds = atsubcmds;
1542 atcmd->objtype = OBJECT_TABLE;
1543 atcmd->missing_ok = false;
1544 result = lcons(atcmd, result);
1545 }
1546
1547 /*
1548 * Process indexes if required.
1549 */
1551 relation->rd_rel->relhasindex &&
1552 childrel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1553 {
1555 ListCell *l;
1556
1558
1559 foreach(l, parent_indexes)
1560 {
1564
1566
1567 /* Build CREATE INDEX statement to recreate the parent_index */
1570 attmap,
1571 NULL);
1572
1573 /* Copy comment on index, if requested */
1575 {
1577
1578 /*
1579 * We make use of IndexStmt's idxcomment option, so as not to
1580 * need to know now what name the index will have.
1581 */
1582 index_stmt->idxcomment = comment;
1583 }
1584
1585 result = lappend(result, index_stmt);
1586
1588 }
1589 }
1590
1591 /*
1592 * Process extended statistics if required.
1593 */
1595 {
1597 ListCell *l;
1598
1600
1601 foreach(l, parent_extstats)
1602 {
1605
1609 attmap);
1610
1611 /* Copy comment on statistics object, if requested */
1613 {
1615
1616 /*
1617 * We make use of CreateStatsStmt's stxcomment option, so as
1618 * not to need to know now what name the statistics will have.
1619 */
1620 stats_stmt->stxcomment = comment;
1621 }
1622
1623 result = lappend(result, stats_stmt);
1624 }
1625
1627 }
1628
1629 /* Done with child rel */
1631
1632 /*
1633 * Close the parent rel, but keep our AccessShareLock on it until xact
1634 * commit. That will prevent someone else from deleting or ALTERing the
1635 * parent before the child is committed.
1636 */
1637 table_close(relation, NoLock);
1638
1639 return result;
1640}
1641
1642static void
1644{
1645 HeapTuple tuple;
1646 TupleDesc tupdesc;
1647 int i;
1648 Oid ofTypeId;
1649
1650 Assert(ofTypename);
1651
1652 tuple = typenameType(cxt->pstate, ofTypename, NULL);
1653 check_of_type(tuple);
1654 ofTypeId = ((Form_pg_type) GETSTRUCT(tuple))->oid;
1655 ofTypename->typeOid = ofTypeId; /* cached for later */
1656
1657 tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
1658 for (i = 0; i < tupdesc->natts; i++)
1659 {
1660 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1661 ColumnDef *n;
1662
1663 if (attr->attisdropped)
1664 continue;
1665
1666 n = makeColumnDef(NameStr(attr->attname), attr->atttypid,
1667 attr->atttypmod, attr->attcollation);
1668 n->is_from_type = true;
1669
1670 cxt->columns = lappend(cxt->columns, n);
1671 }
1672 ReleaseTupleDesc(tupdesc);
1673
1674 ReleaseSysCache(tuple);
1675}
1676
1677/*
1678 * Generate an IndexStmt node using information from an already existing index
1679 * "source_idx".
1680 *
1681 * heapRel is stored into the IndexStmt's relation field, but we don't use it
1682 * otherwise; some callers pass NULL, if they don't need it to be valid.
1683 * (The target relation might not exist yet, so we mustn't try to access it.)
1684 *
1685 * Attribute numbers in expression Vars are adjusted according to attmap.
1686 *
1687 * If constraintOid isn't NULL, we store the OID of any constraint associated
1688 * with the index there.
1689 *
1690 * Unlike transformIndexConstraint, we don't make any effort to force primary
1691 * key columns to be not-null. The larger cloning process this is part of
1692 * should have cloned their not-null status separately (and DefineIndex will
1693 * complain if that fails to happen).
1694 */
1695IndexStmt *
1697 const AttrMap *attmap,
1699{
1710 List *indexprs;
1712 Oid indrelid;
1713 int keyno;
1715 Datum datum;
1716 bool isnull;
1717
1718 if (constraintOid)
1720
1721 /*
1722 * Fetch pg_class tuple of source index. We can't use the copy in the
1723 * relcache entry because it doesn't include optional fields.
1724 */
1727 elog(ERROR, "cache lookup failed for relation %u", source_relid);
1729
1730 /* Fetch pg_index tuple for source index from relcache entry */
1731 ht_idx = source_idx->rd_indextuple;
1733 indrelid = idxrec->indrelid;
1734
1735 /* Fetch the pg_am tuple of the index' access method */
1737 if (!HeapTupleIsValid(ht_am))
1738 elog(ERROR, "cache lookup failed for access method %u",
1739 idxrelrec->relam);
1741
1742 /* Extract indcollation from the pg_index tuple */
1746
1747 /* Extract indclass from the pg_index tuple */
1749 indclass = (oidvector *) DatumGetPointer(datum);
1750
1751 /* Begin building the IndexStmt */
1753 index->relation = heapRel;
1754 index->accessMethod = pstrdup(NameStr(amrec->amname));
1755 if (OidIsValid(idxrelrec->reltablespace))
1756 index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
1757 else
1758 index->tableSpace = NULL;
1759 index->excludeOpNames = NIL;
1760 index->idxcomment = NULL;
1761 index->indexOid = InvalidOid;
1762 index->oldNumber = InvalidRelFileNumber;
1763 index->oldCreateSubid = InvalidSubTransactionId;
1764 index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
1765 index->unique = idxrec->indisunique;
1766 index->nulls_not_distinct = idxrec->indnullsnotdistinct;
1767 index->primary = idxrec->indisprimary;
1768 index->iswithoutoverlaps = (idxrec->indisprimary || idxrec->indisunique) && idxrec->indisexclusion;
1769 index->transformed = true; /* don't need transformIndexStmt */
1770 index->concurrent = false;
1771 index->if_not_exists = false;
1772 index->reset_default_tblspc = false;
1773
1774 /*
1775 * We don't try to preserve the name of the source index; instead, just
1776 * let DefineIndex() choose a reasonable name. (If we tried to preserve
1777 * the name, we'd get duplicate-relation-name failures unless the source
1778 * table was in a different schema.)
1779 */
1780 index->idxname = NULL;
1781
1782 /*
1783 * If the index is marked PRIMARY or has an exclusion condition, it's
1784 * certainly from a constraint; else, if it's not marked UNIQUE, it
1785 * certainly isn't. If it is or might be from a constraint, we have to
1786 * fetch the pg_constraint record.
1787 */
1788 if (index->primary || index->unique || idxrec->indisexclusion)
1789 {
1791
1793 {
1796
1797 if (constraintOid)
1799
1803 elog(ERROR, "cache lookup failed for constraint %u",
1804 constraintId);
1806
1807 index->isconstraint = true;
1808 index->deferrable = conrec->condeferrable;
1809 index->initdeferred = conrec->condeferred;
1810
1811 /* If it's an exclusion constraint, we need the operator names */
1812 if (idxrec->indisexclusion)
1813 {
1814 Datum *elems;
1815 int nElems;
1816 int i;
1817
1818 Assert(conrec->contype == CONSTRAINT_EXCLUSION ||
1819 (index->iswithoutoverlaps &&
1820 (conrec->contype == CONSTRAINT_PRIMARY || conrec->contype == CONSTRAINT_UNIQUE)));
1821 /* Extract operator OIDs from the pg_constraint tuple */
1824 deconstruct_array_builtin(DatumGetArrayTypeP(datum), OIDOID, &elems, NULL, &nElems);
1825
1826 for (i = 0; i < nElems; i++)
1827 {
1828 Oid operid = DatumGetObjectId(elems[i]);
1831 char *oprname;
1832 char *nspname;
1833 List *namelist;
1834
1838 elog(ERROR, "cache lookup failed for operator %u",
1839 operid);
1841 oprname = pstrdup(NameStr(operform->oprname));
1842 /* For simplicity we always schema-qualify the op name */
1843 nspname = get_namespace_name(operform->oprnamespace);
1844 namelist = list_make2(makeString(nspname),
1845 makeString(oprname));
1846 index->excludeOpNames = lappend(index->excludeOpNames,
1847 namelist);
1849 }
1850 }
1851
1853 }
1854 else
1855 index->isconstraint = false;
1856 }
1857 else
1858 index->isconstraint = false;
1859
1860 /* Get the index expressions, if any */
1862 Anum_pg_index_indexprs, &isnull);
1863 if (!isnull)
1864 {
1865 char *exprsString;
1866
1869 }
1870 else
1871 indexprs = NIL;
1872
1873 /* Build the list of IndexElem */
1874 index->indexParams = NIL;
1875 index->indexIncludingParams = NIL;
1876
1878 for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
1879 {
1881 AttrNumber attnum = idxrec->indkey.values[keyno];
1883 keyno);
1884 int16 opt = source_idx->rd_indoption[keyno];
1885
1887
1889 {
1890 /* Simple index column */
1891 char *attname;
1892
1895
1896 iparam->name = attname;
1897 iparam->expr = NULL;
1898 }
1899 else
1900 {
1901 /* Expressional index */
1902 Node *indexkey;
1903 bool found_whole_row;
1904
1905 if (indexpr_item == NULL)
1906 elog(ERROR, "too few entries in indexprs list");
1909
1910 /* Adjust Vars to match new table's column numbering */
1912 1, 0,
1913 attmap,
1914 InvalidOid, &found_whole_row);
1915
1916 /* As in expandTableLikeClause, reject whole-row variables */
1917 if (found_whole_row)
1918 ereport(ERROR,
1920 errmsg("cannot convert whole-row table reference"),
1921 errdetail("Index \"%s\" contains a whole-row table reference.",
1923
1924 iparam->name = NULL;
1925 iparam->expr = indexkey;
1926
1928 }
1929
1930 /* Copy the original index column name */
1931 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1932
1933 /* Add the collation name, if non-default */
1934 iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
1935
1936 /* Add the operator class name, if non-default */
1937 iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
1938 iparam->opclassopts =
1940
1941 iparam->ordering = SORTBY_DEFAULT;
1942 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
1943
1944 /* Adjust options if necessary */
1945 if (source_idx->rd_indam->amcanorder)
1946 {
1947 /*
1948 * If it supports sort ordering, copy DESC and NULLS opts. Don't
1949 * set non-default settings unnecessarily, though, so as to
1950 * improve the chance of recognizing equivalence to constraint
1951 * indexes.
1952 */
1953 if (opt & INDOPTION_DESC)
1954 {
1955 iparam->ordering = SORTBY_DESC;
1956 if ((opt & INDOPTION_NULLS_FIRST) == 0)
1957 iparam->nulls_ordering = SORTBY_NULLS_LAST;
1958 }
1959 else
1960 {
1961 if (opt & INDOPTION_NULLS_FIRST)
1962 iparam->nulls_ordering = SORTBY_NULLS_FIRST;
1963 }
1964 }
1965
1966 iparam->location = -1;
1967
1968 index->indexParams = lappend(index->indexParams, iparam);
1969 }
1970
1971 /* Handle included columns separately */
1972 for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
1973 {
1975 AttrNumber attnum = idxrec->indkey.values[keyno];
1977 keyno);
1978
1980
1982 {
1983 /* Simple index column */
1984 char *attname;
1985
1987
1988 iparam->name = attname;
1989 iparam->expr = NULL;
1990 }
1991 else
1992 ereport(ERROR,
1994 errmsg("expressions are not supported in included columns")));
1995
1996 /* Copy the original index column name */
1997 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1998
1999 iparam->location = -1;
2000
2001 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
2002 }
2003 /* Copy reloptions if any */
2005 Anum_pg_class_reloptions, &isnull);
2006 if (!isnull)
2007 index->options = untransformRelOptions(datum);
2008
2009 /* If it's a partial index, decompile and append the predicate */
2011 Anum_pg_index_indpred, &isnull);
2012 if (!isnull)
2013 {
2014 char *pred_str;
2015 Node *pred_tree;
2016 bool found_whole_row;
2017
2018 /* Convert text string to node tree */
2021
2022 /* Adjust Vars to match new table's column numbering */
2024 1, 0,
2025 attmap,
2026 InvalidOid, &found_whole_row);
2027
2028 /* As in expandTableLikeClause, reject whole-row variables */
2029 if (found_whole_row)
2030 ereport(ERROR,
2032 errmsg("cannot convert whole-row table reference"),
2033 errdetail("Index \"%s\" contains a whole-row table reference.",
2035
2036 index->whereClause = pred_tree;
2037 }
2038
2039 /* Clean up */
2042
2043 return index;
2044}
2045
2046/*
2047 * Generate a CreateStatsStmt node using information from an already existing
2048 * extended statistic "source_statsid", for the rel identified by heapRel and
2049 * heapRelid.
2050 *
2051 * Attribute numbers in expression Vars are adjusted according to attmap.
2052 */
2053static CreateStatsStmt *
2056{
2059 CreateStatsStmt *stats;
2060 List *stat_types = NIL;
2061 List *def_names = NIL;
2062 bool isnull;
2063 Datum datum;
2064 ArrayType *arr;
2065 char *enabled;
2066 int i;
2067
2069 Assert(heapRel != NULL);
2070
2071 /*
2072 * Fetch pg_statistic_ext tuple of source statistics object.
2073 */
2076 elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
2078
2079 /* Determine which statistics types exist */
2082 arr = DatumGetArrayTypeP(datum);
2083 if (ARR_NDIM(arr) != 1 ||
2084 ARR_HASNULL(arr) ||
2085 ARR_ELEMTYPE(arr) != CHAROID)
2086 elog(ERROR, "stxkind is not a 1-D char array");
2087 enabled = (char *) ARR_DATA_PTR(arr);
2088 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
2089 {
2090 if (enabled[i] == STATS_EXT_NDISTINCT)
2091 stat_types = lappend(stat_types, makeString("ndistinct"));
2092 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
2093 stat_types = lappend(stat_types, makeString("dependencies"));
2094 else if (enabled[i] == STATS_EXT_MCV)
2095 stat_types = lappend(stat_types, makeString("mcv"));
2096 else if (enabled[i] == STATS_EXT_EXPRESSIONS)
2097 /* expression stats are not exposed to users */
2098 continue;
2099 else
2100 elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
2101 }
2102
2103 /* Determine which columns the statistics are on */
2104 for (i = 0; i < statsrec->stxkeys.dim1; i++)
2105 {
2107 AttrNumber attnum = statsrec->stxkeys.values[i];
2108
2109 selem->name = get_attname(heapRelid, attnum, false);
2110 selem->expr = NULL;
2111
2113 }
2114
2115 /*
2116 * Now handle expressions, if there are any. The order (with respect to
2117 * regular attributes) does not really matter for extended stats, so we
2118 * simply append them after simple column references.
2119 *
2120 * XXX Some places during build/estimation treat expressions as if they
2121 * are before attributes, but for the CREATE command that's entirely
2122 * irrelevant.
2123 */
2126
2127 if (!isnull)
2128 {
2129 ListCell *lc;
2130 List *exprs = NIL;
2131 char *exprsString;
2132
2134 exprs = (List *) stringToNode(exprsString);
2135
2136 foreach(lc, exprs)
2137 {
2138 Node *expr = (Node *) lfirst(lc);
2140 bool found_whole_row;
2141
2142 /* Adjust Vars to match new table's column numbering */
2143 expr = map_variable_attnos(expr,
2144 1, 0,
2145 attmap,
2146 InvalidOid,
2147 &found_whole_row);
2148
2149 selem->name = NULL;
2150 selem->expr = expr;
2151
2153 }
2154
2156 }
2157
2158 /* finally, build the output node */
2159 stats = makeNode(CreateStatsStmt);
2160 stats->defnames = NULL;
2161 stats->stat_types = stat_types;
2162 stats->exprs = def_names;
2163 stats->relations = list_make1(heapRel);
2164 stats->stxcomment = NULL;
2165 stats->transformed = true; /* don't need transformStatsStmt again */
2166 stats->if_not_exists = false;
2167
2168 /* Clean up */
2170
2171 return stats;
2172}
2173
2174/*
2175 * get_collation - fetch qualified name of a collation
2176 *
2177 * If collation is InvalidOid or is the default for the given actual_datatype,
2178 * then the return value is NIL.
2179 */
2180static List *
2182{
2183 List *result;
2186 char *nsp_name;
2187 char *coll_name;
2188
2189 if (!OidIsValid(collation))
2190 return NIL; /* easy case */
2191 if (collation == get_typcollation(actual_datatype))
2192 return NIL; /* just let it default */
2193
2196 elog(ERROR, "cache lookup failed for collation %u", collation);
2198
2199 /* For simplicity, we always schema-qualify the name */
2200 nsp_name = get_namespace_name(coll_rec->collnamespace);
2201 coll_name = pstrdup(NameStr(coll_rec->collname));
2203
2205 return result;
2206}
2207
2208/*
2209 * get_opclass - fetch qualified name of an index operator class
2210 *
2211 * If the opclass is the default for the given actual_datatype, then
2212 * the return value is NIL.
2213 */
2214static List *
2216{
2217 List *result = NIL;
2220
2223 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2225
2226 if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
2227 {
2228 /* For simplicity, we always schema-qualify the name */
2229 char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
2230 char *opc_name = pstrdup(NameStr(opc_rec->opcname));
2231
2233 }
2234
2236 return result;
2237}
2238
2239
2240/*
2241 * transformIndexConstraints
2242 * Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
2243 * We also merge in any index definitions arising from
2244 * LIKE ... INCLUDING INDEXES.
2245 */
2246static void
2248{
2250 List *indexlist = NIL;
2252 ListCell *lc;
2253
2254 /*
2255 * Run through the constraints that need to generate an index, and do so.
2256 *
2257 * For PRIMARY KEY, this queues not-null constraints for each column, if
2258 * needed.
2259 */
2260 foreach(lc, cxt->ixconstraints)
2261 {
2262 Constraint *constraint = lfirst_node(Constraint, lc);
2263
2264 Assert(constraint->contype == CONSTR_PRIMARY ||
2265 constraint->contype == CONSTR_UNIQUE ||
2266 constraint->contype == CONSTR_EXCLUSION);
2267
2268 index = transformIndexConstraint(constraint, cxt);
2269
2270 indexlist = lappend(indexlist, index);
2271 }
2272
2273 /*
2274 * Scan the index list and remove any redundant index specifications. This
2275 * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
2276 * strict reading of SQL would suggest raising an error instead, but that
2277 * strikes me as too anal-retentive. - tgl 2001-02-14
2278 *
2279 * XXX in ALTER TABLE case, it'd be nice to look for duplicate
2280 * pre-existing indexes, too.
2281 */
2282 if (cxt->pkey != NULL)
2283 {
2284 /* Make sure we keep the PKEY index in preference to others... */
2286 }
2287
2288 foreach(lc, indexlist)
2289 {
2290 bool keep = true;
2291 ListCell *k;
2292
2293 index = lfirst(lc);
2294
2295 /* if it's pkey, it's already in finalindexlist */
2296 if (index == cxt->pkey)
2297 continue;
2298
2299 foreach(k, finalindexlist)
2300 {
2302
2303 if (equal(index->indexParams, priorindex->indexParams) &&
2304 equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
2305 equal(index->whereClause, priorindex->whereClause) &&
2306 equal(index->excludeOpNames, priorindex->excludeOpNames) &&
2307 strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
2308 index->nulls_not_distinct == priorindex->nulls_not_distinct &&
2309 index->deferrable == priorindex->deferrable &&
2310 index->initdeferred == priorindex->initdeferred)
2311 {
2312 priorindex->unique |= index->unique;
2313
2314 /*
2315 * If the prior index is as yet unnamed, and this one is
2316 * named, then transfer the name to the prior index. This
2317 * ensures that if we have named and unnamed constraints,
2318 * we'll use (at least one of) the names for the index.
2319 */
2320 if (priorindex->idxname == NULL)
2321 priorindex->idxname = index->idxname;
2322 keep = false;
2323 break;
2324 }
2325 }
2326
2327 if (keep)
2329 }
2330
2331 /*
2332 * Now append all the IndexStmts to cxt->alist.
2333 */
2334 cxt->alist = list_concat(cxt->alist, finalindexlist);
2335}
2336
2337/*
2338 * transformIndexConstraint
2339 * Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
2340 * transformIndexConstraints. An IndexStmt is returned.
2341 *
2342 * For a PRIMARY KEY constraint, we additionally create not-null constraints
2343 * for columns that don't already have them.
2344 */
2345static IndexStmt *
2347{
2349 ListCell *lc;
2350
2352
2353 index->unique = (constraint->contype != CONSTR_EXCLUSION);
2354 index->primary = (constraint->contype == CONSTR_PRIMARY);
2355 if (index->primary)
2356 {
2357 if (cxt->pkey != NULL)
2358 ereport(ERROR,
2360 errmsg("multiple primary keys for table \"%s\" are not allowed",
2361 cxt->relation->relname),
2362 parser_errposition(cxt->pstate, constraint->location)));
2363 cxt->pkey = index;
2364
2365 /*
2366 * In ALTER TABLE case, a primary index might already exist, but
2367 * DefineIndex will check for it.
2368 */
2369 }
2370 index->nulls_not_distinct = constraint->nulls_not_distinct;
2371 index->isconstraint = true;
2372 index->iswithoutoverlaps = constraint->without_overlaps;
2373 index->deferrable = constraint->deferrable;
2374 index->initdeferred = constraint->initdeferred;
2375
2376 if (constraint->conname != NULL)
2377 index->idxname = pstrdup(constraint->conname);
2378 else
2379 index->idxname = NULL; /* DefineIndex will choose name */
2380
2381 index->relation = cxt->relation;
2382 index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
2383 index->options = constraint->options;
2384 index->tableSpace = constraint->indexspace;
2385 index->whereClause = constraint->where_clause;
2386 index->indexParams = NIL;
2387 index->indexIncludingParams = NIL;
2388 index->excludeOpNames = NIL;
2389 index->idxcomment = NULL;
2390 index->indexOid = InvalidOid;
2391 index->oldNumber = InvalidRelFileNumber;
2392 index->oldCreateSubid = InvalidSubTransactionId;
2393 index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
2394 index->transformed = false;
2395 index->concurrent = false;
2396 index->if_not_exists = false;
2397 index->reset_default_tblspc = constraint->reset_default_tblspc;
2398
2399 /*
2400 * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
2401 * verify it's usable, then extract the implied column name list. (We
2402 * will not actually need the column name list at runtime, but we need it
2403 * now to check for duplicate column entries below.)
2404 */
2405 if (constraint->indexname != NULL)
2406 {
2407 char *index_name = constraint->indexname;
2408 Relation heap_rel = cxt->rel;
2409 Oid index_oid;
2414 int i;
2415
2416 /* Grammar should not allow this with explicit column list */
2417 Assert(constraint->keys == NIL);
2418
2419 /* Grammar should only allow PRIMARY and UNIQUE constraints */
2420 Assert(constraint->contype == CONSTR_PRIMARY ||
2421 constraint->contype == CONSTR_UNIQUE);
2422
2423 /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
2424 if (!cxt->isalter)
2425 ereport(ERROR,
2427 errmsg("cannot use an existing index in CREATE TABLE"),
2428 parser_errposition(cxt->pstate, constraint->location)));
2429
2430 /* Look for the index in the same schema as the table */
2432
2433 if (!OidIsValid(index_oid))
2434 ereport(ERROR,
2436 errmsg("index \"%s\" does not exist", index_name),
2437 parser_errposition(cxt->pstate, constraint->location)));
2438
2439 /* Open the index (this will throw an error if it is not an index) */
2441 index_form = index_rel->rd_index;
2442
2443 /* Check that it does not have an associated constraint already */
2445 ereport(ERROR,
2447 errmsg("index \"%s\" is already associated with a constraint",
2448 index_name),
2449 parser_errposition(cxt->pstate, constraint->location)));
2450
2451 /* Perform validity checks on the index */
2452 if (index_form->indrelid != RelationGetRelid(heap_rel))
2453 ereport(ERROR,
2455 errmsg("index \"%s\" does not belong to table \"%s\"",
2457 parser_errposition(cxt->pstate, constraint->location)));
2458
2459 if (!index_form->indisvalid)
2460 ereport(ERROR,
2462 errmsg("index \"%s\" is not valid", index_name),
2463 parser_errposition(cxt->pstate, constraint->location)));
2464
2465 /*
2466 * Today we forbid non-unique indexes, but we could permit GiST
2467 * indexes whose last entry is a range type and use that to create a
2468 * WITHOUT OVERLAPS constraint (i.e. a temporal constraint).
2469 */
2470 if (!index_form->indisunique)
2471 ereport(ERROR,
2473 errmsg("\"%s\" is not a unique index", index_name),
2474 errdetail("Cannot create a primary key or unique constraint using such an index."),
2475 parser_errposition(cxt->pstate, constraint->location)));
2476
2478 ereport(ERROR,
2480 errmsg("index \"%s\" contains expressions", index_name),
2481 errdetail("Cannot create a primary key or unique constraint using such an index."),
2482 parser_errposition(cxt->pstate, constraint->location)));
2483
2485 ereport(ERROR,
2487 errmsg("\"%s\" is a partial index", index_name),
2488 errdetail("Cannot create a primary key or unique constraint using such an index."),
2489 parser_errposition(cxt->pstate, constraint->location)));
2490
2491 /*
2492 * It's probably unsafe to change a deferred index to non-deferred. (A
2493 * non-constraint index couldn't be deferred anyway, so this case
2494 * should never occur; no need to sweat, but let's check it.)
2495 */
2496 if (!index_form->indimmediate && !constraint->deferrable)
2497 ereport(ERROR,
2499 errmsg("\"%s\" is a deferrable index", index_name),
2500 errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
2501 parser_errposition(cxt->pstate, constraint->location)));
2502
2503 /*
2504 * Insist on it being a btree. We must have an index that exactly
2505 * matches what you'd get from plain ADD CONSTRAINT syntax, else dump
2506 * and reload will produce a different index (breaking pg_upgrade in
2507 * particular).
2508 */
2509 if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
2510 ereport(ERROR,
2512 errmsg("index \"%s\" is not a btree", index_name),
2513 parser_errposition(cxt->pstate, constraint->location)));
2514
2515 /* Must get indclass the hard way */
2517 index_rel->rd_indextuple,
2520
2521 for (i = 0; i < index_form->indnatts; i++)
2522 {
2523 int16 attnum = index_form->indkey.values[i];
2525 char *attname;
2527
2528 /*
2529 * We shouldn't see attnum == 0 here, since we already rejected
2530 * expression indexes. If we do, SystemAttributeDefinition will
2531 * throw an error.
2532 */
2533 if (attnum > 0)
2534 {
2535 Assert(attnum <= heap_rel->rd_att->natts);
2536 attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
2537 }
2538 else
2540 attname = pstrdup(NameStr(attform->attname));
2541
2543 {
2544 /*
2545 * Insist on default opclass, collation, and sort options.
2546 * While the index would still work as a constraint with
2547 * non-default settings, it might not provide exactly the same
2548 * uniqueness semantics as you'd get from a normally-created
2549 * constraint; and there's also the dump/reload problem
2550 * mentioned above.
2551 */
2552 Datum attoptions =
2554
2556 index_rel->rd_rel->relam);
2557 if (indclass->values[i] != defopclass ||
2558 attform->attcollation != index_rel->rd_indcollation[i] ||
2559 attoptions != (Datum) 0 ||
2560 index_rel->rd_indoption[i] != 0)
2561 ereport(ERROR,
2563 errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
2564 errdetail("Cannot create a primary key or unique constraint using such an index."),
2565 parser_errposition(cxt->pstate, constraint->location)));
2566
2567 /* If a PK, ensure the columns get not null constraints */
2568 if (constraint->contype == CONSTR_PRIMARY)
2569 cxt->nnconstraints =
2572
2573 constraint->keys = lappend(constraint->keys, makeString(attname));
2574 }
2575 else
2576 constraint->including = lappend(constraint->including, makeString(attname));
2577 }
2578
2579 /* Close the index relation but keep the lock */
2581
2582 index->indexOid = index_oid;
2583 }
2584
2585 /*
2586 * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
2587 * IndexElems and operator names. We have to break that apart into
2588 * separate lists.
2589 */
2590 if (constraint->contype == CONSTR_EXCLUSION)
2591 {
2592 foreach(lc, constraint->exclusions)
2593 {
2594 List *pair = (List *) lfirst(lc);
2595 IndexElem *elem;
2596 List *opname;
2597
2598 Assert(list_length(pair) == 2);
2599 elem = linitial_node(IndexElem, pair);
2601
2602 index->indexParams = lappend(index->indexParams, elem);
2603 index->excludeOpNames = lappend(index->excludeOpNames, opname);
2604 }
2605 }
2606
2607 /*
2608 * For UNIQUE and PRIMARY KEY, we just have a list of column names.
2609 *
2610 * Make sure referenced keys exist. If we are making a PRIMARY KEY index,
2611 * also make sure they are not-null. For WITHOUT OVERLAPS constraints, we
2612 * make sure the last part is a range or multirange.
2613 */
2614 else
2615 {
2616 foreach(lc, constraint->keys)
2617 {
2618 char *key = strVal(lfirst(lc));
2619 bool found = false;
2621 ListCell *columns;
2623 Oid typid = InvalidOid;
2624
2625 /* Make sure referenced column exists. */
2626 foreach(columns, cxt->columns)
2627 {
2628 column = lfirst_node(ColumnDef, columns);
2629 if (strcmp(column->colname, key) == 0)
2630 {
2631 found = true;
2632 break;
2633 }
2634 }
2635 if (!found)
2636 column = NULL;
2637
2638 if (found)
2639 {
2640 /*
2641 * column is defined in the new table. For CREATE TABLE with
2642 * a PRIMARY KEY, we can apply the not-null constraint cheaply
2643 * here. If the not-null constraint already exists, we can
2644 * (albeit not so cheaply) verify that it's not a NO INHERIT
2645 * constraint.
2646 *
2647 * Note that ALTER TABLE never needs either check, because
2648 * those constraints have already been added by
2649 * ATPrepAddPrimaryKey.
2650 */
2651 if (constraint->contype == CONSTR_PRIMARY &&
2652 !cxt->isalter)
2653 {
2654 if (column->is_not_null)
2655 {
2657 {
2658 if (strcmp(strVal(linitial(nn->keys)), key) == 0)
2659 {
2660 if (nn->is_no_inherit)
2661 ereport(ERROR,
2663 errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
2664 key));
2665 break;
2666 }
2667 }
2668 }
2669 else
2670 {
2671 column->is_not_null = true;
2672 cxt->nnconstraints =
2675 }
2676 }
2677 else if (constraint->contype == CONSTR_PRIMARY)
2678 Assert(column->is_not_null);
2679 }
2680 else if (SystemAttributeByName(key) != NULL)
2681 {
2682 /*
2683 * column will be a system column in the new table, so accept
2684 * it. System columns can't ever be null, so no need to worry
2685 * about PRIMARY/NOT NULL constraint.
2686 */
2687 found = true;
2688 }
2689 else if (cxt->inhRelations)
2690 {
2691 /* try inherited tables */
2692 ListCell *inher;
2693
2694 foreach(inher, cxt->inhRelations)
2695 {
2697 Relation rel;
2698 int count;
2699
2700 rel = table_openrv(inh, AccessShareLock);
2701 /* check user requested inheritance from valid relkind */
2702 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2703 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2704 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2705 ereport(ERROR,
2707 errmsg("inherited relation \"%s\" is not a table or foreign table",
2708 inh->relname)));
2709 for (count = 0; count < rel->rd_att->natts; count++)
2710 {
2712 count);
2713 char *inhname = NameStr(inhattr->attname);
2714
2715 if (inhattr->attisdropped)
2716 continue;
2717 if (strcmp(key, inhname) == 0)
2718 {
2719 found = true;
2720 typid = inhattr->atttypid;
2721
2722 if (constraint->contype == CONSTR_PRIMARY)
2723 cxt->nnconstraints =
2726 break;
2727 }
2728 }
2729 table_close(rel, NoLock);
2730 if (found)
2731 break;
2732 }
2733 }
2734
2735 /*
2736 * In the ALTER TABLE case, don't complain about index keys not
2737 * created in the command; they may well exist already.
2738 * DefineIndex will complain about them if not.
2739 */
2740 if (!found && !cxt->isalter)
2741 ereport(ERROR,
2743 errmsg("column \"%s\" named in key does not exist", key),
2744 parser_errposition(cxt->pstate, constraint->location)));
2745
2746 /* Check for PRIMARY KEY(foo, foo) */
2747 foreach(columns, index->indexParams)
2748 {
2749 iparam = (IndexElem *) lfirst(columns);
2750 if (iparam->name && strcmp(key, iparam->name) == 0)
2751 {
2752 if (index->primary)
2753 ereport(ERROR,
2755 errmsg("column \"%s\" appears twice in primary key constraint",
2756 key),
2757 parser_errposition(cxt->pstate, constraint->location)));
2758 else
2759 ereport(ERROR,
2761 errmsg("column \"%s\" appears twice in unique constraint",
2762 key),
2763 parser_errposition(cxt->pstate, constraint->location)));
2764 }
2765 }
2766
2767 /*
2768 * The WITHOUT OVERLAPS part (if any) must be a range or
2769 * multirange type.
2770 */
2771 if (constraint->without_overlaps && lc == list_last_cell(constraint->keys))
2772 {
2773 if (!found && cxt->isalter)
2774 {
2775 /*
2776 * Look up the column type on existing table. If we can't
2777 * find it, let things fail in DefineIndex.
2778 */
2779 Relation rel = cxt->rel;
2780
2781 for (int i = 0; i < rel->rd_att->natts; i++)
2782 {
2784 const char *attname;
2785
2786 if (attr->attisdropped)
2787 break;
2788
2789 attname = NameStr(attr->attname);
2790 if (strcmp(attname, key) == 0)
2791 {
2792 found = true;
2793 typid = attr->atttypid;
2794 break;
2795 }
2796 }
2797 }
2798 if (found)
2799 {
2800 if (!OidIsValid(typid) && column)
2801 typid = typenameTypeId(NULL, column->typeName);
2802
2803 if (!OidIsValid(typid) || !(type_is_range(typid) || type_is_multirange(typid)))
2804 ereport(ERROR,
2806 errmsg("column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type", key),
2807 parser_errposition(cxt->pstate, constraint->location)));
2808 }
2809 }
2810
2811 /* OK, add it to the index definition */
2813 iparam->name = pstrdup(key);
2814 iparam->expr = NULL;
2815 iparam->indexcolname = NULL;
2816 iparam->collation = NIL;
2817 iparam->opclass = NIL;
2818 iparam->opclassopts = NIL;
2819 iparam->ordering = SORTBY_DEFAULT;
2820 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
2821 iparam->location = -1;
2822 index->indexParams = lappend(index->indexParams, iparam);
2823 }
2824
2825 if (constraint->without_overlaps)
2826 {
2827 /*
2828 * This enforces that there is at least one equality column
2829 * besides the WITHOUT OVERLAPS columns. This is per SQL
2830 * standard. XXX Do we need this?
2831 */
2832 if (list_length(constraint->keys) < 2)
2833 ereport(ERROR,
2835 errmsg("constraint using WITHOUT OVERLAPS needs at least two columns"));
2836
2837 /* WITHOUT OVERLAPS requires a GiST index */
2838 index->accessMethod = "gist";
2839 }
2840
2841 }
2842
2843 /*
2844 * Add included columns to index definition. This is much like the
2845 * simple-column-name-list code above, except that we don't worry about
2846 * NOT NULL marking; included columns in a primary key should not be
2847 * forced NOT NULL. We don't complain about duplicate columns, either,
2848 * though maybe we should?
2849 */
2850 foreach(lc, constraint->including)
2851 {
2852 char *key = strVal(lfirst(lc));
2853 bool found = false;
2855 ListCell *columns;
2857
2858 foreach(columns, cxt->columns)
2859 {
2860 column = lfirst_node(ColumnDef, columns);
2861 if (strcmp(column->colname, key) == 0)
2862 {
2863 found = true;
2864 break;
2865 }
2866 }
2867
2868 if (!found)
2869 {
2870 if (SystemAttributeByName(key) != NULL)
2871 {
2872 /*
2873 * column will be a system column in the new table, so accept
2874 * it.
2875 */
2876 found = true;
2877 }
2878 else if (cxt->inhRelations)
2879 {
2880 /* try inherited tables */
2881 ListCell *inher;
2882
2883 foreach(inher, cxt->inhRelations)
2884 {
2886 Relation rel;
2887 int count;
2888
2889 rel = table_openrv(inh, AccessShareLock);
2890 /* check user requested inheritance from valid relkind */
2891 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2892 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2893 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2894 ereport(ERROR,
2896 errmsg("inherited relation \"%s\" is not a table or foreign table",
2897 inh->relname)));
2898 for (count = 0; count < rel->rd_att->natts; count++)
2899 {
2901 count);
2902 char *inhname = NameStr(inhattr->attname);
2903
2904 if (inhattr->attisdropped)
2905 continue;
2906 if (strcmp(key, inhname) == 0)
2907 {
2908 found = true;
2909 break;
2910 }
2911 }
2912 table_close(rel, NoLock);
2913 if (found)
2914 break;
2915 }
2916 }
2917 }
2918
2919 /*
2920 * In the ALTER TABLE case, don't complain about index keys not
2921 * created in the command; they may well exist already. DefineIndex
2922 * will complain about them if not.
2923 */
2924 if (!found && !cxt->isalter)
2925 ereport(ERROR,
2927 errmsg("column \"%s\" named in key does not exist", key),
2928 parser_errposition(cxt->pstate, constraint->location)));
2929
2930 /* OK, add it to the index definition */
2932 iparam->name = pstrdup(key);
2933 iparam->expr = NULL;
2934 iparam->indexcolname = NULL;
2935 iparam->collation = NIL;
2936 iparam->opclass = NIL;
2937 iparam->opclassopts = NIL;
2938 iparam->location = -1;
2939 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
2940 }
2941
2942 return index;
2943}
2944
2945/*
2946 * transformCheckConstraints
2947 * handle CHECK constraints
2948 *
2949 * Right now, there's nothing to do here when called from ALTER TABLE,
2950 * but the other constraint-transformation functions are called in both
2951 * the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
2952 * don't do anything if we're not authorized to skip validation.
2953 */
2954static void
2956{
2958
2959 if (cxt->ckconstraints == NIL)
2960 return;
2961
2962 /*
2963 * When creating a new table (but not a foreign table), we can safely skip
2964 * the validation of check constraints and mark them as valid based on the
2965 * constraint enforcement flag, since NOT ENFORCED constraints must always
2966 * be marked as NOT VALID. (This will override any user-supplied NOT VALID
2967 * flag.)
2968 */
2969 if (skipValidation)
2970 {
2971 foreach(ckclist, cxt->ckconstraints)
2972 {
2973 Constraint *constraint = (Constraint *) lfirst(ckclist);
2974
2975 constraint->skip_validation = true;
2976 constraint->initially_valid = constraint->is_enforced;
2977 }
2978 }
2979}
2980
2981/*
2982 * transformFKConstraints
2983 * handle FOREIGN KEY constraints
2984 */
2985static void
2988{
2990
2991 if (cxt->fkconstraints == NIL)
2992 return;
2993
2994 /*
2995 * If CREATE TABLE or adding a column with NULL default, we can safely
2996 * skip validation of FK constraints, and mark them as valid based on the
2997 * constraint enforcement flag, since NOT ENFORCED constraints must always
2998 * be marked as NOT VALID. (This will override any user-supplied NOT VALID
2999 * flag.)
3000 */
3001 if (skipValidation)
3002 {
3003 foreach(fkclist, cxt->fkconstraints)
3004 {
3005 Constraint *constraint = (Constraint *) lfirst(fkclist);
3006
3007 constraint->skip_validation = true;
3008 constraint->initially_valid = constraint->is_enforced;
3009 }
3010 }
3011
3012 /*
3013 * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
3014 * CONSTRAINT command to execute after the basic command is complete. (If
3015 * called from ADD CONSTRAINT, that routine will add the FK constraints to
3016 * its own subcommand list.)
3017 *
3018 * Note: the ADD CONSTRAINT command must also execute after any index
3019 * creation commands. Thus, this should run after
3020 * transformIndexConstraints, so that the CREATE INDEX commands are
3021 * already in cxt->alist. See also the handling of cxt->likeclauses.
3022 */
3023 if (!isAddConstraint)
3024 {
3026
3027 alterstmt->relation = cxt->relation;
3028 alterstmt->cmds = NIL;
3029 alterstmt->objtype = OBJECT_TABLE;
3030
3031 foreach(fkclist, cxt->fkconstraints)
3032 {
3033 Constraint *constraint = (Constraint *) lfirst(fkclist);
3035
3036 altercmd->subtype = AT_AddConstraint;
3037 altercmd->name = NULL;
3038 altercmd->def = (Node *) constraint;
3039 alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
3040 }
3041
3042 cxt->alist = lappend(cxt->alist, alterstmt);
3043 }
3044}
3045
3046/*
3047 * transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
3048 *
3049 * Note: this is a no-op for an index not using either index expressions or
3050 * a predicate expression. There are several code paths that create indexes
3051 * without bothering to call this, because they know they don't have any
3052 * such expressions to deal with.
3053 *
3054 * To avoid race conditions, it's important that this function rely only on
3055 * the passed-in relid (and not on stmt->relation) to determine the target
3056 * relation.
3057 */
3058IndexStmt *
3059transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
3060{
3061 ParseState *pstate;
3063 ListCell *l;
3064 Relation rel;
3065
3066 /* Nothing to do if statement already transformed. */
3067 if (stmt->transformed)
3068 return stmt;
3069
3070 /* Set up pstate */
3071 pstate = make_parsestate(NULL);
3072 pstate->p_sourcetext = queryString;
3073
3074 /*
3075 * Put the parent table into the rtable so that the expressions can refer
3076 * to its fields without qualification. Caller is responsible for locking
3077 * relation, but we still need to open it.
3078 */
3079 rel = relation_open(relid, NoLock);
3082 NULL, false, true);
3083
3084 /* no to join list, yes to namespaces */
3085 addNSItemToQuery(pstate, nsitem, false, true, true);
3086
3087 /* take care of the where clause */
3088 if (stmt->whereClause)
3089 {
3090 stmt->whereClause = transformWhereClause(pstate,
3091 stmt->whereClause,
3093 "WHERE");
3094 /* we have to fix its collations too */
3095 assign_expr_collations(pstate, stmt->whereClause);
3096 }
3097
3098 /* take care of any index expressions */
3099 foreach(l, stmt->indexParams)
3100 {
3101 IndexElem *ielem = (IndexElem *) lfirst(l);
3102
3103 if (ielem->expr)
3104 {
3105 /* Extract preliminary index col name before transforming expr */
3106 if (ielem->indexcolname == NULL)
3108
3109 /* Now do parse transformation of the expression */
3110 ielem->expr = transformExpr(pstate, ielem->expr,
3112
3113 /* We have to fix its collations too */
3114 assign_expr_collations(pstate, ielem->expr);
3115
3116 /*
3117 * transformExpr() should have already rejected subqueries,
3118 * aggregates, window functions, and SRFs, based on the EXPR_KIND_
3119 * for an index expression.
3120 *
3121 * DefineIndex() will make more checks.
3122 */
3123 }
3124 }
3125
3126 /*
3127 * Check that only the base rel is mentioned. (This should be dead code
3128 * now that add_missing_from is history.)
3129 */
3130 if (list_length(pstate->p_rtable) != 1)
3131 ereport(ERROR,
3133 errmsg("index expressions and predicates can refer only to the table being indexed")));
3134
3135 free_parsestate(pstate);
3136
3137 /* Close relation */
3138 table_close(rel, NoLock);
3139
3140 /* Mark statement as successfully transformed */
3141 stmt->transformed = true;
3142
3143 return stmt;
3144}
3145
3146/*
3147 * transformStatsStmt - parse analysis for CREATE STATISTICS
3148 *
3149 * To avoid race conditions, it's important that this function relies only on
3150 * the passed-in relid (and not on stmt->relation) to determine the target
3151 * relation.
3152 */
3154transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
3155{
3156 ParseState *pstate;
3158 ListCell *l;
3159 Relation rel;
3160
3161 /* Nothing to do if statement already transformed. */
3162 if (stmt->transformed)
3163 return stmt;
3164
3165 /* Set up pstate */
3166 pstate = make_parsestate(NULL);
3167 pstate->p_sourcetext = queryString;
3168
3169 /*
3170 * Put the parent table into the rtable so that the expressions can refer
3171 * to its fields without qualification. Caller is responsible for locking
3172 * relation, but we still need to open it.
3173 */
3174 rel = relation_open(relid, NoLock);
3177 NULL, false, true);
3178
3179 /* no to join list, yes to namespaces */
3180 addNSItemToQuery(pstate, nsitem, false, true, true);
3181
3182 /* take care of any expressions */
3183 foreach(l, stmt->exprs)
3184 {
3185 StatsElem *selem = (StatsElem *) lfirst(l);
3186
3187 if (selem->expr)
3188 {
3189 /* Now do parse transformation of the expression */
3190 selem->expr = transformExpr(pstate, selem->expr,
3192
3193 /* We have to fix its collations too */
3194 assign_expr_collations(pstate, selem->expr);
3195 }
3196 }
3197
3198 /*
3199 * Check that only the base rel is mentioned. (This should be dead code
3200 * now that add_missing_from is history.)
3201 */
3202 if (list_length(pstate->p_rtable) != 1)
3203 ereport(ERROR,
3205 errmsg("statistics expressions can refer only to the table being referenced")));
3206
3207 free_parsestate(pstate);
3208
3209 /* Close relation */
3210 table_close(rel, NoLock);
3211
3212 /* Mark statement as successfully transformed */
3213 stmt->transformed = true;
3214
3215 return stmt;
3216}
3217
3218
3219/*
3220 * transformRuleStmt -
3221 * transform a CREATE RULE Statement. The action is a list of parse
3222 * trees which is transformed into a list of query trees, and we also
3223 * transform the WHERE clause if any.
3224 *
3225 * actions and whereClause are output parameters that receive the
3226 * transformed results.
3227 */
3228void
3229transformRuleStmt(RuleStmt *stmt, const char *queryString,
3230 List **actions, Node **whereClause)
3231{
3232 Relation rel;
3233 ParseState *pstate;
3236
3237 /*
3238 * To avoid deadlock, make sure the first thing we do is grab
3239 * AccessExclusiveLock on the target relation. This will be needed by
3240 * DefineQueryRewrite(), and we don't want to grab a lesser lock
3241 * beforehand.
3242 */
3243 rel = table_openrv(stmt->relation, AccessExclusiveLock);
3244
3245 if (rel->rd_rel->relkind == RELKIND_MATVIEW)
3246 ereport(ERROR,
3248 errmsg("rules on materialized views are not supported")));
3249
3250 /* Set up pstate */
3251 pstate = make_parsestate(NULL);
3252 pstate->p_sourcetext = queryString;
3253
3254 /*
3255 * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
3256 * Set up their ParseNamespaceItems in the main pstate for use in parsing
3257 * the rule qualification.
3258 */
3261 makeAlias("old", NIL),
3262 false, false);
3265 makeAlias("new", NIL),
3266 false, false);
3267
3268 /*
3269 * They must be in the namespace too for lookup purposes, but only add the
3270 * one(s) that are relevant for the current kind of rule. In an UPDATE
3271 * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
3272 * there's no need to be so picky for INSERT & DELETE. We do not add them
3273 * to the joinlist.
3274 */
3275 switch (stmt->event)
3276 {
3277 case CMD_SELECT:
3278 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3279 break;
3280 case CMD_UPDATE:
3281 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3282 addNSItemToQuery(pstate, newnsitem, false, true, true);
3283 break;
3284 case CMD_INSERT:
3285 addNSItemToQuery(pstate, newnsitem, false, true, true);
3286 break;
3287 case CMD_DELETE:
3288 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3289 break;
3290 default:
3291 elog(ERROR, "unrecognized event type: %d",
3292 (int) stmt->event);
3293 break;
3294 }
3295
3296 /* take care of the where clause */
3297 *whereClause = transformWhereClause(pstate,
3298 stmt->whereClause,
3300 "WHERE");
3301 /* we have to fix its collations too */
3302 assign_expr_collations(pstate, *whereClause);
3303
3304 /* this is probably dead code without add_missing_from: */
3305 if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
3306 ereport(ERROR,
3308 errmsg("rule WHERE condition cannot contain references to other relations")));
3309
3310 /*
3311 * 'instead nothing' rules with a qualification need a query rangetable so
3312 * the rewrite handler can add the negated rule qualification to the
3313 * original query. We create a query with the new command type CMD_NOTHING
3314 * here that is treated specially by the rewrite system.
3315 */
3316 if (stmt->actions == NIL)
3317 {
3319
3320 nothing_qry->commandType = CMD_NOTHING;
3321 nothing_qry->rtable = pstate->p_rtable;
3322 nothing_qry->rteperminfos = pstate->p_rteperminfos;
3323 nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
3324
3325 *actions = list_make1(nothing_qry);
3326 }
3327 else
3328 {
3329 ListCell *l;
3330 List *newactions = NIL;
3331
3332 /*
3333 * transform each statement, like parse_sub_analyze()
3334 */
3335 foreach(l, stmt->actions)
3336 {
3337 Node *action = (Node *) lfirst(l);
3339 Query *sub_qry,
3340 *top_subqry;
3341 bool has_old,
3342 has_new;
3343
3344 /*
3345 * Since outer ParseState isn't parent of inner, have to pass down
3346 * the query text by hand.
3347 */
3348 sub_pstate->p_sourcetext = queryString;
3349
3350 /*
3351 * Set up OLD/NEW in the rtable for this statement. The entries
3352 * are added only to relnamespace, not varnamespace, because we
3353 * don't want them to be referred to by unqualified field names
3354 * nor "*" in the rule actions. We decide later whether to put
3355 * them in the joinlist.
3356 */
3359 makeAlias("old", NIL),
3360 false, false);
3363 makeAlias("new", NIL),
3364 false, false);
3365 addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
3366 addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
3367
3368 /* Transform the rule action statement */
3370
3371 /*
3372 * We cannot support utility-statement actions (eg NOTIFY) with
3373 * nonempty rule WHERE conditions, because there's no way to make
3374 * the utility action execute conditionally.
3375 */
3376 if (top_subqry->commandType == CMD_UTILITY &&
3377 *whereClause != NULL)
3378 ereport(ERROR,
3380 errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
3381
3382 /*
3383 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
3384 * into the SELECT, and that's what we need to look at. (Ugly
3385 * kluge ... try to fix this when we redesign querytrees.)
3386 */
3388
3389 /*
3390 * If the sub_qry is a setop, we cannot attach any qualifications
3391 * to it, because the planner won't notice them. This could
3392 * perhaps be relaxed someday, but for now, we may as well reject
3393 * such a rule immediately.
3394 */
3395 if (sub_qry->setOperations != NULL && *whereClause != NULL)
3396 ereport(ERROR,
3398 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3399
3400 /*
3401 * Validate action's use of OLD/NEW, qual too
3402 */
3403 has_old =
3405 rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
3406 has_new =
3408 rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
3409
3410 switch (stmt->event)
3411 {
3412 case CMD_SELECT:
3413 if (has_old)
3414 ereport(ERROR,
3416 errmsg("ON SELECT rule cannot use OLD")));
3417 if (has_new)
3418 ereport(ERROR,
3420 errmsg("ON SELECT rule cannot use NEW")));
3421 break;
3422 case CMD_UPDATE:
3423 /* both are OK */
3424 break;
3425 case CMD_INSERT:
3426 if (has_old)
3427 ereport(ERROR,
3429 errmsg("ON INSERT rule cannot use OLD")));
3430 break;
3431 case CMD_DELETE:
3432 if (has_new)
3433 ereport(ERROR,
3435 errmsg("ON DELETE rule cannot use NEW")));
3436 break;
3437 default:
3438 elog(ERROR, "unrecognized event type: %d",
3439 (int) stmt->event);
3440 break;
3441 }
3442
3443 /*
3444 * OLD/NEW are not allowed in WITH queries, because they would
3445 * amount to outer references for the WITH, which we disallow.
3446 * However, they were already in the outer rangetable when we
3447 * analyzed the query, so we have to check.
3448 *
3449 * Note that in the INSERT...SELECT case, we need to examine the
3450 * CTE lists of both top_subqry and sub_qry.
3451 *
3452 * Note that we aren't digging into the body of the query looking
3453 * for WITHs in nested sub-SELECTs. A WITH down there can
3454 * legitimately refer to OLD/NEW, because it'd be an
3455 * indirect-correlated outer reference.
3456 */
3457 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3458 PRS2_OLD_VARNO, 0) ||
3459 rangeTableEntry_used((Node *) sub_qry->cteList,
3460 PRS2_OLD_VARNO, 0))
3461 ereport(ERROR,
3463 errmsg("cannot refer to OLD within WITH query")));
3464 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3465 PRS2_NEW_VARNO, 0) ||
3466 rangeTableEntry_used((Node *) sub_qry->cteList,
3467 PRS2_NEW_VARNO, 0))
3468 ereport(ERROR,
3470 errmsg("cannot refer to NEW within WITH query")));
3471
3472 /*
3473 * For efficiency's sake, add OLD to the rule action's jointree
3474 * only if it was actually referenced in the statement or qual.
3475 *
3476 * For INSERT, NEW is not really a relation (only a reference to
3477 * the to-be-inserted tuple) and should never be added to the
3478 * jointree.
3479 *
3480 * For UPDATE, we treat NEW as being another kind of reference to
3481 * OLD, because it represents references to *transformed* tuples
3482 * of the existing relation. It would be wrong to enter NEW
3483 * separately in the jointree, since that would cause a double
3484 * join of the updated relation. It's also wrong to fail to make
3485 * a jointree entry if only NEW and not OLD is mentioned.
3486 */
3487 if (has_old || (has_new && stmt->event == CMD_UPDATE))
3488 {
3490
3491 /*
3492 * If sub_qry is a setop, manipulating its jointree will do no
3493 * good at all, because the jointree is dummy. (This should be
3494 * a can't-happen case because of prior tests.)
3495 */
3496 if (sub_qry->setOperations != NULL)
3497 ereport(ERROR,
3499 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3500 /* hackishly add OLD to the already-built FROM clause */
3502 rtr->rtindex = oldnsitem->p_rtindex;
3503 sub_qry->jointree->fromlist =
3504 lappend(sub_qry->jointree->fromlist, rtr);
3505 }
3506
3508
3510 }
3511
3512 *actions = newactions;
3513 }
3514
3515 free_parsestate(pstate);
3516
3517 /* Close relation, but keep the exclusive lock */
3518 table_close(rel, NoLock);
3519}
3520
3521
3522/*
3523 * checkPartition
3524 * Check whether partRelOid is a leaf partition of the parent table (rel).
3525 * isMerge: true indicates the operation is "ALTER TABLE ... MERGE PARTITIONS";
3526 * false indicates the operation is "ALTER TABLE ... SPLIT PARTITION".
3527 */
3528static void
3530{
3531 Relation partRel;
3532
3533 partRel = table_open(partRelOid, NoLock);
3534
3535 if (partRel->rd_rel->relkind != RELKIND_RELATION)
3536 ereport(ERROR,
3538 errmsg("\"%s\" is not a table", RelationGetRelationName(partRel)),
3539 isMerge
3540 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")
3541 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions don't have sub-partitions"));
3542
3543 if (!partRel->rd_rel->relispartition)
3544 ereport(ERROR,
3546 errmsg("\"%s\" is not a partition of partitioned table \"%s\"",
3548 isMerge
3549 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")
3550 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions don't have sub-partitions"));
3551
3553 ereport(ERROR,
3555 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
3557 isMerge
3558 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")
3559 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions don't have sub-partitions"));
3560
3561 table_close(partRel, NoLock);
3562}
3563
3564/*
3565 * transformPartitionCmdForSplit -
3566 * analyze the ALTER TABLE ... SPLIT PARTITION command
3567 *
3568 * For each new partition, sps->bound is set to the transformed value of bound.
3569 * Does checks for bounds of new partitions.
3570 */
3571static void
3573{
3574 Relation parent = cxt->rel;
3575 PartitionKey key;
3576 char strategy;
3579 int default_index = -1;
3580 bool isSplitPartDefault;
3582 *listptr2;
3583 List *splitlist;
3584
3585 splitlist = partcmd->partlist;
3586 key = RelationGetPartitionKey(parent);
3587 strategy = get_partition_strategy(key);
3589
3590 /* Transform partition bounds for all partitions in the list: */
3592 {
3593 cxt->partbound = NULL;
3594 transformPartitionCmd(cxt, sps->bound);
3595 /* Assign the transformed value of the partition bound. */
3596 sps->bound = cxt->partbound;
3597 }
3598
3599 /*
3600 * Open and lock the partition, check ownership along the way. We need to
3601 * use AccessExclusiveLock here because this split partition will be
3602 * detached, then dropped in ATExecSplitPartition.
3603 */
3606 NULL);
3607
3608 checkPartition(parent, splitPartOid, false);
3609
3610 switch (strategy)
3611 {
3614 {
3616 {
3617 if (sps->bound->is_default)
3618 {
3619 if (default_index != -1)
3620 ereport(ERROR,
3622 errmsg("DEFAULT partition should be one"),
3623 parser_errposition(cxt->pstate, sps->name->location));
3624
3625 default_index = foreach_current_index(sps);
3626 }
3627 }
3628 }
3629 break;
3630
3632 ereport(ERROR,
3634 errmsg("partition of hash-partitioned table cannot be split"));
3635 break;
3636
3637 default:
3638 elog(ERROR, "unexpected partition strategy: %d",
3639 (int) key->strategy);
3640 break;
3641 }
3642
3643 /* isSplitPartDefault: is the being split partition a DEFAULT partition? */
3645
3646 if (isSplitPartDefault && default_index == -1)
3647 ereport(ERROR,
3649 errmsg("can not split DEFAULT partition \"%s\"",
3651 errhint("To split DEFAULT partition one of the new partition msut be DEFAULT"),
3653
3654 /*
3655 * If the partition being split is not the DEFAULT partition, but the
3656 * DEFAULT partition exists, then none of the resulting split partitions
3657 * can be the DEFAULT.
3658 */
3659 if (!isSplitPartDefault && (default_index != -1) && OidIsValid(defaultPartOid))
3660 {
3662 (SinglePartitionSpec *) list_nth(splitlist, default_index);
3663
3664 ereport(ERROR,
3666 errmsg("can not split non-DEFAULT partition \"%s\"",
3668 errmsg("new partition cannot be DEFAULT because DEFAULT partition \"%s\" already exists",
3670 parser_errposition(cxt->pstate, spsDef->name->location));
3671 }
3672
3673 foreach(listptr, splitlist)
3674 {
3675 Oid nspid;
3677 RangeVar *name = sps->name;
3678
3680
3681 /* Partitions in the list should have different names. */
3683 {
3684 Oid nspid2;
3686 RangeVar *name2 = sps2->name;
3687
3688 if (equal(name, name2))
3689 ereport(ERROR,
3691 errmsg("partition with name \"%s\" is already used", name->relname),
3692 parser_errposition(cxt->pstate, name2->location));
3693
3695
3696 if (nspid2 == nspid && strcmp(name->relname, name2->relname) == 0)
3697 ereport(ERROR,
3699 errmsg("partition with name \"%s\" is already used", name->relname),
3700 parser_errposition(cxt->pstate, name2->location));
3701 }
3702 }
3703
3704 /* Then we should check partitions with transformed bounds. */
3706}
3707
3708
3709/*
3710 * transformPartitionCmdForMerge -
3711 * analyze the ALTER TABLE ... MERGE PARTITIONS command
3712 *
3713 * Does simple checks for merged partitions. Calculates bound of the resulting
3714 * partition.
3715 */
3716static void
3718{
3720 Oid partOid;
3721 Relation parent = cxt->rel;
3722 PartitionKey key;
3723 char strategy;
3725 *listptr2;
3726 bool isDefaultPart = false;
3727 List *partOids = NIL;
3728
3729 key = RelationGetPartitionKey(parent);
3730 strategy = get_partition_strategy(key);
3731
3732 if (strategy == PARTITION_STRATEGY_HASH)
3733 ereport(ERROR,
3735 errmsg("partition of hash-partitioned table cannot be merged"));
3736
3737 /* Does the partitioned table (parent) have a default partition? */
3739
3740 foreach(listptr, partcmd->partlist)
3741 {
3743
3744 /* Partitions in the list should have different names. */
3745 for_each_cell(listptr2, partcmd->partlist, lnext(partcmd->partlist, listptr))
3746 {
3748
3749 if (equal(name, name2))
3750 ereport(ERROR,
3752 errmsg("partition with name \"%s\" is already used", name->relname),
3753 parser_errposition(cxt->pstate, name2->location));
3754 }
3755
3756 /*
3757 * Search the DEFAULT partition in the list. Open and lock partitions
3758 * before calculating the boundary for resulting partition, we also
3759 * check for ownership along the way. We need to use
3760 * AccessExclusiveLock here, because these merged partitions will be
3761 * detached and then dropped in ATExecMergePartitions.
3762 */
3765 NULL);
3766 /* Is the current partition a DEFAULT partition? */
3767 if (partOid == defaultPartOid)
3768 isDefaultPart = true;
3769
3770 /*
3771 * Extended check because the same partition can have different names
3772 * (for example, "part_name" and "public.part_name").
3773 */
3774 foreach(listptr2, partOids)
3775 {
3777
3778 if (curOid == partOid)
3779 ereport(ERROR,
3781 errmsg("partition with name \"%s\" is already used", name->relname),
3782 parser_errposition(cxt->pstate, name->location));
3783 }
3784
3785 checkPartition(parent, partOid, true);
3786
3788 }
3789
3790 /* Allocate the bound of the resulting partition. */
3791 Assert(partcmd->bound == NULL);
3793
3794 /* Fill the partition bound. */
3795 partcmd->bound->strategy = strategy;
3796 partcmd->bound->location = -1;
3797 partcmd->bound->is_default = isDefaultPart;
3798 if (!isDefaultPart)
3800 partOids, partcmd->bound,
3801 cxt->pstate);
3802}
3803
3804/*
3805 * transformAlterTableStmt -
3806 * parse analysis for ALTER TABLE
3807 *
3808 * Returns the transformed AlterTableStmt. There may be additional actions
3809 * to be done before and after the transformed statement, which are returned
3810 * in *beforeStmts and *afterStmts as lists of utility command parsetrees.
3811 *
3812 * To avoid race conditions, it's important that this function rely only on
3813 * the passed-in relid (and not on stmt->relation) to determine the target
3814 * relation.
3815 */
3818 const char *queryString,
3819 List **beforeStmts, List **afterStmts)
3820{
3821 Relation rel;
3822 TupleDesc tupdesc;
3823 ParseState *pstate;
3826 ListCell *lcmd,
3827 *l;
3828 List *newcmds = NIL;
3829 bool skipValidation = true;
3832
3833 /* Caller is responsible for locking the relation */
3834 rel = relation_open(relid, NoLock);
3835 tupdesc = RelationGetDescr(rel);
3836
3837 /* Set up pstate */
3838 pstate = make_parsestate(NULL);
3839 pstate->p_sourcetext = queryString;
3841 rel,
3843 NULL,
3844 false,
3845 true);
3846 addNSItemToQuery(pstate, nsitem, false, true, true);
3847
3848 /* Set up CreateStmtContext */
3849 cxt.pstate = pstate;
3850 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3851 {
3852 cxt.stmtType = "ALTER FOREIGN TABLE";
3853 cxt.isforeign = true;
3854 }
3855 else
3856 {
3857 cxt.stmtType = "ALTER TABLE";
3858 cxt.isforeign = false;
3859 }
3860 cxt.relation = stmt->relation;
3861 cxt.rel = rel;
3862 cxt.inhRelations = NIL;
3863 cxt.isalter = true;
3864 cxt.columns = NIL;
3865 cxt.ckconstraints = NIL;
3866 cxt.nnconstraints = NIL;
3867 cxt.fkconstraints = NIL;
3868 cxt.ixconstraints = NIL;
3869 cxt.likeclauses = NIL;
3870 cxt.blist = NIL;
3871 cxt.alist = NIL;
3872 cxt.pkey = NULL;
3873 cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3874 cxt.partbound = NULL;
3875 cxt.ofType = false;
3876
3877 /*
3878 * Transform ALTER subcommands that need it (most don't). These largely
3879 * re-use code from CREATE TABLE.
3880 */
3881 foreach(lcmd, stmt->cmds)
3882 {
3884
3885 switch (cmd->subtype)
3886 {
3887 case AT_AddColumn:
3888 {
3889 ColumnDef *def = castNode(ColumnDef, cmd->def);
3890
3891 transformColumnDefinition(&cxt, def);
3892
3893 /*
3894 * If the column has a non-null default, we can't skip
3895 * validation of foreign keys.
3896 */
3897 if (def->raw_default != NULL)
3898 skipValidation = false;
3899
3900 /*
3901 * All constraints are processed in other ways. Remove the
3902 * original list
3903 */
3904 def->constraints = NIL;
3905
3906 newcmds = lappend(newcmds, cmd);
3907 break;
3908 }
3909
3910 case AT_AddConstraint:
3911
3912 /*
3913 * The original AddConstraint cmd node doesn't go to newcmds
3914 */
3915 if (IsA(cmd->def, Constraint))
3916 {
3917 transformTableConstraint(&cxt, (Constraint *) cmd->def);
3918 if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
3919 skipValidation = false;
3920 }
3921 else
3922 elog(ERROR, "unrecognized node type: %d",
3923 (int) nodeTag(cmd->def));
3924 break;
3925
3926 case AT_AlterColumnType:
3927 {
3928 ColumnDef *def = castNode(ColumnDef, cmd->def);
3930
3931 /*
3932 * For ALTER COLUMN TYPE, transform the USING clause if
3933 * one was specified.
3934 */
3935 if (def->raw_default)
3936 {
3937 def->cooked_default =
3938 transformExpr(pstate, def->raw_default,
3940 }
3941
3942 /*
3943 * For identity column, create ALTER SEQUENCE command to
3944 * change the data type of the sequence. Identity sequence
3945 * is associated with the top level partitioned table.
3946 * Hence ignore partitions.
3947 */
3949 {
3950 attnum = get_attnum(relid, cmd->name);
3952 ereport(ERROR,
3954 errmsg("column \"%s\" of relation \"%s\" does not exist",
3955 cmd->name, RelationGetRelationName(rel))));
3956
3957 if (attnum > 0 &&
3958 TupleDescAttr(tupdesc, attnum - 1)->attidentity)
3959 {
3960 Oid seq_relid = getIdentitySequence(rel, attnum, false);
3961 Oid typeOid = typenameTypeId(pstate, def->typeName);
3963
3964 altseqstmt->sequence
3967 -1);
3968 altseqstmt->options = list_make1(makeDefElem("as",
3969 (Node *) makeTypeNameFromOid(typeOid, -1),
3970 -1));
3971 altseqstmt->for_identity = true;
3972 cxt.blist = lappend(cxt.blist, altseqstmt);
3973 }
3974 }
3975
3976 newcmds = lappend(newcmds, cmd);
3977 break;
3978 }
3979
3980 case AT_AddIdentity:
3981 {
3982 Constraint *def = castNode(Constraint, cmd->def);
3985
3986 newdef->colname = cmd->name;
3987 newdef->identity = def->generated_when;
3988 cmd->def = (Node *) newdef;
3989
3990 attnum = get_attnum(relid, cmd->name);
3992 ereport(ERROR,
3994 errmsg("column \"%s\" of relation \"%s\" does not exist",
3995 cmd->name, RelationGetRelationName(rel))));
3996
3998 get_atttype(relid, attnum),
3999 def->options, true, true,
4000 NULL, NULL);
4001
4002 newcmds = lappend(newcmds, cmd);
4003 break;
4004 }
4005
4006 case AT_SetIdentity:
4007 {
4008 /*
4009 * Create an ALTER SEQUENCE statement for the internal
4010 * sequence of the identity column.
4011 */
4012 ListCell *lc;
4013 List *newseqopts = NIL;
4014 List *newdef = NIL;
4016 Oid seq_relid;
4017
4018 /*
4019 * Split options into those handled by ALTER SEQUENCE and
4020 * those for ALTER TABLE proper.
4021 */
4022 foreach(lc, castNode(List, cmd->def))
4023 {
4024 DefElem *def = lfirst_node(DefElem, lc);
4025
4026 if (strcmp(def->defname, "generated") == 0)
4027 newdef = lappend(newdef, def);
4028 else
4030 }
4031
4032 attnum = get_attnum(relid, cmd->name);
4034 ereport(ERROR,
4036 errmsg("column \"%s\" of relation \"%s\" does not exist",
4037 cmd->name, RelationGetRelationName(rel))));
4038
4039 seq_relid = getIdentitySequence(rel, attnum, true);
4040
4041 if (seq_relid)
4042 {
4044
4047 get_rel_name(seq_relid), -1);
4048 seqstmt->options = newseqopts;
4049 seqstmt->for_identity = true;
4050 seqstmt->missing_ok = false;
4051
4052 cxt.blist = lappend(cxt.blist, seqstmt);
4053 }
4054
4055 /*
4056 * If column was not an identity column, we just let the
4057 * ALTER TABLE command error out later. (There are cases
4058 * this fails to cover, but we'll need to restructure
4059 * where creation of the sequence dependency linkage
4060 * happens before we can fix it.)
4061 */
4062
4063 cmd->def = (Node *) newdef;
4064 newcmds = lappend(newcmds, cmd);
4065 break;
4066 }
4067
4068 case AT_AttachPartition:
4069 case AT_DetachPartition:
4070 {
4072
4073 transformPartitionCmd(&cxt, partcmd->bound);
4074 /* assign the transformed value of the partition bound */
4075 partcmd->bound = cxt.partbound;
4076 }
4077
4078 newcmds = lappend(newcmds, cmd);
4079 break;
4080
4081 case AT_MergePartitions:
4082 {
4084
4085 if (list_length(partcmd->partlist) < 2)
4086 ereport(ERROR,
4088 errmsg("list of partitions to be merged should include at least two partitions"));
4089
4091 newcmds = lappend(newcmds, cmd);
4092 break;
4093 }
4094
4095 case AT_SplitPartition:
4096 {
4098
4099 if (list_length(partcmd->partlist) < 2)
4100 ereport(ERROR,
4102 errmsg("list of new partitions should contain at least two partitions"));
4103
4105 newcmds = lappend(newcmds, cmd);
4106 break;
4107 }
4108
4109 default:
4110
4111 /*
4112 * Currently, we shouldn't actually get here for the
4113 * subcommand types that don't require transformation; but if
4114 * we do, just emit them unchanged.
4115 */
4116 newcmds = lappend(newcmds, cmd);
4117 break;
4118 }
4119 }
4120
4121 /*
4122 * Transfer anything we already have in cxt.alist into save_alist, to keep
4123 * it separate from the output of transformIndexConstraints.
4124 */
4125 save_alist = cxt.alist;
4126 cxt.alist = NIL;
4127
4128 /* Postprocess constraints */
4131 transformCheckConstraints(&cxt, false);
4132
4133 /*
4134 * Push any index-creation commands into the ALTER, so that they can be
4135 * scheduled nicely by tablecmds.c. Note that tablecmds.c assumes that
4136 * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
4137 * subcommand has already been through transformIndexStmt.
4138 */
4139 foreach(l, cxt.alist)
4140 {
4141 Node *istmt = (Node *) lfirst(l);
4142
4143 /*
4144 * We assume here that cxt.alist contains only IndexStmts generated
4145 * from primary key constraints.
4146 */
4147 if (IsA(istmt, IndexStmt))
4148 {
4149 IndexStmt *idxstmt = (IndexStmt *) istmt;
4150
4151 idxstmt = transformIndexStmt(relid, idxstmt, queryString);
4153 newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
4154 newcmd->def = (Node *) idxstmt;
4156 }
4157 else
4158 elog(ERROR, "unexpected stmt type %d", (int) nodeTag(istmt));
4159 }
4160 cxt.alist = NIL;
4161
4162 /* Append any CHECK, NOT NULL or FK constraints to the commands list */
4164 {
4166 newcmd->subtype = AT_AddConstraint;
4167 newcmd->def = (Node *) def;
4169 }
4171 {
4173 newcmd->subtype = AT_AddConstraint;
4174 newcmd->def = (Node *) def;
4176 }
4178 {
4180 newcmd->subtype = AT_AddConstraint;
4181 newcmd->def = (Node *) def;
4183 }
4184
4185 /* Close rel */
4186 relation_close(rel, NoLock);
4187
4188 /*
4189 * Output results.
4190 */
4191 stmt->cmds = newcmds;
4192
4193 *beforeStmts = cxt.blist;
4194 *afterStmts = list_concat(cxt.alist, save_alist);
4195
4196 return stmt;
4197}
4198
4199
4200/*
4201 * Preprocess a list of column constraint clauses
4202 * to attach constraint attributes to their primary constraint nodes
4203 * and detect inconsistent/misplaced constraint attributes.
4204 *
4205 * NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
4206 * EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
4207 * supported for other constraint types.
4208 */
4209static void
4211{
4213 bool saw_deferrability = false;
4214 bool saw_initially = false;
4215 bool saw_enforced = false;
4216 ListCell *clist;
4217
4218#define SUPPORTS_ATTRS(node) \
4219 ((node) != NULL && \
4220 ((node)->contype == CONSTR_PRIMARY || \
4221 (node)->contype == CONSTR_UNIQUE || \
4222 (node)->contype == CONSTR_EXCLUSION || \
4223 (node)->contype == CONSTR_FOREIGN))
4224
4225 foreach(clist, constraintList)
4226 {
4227 Constraint *con = (Constraint *) lfirst(clist);
4228
4229 if (!IsA(con, Constraint))
4230 elog(ERROR, "unrecognized node type: %d",
4231 (int) nodeTag(con));
4232 switch (con->contype)
4233 {
4236 ereport(ERROR,
4238 errmsg("misplaced DEFERRABLE clause"),
4239 parser_errposition(cxt->pstate, con->location)));
4241 ereport(ERROR,
4243 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
4244 parser_errposition(cxt->pstate, con->location)));
4245 saw_deferrability = true;
4246 lastprimarycon->deferrable = true;
4247 break;
4248
4251 ereport(ERROR,
4253 errmsg("misplaced NOT DEFERRABLE clause"),
4254 parser_errposition(cxt->pstate, con->location)));
4256 ereport(ERROR,
4258 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
4259 parser_errposition(cxt->pstate, con->location)));
4260 saw_deferrability = true;
4261 lastprimarycon->deferrable = false;
4262 if (saw_initially &&
4263 lastprimarycon->initdeferred)
4264 ereport(ERROR,
4266 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
4267 parser_errposition(cxt->pstate, con->location)));
4268 break;
4269
4272 ereport(ERROR,
4274 errmsg("misplaced INITIALLY DEFERRED clause"),
4275 parser_errposition(cxt->pstate, con->location)));
4276 if (saw_initially)
4277 ereport(ERROR,
4279 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
4280 parser_errposition(cxt->pstate, con->location)));
4281 saw_initially = true;
4282 lastprimarycon->initdeferred = true;
4283
4284 /*
4285 * If only INITIALLY DEFERRED appears, assume DEFERRABLE
4286 */
4287 if (!saw_deferrability)
4288 lastprimarycon->deferrable = true;
4289 else if (!lastprimarycon->deferrable)
4290 ereport(ERROR,
4292 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
4293 parser_errposition(cxt->pstate, con->location)));
4294 break;
4295
4298 ereport(ERROR,
4300 errmsg("misplaced INITIALLY IMMEDIATE clause"),
4301 parser_errposition(cxt->pstate, con->location)));
4302 if (saw_initially)
4303 ereport(ERROR,
4305 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
4306 parser_errposition(cxt->pstate, con->location)));
4307 saw_initially = true;
4308 lastprimarycon->initdeferred = false;
4309 break;
4310
4312 if (lastprimarycon == NULL ||
4313 (lastprimarycon->contype != CONSTR_CHECK &&
4314 lastprimarycon->contype != CONSTR_FOREIGN))
4315 ereport(ERROR,
4317 errmsg("misplaced ENFORCED clause"),
4318 parser_errposition(cxt->pstate, con->location)));
4319 if (saw_enforced)
4320 ereport(ERROR,
4322 errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
4323 parser_errposition(cxt->pstate, con->location)));
4324 saw_enforced = true;
4325 lastprimarycon->is_enforced = true;
4326 break;
4327
4329 if (lastprimarycon == NULL ||
4330 (lastprimarycon->contype != CONSTR_CHECK &&
4331 lastprimarycon->contype != CONSTR_FOREIGN))
4332 ereport(ERROR,
4334 errmsg("misplaced NOT ENFORCED clause"),
4335 parser_errposition(cxt->pstate, con->location)));
4336 if (saw_enforced)
4337 ereport(ERROR,
4339 errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
4340 parser_errposition(cxt->pstate, con->location)));
4341 saw_enforced = true;
4342 lastprimarycon->is_enforced = false;
4343
4344 /* A NOT ENFORCED constraint must be marked as invalid. */
4345 lastprimarycon->skip_validation = true;
4346 lastprimarycon->initially_valid = false;
4347 break;
4348
4349 default:
4350 /* Otherwise it's not an attribute */
4351 lastprimarycon = con;
4352 /* reset flags for new primary node */
4353 saw_deferrability = false;
4354 saw_initially = false;
4355 saw_enforced = false;
4356 break;
4357 }
4358 }
4359}
4360
4361/*
4362 * Special handling of type definition for a column
4363 */
4364static void
4366{
4367 /*
4368 * All we really need to do here is verify that the type is valid,
4369 * including any collation spec that might be present.
4370 */
4371 Type ctype = typenameType(cxt->pstate, column->typeName, NULL);
4372
4373 if (column->collClause)
4374 {
4376
4378 column->collClause->collname,
4379 column->collClause->location);
4380 /* Complain if COLLATE is applied to an uncollatable type */
4381 if (!OidIsValid(typtup->typcollation))
4382 ereport(ERROR,
4384 errmsg("collations are not supported by type %s",
4385 format_type_be(typtup->oid)),
4387 column->collClause->location)));
4388 }
4389
4390 ReleaseSysCache(ctype);
4391}
4392
4393
4394/*
4395 * transformCreateSchemaStmtElements -
4396 * analyzes the elements of a CREATE SCHEMA statement
4397 *
4398 * Split the schema element list from a CREATE SCHEMA statement into
4399 * individual commands and place them in the result list in an order
4400 * such that there are no forward references (e.g. GRANT to a table
4401 * created later in the list). Note that the logic we use for determining
4402 * forward references is presently quite incomplete.
4403 *
4404 * "schemaName" is the name of the schema that will be used for the creation
4405 * of the objects listed, that may be compiled from the schema name defined
4406 * in the statement or a role specification.
4407 *
4408 * SQL also allows constraints to make forward references, so thumb through
4409 * the table columns and move forward references to a posterior alter-table
4410 * command.
4411 *
4412 * The result is a list of parse nodes that still need to be analyzed ---
4413 * but we can't analyze the later commands until we've executed the earlier
4414 * ones, because of possible inter-object references.
4415 *
4416 * Note: this breaks the rules a little bit by modifying schema-name fields
4417 * within passed-in structs. However, the transformation would be the same
4418 * if done over, so it should be all right to scribble on the input to this
4419 * extent.
4420 */
4421List *
4423{
4425 List *result;
4426 ListCell *elements;
4427
4428 cxt.schemaname = schemaName;
4429 cxt.sequences = NIL;
4430 cxt.tables = NIL;
4431 cxt.views = NIL;
4432 cxt.indexes = NIL;
4433 cxt.triggers = NIL;
4434 cxt.grants = NIL;
4435
4436 /*
4437 * Run through each schema element in the schema element list. Separate
4438 * statements by type, and do preliminary analysis.
4439 */
4440 foreach(elements, schemaElts)
4441 {
4442 Node *element = lfirst(elements);
4443
4444 switch (nodeTag(element))
4445 {
4446 case T_CreateSeqStmt:
4447 {
4449
4450 setSchemaName(cxt.schemaname, &elp->sequence->schemaname);
4451 cxt.sequences = lappend(cxt.sequences, element);
4452 }
4453 break;
4454
4455 case T_CreateStmt:
4456 {
4458
4459 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
4460
4461 /*
4462 * XXX todo: deal with constraints
4463 */
4464 cxt.tables = lappend(cxt.tables, element);
4465 }
4466 break;
4467
4468 case T_ViewStmt:
4469 {
4471
4472 setSchemaName(cxt.schemaname, &elp->view->schemaname);
4473
4474 /*
4475 * XXX todo: deal with references between views
4476 */
4477 cxt.views = lappend(cxt.views, element);
4478 }
4479 break;
4480
4481 case T_IndexStmt:
4482 {
4484
4485 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
4486 cxt.indexes = lappend(cxt.indexes, element);
4487 }
4488 break;
4489
4490 case T_CreateTrigStmt:
4491 {
4493
4494 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
4495 cxt.triggers = lappend(cxt.triggers, element);
4496 }
4497 break;
4498
4499 case T_GrantStmt:
4500 cxt.grants = lappend(cxt.grants, element);
4501 break;
4502
4503 default:
4504 elog(ERROR, "unrecognized node type: %d",
4505 (int) nodeTag(element));
4506 }
4507 }
4508
4509 result = NIL;
4510 result = list_concat(result, cxt.sequences);
4511 result = list_concat(result, cxt.tables);
4512 result = list_concat(result, cxt.views);
4513 result = list_concat(result, cxt.indexes);
4514 result = list_concat(result, cxt.triggers);
4515 result = list_concat(result, cxt.grants);
4516
4517 return result;
4518}
4519
4520/*
4521 * setSchemaName
4522 * Set or check schema name in an element of a CREATE SCHEMA command
4523 */
4524static void
4526{
4527 if (*stmt_schema_name == NULL)
4529 else if (strcmp(context_schema, *stmt_schema_name) != 0)
4530 ereport(ERROR,
4532 errmsg("CREATE specifies a schema (%s) "
4533 "different from the one being created (%s)",
4535}
4536
4537/*
4538 * transformPartitionCmd
4539 * Analyze the ATTACH/DETACH/SPLIT PARTITION command
4540 *
4541 * In case of the ATTACH/SPLIT PARTITION command, cxt->partbound is set to the
4542 * transformed value of bound.
4543 */
4544static void
4546{
4547 Relation parentRel = cxt->rel;
4548
4549 switch (parentRel->rd_rel->relkind)
4550 {
4552 /* transform the partition bound, if any */
4554 if (bound != NULL)
4556 bound);
4557 break;
4559
4560 /*
4561 * A partitioned index cannot have a partition bound set. ALTER
4562 * INDEX prevents that with its grammar, but not ALTER TABLE.
4563 */
4564 if (bound != NULL)
4565 ereport(ERROR,
4567 errmsg("\"%s\" is not a partitioned table",
4569 break;
4570 case RELKIND_RELATION:
4571 /* the table must be partitioned */
4572 ereport(ERROR,
4574 errmsg("table \"%s\" is not partitioned",
4576 break;
4577 case RELKIND_INDEX:
4578 /* the index must be partitioned */
4579 ereport(ERROR,
4581 errmsg("index \"%s\" is not partitioned",
4583 break;
4584 default:
4585 /* parser shouldn't let this case through */
4586 elog(ERROR, "\"%s\" is not a partitioned table or index",
4588 break;
4589 }
4590}
4591
4592/*
4593 * transformPartitionBound
4594 *
4595 * Transform a partition bound specification
4596 */
4600{
4603 char strategy = get_partition_strategy(key);
4604 int partnatts = get_partition_natts(key);
4605 List *partexprs = get_partition_exprs(key);
4606
4607 /* Avoid scribbling on input */
4609
4610 if (spec->is_default)
4611 {
4612 /*
4613 * Hash partitioning does not support a default partition; there's no
4614 * use case for it (since the set of partitions to create is perfectly
4615 * defined), and if users do get into it accidentally, it's hard to
4616 * back out from it afterwards.
4617 */
4618 if (strategy == PARTITION_STRATEGY_HASH)
4619 ereport(ERROR,
4621 errmsg("a hash-partitioned table may not have a default partition")));
4622
4623 /*
4624 * In case of the default partition, parser had no way to identify the
4625 * partition strategy. Assign the parent's strategy to the default
4626 * partition bound spec.
4627 */
4628 result_spec->strategy = strategy;
4629
4630 return result_spec;
4631 }
4632
4633 if (strategy == PARTITION_STRATEGY_HASH)
4634 {
4635 if (spec->strategy != PARTITION_STRATEGY_HASH)
4636 ereport(ERROR,
4638 errmsg("invalid bound specification for a hash partition"),
4639 parser_errposition(pstate, exprLocation((Node *) spec))));
4640
4641 if (spec->modulus <= 0)
4642 ereport(ERROR,
4644 errmsg("modulus for hash partition must be an integer value greater than zero")));
4645
4646 Assert(spec->remainder >= 0);
4647
4648 if (spec->remainder >= spec->modulus)
4649 ereport(ERROR,
4651 errmsg("remainder for hash partition must be less than modulus")));
4652 }
4653 else if (strategy == PARTITION_STRATEGY_LIST)
4654 {
4655 ListCell *cell;
4656 char *colname;
4657 Oid coltype;
4659 Oid partcollation;
4660
4661 if (spec->strategy != PARTITION_STRATEGY_LIST)
4662 ereport(ERROR,
4664 errmsg("invalid bound specification for a list partition"),
4665 parser_errposition(pstate, exprLocation((Node *) spec))));
4666
4667 /* Get the only column's name in case we need to output an error */
4668 if (key->partattrs[0] != 0)
4669 colname = get_attname(RelationGetRelid(parent),
4670 key->partattrs[0], false);
4671 else
4672 colname = deparse_expression((Node *) linitial(partexprs),
4674 RelationGetRelid(parent)),
4675 false, false);
4676 /* Need its type data too */
4677 coltype = get_partition_col_typid(key, 0);
4679 partcollation = get_partition_col_collation(key, 0);
4680
4681 result_spec->listdatums = NIL;
4682 foreach(cell, spec->listdatums)
4683 {
4684 Node *expr = lfirst(cell);
4685 Const *value;
4686 ListCell *cell2;
4687 bool duplicate;
4688
4689 value = transformPartitionBoundValue(pstate, expr,
4690 colname, coltype, coltypmod,
4691 partcollation);
4692
4693 /* Don't add to the result if the value is a duplicate */
4694 duplicate = false;
4695 foreach(cell2, result_spec->listdatums)
4696 {
4698
4699 if (equal(value, value2))
4700 {
4701 duplicate = true;
4702 break;
4703 }
4704 }
4705 if (duplicate)
4706 continue;
4707
4708 result_spec->listdatums = lappend(result_spec->listdatums,
4709 value);
4710 }
4711 }
4712 else if (strategy == PARTITION_STRATEGY_RANGE)
4713 {
4714 if (spec->strategy != PARTITION_STRATEGY_RANGE)
4715 ereport(ERROR,
4717 errmsg("invalid bound specification for a range partition"),
4718 parser_errposition(pstate, exprLocation((Node *) spec))));
4719
4720 if (list_length(spec->lowerdatums) != partnatts)
4721 ereport(ERROR,
4723 errmsg("FROM must specify exactly one value per partitioning column")));
4724 if (list_length(spec->upperdatums) != partnatts)
4725 ereport(ERROR,
4727 errmsg("TO must specify exactly one value per partitioning column")));
4728
4729 /*
4730 * Convert raw parse nodes into PartitionRangeDatum nodes and perform
4731 * any necessary validation.
4732 */
4733 result_spec->lowerdatums =
4734 transformPartitionRangeBounds(pstate, spec->lowerdatums,
4735 parent);
4736 result_spec->upperdatums =
4737 transformPartitionRangeBounds(pstate, spec->upperdatums,
4738 parent);
4739 }
4740 else
4741 elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
4742
4743 return result_spec;
4744}
4745
4746/*
4747 * transformPartitionRangeBounds
4748 * This converts the expressions for range partition bounds from the raw
4749 * grammar representation to PartitionRangeDatum structs
4750 */
4751static List *
4753 Relation parent)
4754{
4755 List *result = NIL;
4757 List *partexprs = get_partition_exprs(key);
4758 ListCell *lc;
4759 int i,
4760 j;
4761
4762 j = 0;
4763 foreach(lc, blist)
4764 {
4765 Node *expr = lfirst(lc);
4767
4769
4770 /*
4771 * Infinite range bounds -- "minvalue" and "maxvalue" -- get passed in
4772 * as ColumnRefs.
4773 */
4774 if (IsA(expr, ColumnRef))
4775 {
4776 ColumnRef *cref = (ColumnRef *) expr;
4777 char *cname = NULL;
4778
4779 /*
4780 * There should be a single field named either "minvalue" or
4781 * "maxvalue".
4782 */
4783 if (list_length(cref->fields) == 1 &&
4784 IsA(linitial(cref->fields), String))
4785 cname = strVal(linitial(cref->fields));
4786
4787 if (cname == NULL)
4788 {
4789 /*
4790 * ColumnRef is not in the desired single-field-name form. For
4791 * consistency between all partition strategies, let the
4792 * expression transformation report any errors rather than
4793 * doing it ourselves.
4794 */
4795 }
4796 else if (strcmp("minvalue", cname) == 0)
4797 {
4800 prd->value = NULL;
4801 }
4802 else if (strcmp("maxvalue", cname) == 0)
4803 {
4806 prd->value = NULL;
4807 }
4808 }
4809
4810 if (prd == NULL)
4811 {
4812 char *colname;
4813 Oid coltype;
4815 Oid partcollation;
4816 Const *value;
4817
4818 /* Get the column's name in case we need to output an error */
4819 if (key->partattrs[i] != 0)
4820 colname = get_attname(RelationGetRelid(parent),
4821 key->partattrs[i], false);
4822 else
4823 {
4824 colname = deparse_expression((Node *) list_nth(partexprs, j),
4826 RelationGetRelid(parent)),
4827 false, false);
4828 ++j;
4829 }
4830
4831 /* Need its type data too */
4832 coltype = get_partition_col_typid(key, i);
4834 partcollation = get_partition_col_collation(key, i);
4835
4836 value = transformPartitionBoundValue(pstate, expr,
4837 colname,
4838 coltype, coltypmod,
4839 partcollation);
4840 if (value->constisnull)
4841 ereport(ERROR,
4843 errmsg("cannot specify NULL in range bound")));
4846 prd->value = (Node *) value;
4847 }
4848
4849 prd->location = exprLocation(expr);
4850
4851 result = lappend(result, prd);
4852 }
4853
4854 /*
4855 * Once we see MINVALUE or MAXVALUE for one column, the remaining columns
4856 * must be the same.
4857 */
4858 validateInfiniteBounds(pstate, result);
4859
4860 return result;
4861}
4862
4863/*
4864 * validateInfiniteBounds
4865 *
4866 * Check that a MAXVALUE or MINVALUE specification in a partition bound is
4867 * followed only by more of the same.
4868 */
4869static void
4871{
4872 ListCell *lc;
4874
4875 foreach(lc, blist)
4876 {
4878
4879 if (kind == prd->kind)
4880 continue;
4881
4882 switch (kind)
4883 {
4885 kind = prd->kind;
4886 break;
4887
4889 ereport(ERROR,
4891 errmsg("every bound following MAXVALUE must also be MAXVALUE"),
4892 parser_errposition(pstate, exprLocation((Node *) prd))));
4893 break;
4894
4896 ereport(ERROR,
4898 errmsg("every bound following MINVALUE must also be MINVALUE"),
4899 parser_errposition(pstate, exprLocation((Node *) prd))));
4900 break;
4901 }
4902 }
4903}
4904
4905/*
4906 * Transform one entry in a partition bound spec, producing a constant.
4907 */
4908static Const *
4910 const char *colName, Oid colType, int32 colTypmod,
4912{
4913 Node *value;
4914
4915 /* Transform raw parsetree */
4917
4918 /*
4919 * transformExpr() should have already rejected column references,
4920 * subqueries, aggregates, window functions, and SRFs, based on the
4921 * EXPR_KIND_ of a partition bound expression.
4922 */
4924
4925 /*
4926 * Coerce to the correct type. This might cause an explicit coercion step
4927 * to be added on top of the expression, which must be evaluated before
4928 * returning the result to the caller.
4929 */
4932 colType,
4933 colTypmod,
4936 -1);
4937
4938 if (value == NULL)
4939 ereport(ERROR,
4941 errmsg("specified value cannot be cast to type %s for column \"%s\"",
4944
4945 /*
4946 * Evaluate the expression, if needed, assigning the partition key's data
4947 * type and collation to the resulting Const node.
4948 */
4949 if (!IsA(value, Const))
4950 {
4955 if (!IsA(value, Const))
4956 elog(ERROR, "could not evaluate partition bound expression");
4957 }
4958 else
4959 {
4960 /*
4961 * If the expression is already a Const, as is often the case, we can
4962 * skip the rather expensive steps above. But we still have to insert
4963 * the right collation, since coerce_to_target_type doesn't handle
4964 * that.
4965 */
4966 ((Const *) value)->constcollid = partCollation;
4967 }
4968
4969 /*
4970 * Attach original expression's parse location to the Const, so that
4971 * that's what will be reported for any later errors related to this
4972 * partition bound.
4973 */
4974 ((Const *) value)->location = exprLocation(val);
4975
4976 return (Const *) value;
4977}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4082
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition amcmds.c:163
#define ARR_NDIM(a)
Definition array.h:290
#define ARR_DATA_PTR(a)
Definition array.h:322
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_HASNULL(a)
Definition array.h:291
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition attmap.c:175
int16 AttrNumber
Definition attnum.h:21
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
#define InvalidAttrNumber
Definition attnum.h:23
char * get_tablespace_name(Oid spc_oid)
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:837
#define unconstify(underlying_type, expr)
Definition c.h:1327
#define InvalidSubTransactionId
Definition c.h:744
#define Assert(condition)
Definition c.h:945
int16_t int16
Definition c.h:613
int32_t int32
Definition c.h:614
#define pg_fallthrough
Definition c.h:152
#define OidIsValid(objectId)
Definition c.h:860
Expr * evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, Oid result_collation)
Definition clauses.c:5688
int nspid
List * sequence_options(Oid relid)
Definition sequence.c:1712
char * GetComment(Oid oid, Oid classoid, int32 subid)
Definition comment.c:420
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define DEBUG1
Definition elog.h:30
#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
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
char * format_type_be(Oid type_oid)
const FormData_pg_attribute * SystemAttributeByName(const char *attname)
Definition heap.c:248
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition heap.c:236
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
#define comment
#define DEFAULT_INDEX_TYPE
Definition index.h:27
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition indexcmds.c:2632
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2369
long val
Definition informix.c:689
static struct @174 value
int j
Definition isn.c:78
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
List * list_copy(const List *oldlist)
Definition list.c:1573
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
List * lcons(void *datum, List *list)
Definition list.c:495
void list_free(List *list)
Definition list.c:1546
#define NoLock
Definition lockdefs.h:34
#define AccessExclusiveLock
Definition lockdefs.h:43
#define AccessShareLock
Definition lockdefs.h:36
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:977
bool type_is_range(Oid typid)
Definition lsyscache.c:2910
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2172
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3278
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:946
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
Oid get_atttype(Oid relid, AttrNumber attnum)
Definition lsyscache.c:1032
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition lsyscache.c:2105
bool type_is_multirange(Oid typid)
Definition lsyscache.c:2920
Alias * makeAlias(const char *aliasname, List *colnames)
Definition makefuncs.c:438
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition makefuncs.c:637
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition makefuncs.c:336
ColumnDef * makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
Definition makefuncs.c:565
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition makefuncs.c:473
FuncCall * makeFuncCall(List *name, List *args, CoercionForm funcformat, int location)
Definition makefuncs.c:676
Constraint * makeNotNullConstraint(String *colname)
Definition makefuncs.c:493
TypeName * makeTypeNameFromOid(Oid typeOid, int32 typmod)
Definition makefuncs.c:547
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
Oid GetUserId(void)
Definition miscinit.c:470
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition namespace.c:740
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition namespace.c:847
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition namespace.c:655
RangeVar * makeRangeVarFromNameList(const List *names)
Definition namespace.c:3626
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int exprLocation(const Node *expr)
Definition nodeFuncs.c:1392
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define copyObject(obj)
Definition nodes.h:232
#define nodeTag(nodeptr)
Definition nodes.h:139
@ CMD_UTILITY
Definition nodes.h:280
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_SELECT
Definition nodes.h:275
@ CMD_NOTHING
Definition nodes.h:282
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static char * errmsg
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSet(addr, class_id, object_id)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
void cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
Definition parse_node.c:156
void free_parsestate(ParseState *pstate)
Definition parse_node.c:72
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
void setup_parser_errposition_callback(ParseCallbackState *pcbstate, ParseState *pstate, int location)
Definition parse_node.c:140
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
@ EXPR_KIND_STATS_EXPRESSION
Definition parse_node.h:74
@ EXPR_KIND_INDEX_EXPRESSION
Definition parse_node.h:72
@ EXPR_KIND_PARTITION_BOUND
Definition parse_node.h:79
@ EXPR_KIND_INDEX_PREDICATE
Definition parse_node.h:73
@ EXPR_KIND_ALTER_COL_TRANSFORM
Definition parse_node.h:75
@ EXPR_KIND_WHERE
Definition parse_node.h:46
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
char * FigureIndexColname(Node *node)
Oid LookupCollation(ParseState *pstate, List *collnames, int location)
Definition parse_type.c:515
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition parse_type.c:264
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
static void generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column, Oid seqtypid, List *seqoptions, bool for_identity, bool col_exists, char **snamespace_p, char **sname_p)
List * transformCreateStmt(CreateStmt *stmt, const char *queryString)
IndexStmt * transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
List * transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName)
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)
static void transformIndexConstraints(CreateStmtContext *cxt)
static List * get_collation(Oid collation, Oid actual_datatype)
static IndexStmt * transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
AlterTableStmt * transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, const char *queryString, List **beforeStmts, List **afterStmts)
static void transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
static void transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList)
List * expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
static void transformPartitionCmdForSplit(CreateStmtContext *cxt, PartitionCmd *partcmd)
static void transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
static List * get_opclass(Oid opclass, Oid actual_datatype)
static void transformPartitionCmdForMerge(CreateStmtContext *cxt, PartitionCmd *partcmd)
static void checkPartition(Relation rel, Oid partRelOid, bool isMerge)
static List * transformPartitionRangeBounds(ParseState *pstate, List *blist, Relation parent)
static void setSchemaName(const char *context_schema, char **stmt_schema_name)
CreateStatsStmt * transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
static void validateInfiniteBounds(ParseState *pstate, List *blist)
static void transformPartitionCmd(CreateStmtContext *cxt, PartitionBoundSpec *bound)
static Const * transformPartitionBoundValue(ParseState *pstate, Node *val, const char *colName, Oid colType, int32 colTypmod, Oid partCollation)
static void transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
static void transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
static CreateStatsStmt * generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid, Oid source_statsid, const AttrMap *attmap)
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
static void transformFKConstraints(CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint)
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
#define SUPPORTS_ATTRS(node)
@ SORTBY_NULLS_DEFAULT
Definition parsenodes.h:54
@ SORTBY_NULLS_LAST
Definition parsenodes.h:56
@ SORTBY_NULLS_FIRST
Definition parsenodes.h:55
#define ACL_USAGE
Definition parsenodes.h:84
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:916
@ PARTITION_STRATEGY_LIST
Definition parsenodes.h:914
@ PARTITION_STRATEGY_RANGE
Definition parsenodes.h:915
@ CONSTR_ATTR_ENFORCED
@ CONSTR_FOREIGN
@ CONSTR_ATTR_DEFERRED
@ CONSTR_IDENTITY
@ CONSTR_UNIQUE
@ CONSTR_ATTR_NOT_DEFERRABLE
@ CONSTR_DEFAULT
@ CONSTR_NOTNULL
@ CONSTR_ATTR_IMMEDIATE
@ CONSTR_CHECK
@ CONSTR_NULL
@ CONSTR_GENERATED
@ CONSTR_EXCLUSION
@ CONSTR_ATTR_DEFERRABLE
@ CONSTR_ATTR_NOT_ENFORCED
@ CONSTR_PRIMARY
PartitionRangeDatumKind
Definition parsenodes.h:965
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition parsenodes.h:968
@ PARTITION_RANGE_DATUM_VALUE
Definition parsenodes.h:967
@ PARTITION_RANGE_DATUM_MINVALUE
Definition parsenodes.h:966
@ DROP_RESTRICT
@ OBJECT_FOREIGN_TABLE
@ OBJECT_COLUMN
@ OBJECT_TABLE
@ OBJECT_TYPE
@ OBJECT_TABCONSTRAINT
@ AT_AddIndexConstraint
@ AT_MergePartitions
@ AT_SetIdentity
@ AT_AddIndex
@ AT_AddIdentity
@ AT_AlterColumnType
@ AT_AlterColumnGenericOptions
@ AT_DetachPartition
@ AT_AttachPartition
@ AT_AddConstraint
@ AT_CookedColumnDefault
@ AT_SplitPartition
@ AT_AddColumn
#define ACL_SELECT
Definition parsenodes.h:77
@ SORTBY_DESC
Definition parsenodes.h:48
@ SORTBY_DEFAULT
Definition parsenodes.h:46
@ CREATE_TABLE_LIKE_COMMENTS
Definition parsenodes.h:802
@ CREATE_TABLE_LIKE_GENERATED
Definition parsenodes.h:806
@ CREATE_TABLE_LIKE_IDENTITY
Definition parsenodes.h:807
@ CREATE_TABLE_LIKE_COMPRESSION
Definition parsenodes.h:803
@ CREATE_TABLE_LIKE_STORAGE
Definition parsenodes.h:810
@ CREATE_TABLE_LIKE_INDEXES
Definition parsenodes.h:808
@ CREATE_TABLE_LIKE_DEFAULTS
Definition parsenodes.h:805
@ CREATE_TABLE_LIKE_STATISTICS
Definition parsenodes.h:809
@ CREATE_TABLE_LIKE_CONSTRAINTS
Definition parsenodes.h:804
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition analyze.c:324
List * SystemFuncName(char *name)
TypeName * SystemTypeName(char *name)
void check_partitions_for_split(Relation parent, Oid splitPartOid, List *partlist, ParseState *pstate)
void calculate_partition_bound_for_merge(Relation parent, List *partNames, List *partOids, PartitionBoundSpec *spec, ParseState *pstate)
PartitionKey RelationGetPartitionKey(Relation rel)
Definition partcache.c:51
static int get_partition_strategy(PartitionKey key)
Definition partcache.h:59
static int32 get_partition_col_typmod(PartitionKey key, int col)
Definition partcache.h:92
static int get_partition_natts(PartitionKey key)
Definition partcache.h:65
static Oid get_partition_col_typid(PartitionKey key, int col)
Definition partcache.h:86
static List * get_partition_exprs(PartitionKey key)
Definition partcache.h:71
static Oid get_partition_col_collation(PartitionKey key, int col)
Definition partcache.h:98
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition partdesc.c:501
Oid get_partition_parent(Oid relid, bool even_if_detached)
Definition partition.c:53
END_CATALOG_STRUCT typedef FormData_pg_am * Form_pg_am
Definition pg_am.h:52
FormData_pg_attribute
NameData attname
int16 attnum
FormData_pg_attribute * Form_pg_attribute
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_collation * Form_pg_collation
List * RelationGetNotNullConstraints(Oid relid, bool cooked, bool include_noinh)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition pg_depend.c:260
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition pg_depend.c:1018
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1061
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial_node(type, l)
Definition pg_list.h:181
#define NIL
Definition pg_list.h:68
#define lsecond_node(type, l)
Definition pg_list.h:186
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
#define list_make1(x1)
Definition pg_list.h:212
#define for_each_cell(cell, lst, initcell)
Definition pg_list.h:438
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define linitial(l)
Definition pg_list.h:178
#define list_make3(x1, x2, x3)
Definition pg_list.h:216
#define foreach_node(type, var, lst)
Definition pg_list.h:496
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
#define lfirst_oid(lc)
Definition pg_list.h:174
#define list_make2(x1, x2)
Definition pg_list.h:214
static ListCell * list_last_cell(const List *list)
Definition pg_list.h:288
END_CATALOG_STRUCT typedef FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:87
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
END_CATALOG_STRUCT typedef FormData_pg_statistic_ext * Form_pg_statistic_ext
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
NameData typname
Definition pg_type.h:43
Expr * expression_planner(Expr *expr)
Definition planner.c:6819
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define PRS2_OLD_VARNO
Definition primnodes.h:251
#define PRS2_NEW_VARNO
Definition primnodes.h:252
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCE_EXPLICIT_CALL
Definition primnodes.h:767
@ COERCION_ASSIGNMENT
Definition primnodes.h:748
void * stringToNode(const char *str)
Definition read.c:90
static chr element(struct vars *v, const chr *startp, const chr *endp)
#define RelationGetForm(relation)
Definition rel.h:508
#define RelationGetRelid(relation)
Definition rel.h:514
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationGetNamespace(relation)
Definition rel.h:555
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4826
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5200
List * RelationGetStatExtList(Relation relation)
Definition relcache.c:4967
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5087
List * untransformRelOptions(Datum options)
#define InvalidRelFileNumber
Definition relpath.h:26
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
char * quote_qualified_identifier(const char *qualifier, const char *ident)
List * deparse_context_for(const char *aliasname, Oid relid)
Definition ruleutils.c:4068
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition ruleutils.c:4005
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition relation.c:137
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
DropBehavior behavior
AlterTableType subtype
char identity
Definition parsenodes.h:778
List * constraints
Definition parsenodes.h:784
Node * cooked_default
Definition parsenodes.h:777
char * colname
Definition parsenodes.h:767
TypeName * typeName
Definition parsenodes.h:768
char generated
Definition parsenodes.h:781
bool is_from_type
Definition parsenodes.h:773
Node * raw_default
Definition parsenodes.h:776
char storage
Definition parsenodes.h:774
char * compression
Definition parsenodes.h:769
char * ccname
Definition tupdesc.h:30
bool ccenforced
Definition tupdesc.h:32
bool ccnoinherit
Definition tupdesc.h:34
char * ccbin
Definition tupdesc.h:31
bool initdeferred
List * exclusions
ParseLoc location
bool reset_default_tblspc
List * keys
Node * where_clause
char * indexname
char * indexspace
ConstrType contype
char * access_method
bool is_no_inherit
List * options
bool is_enforced
bool nulls_not_distinct
char * cooked_expr
bool initially_valid
bool skip_validation
bool without_overlaps
bool deferrable
Node * raw_expr
char * conname
char generated_when
List * including
const char * stmtType
RangeVar * relation
ParseState * pstate
PartitionBoundSpec * partbound
char * defname
Definition parsenodes.h:857
char * indexcolname
Definition parsenodes.h:826
Definition pg_list.h:54
Definition nodes.h:135
const char * p_sourcetext
Definition parse_node.h:210
List * p_rteperminfos
Definition parse_node.h:212
List * p_rtable
Definition parse_node.h:211
char * relname
Definition primnodes.h:84
char relpersistence
Definition primnodes.h:90
char * schemaname
Definition primnodes.h:81
TupleDesc rd_att
Definition rel.h:112
Form_pg_class rd_rel
Definition rel.h:111
Node * expr
Definition value.h:64
ConstrCheck * check
Definition tupdesc.h:41
uint16 num_check
Definition tupdesc.h:44
Oid typeOid
Definition parsenodes.h:286
Definition type.h:96
Definition c.h:817
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition table.c:83
void check_of_type(HeapTuple typetuple)
Definition tablecmds.c:7205
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
const char * GetCompressionMethodName(char method)
#define CompressionMethodIsValid(cm)
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition tupdesc.c:1149
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:238
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1947
String * makeString(char *str)
Definition value.c:63
#define strVal(v)
Definition value.h:82
bool contain_var_clause(Node *node)
Definition var.c:406
const char * name