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
106 Constraint *constraint);
109static void transformOfType(CreateStmtContext *cxt,
110 TypeName *ofTypename);
114 const AttrMap *attmap);
115static List *get_collation(Oid collation, Oid actual_datatype);
116static List *get_opclass(Oid opclass, Oid actual_datatype);
119 CreateStmtContext *cxt);
121 bool skipValidation,
122 bool isAddConstraint);
124 bool skipValidation);
125static void transformConstraintAttrs(ParseState *pstate,
128static void checkSchemaNameRV(ParseState *pstate, const char *context_schema,
129 RangeVar *relation);
130static void checkSchemaNameList(const char *context_schema,
134 List **fk_elements);
136static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
137 Relation parent);
138static void validateInfiniteBounds(ParseState *pstate, List *blist);
140 const char *colName, Oid colType, int32 colTypmod,
142
143
144/*
145 * transformCreateStmt -
146 * parse analysis for CREATE TABLE
147 *
148 * Returns a List of utility commands to be done in sequence. One of these
149 * will be the transformed CreateStmt, but there may be additional actions
150 * to be done before and after the actual DefineRelation() call.
151 * In addition to normal utility commands such as AlterTableStmt and
152 * IndexStmt, the result list may contain TableLikeClause(s), representing
153 * the need to perform additional parse analysis after DefineRelation().
154 *
155 * SQL allows constraints to be scattered all over, so thumb through
156 * the columns and collect all constraints into one place.
157 * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
158 * then expand those into multiple IndexStmt blocks.
159 * - thomas 1997-12-02
160 */
161List *
162transformCreateStmt(CreateStmt *stmt, const char *queryString)
163{
164 ParseState *pstate;
166 List *result;
168 ListCell *elements;
172
173 /* Set up pstate */
174 pstate = make_parsestate(NULL);
175 pstate->p_sourcetext = queryString;
176
177 /*
178 * Look up the creation namespace. This also checks permissions on the
179 * target namespace, locks it against concurrent drops, checks for a
180 * preexisting relation in that namespace with the same name, and updates
181 * stmt->relation->relpersistence if the selected namespace is temporary.
182 */
184 stmt->relation->location);
189
190 /*
191 * If the relation already exists and the user specified "IF NOT EXISTS",
192 * bail out with a NOTICE.
193 */
194 if (stmt->if_not_exists && OidIsValid(existing_relid))
195 {
196 /*
197 * If we are in an extension script, insist that the pre-existing
198 * object be a member of the extension, to avoid security risks.
199 */
200 ObjectAddress address;
201
204
205 /* OK to skip */
208 errmsg("relation \"%s\" already exists, skipping",
209 stmt->relation->relname)));
210 return NIL;
211 }
212
213 /*
214 * If the target relation name isn't schema-qualified, make it so. This
215 * prevents some corner cases in which added-on rewritten commands might
216 * think they should apply to other relations that have the same name and
217 * are earlier in the search path. But a local temp table is effectively
218 * specified to be in pg_temp, so no need for anything extra in that case.
219 */
220 if (stmt->relation->schemaname == NULL
221 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
222 stmt->relation->schemaname = get_namespace_name(namespaceid);
223
224 /* Set up CreateStmtContext */
225 cxt.pstate = pstate;
227 {
228 cxt.stmtType = "CREATE FOREIGN TABLE";
229 cxt.isforeign = true;
230 }
231 else
232 {
233 cxt.stmtType = "CREATE TABLE";
234 cxt.isforeign = false;
235 }
236 cxt.relation = stmt->relation;
237 cxt.rel = NULL;
238 cxt.inhRelations = stmt->inhRelations;
239 cxt.isalter = false;
240 cxt.columns = NIL;
241 cxt.ckconstraints = NIL;
242 cxt.nnconstraints = NIL;
243 cxt.fkconstraints = NIL;
244 cxt.ixconstraints = NIL;
245 cxt.likeclauses = NIL;
246 cxt.blist = NIL;
247 cxt.alist = NIL;
248 cxt.pkey = NULL;
249 cxt.ispartitioned = stmt->partspec != NULL;
250 cxt.partbound = stmt->partbound;
251 cxt.ofType = (stmt->ofTypename != NULL);
252
253 Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
254
255 if (stmt->ofTypename)
256 transformOfType(&cxt, stmt->ofTypename);
257
258 if (stmt->partspec)
259 {
260 if (stmt->inhRelations && !stmt->partbound)
263 errmsg("cannot create partitioned table as inheritance child")));
264 }
265
266 /*
267 * Run through each primary element in the table creation clause. Separate
268 * column defs from constraints, and do preliminary analysis.
269 */
270 foreach(elements, stmt->tableElts)
271 {
272 Node *element = lfirst(elements);
273
274 switch (nodeTag(element))
275 {
276 case T_ColumnDef:
278 break;
279
280 case T_Constraint:
282 break;
283
286 break;
287
288 default:
289 elog(ERROR, "unrecognized node type: %d",
290 (int) nodeTag(element));
291 break;
292 }
293 }
294
295 /*
296 * Transfer anything we already have in cxt.alist into save_alist, to keep
297 * it separate from the output of transformIndexConstraints. (This may
298 * not be necessary anymore, but we'll keep doing it to preserve the
299 * historical order of execution of the alist commands.)
300 */
301 save_alist = cxt.alist;
302 cxt.alist = NIL;
303
304 Assert(stmt->constraints == NIL);
305
306 /*
307 * Before processing index constraints, which could include a primary key,
308 * we must scan all not-null constraints to propagate the is_not_null flag
309 * to each corresponding ColumnDef. This is necessary because table-level
310 * not-null constraints have not been marked in each ColumnDef, and the PK
311 * processing code needs to know whether one constraint has already been
312 * declared in order not to declare a redundant one.
313 */
315 {
316 char *colname = strVal(linitial(nn->keys));
317
319 {
320 /* not our column? */
321 if (strcmp(cd->colname, colname) != 0)
322 continue;
323 /* Already marked not-null? Nothing to do */
324 if (cd->is_not_null)
325 break;
326 /* Bingo, we're done for this constraint */
327 cd->is_not_null = true;
328 break;
329 }
330 }
331
332 /*
333 * Postprocess constraints that give rise to index definitions.
334 */
336
337 /*
338 * Re-consideration of LIKE clauses should happen after creation of
339 * indexes, but before creation of foreign keys. This order is critical
340 * because a LIKE clause may attempt to create a primary key. If there's
341 * also a pkey in the main CREATE TABLE list, creation of that will not
342 * check for a duplicate at runtime (since index_check_primary_key()
343 * expects that we rejected dups here). Creation of the LIKE-generated
344 * pkey behaves like ALTER TABLE ADD, so it will check, but obviously that
345 * only works if it happens second. On the other hand, we want to make
346 * pkeys before foreign key constraints, in case the user tries to make a
347 * self-referential FK.
348 */
349 cxt.alist = list_concat(cxt.alist, cxt.likeclauses);
350
351 /*
352 * Postprocess foreign-key constraints.
353 */
354 transformFKConstraints(&cxt, true, false);
355
356 /*
357 * Postprocess check constraints.
358 *
359 * For regular tables all constraints can be marked valid immediately,
360 * because the table is new therefore empty. Not so for foreign tables.
361 */
363
364 /*
365 * Output results.
366 */
367 stmt->tableElts = cxt.columns;
368 stmt->constraints = cxt.ckconstraints;
369 stmt->nnconstraints = cxt.nnconstraints;
370
371 result = lappend(cxt.blist, stmt);
374
375 return result;
376}
377
378/*
379 * generateSerialExtraStmts
380 * Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
381 * to create the sequence for a serial or identity column.
382 *
383 * This includes determining the name the sequence will have. The caller
384 * can ask to get back the name components by passing non-null pointers
385 * for snamespace_p and sname_p.
386 */
387static void
389 Oid seqtypid, List *seqoptions,
390 bool for_identity, bool col_exists,
391 char **snamespace_p, char **sname_p)
392{
397 char *snamespace;
398 char *sname;
399 char seqpersistence;
403
404 /* Make a copy of this as we may end up modifying it in the code below */
406
407 /*
408 * Check for non-SQL-standard options (not supported within CREATE
409 * SEQUENCE, because they'd be redundant), and remove them from the
410 * seqoptions list if found.
411 */
412 foreach(option, seqoptions)
413 {
415
416 if (strcmp(defel->defname, "sequence_name") == 0)
417 {
418 if (nameEl)
420 nameEl = defel;
422 }
423 else if (strcmp(defel->defname, "logged") == 0 ||
424 strcmp(defel->defname, "unlogged") == 0)
425 {
426 if (loggedEl)
428 loggedEl = defel;
430 }
431 }
432
433 /*
434 * Determine namespace and name to use for the sequence.
435 */
436 if (nameEl)
437 {
438 /* Use specified name */
440
442 if (!snamespace)
443 {
444 /* Given unqualified SEQUENCE NAME, select namespace */
445 if (cxt->rel)
447 else
450 }
451 sname = rv->relname;
452 }
453 else
454 {
455 /*
456 * Generate a name.
457 *
458 * Although we use ChooseRelationName, it's not guaranteed that the
459 * selected sequence name won't conflict; given sufficiently long
460 * field names, two different serial columns in the same table could
461 * be assigned the same sequence name, and we'd not notice since we
462 * aren't creating the sequence quite yet. In practice this seems
463 * quite unlikely to be a problem, especially since few people would
464 * need two serial columns in one table.
465 */
466 if (cxt->rel)
468 else
469 {
472 }
475 column->colname,
476 "seq",
478 false);
479 }
480
482 (errmsg_internal("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
483 cxt->stmtType, sname,
484 cxt->relation->relname, column->colname)));
485
486 /*
487 * Determine the persistence of the sequence. By default we copy the
488 * persistence of the table, but if LOGGED or UNLOGGED was specified, use
489 * that (as long as the table isn't TEMP).
490 *
491 * For CREATE TABLE, we get the persistence from cxt->relation, which
492 * comes from the CreateStmt in progress. For ALTER TABLE, the parser
493 * won't set cxt->relation->relpersistence, but we have cxt->rel as the
494 * existing table, so we copy the persistence from there.
495 */
496 seqpersistence = cxt->rel ? cxt->rel->rd_rel->relpersistence : cxt->relation->relpersistence;
497 if (loggedEl)
498 {
502 errmsg("cannot set logged status of a temporary sequence"),
503 parser_errposition(cxt->pstate, loggedEl->location)));
504 else if (strcmp(loggedEl->defname, "logged") == 0)
506 else
508 }
509
510 /*
511 * Build a CREATE SEQUENCE command to create the sequence object, and add
512 * it to the list of things to be done before this CREATE/ALTER TABLE.
513 */
515 seqstmt->for_identity = for_identity;
516 seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
517 seqstmt->sequence->relpersistence = seqpersistence;
518 seqstmt->options = seqoptions;
519
520 /*
521 * If a sequence data type was specified, add it to the options. Prepend
522 * to the list rather than append; in case a user supplied their own AS
523 * clause, the "redundant options" error will point to their occurrence,
524 * not our synthetic one.
525 */
526 if (seqtypid)
527 seqstmt->options = lcons(makeDefElem("as",
528 (Node *) makeTypeNameFromOid(seqtypid, -1),
529 -1),
530 seqstmt->options);
531
532 /*
533 * If this is ALTER ADD COLUMN, make sure the sequence will be owned by
534 * the table's owner. The current user might be someone else (perhaps a
535 * superuser, or someone who's only a member of the owning role), but the
536 * SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
537 * exactly the same owning role.
538 */
539 if (cxt->rel)
540 seqstmt->ownerId = cxt->rel->rd_rel->relowner;
541 else
542 seqstmt->ownerId = InvalidOid;
543
544 cxt->blist = lappend(cxt->blist, seqstmt);
545
546 /*
547 * Store the identity sequence name that we decided on. ALTER TABLE ...
548 * ADD COLUMN ... IDENTITY needs this so that it can fill the new column
549 * with values from the sequence, while the association of the sequence
550 * with the table is not set until after the ALTER TABLE.
551 */
552 column->identitySequence = seqstmt->sequence;
553
554 /*
555 * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
556 * owned by this column, and add it to the appropriate list of things to
557 * be done along with this CREATE/ALTER TABLE. In a CREATE or ALTER ADD
558 * COLUMN, it must be done after the statement because we don't know the
559 * column's attnum yet. But if we do have the attnum (in AT_AddIdentity),
560 * we can do the marking immediately, which improves some ALTER TABLE
561 * behaviors.
562 */
564 altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
567 makeString(column->colname));
568 altseqstmt->options = list_make1(makeDefElem("owned_by",
569 (Node *) attnamelist, -1));
570 altseqstmt->for_identity = for_identity;
571
572 if (col_exists)
573 cxt->blist = lappend(cxt->blist, altseqstmt);
574 else
575 cxt->alist = lappend(cxt->alist, altseqstmt);
576
577 if (snamespace_p)
579 if (sname_p)
580 *sname_p = sname;
581}
582
583/*
584 * transformColumnDefinition -
585 * transform a single ColumnDef within CREATE TABLE
586 * Also used in ALTER TABLE ADD COLUMN
587 */
588static void
590{
591 bool is_serial;
592 bool saw_nullable;
593 bool saw_default;
594 bool saw_identity;
595 bool saw_generated;
596 bool need_notnull = false;
597 bool disallow_noinherit_notnull = false;
599
600 cxt->columns = lappend(cxt->columns, column);
601
602 /* Check for SERIAL pseudo-types */
603 is_serial = false;
604 if (column->typeName
605 && list_length(column->typeName->names) == 1
606 && !column->typeName->pct_type)
607 {
608 char *typname = strVal(linitial(column->typeName->names));
609
610 if (strcmp(typname, "smallserial") == 0 ||
611 strcmp(typname, "serial2") == 0)
612 {
613 is_serial = true;
614 column->typeName->names = NIL;
615 column->typeName->typeOid = INT2OID;
616 }
617 else if (strcmp(typname, "serial") == 0 ||
618 strcmp(typname, "serial4") == 0)
619 {
620 is_serial = true;
621 column->typeName->names = NIL;
622 column->typeName->typeOid = INT4OID;
623 }
624 else if (strcmp(typname, "bigserial") == 0 ||
625 strcmp(typname, "serial8") == 0)
626 {
627 is_serial = true;
628 column->typeName->names = NIL;
629 column->typeName->typeOid = INT8OID;
630 }
631
632 /*
633 * We have to reject "serial[]" explicitly, because once we've set
634 * typeid, LookupTypeName won't notice arrayBounds. We don't need any
635 * special coding for serial(typmod) though.
636 */
637 if (is_serial && column->typeName->arrayBounds != NIL)
640 errmsg("array of serial is not implemented"),
642 column->typeName->location)));
643 }
644
645 /* Do necessary work on the column type declaration */
646 if (column->typeName)
648
649 /* Special actions for SERIAL pseudo-types */
650 if (is_serial)
651 {
652 char *snamespace;
653 char *sname;
654 char *qstring;
658 Constraint *constraint;
659
661 column->typeName->typeOid, NIL,
662 false, false,
663 &snamespace, &sname);
664
665 /*
666 * Create appropriate constraints for SERIAL. We do this in full,
667 * rather than shortcutting, so that we will detect any conflicting
668 * constraints the user wrote (like a different DEFAULT).
669 *
670 * Create an expression tree representing the function call
671 * nextval('sequencename'). We cannot reduce the raw tree to cooked
672 * form until after the sequence is created, but there's no need to do
673 * so.
674 */
677 snamenode->val.node.type = T_String;
678 snamenode->val.sval.sval = qstring;
679 snamenode->location = -1;
681 castnode->typeName = SystemTypeName("regclass");
682 castnode->arg = (Node *) snamenode;
683 castnode->location = -1;
687 -1);
688 constraint = makeNode(Constraint);
689 constraint->contype = CONSTR_DEFAULT;
690 constraint->location = -1;
691 constraint->raw_expr = (Node *) funccallnode;
692 constraint->cooked_expr = NULL;
693 column->constraints = lappend(column->constraints, constraint);
694
695 /* have a not-null constraint added later */
696 need_notnull = true;
698 }
699
700 /* Process column constraints, if any... */
701 transformConstraintAttrs(cxt->pstate, column->constraints);
702
703 /*
704 * First, scan the column's constraints to see if a not-null constraint
705 * that we add must be prevented from being NO INHERIT. This should be
706 * enforced only for PRIMARY KEY, not IDENTITY or SERIAL. However, if the
707 * not-null constraint is specified as a table constraint rather than as a
708 * column constraint, AddRelationNotNullConstraints would raise an error
709 * if a NO INHERIT mismatch is found. To avoid inconsistently disallowing
710 * it in the table constraint case but not the column constraint case, we
711 * disallow it here as well. Maybe AddRelationNotNullConstraints can be
712 * improved someday, so that it doesn't complain, and then we can remove
713 * the restriction for SERIAL and IDENTITY here as well.
714 */
716 {
717 foreach_node(Constraint, constraint, column->constraints)
718 {
719 switch (constraint->contype)
720 {
721 case CONSTR_IDENTITY:
722 case CONSTR_PRIMARY:
724 break;
725 default:
726 break;
727 }
728 }
729 }
730
731 /* Now scan them again to do full processing */
732 saw_nullable = false;
733 saw_default = false;
734 saw_identity = false;
735 saw_generated = false;
736
737 foreach_node(Constraint, constraint, column->constraints)
738 {
739 switch (constraint->contype)
740 {
741 case CONSTR_NULL:
742 if ((saw_nullable && column->is_not_null) || need_notnull)
745 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
746 column->colname, cxt->relation->relname),
748 constraint->location)));
749 column->is_not_null = false;
750 saw_nullable = true;
751 break;
752
753 case CONSTR_NOTNULL:
754 if (cxt->ispartitioned && constraint->is_no_inherit)
757 errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
758
759 /* Disallow conflicting [NOT] NULL markings */
760 if (saw_nullable && !column->is_not_null)
763 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
764 column->colname, cxt->relation->relname),
766 constraint->location)));
767
768 if (disallow_noinherit_notnull && constraint->is_no_inherit)
771 errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
772 column->colname));
773
774 /*
775 * If this is the first time we see this column being marked
776 * not-null, add the constraint entry and keep track of it.
777 * Also, remove previous markings that we need one.
778 *
779 * If this is a redundant not-null specification, just check
780 * that it doesn't conflict with what was specified earlier.
781 *
782 * Any conflicts with table constraints will be further
783 * checked in AddRelationNotNullConstraints().
784 */
785 if (!column->is_not_null)
786 {
787 column->is_not_null = true;
788 saw_nullable = true;
789 need_notnull = false;
790
791 constraint->keys = list_make1(makeString(column->colname));
792 notnull_constraint = constraint;
793 cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
794 }
795 else if (notnull_constraint)
796 {
797 if (constraint->conname &&
798 notnull_constraint->conname &&
799 strcmp(notnull_constraint->conname, constraint->conname) != 0)
800 elog(ERROR, "conflicting not-null constraint names \"%s\" and \"%s\"",
801 notnull_constraint->conname, constraint->conname);
802
803 if (notnull_constraint->is_no_inherit != constraint->is_no_inherit)
806 errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
807 column->colname));
808
809 if (!notnull_constraint->conname && constraint->conname)
810 notnull_constraint->conname = constraint->conname;
811 }
812
813 break;
814
815 case CONSTR_DEFAULT:
816 if (saw_default)
819 errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
820 column->colname, cxt->relation->relname),
822 constraint->location)));
823 column->raw_default = constraint->raw_expr;
824 Assert(constraint->cooked_expr == NULL);
825 saw_default = true;
826 break;
827
828 case CONSTR_IDENTITY:
829 {
830 Type ctype;
831 Oid typeOid;
832
833 if (cxt->ofType)
836 errmsg("identity columns are not supported on typed tables")));
837 if (cxt->partbound)
840 errmsg("identity columns are not supported on partitions")));
841
842 ctype = typenameType(cxt->pstate, column->typeName, NULL);
843 typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid;
844 ReleaseSysCache(ctype);
845
846 if (saw_identity)
849 errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
850 column->colname, cxt->relation->relname),
852 constraint->location)));
853
855 typeOid, constraint->options,
856 true, false,
857 NULL, NULL);
858
859 column->identity = constraint->generated_when;
860 saw_identity = true;
861
862 /*
863 * Identity columns are always NOT NULL, but we may have a
864 * constraint already.
865 */
866 if (!saw_nullable)
867 need_notnull = true;
868 else if (!column->is_not_null)
871 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
872 column->colname, cxt->relation->relname),
874 constraint->location)));
875 break;
876 }
877
878 case CONSTR_GENERATED:
879 if (cxt->ofType)
882 errmsg("generated columns are not supported on typed tables")));
883 if (saw_generated)
886 errmsg("multiple generation clauses specified for column \"%s\" of table \"%s\"",
887 column->colname, cxt->relation->relname),
889 constraint->location)));
890 column->generated = constraint->generated_kind;
891 column->raw_default = constraint->raw_expr;
892 Assert(constraint->cooked_expr == NULL);
893 saw_generated = true;
894 break;
895
896 case CONSTR_CHECK:
897 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
898 break;
899
900 case CONSTR_PRIMARY:
901 if (saw_nullable && !column->is_not_null)
904 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
905 column->colname, cxt->relation->relname),
907 constraint->location)));
908 need_notnull = true;
909
910 if (cxt->isforeign)
913 errmsg("primary key constraints are not supported on foreign tables"),
915 constraint->location)));
917
918 case CONSTR_UNIQUE:
919 if (cxt->isforeign)
922 errmsg("unique constraints are not supported on foreign tables"),
924 constraint->location)));
925 if (constraint->keys == NIL)
926 constraint->keys = list_make1(makeString(column->colname));
927 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
928 break;
929
930 case CONSTR_EXCLUSION:
931 /* grammar does not allow EXCLUDE as a column constraint */
932 elog(ERROR, "column exclusion constraints are not supported");
933 break;
934
935 case CONSTR_FOREIGN:
936 if (cxt->isforeign)
939 errmsg("foreign key constraints are not supported on foreign tables"),
941 constraint->location)));
942
943 /*
944 * Fill in the current attribute's name and throw it into the
945 * list of FK constraints to be processed later.
946 */
947 constraint->fk_attrs = list_make1(makeString(column->colname));
948 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
949 break;
950
957 /* transformConstraintAttrs took care of these */
958 break;
959
960 default:
961 elog(ERROR, "unrecognized constraint type: %d",
962 constraint->contype);
963 break;
964 }
965
969 errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
970 column->colname, cxt->relation->relname),
972 constraint->location)));
973
977 errmsg("both default and generation expression specified for column \"%s\" of table \"%s\"",
978 column->colname, cxt->relation->relname),
980 constraint->location)));
981
985 errmsg("both identity and generation expression specified for column \"%s\" of table \"%s\"",
986 column->colname, cxt->relation->relname),
988 constraint->location)));
989 }
990
991 /*
992 * If we need a not-null constraint for PRIMARY KEY, SERIAL or IDENTITY,
993 * and one was not explicitly specified, add one now.
994 */
995 if (need_notnull && !(saw_nullable && column->is_not_null))
996 {
997 column->is_not_null = true;
1000 }
1001
1002 /*
1003 * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
1004 * per-column foreign data wrapper options to this column after creation.
1005 */
1006 if (column->fdwoptions != NIL)
1007 {
1009 AlterTableCmd *cmd;
1010
1011 cmd = makeNode(AlterTableCmd);
1013 cmd->name = column->colname;
1014 cmd->def = (Node *) column->fdwoptions;
1015 cmd->behavior = DROP_RESTRICT;
1016 cmd->missing_ok = false;
1017
1019 stmt->relation = cxt->relation;
1020 stmt->cmds = NIL;
1021 stmt->objtype = OBJECT_FOREIGN_TABLE;
1022 stmt->cmds = lappend(stmt->cmds, cmd);
1023
1024 cxt->alist = lappend(cxt->alist, stmt);
1025 }
1026}
1027
1028/*
1029 * transformTableConstraint
1030 * transform a Constraint node within CREATE TABLE or ALTER TABLE
1031 */
1032static void
1034{
1035 switch (constraint->contype)
1036 {
1037 case CONSTR_PRIMARY:
1038 if (cxt->isforeign)
1039 ereport(ERROR,
1041 errmsg("primary key constraints are not supported on foreign tables"),
1043 constraint->location)));
1044 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1045 break;
1046
1047 case CONSTR_UNIQUE:
1048 if (cxt->isforeign)
1049 ereport(ERROR,
1051 errmsg("unique constraints are not supported on foreign tables"),
1053 constraint->location)));
1054 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1055 break;
1056
1057 case CONSTR_EXCLUSION:
1058 if (cxt->isforeign)
1059 ereport(ERROR,
1061 errmsg("exclusion constraints are not supported on foreign tables"),
1063 constraint->location)));
1064 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
1065 break;
1066
1067 case CONSTR_CHECK:
1068 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
1069 break;
1070
1071 case CONSTR_NOTNULL:
1072 if (cxt->ispartitioned && constraint->is_no_inherit)
1073 ereport(ERROR,
1075 errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
1076
1077 cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
1078 break;
1079
1080 case CONSTR_FOREIGN:
1081 if (cxt->isforeign)
1082 ereport(ERROR,
1084 errmsg("foreign key constraints are not supported on foreign tables"),
1086 constraint->location)));
1087 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
1088 break;
1089
1090 case CONSTR_NULL:
1091 case CONSTR_DEFAULT:
1098 elog(ERROR, "invalid context for constraint type %d",
1099 constraint->contype);
1100 break;
1101
1102 default:
1103 elog(ERROR, "unrecognized constraint type: %d",
1104 constraint->contype);
1105 break;
1106 }
1107}
1108
1109/*
1110 * transformTableLikeClause
1111 *
1112 * Change the LIKE <srctable> portion of a CREATE TABLE statement into
1113 * column definitions that recreate the user defined column portions of
1114 * <srctable>. Also, if there are any LIKE options that we can't fully
1115 * process at this point, add the TableLikeClause to cxt->likeclauses, which
1116 * will cause utility.c to call expandTableLikeClause() after the new
1117 * table has been created.
1118 *
1119 * Some options are ignored. For example, as foreign tables have no storage,
1120 * these INCLUDING options have no effect: STORAGE, COMPRESSION, IDENTITY
1121 * and INDEXES. Similarly, INCLUDING INDEXES is ignored from a view.
1122 */
1123static void
1125{
1127 Relation relation;
1130 char *comment;
1132
1134 table_like_clause->relation->location);
1135
1136 /* Open the relation referenced by the LIKE clause */
1137 relation = relation_openrv(table_like_clause->relation, AccessShareLock);
1138
1139 if (relation->rd_rel->relkind != RELKIND_RELATION &&
1140 relation->rd_rel->relkind != RELKIND_VIEW &&
1141 relation->rd_rel->relkind != RELKIND_MATVIEW &&
1142 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
1143 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
1144 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1145 ereport(ERROR,
1147 errmsg("relation \"%s\" is invalid in LIKE clause",
1148 RelationGetRelationName(relation)),
1149 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
1150
1152
1153 /*
1154 * Check for privileges
1155 */
1156 if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
1157 {
1158 aclresult = object_aclcheck(TypeRelationId, relation->rd_rel->reltype, GetUserId(),
1159 ACL_USAGE);
1160 if (aclresult != ACLCHECK_OK)
1162 RelationGetRelationName(relation));
1163 }
1164 else
1165 {
1167 ACL_SELECT);
1168 if (aclresult != ACLCHECK_OK)
1170 RelationGetRelationName(relation));
1171 }
1172
1173 tupleDesc = RelationGetDescr(relation);
1174
1175 /*
1176 * Insert the copied attributes into the cxt for the new table definition.
1177 * We must do this now so that they appear in the table in the relative
1178 * position where the LIKE clause is, as required by SQL99.
1179 */
1180 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1181 parent_attno++)
1182 {
1184 parent_attno - 1);
1185 ColumnDef *def;
1186
1187 /*
1188 * Ignore dropped columns in the parent.
1189 */
1190 if (attribute->attisdropped)
1191 continue;
1192
1193 /*
1194 * Create a new column definition
1195 */
1196 def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid,
1197 attribute->atttypmod, attribute->attcollation);
1198
1199 /*
1200 * Add to column list
1201 */
1202 cxt->columns = lappend(cxt->columns, def);
1203
1204 /*
1205 * Although we don't transfer the column's default/generation
1206 * expression now, we need to mark it GENERATED if appropriate.
1207 */
1208 if (attribute->atthasdef && attribute->attgenerated &&
1210 def->generated = attribute->attgenerated;
1211
1212 /*
1213 * Copy identity if requested
1214 */
1215 if (attribute->attidentity &&
1217 !cxt->isforeign)
1218 {
1219 Oid seq_relid;
1221
1222 /*
1223 * find sequence owned by old column; extract sequence parameters;
1224 * build new create sequence command
1225 */
1226 seq_relid = getIdentitySequence(relation, attribute->attnum, false);
1228 generateSerialExtraStmts(cxt, def,
1230 true, false,
1231 NULL, NULL);
1232 def->identity = attribute->attidentity;
1233 }
1234
1235 /* Likewise, copy storage if requested */
1237 !cxt->isforeign)
1238 def->storage = attribute->attstorage;
1239 else
1240 def->storage = 0;
1241
1242 /* Likewise, copy compression if requested */
1243 if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0 &&
1244 CompressionMethodIsValid(attribute->attcompression) &&
1245 !cxt->isforeign)
1246 def->compression =
1247 pstrdup(GetCompressionMethodName(attribute->attcompression));
1248 else
1249 def->compression = NULL;
1250
1251 /* Likewise, copy comment if requested */
1253 (comment = GetComment(attribute->attrelid,
1255 attribute->attnum)) != NULL)
1256 {
1258
1259 stmt->objtype = OBJECT_COLUMN;
1260 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1262 makeString(def->colname));
1263 stmt->comment = comment;
1264
1265 cxt->alist = lappend(cxt->alist, stmt);
1266 }
1267 }
1268
1269 /*
1270 * Reproduce not-null constraints, if any, by copying them. We do this
1271 * regardless of options given.
1272 */
1273 if (tupleDesc->constr && tupleDesc->constr->has_not_null)
1274 {
1275 List *lst;
1276
1278 true);
1280
1281 /* Copy comments on not-null constraints */
1283 {
1285 {
1287 nnconstr->conname, false),
1289 0)) != NULL)
1290 {
1292
1293 stmt->objtype = OBJECT_TABCONSTRAINT;
1294 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1296 makeString(nnconstr->conname));
1297 stmt->comment = comment;
1298 cxt->alist = lappend(cxt->alist, stmt);
1299 }
1300 }
1301 }
1302 }
1303
1304 /*
1305 * We cannot yet deal with defaults, CHECK constraints, indexes, or
1306 * statistics, since we don't yet know what column numbers the copied
1307 * columns will have in the finished table. If any of those options are
1308 * specified, add the LIKE clause to cxt->likeclauses so that
1309 * expandTableLikeClause will be called after we do know that.
1310 *
1311 * In order for this to work, we remember the relation OID so that
1312 * expandTableLikeClause is certain to open the same table.
1313 */
1314 if (table_like_clause->options &
1320 {
1321 table_like_clause->relationOid = RelationGetRelid(relation);
1323 }
1324
1325 /*
1326 * Close the parent rel, but keep our AccessShareLock on it until xact
1327 * commit. That will prevent someone else from deleting or ALTERing the
1328 * parent before we can run expandTableLikeClause.
1329 */
1330 table_close(relation, NoLock);
1331}
1332
1333/*
1334 * expandTableLikeClause
1335 *
1336 * Process LIKE options that require knowing the final column numbers
1337 * assigned to the new table's columns. This executes after we have
1338 * run DefineRelation for the new table. It returns a list of utility
1339 * commands that should be run to generate indexes etc.
1340 */
1341List *
1343{
1344 List *result = NIL;
1345 List *atsubcmds = NIL;
1347 Relation relation;
1350 TupleConstr *constr;
1351 AttrMap *attmap;
1352 char *comment;
1353
1354 /*
1355 * Open the relation referenced by the LIKE clause. We should still have
1356 * the table lock obtained by transformTableLikeClause (and this'll throw
1357 * an assertion failure if not). Hence, no need to recheck privileges
1358 * etc. We must open the rel by OID not name, to be sure we get the same
1359 * table.
1360 */
1361 if (!OidIsValid(table_like_clause->relationOid))
1362 elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause");
1363
1364 relation = relation_open(table_like_clause->relationOid, NoLock);
1365
1366 tupleDesc = RelationGetDescr(relation);
1367 constr = tupleDesc->constr;
1368
1369 /*
1370 * Open the newly-created child relation; we have lock on that too.
1371 */
1372 childrel = relation_openrv(heapRel, NoLock);
1373
1374 /*
1375 * Construct a map from the LIKE relation's attnos to the child rel's.
1376 * This re-checks type match etc, although it shouldn't be possible to
1377 * have a failure since both tables are locked.
1378 */
1380 tupleDesc,
1381 false);
1382
1383 /*
1384 * Process defaults, if required.
1385 */
1386 if ((table_like_clause->options &
1388 constr != NULL)
1389 {
1390 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1391 parent_attno++)
1392 {
1394 parent_attno - 1);
1395
1396 /*
1397 * Ignore dropped columns in the parent.
1398 */
1399 if (attribute->attisdropped)
1400 continue;
1401
1402 /*
1403 * Copy default, if present and it should be copied. We have
1404 * separate options for plain default expressions and GENERATED
1405 * defaults.
1406 */
1407 if (attribute->atthasdef &&
1408 (attribute->attgenerated ?
1411 {
1414 bool found_whole_row;
1415
1417 if (this_default == NULL)
1418 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1420
1423 atsubcmd->num = attmap->attnums[parent_attno - 1];
1425 1, 0,
1426 attmap,
1427 InvalidOid,
1428 &found_whole_row);
1429
1430 /*
1431 * Prevent this for the same reason as for constraints below.
1432 * Note that defaults cannot contain any vars, so it's OK that
1433 * the error message refers to generated columns.
1434 */
1435 if (found_whole_row)
1436 ereport(ERROR,
1438 errmsg("cannot convert whole-row table reference"),
1439 errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
1440 NameStr(attribute->attname),
1441 RelationGetRelationName(relation))));
1442
1444 }
1445 }
1446 }
1447
1448 /*
1449 * Copy CHECK constraints if requested, being careful to adjust attribute
1450 * numbers so they match the child.
1451 */
1453 constr != NULL)
1454 {
1455 int ccnum;
1456
1457 for (ccnum = 0; ccnum < constr->num_check; ccnum++)
1458 {
1459 char *ccname = constr->check[ccnum].ccname;
1460 char *ccbin = constr->check[ccnum].ccbin;
1461 bool ccenforced = constr->check[ccnum].ccenforced;
1462 bool ccnoinherit = constr->check[ccnum].ccnoinherit;
1464 bool found_whole_row;
1465 Constraint *n;
1467
1469 1, 0,
1470 attmap,
1471 InvalidOid, &found_whole_row);
1472
1473 /*
1474 * We reject whole-row variables because the whole point of LIKE
1475 * is that the new table's rowtype might later diverge from the
1476 * parent's. So, while translation might be possible right now,
1477 * it wouldn't be possible to guarantee it would work in future.
1478 */
1479 if (found_whole_row)
1480 ereport(ERROR,
1482 errmsg("cannot convert whole-row table reference"),
1483 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1484 ccname,
1485 RelationGetRelationName(relation))));
1486
1487 n = makeNode(Constraint);
1488 n->contype = CONSTR_CHECK;
1489 n->conname = pstrdup(ccname);
1490 n->location = -1;
1491 n->is_enforced = ccenforced;
1492 n->initially_valid = ccenforced; /* sic */
1493 n->is_no_inherit = ccnoinherit;
1494 n->raw_expr = NULL;
1496
1497 /* We can skip validation, since the new table should be empty. */
1498 n->skip_validation = true;
1499
1501 atsubcmd->subtype = AT_AddConstraint;
1502 atsubcmd->def = (Node *) n;
1504
1505 /* Copy comment on constraint */
1508 n->conname, false),
1510 0)) != NULL)
1511 {
1513
1514 stmt->objtype = OBJECT_TABCONSTRAINT;
1515 stmt->object = (Node *) list_make3(makeString(heapRel->schemaname),
1516 makeString(heapRel->relname),
1517 makeString(n->conname));
1518 stmt->comment = comment;
1519
1521 }
1522 }
1523 }
1524
1525 /*
1526 * If we generated any ALTER TABLE actions above, wrap them into a single
1527 * ALTER TABLE command. Stick it at the front of the result, so it runs
1528 * before any CommentStmts we made above.
1529 */
1530 if (atsubcmds)
1531 {
1533
1534 atcmd->relation = copyObject(heapRel);
1535 atcmd->cmds = atsubcmds;
1536 atcmd->objtype = OBJECT_TABLE;
1537 atcmd->missing_ok = false;
1539 }
1540
1541 /*
1542 * Process indexes if required.
1543 */
1545 relation->rd_rel->relhasindex &&
1546 childrel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1547 {
1549 ListCell *l;
1550
1552
1553 foreach(l, parent_indexes)
1554 {
1558
1560
1561 /* Build CREATE INDEX statement to recreate the parent_index */
1564 attmap,
1565 NULL);
1566
1567 /* Copy comment on index, if requested */
1569 {
1571
1572 /*
1573 * We make use of IndexStmt's idxcomment option, so as not to
1574 * need to know now what name the index will have.
1575 */
1576 index_stmt->idxcomment = comment;
1577 }
1578
1580
1582 }
1583 }
1584
1585 /*
1586 * Process extended statistics if required.
1587 */
1589 {
1591 ListCell *l;
1592
1594
1595 foreach(l, parent_extstats)
1596 {
1599
1603 attmap);
1604
1605 /* Copy comment on statistics object, if requested */
1607 {
1609
1610 /*
1611 * We make use of CreateStatsStmt's stxcomment option, so as
1612 * not to need to know now what name the statistics will have.
1613 */
1614 stats_stmt->stxcomment = comment;
1615 }
1616
1618 }
1619
1621 }
1622
1623 /* Done with child rel */
1625
1626 /*
1627 * Close the parent rel, but keep our AccessShareLock on it until xact
1628 * commit. That will prevent someone else from deleting or ALTERing the
1629 * parent before the child is committed.
1630 */
1631 table_close(relation, NoLock);
1632
1633 return result;
1634}
1635
1636static void
1638{
1639 HeapTuple tuple;
1640 TupleDesc tupdesc;
1641 int i;
1642 Oid ofTypeId;
1643
1644 Assert(ofTypename);
1645
1646 tuple = typenameType(cxt->pstate, ofTypename, NULL);
1647 check_of_type(tuple);
1648 ofTypeId = ((Form_pg_type) GETSTRUCT(tuple))->oid;
1649 ofTypename->typeOid = ofTypeId; /* cached for later */
1650
1651 tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
1652 for (i = 0; i < tupdesc->natts; i++)
1653 {
1654 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1655 ColumnDef *n;
1656
1657 if (attr->attisdropped)
1658 continue;
1659
1660 n = makeColumnDef(NameStr(attr->attname), attr->atttypid,
1661 attr->atttypmod, attr->attcollation);
1662 n->is_from_type = true;
1663
1664 cxt->columns = lappend(cxt->columns, n);
1665 }
1666 ReleaseTupleDesc(tupdesc);
1667
1668 ReleaseSysCache(tuple);
1669}
1670
1671/*
1672 * Generate an IndexStmt node using information from an already existing index
1673 * "source_idx".
1674 *
1675 * heapRel is stored into the IndexStmt's relation field, but we don't use it
1676 * otherwise; some callers pass NULL, if they don't need it to be valid.
1677 * (The target relation might not exist yet, so we mustn't try to access it.)
1678 *
1679 * Attribute numbers in expression Vars are adjusted according to attmap.
1680 *
1681 * If constraintOid isn't NULL, we store the OID of any constraint associated
1682 * with the index there.
1683 *
1684 * Unlike transformIndexConstraint, we don't make any effort to force primary
1685 * key columns to be not-null. The larger cloning process this is part of
1686 * should have cloned their not-null status separately (and DefineIndex will
1687 * complain if that fails to happen).
1688 */
1689IndexStmt *
1691 const AttrMap *attmap,
1693{
1704 List *indexprs;
1706 Oid indrelid;
1707 int keyno;
1709 Datum datum;
1710 bool isnull;
1711
1712 if (constraintOid)
1714
1715 /*
1716 * Fetch pg_class tuple of source index. We can't use the copy in the
1717 * relcache entry because it doesn't include optional fields.
1718 */
1721 elog(ERROR, "cache lookup failed for relation %u", source_relid);
1723
1724 /* Fetch pg_index tuple for source index from relcache entry */
1725 ht_idx = source_idx->rd_indextuple;
1727 indrelid = idxrec->indrelid;
1728
1729 /* Fetch the pg_am tuple of the index' access method */
1731 if (!HeapTupleIsValid(ht_am))
1732 elog(ERROR, "cache lookup failed for access method %u",
1733 idxrelrec->relam);
1735
1736 /* Extract indcollation from the pg_index tuple */
1740
1741 /* Extract indclass from the pg_index tuple */
1743 indclass = (oidvector *) DatumGetPointer(datum);
1744
1745 /* Begin building the IndexStmt */
1747 index->relation = heapRel;
1748 index->accessMethod = pstrdup(NameStr(amrec->amname));
1749 if (OidIsValid(idxrelrec->reltablespace))
1750 index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
1751 else
1752 index->tableSpace = NULL;
1753 index->excludeOpNames = NIL;
1754 index->idxcomment = NULL;
1755 index->indexOid = InvalidOid;
1756 index->oldNumber = InvalidRelFileNumber;
1757 index->oldCreateSubid = InvalidSubTransactionId;
1758 index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
1759 index->unique = idxrec->indisunique;
1760 index->nulls_not_distinct = idxrec->indnullsnotdistinct;
1761 index->primary = idxrec->indisprimary;
1762 index->iswithoutoverlaps = (idxrec->indisprimary || idxrec->indisunique) && idxrec->indisexclusion;
1763 index->transformed = true; /* don't need transformIndexStmt */
1764 index->concurrent = false;
1765 index->if_not_exists = false;
1766 index->reset_default_tblspc = false;
1767
1768 /*
1769 * We don't try to preserve the name of the source index; instead, just
1770 * let DefineIndex() choose a reasonable name. (If we tried to preserve
1771 * the name, we'd get duplicate-relation-name failures unless the source
1772 * table was in a different schema.)
1773 */
1774 index->idxname = NULL;
1775
1776 /*
1777 * If the index is marked PRIMARY or has an exclusion condition, it's
1778 * certainly from a constraint; else, if it's not marked UNIQUE, it
1779 * certainly isn't. If it is or might be from a constraint, we have to
1780 * fetch the pg_constraint record.
1781 */
1782 if (index->primary || index->unique || idxrec->indisexclusion)
1783 {
1785
1787 {
1790
1791 if (constraintOid)
1793
1797 elog(ERROR, "cache lookup failed for constraint %u",
1798 constraintId);
1800
1801 index->isconstraint = true;
1802 index->deferrable = conrec->condeferrable;
1803 index->initdeferred = conrec->condeferred;
1804
1805 /* If it's an exclusion constraint, we need the operator names */
1806 if (idxrec->indisexclusion)
1807 {
1808 Datum *elems;
1809 int nElems;
1810 int i;
1811
1812 Assert(conrec->contype == CONSTRAINT_EXCLUSION ||
1813 (index->iswithoutoverlaps &&
1814 (conrec->contype == CONSTRAINT_PRIMARY || conrec->contype == CONSTRAINT_UNIQUE)));
1815 /* Extract operator OIDs from the pg_constraint tuple */
1818 deconstruct_array_builtin(DatumGetArrayTypeP(datum), OIDOID, &elems, NULL, &nElems);
1819
1820 for (i = 0; i < nElems; i++)
1821 {
1822 Oid operid = DatumGetObjectId(elems[i]);
1825 char *oprname;
1826 char *nspname;
1827 List *namelist;
1828
1832 elog(ERROR, "cache lookup failed for operator %u",
1833 operid);
1835 oprname = pstrdup(NameStr(operform->oprname));
1836 /* For simplicity we always schema-qualify the op name */
1837 nspname = get_namespace_name(operform->oprnamespace);
1838 namelist = list_make2(makeString(nspname),
1839 makeString(oprname));
1840 index->excludeOpNames = lappend(index->excludeOpNames,
1841 namelist);
1843 }
1844 }
1845
1847 }
1848 else
1849 index->isconstraint = false;
1850 }
1851 else
1852 index->isconstraint = false;
1853
1854 /* Get the index expressions, if any */
1856 Anum_pg_index_indexprs, &isnull);
1857 if (!isnull)
1858 {
1859 char *exprsString;
1860
1863 }
1864 else
1865 indexprs = NIL;
1866
1867 /* Build the list of IndexElem */
1868 index->indexParams = NIL;
1869 index->indexIncludingParams = NIL;
1870
1872 for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
1873 {
1875 AttrNumber attnum = idxrec->indkey.values[keyno];
1877 keyno);
1878 int16 opt = source_idx->rd_indoption[keyno];
1879
1881
1883 {
1884 /* Simple index column */
1885 char *attname;
1886
1889
1890 iparam->name = attname;
1891 iparam->expr = NULL;
1892 }
1893 else
1894 {
1895 /* Expressional index */
1896 Node *indexkey;
1897 bool found_whole_row;
1898
1899 if (indexpr_item == NULL)
1900 elog(ERROR, "too few entries in indexprs list");
1903
1904 /* Adjust Vars to match new table's column numbering */
1906 1, 0,
1907 attmap,
1908 InvalidOid, &found_whole_row);
1909
1910 /* As in expandTableLikeClause, reject whole-row variables */
1911 if (found_whole_row)
1912 ereport(ERROR,
1914 errmsg("cannot convert whole-row table reference"),
1915 errdetail("Index \"%s\" contains a whole-row table reference.",
1917
1918 iparam->name = NULL;
1919 iparam->expr = indexkey;
1920
1922 }
1923
1924 /* Copy the original index column name */
1925 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1926
1927 /* Add the collation name, if non-default */
1928 iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
1929
1930 /* Add the operator class name, if non-default */
1931 iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
1932 iparam->opclassopts =
1934
1935 iparam->ordering = SORTBY_DEFAULT;
1936 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
1937
1938 /* Adjust options if necessary */
1939 if (source_idx->rd_indam->amcanorder)
1940 {
1941 /*
1942 * If it supports sort ordering, copy DESC and NULLS opts. Don't
1943 * set non-default settings unnecessarily, though, so as to
1944 * improve the chance of recognizing equivalence to constraint
1945 * indexes.
1946 */
1947 if (opt & INDOPTION_DESC)
1948 {
1949 iparam->ordering = SORTBY_DESC;
1950 if ((opt & INDOPTION_NULLS_FIRST) == 0)
1951 iparam->nulls_ordering = SORTBY_NULLS_LAST;
1952 }
1953 else
1954 {
1955 if (opt & INDOPTION_NULLS_FIRST)
1956 iparam->nulls_ordering = SORTBY_NULLS_FIRST;
1957 }
1958 }
1959
1960 iparam->location = -1;
1961
1962 index->indexParams = lappend(index->indexParams, iparam);
1963 }
1964
1965 /* Handle included columns separately */
1966 for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
1967 {
1969 AttrNumber attnum = idxrec->indkey.values[keyno];
1971 keyno);
1972
1974
1976 {
1977 /* Simple index column */
1978 char *attname;
1979
1981
1982 iparam->name = attname;
1983 iparam->expr = NULL;
1984 }
1985 else
1986 ereport(ERROR,
1988 errmsg("expressions are not supported in included columns")));
1989
1990 /* Copy the original index column name */
1991 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1992
1993 iparam->location = -1;
1994
1995 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
1996 }
1997 /* Copy reloptions if any */
1999 Anum_pg_class_reloptions, &isnull);
2000 if (!isnull)
2001 index->options = untransformRelOptions(datum);
2002
2003 /* If it's a partial index, decompile and append the predicate */
2005 Anum_pg_index_indpred, &isnull);
2006 if (!isnull)
2007 {
2008 char *pred_str;
2009 Node *pred_tree;
2010 bool found_whole_row;
2011
2012 /* Convert text string to node tree */
2015
2016 /* Adjust Vars to match new table's column numbering */
2018 1, 0,
2019 attmap,
2020 InvalidOid, &found_whole_row);
2021
2022 /* As in expandTableLikeClause, reject whole-row variables */
2023 if (found_whole_row)
2024 ereport(ERROR,
2026 errmsg("cannot convert whole-row table reference"),
2027 errdetail("Index \"%s\" contains a whole-row table reference.",
2029
2030 index->whereClause = pred_tree;
2031 }
2032
2033 /* Clean up */
2036
2037 return index;
2038}
2039
2040/*
2041 * Generate a CreateStatsStmt node using information from an already existing
2042 * extended statistic "source_statsid", for the rel identified by heapRel and
2043 * heapRelid.
2044 *
2045 * stxkeys in the source statistic holds attribute numbers from the parent
2046 * relation. Those attnums, along with the attribute numbers referenced by
2047 * Vars inside the expression tree, are remapped to the new relation's
2048 * numbering according to attmap.
2049 */
2050static CreateStatsStmt *
2053{
2056 CreateStatsStmt *stats;
2057 List *stat_types = NIL;
2058 List *def_names = NIL;
2059 bool isnull;
2060 Datum datum;
2061 ArrayType *arr;
2062 char *enabled;
2063 int i;
2064
2066 Assert(heapRel != NULL);
2067
2068 /*
2069 * Fetch pg_statistic_ext tuple of source statistics object.
2070 */
2073 elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
2075
2076 /* Determine which statistics types exist */
2079 arr = DatumGetArrayTypeP(datum);
2080 if (ARR_NDIM(arr) != 1 ||
2081 ARR_HASNULL(arr) ||
2082 ARR_ELEMTYPE(arr) != CHAROID)
2083 elog(ERROR, "stxkind is not a 1-D char array");
2084 enabled = (char *) ARR_DATA_PTR(arr);
2085 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
2086 {
2087 if (enabled[i] == STATS_EXT_NDISTINCT)
2088 stat_types = lappend(stat_types, makeString("ndistinct"));
2089 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
2090 stat_types = lappend(stat_types, makeString("dependencies"));
2091 else if (enabled[i] == STATS_EXT_MCV)
2092 stat_types = lappend(stat_types, makeString("mcv"));
2093 else if (enabled[i] == STATS_EXT_EXPRESSIONS)
2094 /* expression stats are not exposed to users */
2095 continue;
2096 else
2097 elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
2098 }
2099
2100 /* Determine which columns the statistics are on */
2101 for (i = 0; i < statsrec->stxkeys.dim1; i++)
2102 {
2104 AttrNumber attnum = statsrec->stxkeys.values[i];
2105
2106 selem->name =
2107 get_attname(heapRelid, attmap->attnums[attnum - 1], false);
2108 selem->expr = NULL;
2109
2111 }
2112
2113 /*
2114 * Now handle expressions, if there are any. The order (with respect to
2115 * regular attributes) does not really matter for extended stats, so we
2116 * simply append them after simple column references.
2117 *
2118 * XXX Some places during build/estimation treat expressions as if they
2119 * are before attributes, but for the CREATE command that's entirely
2120 * irrelevant.
2121 */
2124
2125 if (!isnull)
2126 {
2127 ListCell *lc;
2128 List *exprs = NIL;
2129 char *exprsString;
2130
2132 exprs = (List *) stringToNode(exprsString);
2133
2134 foreach(lc, exprs)
2135 {
2136 Node *expr = (Node *) lfirst(lc);
2138 bool found_whole_row;
2139
2140 /* Adjust Vars to match new table's column numbering */
2141 expr = map_variable_attnos(expr,
2142 1, 0,
2143 attmap,
2144 InvalidOid,
2145 &found_whole_row);
2146
2147 selem->name = NULL;
2148 selem->expr = expr;
2149
2151 }
2152
2154 }
2155
2156 /* finally, build the output node */
2157 stats = makeNode(CreateStatsStmt);
2158 stats->defnames = NULL;
2159 stats->stat_types = stat_types;
2160 stats->exprs = def_names;
2161 stats->relations = list_make1(heapRel);
2162 stats->stxcomment = NULL;
2163 stats->transformed = true; /* don't need transformStatsStmt again */
2164 stats->if_not_exists = false;
2165
2166 /* Clean up */
2168
2169 return stats;
2170}
2171
2172/*
2173 * get_collation - fetch qualified name of a collation
2174 *
2175 * If collation is InvalidOid or is the default for the given actual_datatype,
2176 * then the return value is NIL.
2177 */
2178static List *
2180{
2181 List *result;
2184 char *nsp_name;
2185 char *coll_name;
2186
2187 if (!OidIsValid(collation))
2188 return NIL; /* easy case */
2189 if (collation == get_typcollation(actual_datatype))
2190 return NIL; /* just let it default */
2191
2194 elog(ERROR, "cache lookup failed for collation %u", collation);
2196
2197 /* For simplicity, we always schema-qualify the name */
2198 nsp_name = get_namespace_name(coll_rec->collnamespace);
2199 coll_name = pstrdup(NameStr(coll_rec->collname));
2201
2203 return result;
2204}
2205
2206/*
2207 * get_opclass - fetch qualified name of an index operator class
2208 *
2209 * If the opclass is the default for the given actual_datatype, then
2210 * the return value is NIL.
2211 */
2212static List *
2214{
2215 List *result = NIL;
2218
2221 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2223
2224 if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
2225 {
2226 /* For simplicity, we always schema-qualify the name */
2227 char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
2228 char *opc_name = pstrdup(NameStr(opc_rec->opcname));
2229
2231 }
2232
2234 return result;
2235}
2236
2237
2238/*
2239 * transformIndexConstraints
2240 * Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
2241 * We also merge in any index definitions arising from
2242 * LIKE ... INCLUDING INDEXES.
2243 */
2244static void
2246{
2248 List *indexlist = NIL;
2250 ListCell *lc;
2251
2252 /*
2253 * Run through the constraints that need to generate an index, and do so.
2254 *
2255 * For PRIMARY KEY, this queues not-null constraints for each column, if
2256 * needed.
2257 */
2258 foreach(lc, cxt->ixconstraints)
2259 {
2260 Constraint *constraint = lfirst_node(Constraint, lc);
2261
2262 Assert(constraint->contype == CONSTR_PRIMARY ||
2263 constraint->contype == CONSTR_UNIQUE ||
2264 constraint->contype == CONSTR_EXCLUSION);
2265
2266 index = transformIndexConstraint(constraint, cxt);
2267
2268 indexlist = lappend(indexlist, index);
2269 }
2270
2271 /*
2272 * Scan the index list and remove any redundant index specifications. This
2273 * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
2274 * strict reading of SQL would suggest raising an error instead, but that
2275 * strikes me as too anal-retentive. - tgl 2001-02-14
2276 *
2277 * XXX in ALTER TABLE case, it'd be nice to look for duplicate
2278 * pre-existing indexes, too.
2279 */
2280 if (cxt->pkey != NULL)
2281 {
2282 /* Make sure we keep the PKEY index in preference to others... */
2284 }
2285
2286 foreach(lc, indexlist)
2287 {
2288 bool keep = true;
2289 ListCell *k;
2290
2291 index = lfirst(lc);
2292
2293 /* if it's pkey, it's already in finalindexlist */
2294 if (index == cxt->pkey)
2295 continue;
2296
2297 foreach(k, finalindexlist)
2298 {
2300
2301 if (equal(index->indexParams, priorindex->indexParams) &&
2302 equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
2303 equal(index->whereClause, priorindex->whereClause) &&
2304 equal(index->excludeOpNames, priorindex->excludeOpNames) &&
2305 strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
2306 index->nulls_not_distinct == priorindex->nulls_not_distinct &&
2307 index->deferrable == priorindex->deferrable &&
2308 index->initdeferred == priorindex->initdeferred)
2309 {
2310 priorindex->unique |= index->unique;
2311
2312 /*
2313 * If the prior index is as yet unnamed, and this one is
2314 * named, then transfer the name to the prior index. This
2315 * ensures that if we have named and unnamed constraints,
2316 * we'll use (at least one of) the names for the index.
2317 */
2318 if (priorindex->idxname == NULL)
2319 priorindex->idxname = index->idxname;
2320 keep = false;
2321 break;
2322 }
2323 }
2324
2325 if (keep)
2327 }
2328
2329 /*
2330 * Now append all the IndexStmts to cxt->alist.
2331 */
2332 cxt->alist = list_concat(cxt->alist, finalindexlist);
2333}
2334
2335/*
2336 * transformIndexConstraint
2337 * Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
2338 * transformIndexConstraints. An IndexStmt is returned.
2339 *
2340 * For a PRIMARY KEY constraint, we additionally create not-null constraints
2341 * for columns that don't already have them.
2342 */
2343static IndexStmt *
2345{
2347 ListCell *lc;
2348
2350
2351 index->unique = (constraint->contype != CONSTR_EXCLUSION);
2352 index->primary = (constraint->contype == CONSTR_PRIMARY);
2353 if (index->primary)
2354 {
2355 if (cxt->pkey != NULL)
2356 ereport(ERROR,
2358 errmsg("multiple primary keys for table \"%s\" are not allowed",
2359 cxt->relation->relname),
2360 parser_errposition(cxt->pstate, constraint->location)));
2361 cxt->pkey = index;
2362
2363 /*
2364 * In ALTER TABLE case, a primary index might already exist, but
2365 * DefineIndex will check for it.
2366 */
2367 }
2368 index->nulls_not_distinct = constraint->nulls_not_distinct;
2369 index->isconstraint = true;
2370 index->iswithoutoverlaps = constraint->without_overlaps;
2371 index->deferrable = constraint->deferrable;
2372 index->initdeferred = constraint->initdeferred;
2373
2374 if (constraint->conname != NULL)
2375 index->idxname = pstrdup(constraint->conname);
2376 else
2377 index->idxname = NULL; /* DefineIndex will choose name */
2378
2379 index->relation = cxt->relation;
2380 index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
2381 index->options = constraint->options;
2382 index->tableSpace = constraint->indexspace;
2383 index->whereClause = constraint->where_clause;
2384 index->indexParams = NIL;
2385 index->indexIncludingParams = NIL;
2386 index->excludeOpNames = NIL;
2387 index->idxcomment = NULL;
2388 index->indexOid = InvalidOid;
2389 index->oldNumber = InvalidRelFileNumber;
2390 index->oldCreateSubid = InvalidSubTransactionId;
2391 index->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
2392 index->transformed = false;
2393 index->concurrent = false;
2394 index->if_not_exists = false;
2395 index->reset_default_tblspc = constraint->reset_default_tblspc;
2396
2397 /*
2398 * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
2399 * verify it's usable, then extract the implied column name list. (We
2400 * will not actually need the column name list at runtime, but we need it
2401 * now to check for duplicate column entries below.)
2402 */
2403 if (constraint->indexname != NULL)
2404 {
2405 char *index_name = constraint->indexname;
2406 Relation heap_rel = cxt->rel;
2407 Oid index_oid;
2412 int i;
2413
2414 /* Grammar should not allow this with explicit column list */
2415 Assert(constraint->keys == NIL);
2416
2417 /* Grammar should only allow PRIMARY and UNIQUE constraints */
2418 Assert(constraint->contype == CONSTR_PRIMARY ||
2419 constraint->contype == CONSTR_UNIQUE);
2420
2421 /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
2422 if (!cxt->isalter)
2423 ereport(ERROR,
2425 errmsg("cannot use an existing index in CREATE TABLE"),
2426 parser_errposition(cxt->pstate, constraint->location)));
2427
2428 /* Look for the index in the same schema as the table */
2430
2431 if (!OidIsValid(index_oid))
2432 ereport(ERROR,
2434 errmsg("index \"%s\" does not exist", index_name),
2435 parser_errposition(cxt->pstate, constraint->location)));
2436
2437 /* Open the index (this will throw an error if it is not an index) */
2439 index_form = index_rel->rd_index;
2440
2441 /* Check that it does not have an associated constraint already */
2443 ereport(ERROR,
2445 errmsg("index \"%s\" is already associated with a constraint",
2446 index_name),
2447 parser_errposition(cxt->pstate, constraint->location)));
2448
2449 /* Perform validity checks on the index */
2450 if (index_form->indrelid != RelationGetRelid(heap_rel))
2451 ereport(ERROR,
2453 errmsg("index \"%s\" does not belong to table \"%s\"",
2455 parser_errposition(cxt->pstate, constraint->location)));
2456
2457 if (!index_form->indisvalid)
2458 ereport(ERROR,
2460 errmsg("index \"%s\" is not valid", index_name),
2461 parser_errposition(cxt->pstate, constraint->location)));
2462
2463 /*
2464 * Today we forbid non-unique indexes, but we could permit GiST
2465 * indexes whose last entry is a range type and use that to create a
2466 * WITHOUT OVERLAPS constraint (i.e. a temporal constraint).
2467 */
2468 if (!index_form->indisunique)
2469 ereport(ERROR,
2471 errmsg("\"%s\" is not a unique index", index_name),
2472 errdetail("Cannot create a primary key or unique constraint using such an index."),
2473 parser_errposition(cxt->pstate, constraint->location)));
2474
2476 ereport(ERROR,
2478 errmsg("index \"%s\" contains expressions", index_name),
2479 errdetail("Cannot create a primary key or unique constraint using such an index."),
2480 parser_errposition(cxt->pstate, constraint->location)));
2481
2483 ereport(ERROR,
2485 errmsg("\"%s\" is a partial index", index_name),
2486 errdetail("Cannot create a primary key or unique constraint using such an index."),
2487 parser_errposition(cxt->pstate, constraint->location)));
2488
2489 /*
2490 * It's probably unsafe to change a deferred index to non-deferred. (A
2491 * non-constraint index couldn't be deferred anyway, so this case
2492 * should never occur; no need to sweat, but let's check it.)
2493 */
2494 if (!index_form->indimmediate && !constraint->deferrable)
2495 ereport(ERROR,
2497 errmsg("\"%s\" is a deferrable index", index_name),
2498 errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
2499 parser_errposition(cxt->pstate, constraint->location)));
2500
2501 /*
2502 * Insist on it being a btree. We must have an index that exactly
2503 * matches what you'd get from plain ADD CONSTRAINT syntax, else dump
2504 * and reload will produce a different index (breaking pg_upgrade in
2505 * particular).
2506 */
2507 if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
2508 ereport(ERROR,
2510 errmsg("index \"%s\" is not a btree", index_name),
2511 parser_errposition(cxt->pstate, constraint->location)));
2512
2513 /* Must get indclass the hard way */
2515 index_rel->rd_indextuple,
2518
2519 for (i = 0; i < index_form->indnatts; i++)
2520 {
2521 int16 attnum = index_form->indkey.values[i];
2523 char *attname;
2525
2526 /*
2527 * We shouldn't see attnum == 0 here, since we already rejected
2528 * expression indexes. If we do, SystemAttributeDefinition will
2529 * throw an error.
2530 */
2531 if (attnum > 0)
2532 {
2533 Assert(attnum <= heap_rel->rd_att->natts);
2534 attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
2535 }
2536 else
2538 attname = pstrdup(NameStr(attform->attname));
2539
2541 {
2542 /*
2543 * Insist on default opclass, collation, and sort options.
2544 * While the index would still work as a constraint with
2545 * non-default settings, it might not provide exactly the same
2546 * uniqueness semantics as you'd get from a normally-created
2547 * constraint; and there's also the dump/reload problem
2548 * mentioned above.
2549 */
2550 Datum attoptions =
2552
2554 index_rel->rd_rel->relam);
2555 if (indclass->values[i] != defopclass ||
2556 attform->attcollation != index_rel->rd_indcollation[i] ||
2557 attoptions != (Datum) 0 ||
2558 index_rel->rd_indoption[i] != 0)
2559 ereport(ERROR,
2561 errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
2562 errdetail("Cannot create a primary key or unique constraint using such an index."),
2563 parser_errposition(cxt->pstate, constraint->location)));
2564
2565 /* If a PK, ensure the columns get not null constraints */
2566 if (constraint->contype == CONSTR_PRIMARY)
2567 cxt->nnconstraints =
2570
2571 constraint->keys = lappend(constraint->keys, makeString(attname));
2572 }
2573 else
2574 constraint->including = lappend(constraint->including, makeString(attname));
2575 }
2576
2577 /* Close the index relation but keep the lock */
2579
2580 index->indexOid = index_oid;
2581 }
2582
2583 /*
2584 * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
2585 * IndexElems and operator names. We have to break that apart into
2586 * separate lists.
2587 */
2588 if (constraint->contype == CONSTR_EXCLUSION)
2589 {
2590 foreach(lc, constraint->exclusions)
2591 {
2592 List *pair = (List *) lfirst(lc);
2593 IndexElem *elem;
2594 List *opname;
2595
2596 Assert(list_length(pair) == 2);
2597 elem = linitial_node(IndexElem, pair);
2599
2600 index->indexParams = lappend(index->indexParams, elem);
2601 index->excludeOpNames = lappend(index->excludeOpNames, opname);
2602 }
2603 }
2604
2605 /*
2606 * For UNIQUE and PRIMARY KEY, we just have a list of column names.
2607 *
2608 * Make sure referenced keys exist. If we are making a PRIMARY KEY index,
2609 * also make sure they are not-null. For WITHOUT OVERLAPS constraints, we
2610 * make sure the last part is a range or multirange.
2611 */
2612 else
2613 {
2614 foreach(lc, constraint->keys)
2615 {
2616 char *key = strVal(lfirst(lc));
2617 bool found = false;
2619 ListCell *columns;
2621 Oid typid = InvalidOid;
2622
2623 /* Make sure referenced column exists. */
2624 foreach(columns, cxt->columns)
2625 {
2626 column = lfirst_node(ColumnDef, columns);
2627 if (strcmp(column->colname, key) == 0)
2628 {
2629 found = true;
2630 break;
2631 }
2632 }
2633 if (!found)
2634 column = NULL;
2635
2636 if (found)
2637 {
2638 /*
2639 * column is defined in the new table. For CREATE TABLE with
2640 * a PRIMARY KEY, we can apply the not-null constraint cheaply
2641 * here. If the not-null constraint already exists, we can
2642 * (albeit not so cheaply) verify that it's not a NO INHERIT
2643 * constraint.
2644 *
2645 * Note that ALTER TABLE never needs either check, because
2646 * those constraints have already been added by
2647 * ATPrepAddPrimaryKey.
2648 */
2649 if (constraint->contype == CONSTR_PRIMARY &&
2650 !cxt->isalter)
2651 {
2652 if (column->is_not_null)
2653 {
2655 {
2656 if (strcmp(strVal(linitial(nn->keys)), key) == 0)
2657 {
2658 if (nn->is_no_inherit)
2659 ereport(ERROR,
2661 errmsg("conflicting NO INHERIT declaration for not-null constraint on column \"%s\"",
2662 key));
2663 break;
2664 }
2665 }
2666 }
2667 else
2668 {
2669 column->is_not_null = true;
2670 cxt->nnconstraints =
2673 }
2674 }
2675 else if (constraint->contype == CONSTR_PRIMARY)
2676 Assert(column->is_not_null);
2677 }
2678 else if (SystemAttributeByName(key) != NULL)
2679 {
2680 /*
2681 * column will be a system column in the new table, so accept
2682 * it. System columns can't ever be null, so no need to worry
2683 * about PRIMARY/NOT NULL constraint.
2684 */
2685 found = true;
2686 }
2687 else if (cxt->inhRelations)
2688 {
2689 /* try inherited tables */
2690 ListCell *inher;
2691
2692 foreach(inher, cxt->inhRelations)
2693 {
2695 Relation rel;
2696 int count;
2697
2698 rel = table_openrv(inh, AccessShareLock);
2699 /* check user requested inheritance from valid relkind */
2700 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2701 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2702 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2703 ereport(ERROR,
2705 errmsg("inherited relation \"%s\" is not a table or foreign table",
2706 inh->relname)));
2707 for (count = 0; count < rel->rd_att->natts; count++)
2708 {
2710 count);
2711 char *inhname = NameStr(inhattr->attname);
2712
2713 if (inhattr->attisdropped)
2714 continue;
2715 if (strcmp(key, inhname) == 0)
2716 {
2717 found = true;
2718 typid = inhattr->atttypid;
2719
2720 if (constraint->contype == CONSTR_PRIMARY)
2721 cxt->nnconstraints =
2724 break;
2725 }
2726 }
2727 table_close(rel, NoLock);
2728 if (found)
2729 break;
2730 }
2731 }
2732
2733 /*
2734 * In the ALTER TABLE case, don't complain about index keys not
2735 * created in the command; they may well exist already.
2736 * DefineIndex will complain about them if not.
2737 */
2738 if (!found && !cxt->isalter)
2739 ereport(ERROR,
2741 errmsg("column \"%s\" named in key does not exist", key),
2742 parser_errposition(cxt->pstate, constraint->location)));
2743
2744 /* Check for PRIMARY KEY(foo, foo) */
2745 foreach(columns, index->indexParams)
2746 {
2747 iparam = (IndexElem *) lfirst(columns);
2748 if (iparam->name && strcmp(key, iparam->name) == 0)
2749 {
2750 if (index->primary)
2751 ereport(ERROR,
2753 errmsg("column \"%s\" appears twice in primary key constraint",
2754 key),
2755 parser_errposition(cxt->pstate, constraint->location)));
2756 else
2757 ereport(ERROR,
2759 errmsg("column \"%s\" appears twice in unique constraint",
2760 key),
2761 parser_errposition(cxt->pstate, constraint->location)));
2762 }
2763 }
2764
2765 /*
2766 * The WITHOUT OVERLAPS part (if any) must be a range or
2767 * multirange type, or a domain over such a type.
2768 */
2769 if (constraint->without_overlaps && lc == list_last_cell(constraint->keys))
2770 {
2771 if (!found && cxt->isalter)
2772 {
2773 /*
2774 * Look up the column type on existing table. If we can't
2775 * find it, let things fail in DefineIndex.
2776 */
2777 Relation rel = cxt->rel;
2778
2779 for (int i = 0; i < rel->rd_att->natts; i++)
2780 {
2782 const char *attname;
2783
2784 if (attr->attisdropped)
2785 continue;
2786 attname = NameStr(attr->attname);
2787 if (strcmp(attname, key) == 0)
2788 {
2789 found = true;
2790 typid = attr->atttypid;
2791 break;
2792 }
2793 }
2794 }
2795 if (found)
2796 {
2797 /* Look up column type if we didn't already */
2798 if (!OidIsValid(typid) && column)
2799 typid = typenameTypeId(cxt->pstate,
2800 column->typeName);
2801 /* Look through any domain */
2802 if (OidIsValid(typid))
2803 typid = getBaseType(typid);
2804 /* Complain if not range/multirange */
2805 if (!OidIsValid(typid) ||
2806 !(type_is_range(typid) || type_is_multirange(typid)))
2807 ereport(ERROR,
2809 errmsg("column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type", key),
2810 parser_errposition(cxt->pstate, constraint->location)));
2811 }
2812 }
2813
2814 /* OK, add it to the index definition */
2816 iparam->name = pstrdup(key);
2817 iparam->expr = NULL;
2818 iparam->indexcolname = NULL;
2819 iparam->collation = NIL;
2820 iparam->opclass = NIL;
2821 iparam->opclassopts = NIL;
2822 iparam->ordering = SORTBY_DEFAULT;
2823 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
2824 iparam->location = -1;
2825 index->indexParams = lappend(index->indexParams, iparam);
2826 }
2827
2828 if (constraint->without_overlaps)
2829 {
2830 /*
2831 * This enforces that there is at least one equality column
2832 * besides the WITHOUT OVERLAPS columns. This is per SQL
2833 * standard. XXX Do we need this?
2834 */
2835 if (list_length(constraint->keys) < 2)
2836 ereport(ERROR,
2838 errmsg("constraint using WITHOUT OVERLAPS needs at least two columns"));
2839
2840 /* WITHOUT OVERLAPS requires a GiST index */
2841 index->accessMethod = "gist";
2842 }
2843
2844 }
2845
2846 /*
2847 * Add included columns to index definition. This is much like the
2848 * simple-column-name-list code above, except that we don't worry about
2849 * NOT NULL marking; included columns in a primary key should not be
2850 * forced NOT NULL. We don't complain about duplicate columns, either,
2851 * though maybe we should?
2852 */
2853 foreach(lc, constraint->including)
2854 {
2855 char *key = strVal(lfirst(lc));
2856 bool found = false;
2858 ListCell *columns;
2860
2861 foreach(columns, cxt->columns)
2862 {
2863 column = lfirst_node(ColumnDef, columns);
2864 if (strcmp(column->colname, key) == 0)
2865 {
2866 found = true;
2867 break;
2868 }
2869 }
2870
2871 if (!found)
2872 {
2873 if (SystemAttributeByName(key) != NULL)
2874 {
2875 /*
2876 * column will be a system column in the new table, so accept
2877 * it.
2878 */
2879 found = true;
2880 }
2881 else if (cxt->inhRelations)
2882 {
2883 /* try inherited tables */
2884 ListCell *inher;
2885
2886 foreach(inher, cxt->inhRelations)
2887 {
2889 Relation rel;
2890 int count;
2891
2892 rel = table_openrv(inh, AccessShareLock);
2893 /* check user requested inheritance from valid relkind */
2894 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2895 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2896 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2897 ereport(ERROR,
2899 errmsg("inherited relation \"%s\" is not a table or foreign table",
2900 inh->relname)));
2901 for (count = 0; count < rel->rd_att->natts; count++)
2902 {
2904 count);
2905 char *inhname = NameStr(inhattr->attname);
2906
2907 if (inhattr->attisdropped)
2908 continue;
2909 if (strcmp(key, inhname) == 0)
2910 {
2911 found = true;
2912 break;
2913 }
2914 }
2915 table_close(rel, NoLock);
2916 if (found)
2917 break;
2918 }
2919 }
2920 }
2921
2922 /*
2923 * In the ALTER TABLE case, don't complain about index keys not
2924 * created in the command; they may well exist already. DefineIndex
2925 * will complain about them if not.
2926 */
2927 if (!found && !cxt->isalter)
2928 ereport(ERROR,
2930 errmsg("column \"%s\" named in key does not exist", key),
2931 parser_errposition(cxt->pstate, constraint->location)));
2932
2933 /* OK, add it to the index definition */
2935 iparam->name = pstrdup(key);
2936 iparam->expr = NULL;
2937 iparam->indexcolname = NULL;
2938 iparam->collation = NIL;
2939 iparam->opclass = NIL;
2940 iparam->opclassopts = NIL;
2941 iparam->location = -1;
2942 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
2943 }
2944
2945 return index;
2946}
2947
2948/*
2949 * transformCheckConstraints
2950 * handle CHECK constraints
2951 *
2952 * Right now, there's nothing to do here when called from ALTER TABLE,
2953 * but the other constraint-transformation functions are called in both
2954 * the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
2955 * don't do anything if we're not authorized to skip validation.
2956 */
2957static void
2959{
2961
2962 if (cxt->ckconstraints == NIL)
2963 return;
2964
2965 /*
2966 * When creating a new table (but not a foreign table), we can safely skip
2967 * the validation of check constraints and mark them as valid based on the
2968 * constraint enforcement flag, since NOT ENFORCED constraints must always
2969 * be marked as NOT VALID. (This will override any user-supplied NOT VALID
2970 * flag.)
2971 */
2972 if (skipValidation)
2973 {
2974 foreach(ckclist, cxt->ckconstraints)
2975 {
2976 Constraint *constraint = (Constraint *) lfirst(ckclist);
2977
2978 constraint->skip_validation = true;
2979 constraint->initially_valid = constraint->is_enforced;
2980 }
2981 }
2982}
2983
2984/*
2985 * transformFKConstraints
2986 * handle FOREIGN KEY constraints
2987 */
2988static void
2991{
2993
2994 if (cxt->fkconstraints == NIL)
2995 return;
2996
2997 /*
2998 * If CREATE TABLE or adding a column with NULL default, we can safely
2999 * skip validation of FK constraints, and mark them as valid based on the
3000 * constraint enforcement flag, since NOT ENFORCED constraints must always
3001 * be marked as NOT VALID. (This will override any user-supplied NOT VALID
3002 * flag.)
3003 */
3004 if (skipValidation)
3005 {
3006 foreach(fkclist, cxt->fkconstraints)
3007 {
3008 Constraint *constraint = (Constraint *) lfirst(fkclist);
3009
3010 constraint->skip_validation = true;
3011 constraint->initially_valid = constraint->is_enforced;
3012 }
3013 }
3014
3015 /*
3016 * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
3017 * CONSTRAINT command to execute after the basic command is complete. (If
3018 * called from ADD CONSTRAINT, that routine will add the FK constraints to
3019 * its own subcommand list.)
3020 *
3021 * Note: the ADD CONSTRAINT command must also execute after any index
3022 * creation commands. Thus, this should run after
3023 * transformIndexConstraints, so that the CREATE INDEX commands are
3024 * already in cxt->alist. See also the handling of cxt->likeclauses.
3025 */
3026 if (!isAddConstraint)
3027 {
3029
3030 alterstmt->relation = cxt->relation;
3031 alterstmt->cmds = NIL;
3032 alterstmt->objtype = OBJECT_TABLE;
3033
3034 foreach(fkclist, cxt->fkconstraints)
3035 {
3036 Constraint *constraint = (Constraint *) lfirst(fkclist);
3038
3039 altercmd->subtype = AT_AddConstraint;
3040 altercmd->name = NULL;
3041 altercmd->def = (Node *) constraint;
3042 alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
3043 }
3044
3045 cxt->alist = lappend(cxt->alist, alterstmt);
3046 }
3047}
3048
3049/*
3050 * transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
3051 *
3052 * Note: this is a no-op for an index not using either index expressions or
3053 * a predicate expression. There are several code paths that create indexes
3054 * without bothering to call this, because they know they don't have any
3055 * such expressions to deal with.
3056 *
3057 * To avoid race conditions, it's important that this function rely only on
3058 * the passed-in relid (and not on stmt->relation) to determine the target
3059 * relation.
3060 */
3061IndexStmt *
3062transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
3063{
3064 ParseState *pstate;
3066 ListCell *l;
3067 Relation rel;
3068
3069 /* Nothing to do if statement already transformed. */
3070 if (stmt->transformed)
3071 return stmt;
3072
3073 /* Set up pstate */
3074 pstate = make_parsestate(NULL);
3075 pstate->p_sourcetext = queryString;
3076
3077 /*
3078 * Put the parent table into the rtable so that the expressions can refer
3079 * to its fields without qualification. Caller is responsible for locking
3080 * relation, but we still need to open it.
3081 */
3082 rel = relation_open(relid, NoLock);
3085 NULL, false, true);
3086
3087 /* no to join list, yes to namespaces */
3088 addNSItemToQuery(pstate, nsitem, false, true, true);
3089
3090 /* take care of the where clause */
3091 if (stmt->whereClause)
3092 {
3093 stmt->whereClause = transformWhereClause(pstate,
3094 stmt->whereClause,
3096 "WHERE");
3097 /* we have to fix its collations too */
3098 assign_expr_collations(pstate, stmt->whereClause);
3099 }
3100
3101 /* take care of any index expressions */
3102 foreach(l, stmt->indexParams)
3103 {
3104 IndexElem *ielem = (IndexElem *) lfirst(l);
3105
3106 if (ielem->expr)
3107 {
3108 /* Do parse transformation of the expression */
3109 ielem->expr = transformExpr(pstate, ielem->expr,
3111
3112 /* We have to fix its collations too */
3113 assign_expr_collations(pstate, ielem->expr);
3114
3115 /*
3116 * transformExpr() should have already rejected subqueries,
3117 * aggregates, window functions, and SRFs, based on the EXPR_KIND_
3118 * for an index expression.
3119 *
3120 * DefineIndex() will make more checks.
3121 */
3122 }
3123 }
3124
3125 /*
3126 * Likewise take care of any expressions in INCLUDING. (At this writing,
3127 * those will be rejected later on, but probably someday we'll wish to
3128 * support them.)
3129 */
3130 foreach(l, stmt->indexIncludingParams)
3131 {
3132 IndexElem *ielem = (IndexElem *) lfirst(l);
3133
3134 if (ielem->expr)
3135 {
3136 /* Do parse transformation of the expression */
3137 ielem->expr = transformExpr(pstate, ielem->expr,
3139
3140 /* We have to fix its collations too */
3141 assign_expr_collations(pstate, ielem->expr);
3142 }
3143 }
3144
3145 /*
3146 * Check that only the base rel is mentioned. (This should be dead code
3147 * now that add_missing_from is history.)
3148 */
3149 if (list_length(pstate->p_rtable) != 1)
3150 ereport(ERROR,
3152 errmsg("index expressions and predicates can refer only to the table being indexed")));
3153
3154 free_parsestate(pstate);
3155
3156 /* Close relation */
3157 table_close(rel, NoLock);
3158
3159 /* Mark statement as successfully transformed */
3160 stmt->transformed = true;
3161
3162 return stmt;
3163}
3164
3165/*
3166 * transformStatsStmt - parse analysis for CREATE STATISTICS
3167 *
3168 * To avoid race conditions, it's important that this function relies only on
3169 * the passed-in relid (and not on stmt->relation) to determine the target
3170 * relation.
3171 */
3173transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
3174{
3175 ParseState *pstate;
3177 ListCell *l;
3178 Relation rel;
3179
3180 /* Nothing to do if statement already transformed. */
3181 if (stmt->transformed)
3182 return stmt;
3183
3184 /* Set up pstate */
3185 pstate = make_parsestate(NULL);
3186 pstate->p_sourcetext = queryString;
3187
3188 /*
3189 * Put the parent table into the rtable so that the expressions can refer
3190 * to its fields without qualification. Caller is responsible for locking
3191 * relation, but we still need to open it.
3192 */
3193 rel = relation_open(relid, NoLock);
3196 NULL, false, true);
3197
3198 /* no to join list, yes to namespaces */
3199 addNSItemToQuery(pstate, nsitem, false, true, true);
3200
3201 /* take care of any expressions */
3202 foreach(l, stmt->exprs)
3203 {
3204 StatsElem *selem = (StatsElem *) lfirst(l);
3205
3206 if (selem->expr)
3207 {
3208 /* Now do parse transformation of the expression */
3209 selem->expr = transformExpr(pstate, selem->expr,
3211
3212 /* We have to fix its collations too */
3213 assign_expr_collations(pstate, selem->expr);
3214 }
3215 }
3216
3217 /*
3218 * Check that only the base rel is mentioned. (This should be dead code
3219 * now that add_missing_from is history.)
3220 */
3221 if (list_length(pstate->p_rtable) != 1)
3222 ereport(ERROR,
3224 errmsg("statistics expressions can refer only to the table being referenced")));
3225
3226 free_parsestate(pstate);
3227
3228 /* Close relation */
3229 table_close(rel, NoLock);
3230
3231 /* Mark statement as successfully transformed */
3232 stmt->transformed = true;
3233
3234 return stmt;
3235}
3236
3237
3238/*
3239 * transformRuleStmt -
3240 * transform a CREATE RULE Statement. The action is a list of parse
3241 * trees which is transformed into a list of query trees, and we also
3242 * transform the WHERE clause if any.
3243 *
3244 * actions and whereClause are output parameters that receive the
3245 * transformed results.
3246 */
3247void
3248transformRuleStmt(RuleStmt *stmt, const char *queryString,
3249 List **actions, Node **whereClause)
3250{
3251 Relation rel;
3252 ParseState *pstate;
3255
3256 /*
3257 * To avoid deadlock, make sure the first thing we do is grab
3258 * AccessExclusiveLock on the target relation. This will be needed by
3259 * DefineQueryRewrite(), and we don't want to grab a lesser lock
3260 * beforehand.
3261 */
3262 rel = table_openrv(stmt->relation, AccessExclusiveLock);
3263
3264 if (rel->rd_rel->relkind == RELKIND_MATVIEW)
3265 ereport(ERROR,
3267 errmsg("rules on materialized views are not supported")));
3268
3269 /* Set up pstate */
3270 pstate = make_parsestate(NULL);
3271 pstate->p_sourcetext = queryString;
3272
3273 /*
3274 * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
3275 * Set up their ParseNamespaceItems in the main pstate for use in parsing
3276 * the rule qualification.
3277 */
3280 makeAlias("old", NIL),
3281 false, false);
3284 makeAlias("new", NIL),
3285 false, false);
3286
3287 /*
3288 * They must be in the namespace too for lookup purposes, but only add the
3289 * one(s) that are relevant for the current kind of rule. In an UPDATE
3290 * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
3291 * there's no need to be so picky for INSERT & DELETE. We do not add them
3292 * to the joinlist.
3293 */
3294 switch (stmt->event)
3295 {
3296 case CMD_SELECT:
3297 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3298 break;
3299 case CMD_UPDATE:
3300 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3301 addNSItemToQuery(pstate, newnsitem, false, true, true);
3302 break;
3303 case CMD_INSERT:
3304 addNSItemToQuery(pstate, newnsitem, false, true, true);
3305 break;
3306 case CMD_DELETE:
3307 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3308 break;
3309 default:
3310 elog(ERROR, "unrecognized event type: %d",
3311 (int) stmt->event);
3312 break;
3313 }
3314
3315 /* take care of the where clause */
3316 *whereClause = transformWhereClause(pstate,
3317 stmt->whereClause,
3319 "WHERE");
3320 /* we have to fix its collations too */
3321 assign_expr_collations(pstate, *whereClause);
3322
3323 /* this is probably dead code without add_missing_from: */
3324 if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
3325 ereport(ERROR,
3327 errmsg("rule WHERE condition cannot contain references to other relations")));
3328
3329 /*
3330 * 'instead nothing' rules with a qualification need a query rangetable so
3331 * the rewrite handler can add the negated rule qualification to the
3332 * original query. We create a query with the new command type CMD_NOTHING
3333 * here that is treated specially by the rewrite system.
3334 */
3335 if (stmt->actions == NIL)
3336 {
3338
3339 nothing_qry->commandType = CMD_NOTHING;
3340 nothing_qry->rtable = pstate->p_rtable;
3341 nothing_qry->rteperminfos = pstate->p_rteperminfos;
3342 nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
3343
3344 *actions = list_make1(nothing_qry);
3345 }
3346 else
3347 {
3348 ListCell *l;
3349 List *newactions = NIL;
3350
3351 /*
3352 * transform each statement, like parse_sub_analyze()
3353 */
3354 foreach(l, stmt->actions)
3355 {
3356 Node *action = (Node *) lfirst(l);
3358 Query *sub_qry,
3359 *top_subqry;
3360 bool has_old,
3361 has_new;
3362
3363 /*
3364 * Since outer ParseState isn't parent of inner, have to pass down
3365 * the query text by hand.
3366 */
3367 sub_pstate->p_sourcetext = queryString;
3368
3369 /*
3370 * Set up OLD/NEW in the rtable for this statement. The entries
3371 * are added only to relnamespace, not varnamespace, because we
3372 * don't want them to be referred to by unqualified field names
3373 * nor "*" in the rule actions. We decide later whether to put
3374 * them in the joinlist.
3375 */
3378 makeAlias("old", NIL),
3379 false, false);
3382 makeAlias("new", NIL),
3383 false, false);
3384 addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
3385 addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
3386
3387 /* Transform the rule action statement */
3389
3390 /*
3391 * We cannot support utility-statement actions (eg NOTIFY) with
3392 * nonempty rule WHERE conditions, because there's no way to make
3393 * the utility action execute conditionally.
3394 */
3395 if (top_subqry->commandType == CMD_UTILITY &&
3396 *whereClause != NULL)
3397 ereport(ERROR,
3399 errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
3400
3401 /*
3402 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
3403 * into the SELECT, and that's what we need to look at. (Ugly
3404 * kluge ... try to fix this when we redesign querytrees.)
3405 */
3407
3408 /*
3409 * If the sub_qry is a setop, we cannot attach any qualifications
3410 * to it, because the planner won't notice them. This could
3411 * perhaps be relaxed someday, but for now, we may as well reject
3412 * such a rule immediately.
3413 */
3414 if (sub_qry->setOperations != NULL && *whereClause != NULL)
3415 ereport(ERROR,
3417 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3418
3419 /*
3420 * Validate action's use of OLD/NEW, qual too
3421 */
3422 has_old =
3424 rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
3425 has_new =
3427 rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
3428
3429 switch (stmt->event)
3430 {
3431 case CMD_SELECT:
3432 if (has_old)
3433 ereport(ERROR,
3435 errmsg("ON SELECT rule cannot use OLD")));
3436 if (has_new)
3437 ereport(ERROR,
3439 errmsg("ON SELECT rule cannot use NEW")));
3440 break;
3441 case CMD_UPDATE:
3442 /* both are OK */
3443 break;
3444 case CMD_INSERT:
3445 if (has_old)
3446 ereport(ERROR,
3448 errmsg("ON INSERT rule cannot use OLD")));
3449 break;
3450 case CMD_DELETE:
3451 if (has_new)
3452 ereport(ERROR,
3454 errmsg("ON DELETE rule cannot use NEW")));
3455 break;
3456 default:
3457 elog(ERROR, "unrecognized event type: %d",
3458 (int) stmt->event);
3459 break;
3460 }
3461
3462 /*
3463 * OLD/NEW are not allowed in WITH queries, because they would
3464 * amount to outer references for the WITH, which we disallow.
3465 * However, they were already in the outer rangetable when we
3466 * analyzed the query, so we have to check.
3467 *
3468 * Note that in the INSERT...SELECT case, we need to examine the
3469 * CTE lists of both top_subqry and sub_qry.
3470 *
3471 * Note that we aren't digging into the body of the query looking
3472 * for WITHs in nested sub-SELECTs. A WITH down there can
3473 * legitimately refer to OLD/NEW, because it'd be an
3474 * indirect-correlated outer reference.
3475 */
3476 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3477 PRS2_OLD_VARNO, 0) ||
3478 rangeTableEntry_used((Node *) sub_qry->cteList,
3479 PRS2_OLD_VARNO, 0))
3480 ereport(ERROR,
3482 errmsg("cannot refer to OLD within WITH query")));
3483 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3484 PRS2_NEW_VARNO, 0) ||
3485 rangeTableEntry_used((Node *) sub_qry->cteList,
3486 PRS2_NEW_VARNO, 0))
3487 ereport(ERROR,
3489 errmsg("cannot refer to NEW within WITH query")));
3490
3491 /*
3492 * For efficiency's sake, add OLD to the rule action's jointree
3493 * only if it was actually referenced in the statement or qual.
3494 *
3495 * For INSERT, NEW is not really a relation (only a reference to
3496 * the to-be-inserted tuple) and should never be added to the
3497 * jointree.
3498 *
3499 * For UPDATE, we treat NEW as being another kind of reference to
3500 * OLD, because it represents references to *transformed* tuples
3501 * of the existing relation. It would be wrong to enter NEW
3502 * separately in the jointree, since that would cause a double
3503 * join of the updated relation. It's also wrong to fail to make
3504 * a jointree entry if only NEW and not OLD is mentioned.
3505 */
3506 if (has_old || (has_new && stmt->event == CMD_UPDATE))
3507 {
3509
3510 /*
3511 * If sub_qry is a setop, manipulating its jointree will do no
3512 * good at all, because the jointree is dummy. (This should be
3513 * a can't-happen case because of prior tests.)
3514 */
3515 if (sub_qry->setOperations != NULL)
3516 ereport(ERROR,
3518 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3519 /* hackishly add OLD to the already-built FROM clause */
3521 rtr->rtindex = oldnsitem->p_rtindex;
3522 sub_qry->jointree->fromlist =
3523 lappend(sub_qry->jointree->fromlist, rtr);
3524 }
3525
3527
3529 }
3530
3531 *actions = newactions;
3532 }
3533
3534 free_parsestate(pstate);
3535
3536 /* Close relation, but keep the exclusive lock */
3537 table_close(rel, NoLock);
3538}
3539
3540
3541/*
3542 * checkPartition
3543 * Check whether partRelOid is a leaf partition of the parent table (rel).
3544 * isMerge: true indicates the operation is "ALTER TABLE ... MERGE PARTITIONS";
3545 * false indicates the operation is "ALTER TABLE ... SPLIT PARTITION".
3546 */
3547static void
3549{
3550 Relation partRel;
3551
3552 partRel = table_open(partRelOid, NoLock);
3553
3554 if (partRel->rd_rel->relkind != RELKIND_RELATION)
3555 ereport(ERROR,
3557 errmsg("\"%s\" is not a table", RelationGetRelationName(partRel)),
3558 isMerge
3559 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
3560 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
3561
3562 if (!partRel->rd_rel->relispartition)
3563 ereport(ERROR,
3565 errmsg("\"%s\" is not a partition of partitioned table \"%s\"",
3567 isMerge
3568 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
3569 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
3570
3572 ereport(ERROR,
3574 errmsg("relation \"%s\" is not a partition of relation \"%s\"",
3576 isMerge
3577 ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions that don't have sub-partitions.")
3578 : errhint("ALTER TABLE ... SPLIT PARTITION can only split partitions that don't have sub-partitions."));
3579
3580 table_close(partRel, NoLock);
3581}
3582
3583/*
3584 * transformPartitionCmdForSplit -
3585 * analyze the ALTER TABLE ... SPLIT PARTITION command
3586 *
3587 * For each new partition, sps->bound is set to the transformed value of bound.
3588 * Does checks for bounds of new partitions.
3589 */
3590static void
3592{
3593 Relation parent = cxt->rel;
3594 PartitionKey key;
3595 char strategy;
3598 int default_index = -1;
3599 bool isSplitPartDefault;
3601 *listptr2;
3602 List *splitlist;
3603
3604 splitlist = partcmd->partlist;
3605 key = RelationGetPartitionKey(parent);
3606 strategy = get_partition_strategy(key);
3608
3609 /* Transform partition bounds for all partitions in the list: */
3611 {
3612 cxt->partbound = NULL;
3613 transformPartitionCmd(cxt, sps->bound);
3614 /* Assign the transformed value of the partition bound. */
3615 sps->bound = cxt->partbound;
3616 }
3617
3618 /*
3619 * Open and lock the partition, check ownership along the way. We need to
3620 * use AccessExclusiveLock here because this split partition will be
3621 * detached, then dropped in ATExecSplitPartition.
3622 */
3625 NULL);
3626
3627 checkPartition(parent, splitPartOid, false);
3628
3629 switch (strategy)
3630 {
3633 {
3635 {
3636 if (sps->bound->is_default)
3637 {
3638 if (default_index != -1)
3639 ereport(ERROR,
3641 errmsg("cannot specify more than one DEFAULT partition"),
3642 parser_errposition(cxt->pstate, sps->name->location));
3643
3644 default_index = foreach_current_index(sps);
3645 }
3646 }
3647 }
3648 break;
3649
3651 ereport(ERROR,
3653 errmsg("partition of hash-partitioned table cannot be split"));
3654 break;
3655
3656 default:
3657 elog(ERROR, "unexpected partition strategy: %d",
3658 (int) key->strategy);
3659 break;
3660 }
3661
3662 /* isSplitPartDefault: is the being split partition a DEFAULT partition? */
3664
3665 if (isSplitPartDefault && default_index == -1)
3666 ereport(ERROR,
3668 errmsg("cannot split DEFAULT partition \"%s\"",
3670 errhint("To split a DEFAULT partition, one of the new partitions must be DEFAULT."));
3671
3672 /*
3673 * If the partition being split is not the DEFAULT partition, but the
3674 * DEFAULT partition exists, then none of the resulting split partitions
3675 * can be the DEFAULT.
3676 */
3677 if (!isSplitPartDefault && (default_index != -1) && OidIsValid(defaultPartOid))
3678 {
3680 (SinglePartitionSpec *) list_nth(splitlist, default_index);
3681
3682 ereport(ERROR,
3684 errmsg("cannot split non-DEFAULT partition \"%s\"",
3686 errdetail("New partition cannot be DEFAULT because DEFAULT partition \"%s\" already exists.",
3688 parser_errposition(cxt->pstate, spsDef->name->location));
3689 }
3690
3691 foreach(listptr, splitlist)
3692 {
3693 Oid nspid;
3695 RangeVar *name = sps->name;
3696
3698
3699 /* Partitions in the list should have different names. */
3701 {
3702 Oid nspid2;
3704 RangeVar *name2 = sps2->name;
3705
3706 if (equal(name, name2))
3707 ereport(ERROR,
3709 errmsg("partition with name \"%s\" is already used", name->relname),
3710 parser_errposition(cxt->pstate, name2->location));
3711
3713
3714 if (nspid2 == nspid && strcmp(name->relname, name2->relname) == 0)
3715 ereport(ERROR,
3717 errmsg("partition with name \"%s\" is already used", name->relname),
3718 parser_errposition(cxt->pstate, name2->location));
3719 }
3720 }
3721
3722 /* Then we should check partitions with transformed bounds. */
3724}
3725
3726
3727/*
3728 * transformPartitionCmdForMerge -
3729 * analyze the ALTER TABLE ... MERGE PARTITIONS command
3730 *
3731 * Does simple checks for merged partitions. Calculates bound of the resulting
3732 * partition.
3733 */
3734static void
3736{
3738 Oid partOid;
3739 Relation parent = cxt->rel;
3740 PartitionKey key;
3741 char strategy;
3743 *listptr2;
3744 bool isDefaultPart = false;
3745 List *partOids = NIL;
3746
3747 key = RelationGetPartitionKey(parent);
3748 strategy = get_partition_strategy(key);
3749
3750 if (strategy == PARTITION_STRATEGY_HASH)
3751 ereport(ERROR,
3753 errmsg("partition of hash-partitioned table cannot be merged"));
3754
3755 /* Does the partitioned table (parent) have a default partition? */
3757
3758 foreach(listptr, partcmd->partlist)
3759 {
3761
3762 /* Partitions in the list should have different names. */
3763 for_each_cell(listptr2, partcmd->partlist, lnext(partcmd->partlist, listptr))
3764 {
3766
3767 if (equal(name, name2))
3768 ereport(ERROR,
3770 errmsg("partition with name \"%s\" is already used", name->relname),
3771 parser_errposition(cxt->pstate, name2->location));
3772 }
3773
3774 /*
3775 * Search the DEFAULT partition in the list. Open and lock partitions
3776 * before calculating the boundary for resulting partition, we also
3777 * check for ownership along the way. We need to use
3778 * AccessExclusiveLock here, because these merged partitions will be
3779 * detached and then dropped in ATExecMergePartitions.
3780 */
3783 NULL);
3784 /* Is the current partition a DEFAULT partition? */
3785 if (partOid == defaultPartOid)
3786 isDefaultPart = true;
3787
3788 /*
3789 * Extended check because the same partition can have different names
3790 * (for example, "part_name" and "public.part_name").
3791 */
3792 foreach(listptr2, partOids)
3793 {
3795
3796 if (curOid == partOid)
3797 ereport(ERROR,
3799 errmsg("partition with name \"%s\" is already used", name->relname),
3800 parser_errposition(cxt->pstate, name->location));
3801 }
3802
3803 checkPartition(parent, partOid, true);
3804
3806 }
3807
3808 /* Allocate the bound of the resulting partition. */
3809 Assert(partcmd->bound == NULL);
3811
3812 /* Fill the partition bound. */
3813 partcmd->bound->strategy = strategy;
3814 partcmd->bound->location = -1;
3815 partcmd->bound->is_default = isDefaultPart;
3816 if (!isDefaultPart)
3818 partOids, partcmd->bound,
3819 cxt->pstate);
3820}
3821
3822/*
3823 * transformAlterTableStmt -
3824 * parse analysis for ALTER TABLE
3825 *
3826 * Returns the transformed AlterTableStmt. There may be additional actions
3827 * to be done before and after the transformed statement, which are returned
3828 * in *beforeStmts and *afterStmts as lists of utility command parsetrees.
3829 *
3830 * To avoid race conditions, it's important that this function rely only on
3831 * the passed-in relid (and not on stmt->relation) to determine the target
3832 * relation.
3833 */
3836 const char *queryString,
3837 List **beforeStmts, List **afterStmts)
3838{
3839 Relation rel;
3840 TupleDesc tupdesc;
3841 ParseState *pstate;
3844 ListCell *lcmd,
3845 *l;
3846 List *newcmds = NIL;
3847 bool skipValidation = true;
3850
3851 /* Caller is responsible for locking the relation */
3852 rel = relation_open(relid, NoLock);
3853 tupdesc = RelationGetDescr(rel);
3854
3855 /* Set up pstate */
3856 pstate = make_parsestate(NULL);
3857 pstate->p_sourcetext = queryString;
3859 rel,
3861 NULL,
3862 false,
3863 true);
3864 addNSItemToQuery(pstate, nsitem, false, true, true);
3865
3866 /* Set up CreateStmtContext */
3867 cxt.pstate = pstate;
3868 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3869 {
3870 cxt.stmtType = "ALTER FOREIGN TABLE";
3871 cxt.isforeign = true;
3872 }
3873 else
3874 {
3875 cxt.stmtType = "ALTER TABLE";
3876 cxt.isforeign = false;
3877 }
3878 cxt.relation = stmt->relation;
3879 cxt.rel = rel;
3880 cxt.inhRelations = NIL;
3881 cxt.isalter = true;
3882 cxt.columns = NIL;
3883 cxt.ckconstraints = NIL;
3884 cxt.nnconstraints = NIL;
3885 cxt.fkconstraints = NIL;
3886 cxt.ixconstraints = NIL;
3887 cxt.likeclauses = NIL;
3888 cxt.blist = NIL;
3889 cxt.alist = NIL;
3890 cxt.pkey = NULL;
3891 cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3892 cxt.partbound = NULL;
3893 cxt.ofType = false;
3894
3895 /*
3896 * Transform ALTER subcommands that need it (most don't). These largely
3897 * re-use code from CREATE TABLE.
3898 */
3899 foreach(lcmd, stmt->cmds)
3900 {
3902
3903 switch (cmd->subtype)
3904 {
3905 case AT_AddColumn:
3906 {
3907 ColumnDef *def = castNode(ColumnDef, cmd->def);
3908
3909 transformColumnDefinition(&cxt, def);
3910
3911 /*
3912 * If the column has a non-null default, we can't skip
3913 * validation of foreign keys.
3914 */
3915 if (def->raw_default != NULL)
3916 skipValidation = false;
3917
3918 /*
3919 * All constraints are processed in other ways. Remove the
3920 * original list
3921 */
3922 def->constraints = NIL;
3923
3924 newcmds = lappend(newcmds, cmd);
3925 break;
3926 }
3927
3928 case AT_AddConstraint:
3929
3930 /*
3931 * The original AddConstraint cmd node doesn't go to newcmds
3932 */
3933 if (IsA(cmd->def, Constraint))
3934 {
3935 transformTableConstraint(&cxt, (Constraint *) cmd->def);
3936 if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
3937 skipValidation = false;
3938 }
3939 else
3940 elog(ERROR, "unrecognized node type: %d",
3941 (int) nodeTag(cmd->def));
3942 break;
3943
3944 case AT_AlterColumnType:
3945 {
3946 ColumnDef *def = castNode(ColumnDef, cmd->def);
3948
3949 /*
3950 * For ALTER COLUMN TYPE, transform the USING clause if
3951 * one was specified.
3952 */
3953 if (def->raw_default)
3954 {
3955 def->cooked_default =
3956 transformExpr(pstate, def->raw_default,
3958 }
3959
3960 /*
3961 * For identity column, create ALTER SEQUENCE command to
3962 * change the data type of the sequence. Identity sequence
3963 * is associated with the top level partitioned table.
3964 * Hence ignore partitions.
3965 */
3967 {
3968 attnum = get_attnum(relid, cmd->name);
3970 ereport(ERROR,
3972 errmsg("column \"%s\" of relation \"%s\" does not exist",
3973 cmd->name, RelationGetRelationName(rel))));
3974
3975 if (attnum > 0 &&
3976 TupleDescAttr(tupdesc, attnum - 1)->attidentity)
3977 {
3978 Oid seq_relid = getIdentitySequence(rel, attnum, false);
3979 Oid typeOid = typenameTypeId(pstate, def->typeName);
3981
3982 altseqstmt->sequence
3985 -1);
3986 altseqstmt->options = list_make1(makeDefElem("as",
3987 (Node *) makeTypeNameFromOid(typeOid, -1),
3988 -1));
3989 altseqstmt->for_identity = true;
3990 cxt.blist = lappend(cxt.blist, altseqstmt);
3991 }
3992 }
3993
3994 newcmds = lappend(newcmds, cmd);
3995 break;
3996 }
3997
3998 case AT_AddIdentity:
3999 {
4000 Constraint *def = castNode(Constraint, cmd->def);
4003
4004 newdef->colname = cmd->name;
4005 newdef->identity = def->generated_when;
4006 cmd->def = (Node *) newdef;
4007
4008 attnum = get_attnum(relid, cmd->name);
4010 ereport(ERROR,
4012 errmsg("column \"%s\" of relation \"%s\" does not exist",
4013 cmd->name, RelationGetRelationName(rel))));
4014
4016 get_atttype(relid, attnum),
4017 def->options, true, true,
4018 NULL, NULL);
4019
4020 newcmds = lappend(newcmds, cmd);
4021 break;
4022 }
4023
4024 case AT_SetIdentity:
4025 {
4026 /*
4027 * Create an ALTER SEQUENCE statement for the internal
4028 * sequence of the identity column.
4029 */
4030 ListCell *lc;
4031 List *newseqopts = NIL;
4032 List *newdef = NIL;
4034 Oid seq_relid;
4035
4036 /*
4037 * Split options into those handled by ALTER SEQUENCE and
4038 * those for ALTER TABLE proper.
4039 */
4040 foreach(lc, castNode(List, cmd->def))
4041 {
4042 DefElem *def = lfirst_node(DefElem, lc);
4043
4044 if (strcmp(def->defname, "generated") == 0)
4045 newdef = lappend(newdef, def);
4046 else
4048 }
4049
4050 attnum = get_attnum(relid, cmd->name);
4052 ereport(ERROR,
4054 errmsg("column \"%s\" of relation \"%s\" does not exist",
4055 cmd->name, RelationGetRelationName(rel))));
4056
4057 seq_relid = getIdentitySequence(rel, attnum, true);
4058
4059 if (seq_relid)
4060 {
4062
4065 get_rel_name(seq_relid), -1);
4066 seqstmt->options = newseqopts;
4067 seqstmt->for_identity = true;
4068 seqstmt->missing_ok = false;
4069
4070 cxt.blist = lappend(cxt.blist, seqstmt);
4071 }
4072
4073 /*
4074 * If column was not an identity column, we just let the
4075 * ALTER TABLE command error out later. (There are cases
4076 * this fails to cover, but we'll need to restructure
4077 * where creation of the sequence dependency linkage
4078 * happens before we can fix it.)
4079 */
4080
4081 cmd->def = (Node *) newdef;
4082 newcmds = lappend(newcmds, cmd);
4083 break;
4084 }
4085
4086 case AT_AttachPartition:
4087 case AT_DetachPartition:
4088 {
4090
4091 transformPartitionCmd(&cxt, partcmd->bound);
4092 /* assign the transformed value of the partition bound */
4093 partcmd->bound = cxt.partbound;
4094 }
4095
4096 newcmds = lappend(newcmds, cmd);
4097 break;
4098
4099 case AT_MergePartitions:
4100 {
4102
4103 if (list_length(partcmd->partlist) < 2)
4104 ereport(ERROR,
4106 errmsg("list of partitions to be merged should include at least two partitions"));
4107
4109 newcmds = lappend(newcmds, cmd);
4110 break;
4111 }
4112
4113 case AT_SplitPartition:
4114 {
4116
4117 if (list_length(partcmd->partlist) < 2)
4118 ereport(ERROR,
4120 errmsg("list of new partitions should contain at least two partitions"));
4121
4123 newcmds = lappend(newcmds, cmd);
4124 break;
4125 }
4126
4127 default:
4128
4129 /*
4130 * Currently, we shouldn't actually get here for the
4131 * subcommand types that don't require transformation; but if
4132 * we do, just emit them unchanged.
4133 */
4134 newcmds = lappend(newcmds, cmd);
4135 break;
4136 }
4137 }
4138
4139 /*
4140 * Transfer anything we already have in cxt.alist into save_alist, to keep
4141 * it separate from the output of transformIndexConstraints.
4142 */
4143 save_alist = cxt.alist;
4144 cxt.alist = NIL;
4145
4146 /* Postprocess constraints */
4149 transformCheckConstraints(&cxt, false);
4150
4151 /*
4152 * Push any index-creation commands into the ALTER, so that they can be
4153 * scheduled nicely by tablecmds.c. Note that tablecmds.c assumes that
4154 * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
4155 * subcommand has already been through transformIndexStmt.
4156 */
4157 foreach(l, cxt.alist)
4158 {
4159 Node *istmt = (Node *) lfirst(l);
4160
4161 /*
4162 * We assume here that cxt.alist contains only IndexStmts generated
4163 * from primary key constraints.
4164 */
4165 if (IsA(istmt, IndexStmt))
4166 {
4167 IndexStmt *idxstmt = (IndexStmt *) istmt;
4168
4169 idxstmt = transformIndexStmt(relid, idxstmt, queryString);
4171 newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
4172 newcmd->def = (Node *) idxstmt;
4174 }
4175 else
4176 elog(ERROR, "unexpected stmt type %d", (int) nodeTag(istmt));
4177 }
4178 cxt.alist = NIL;
4179
4180 /* Append any CHECK, NOT NULL or FK constraints to the commands list */
4182 {
4184 newcmd->subtype = AT_AddConstraint;
4185 newcmd->def = (Node *) def;
4187 }
4189 {
4191 newcmd->subtype = AT_AddConstraint;
4192 newcmd->def = (Node *) def;
4194 }
4196 {
4198 newcmd->subtype = AT_AddConstraint;
4199 newcmd->def = (Node *) def;
4201 }
4202
4203 /* Close rel */
4204 relation_close(rel, NoLock);
4205
4206 /*
4207 * Output results.
4208 */
4209 stmt->cmds = newcmds;
4210
4211 *beforeStmts = cxt.blist;
4212 *afterStmts = list_concat(cxt.alist, save_alist);
4213
4214 return stmt;
4215}
4216
4217
4218/*
4219 * Preprocess a list of column constraint clauses
4220 * to attach constraint attributes to their primary constraint nodes
4221 * and detect inconsistent/misplaced constraint attributes.
4222 *
4223 * NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
4224 * EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
4225 * supported for other constraint types.
4226 *
4227 * NOTE: this must be idempotent in non-error cases; see
4228 * transformCreateSchemaCreateTable.
4229 */
4230static void
4232{
4234 bool saw_deferrability = false;
4235 bool saw_initially = false;
4236 bool saw_enforced = false;
4237 ListCell *clist;
4238
4239#define SUPPORTS_ATTRS(node) \
4240 ((node) != NULL && \
4241 ((node)->contype == CONSTR_PRIMARY || \
4242 (node)->contype == CONSTR_UNIQUE || \
4243 (node)->contype == CONSTR_EXCLUSION || \
4244 (node)->contype == CONSTR_FOREIGN))
4245
4246 foreach(clist, constraintList)
4247 {
4248 Constraint *con = (Constraint *) lfirst(clist);
4249
4250 if (!IsA(con, Constraint))
4251 elog(ERROR, "unrecognized node type: %d",
4252 (int) nodeTag(con));
4253 switch (con->contype)
4254 {
4257 ereport(ERROR,
4259 errmsg("misplaced DEFERRABLE clause"),
4260 parser_errposition(pstate, con->location)));
4262 ereport(ERROR,
4264 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
4265 parser_errposition(pstate, con->location)));
4266 saw_deferrability = true;
4267 lastprimarycon->deferrable = true;
4268 break;
4269
4272 ereport(ERROR,
4274 errmsg("misplaced NOT DEFERRABLE clause"),
4275 parser_errposition(pstate, con->location)));
4277 ereport(ERROR,
4279 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
4280 parser_errposition(pstate, con->location)));
4281 saw_deferrability = true;
4282 lastprimarycon->deferrable = false;
4283 if (saw_initially &&
4284 lastprimarycon->initdeferred)
4285 ereport(ERROR,
4287 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
4288 parser_errposition(pstate, con->location)));
4289 break;
4290
4293 ereport(ERROR,
4295 errmsg("misplaced INITIALLY DEFERRED clause"),
4296 parser_errposition(pstate, con->location)));
4297 if (saw_initially)
4298 ereport(ERROR,
4300 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
4301 parser_errposition(pstate, con->location)));
4302 saw_initially = true;
4303 lastprimarycon->initdeferred = true;
4304
4305 /*
4306 * If only INITIALLY DEFERRED appears, assume DEFERRABLE
4307 */
4308 if (!saw_deferrability)
4309 lastprimarycon->deferrable = true;
4310 else if (!lastprimarycon->deferrable)
4311 ereport(ERROR,
4313 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
4314 parser_errposition(pstate, con->location)));
4315 break;
4316
4319 ereport(ERROR,
4321 errmsg("misplaced INITIALLY IMMEDIATE clause"),
4322 parser_errposition(pstate, con->location)));
4323 if (saw_initially)
4324 ereport(ERROR,
4326 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
4327 parser_errposition(pstate, con->location)));
4328 saw_initially = true;
4329 lastprimarycon->initdeferred = false;
4330 break;
4331
4333 if (lastprimarycon == NULL ||
4334 (lastprimarycon->contype != CONSTR_CHECK &&
4335 lastprimarycon->contype != CONSTR_FOREIGN))
4336 ereport(ERROR,
4338 errmsg("misplaced ENFORCED clause"),
4339 parser_errposition(pstate, con->location)));
4340 if (saw_enforced)
4341 ereport(ERROR,
4343 errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
4344 parser_errposition(pstate, con->location)));
4345 saw_enforced = true;
4346 lastprimarycon->is_enforced = true;
4347 break;
4348
4350 if (lastprimarycon == NULL ||
4351 (lastprimarycon->contype != CONSTR_CHECK &&
4352 lastprimarycon->contype != CONSTR_FOREIGN))
4353 ereport(ERROR,
4355 errmsg("misplaced NOT ENFORCED clause"),
4356 parser_errposition(pstate, con->location)));
4357 if (saw_enforced)
4358 ereport(ERROR,
4360 errmsg("multiple ENFORCED/NOT ENFORCED clauses not allowed"),
4361 parser_errposition(pstate, con->location)));
4362 saw_enforced = true;
4363 lastprimarycon->is_enforced = false;
4364
4365 /* A NOT ENFORCED constraint must be marked as invalid. */
4366 lastprimarycon->skip_validation = true;
4367 lastprimarycon->initially_valid = false;
4368 break;
4369
4370 default:
4371 /* Otherwise it's not an attribute */
4372 lastprimarycon = con;
4373 /* reset flags for new primary node */
4374 saw_deferrability = false;
4375 saw_initially = false;
4376 saw_enforced = false;
4377 break;
4378 }
4379 }
4380}
4381
4382/*
4383 * Special handling of type definition for a column
4384 */
4385static void
4387{
4388 /*
4389 * All we really need to do here is verify that the type is valid,
4390 * including any collation spec that might be present.
4391 */
4392 Type ctype = typenameType(cxt->pstate, column->typeName, NULL);
4393
4394 if (column->collClause)
4395 {
4397
4399 column->collClause->collname,
4400 column->collClause->location);
4401 /* Complain if COLLATE is applied to an uncollatable type */
4402 if (!OidIsValid(typtup->typcollation))
4403 ereport(ERROR,
4405 errmsg("collations are not supported by type %s",
4406 format_type_be(typtup->oid)),
4408 column->collClause->location)));
4409 }
4410
4411 ReleaseSysCache(ctype);
4412}
4413
4414
4415/*
4416 * transformCreateSchemaStmtElements -
4417 * analyzes the elements of a CREATE SCHEMA statement
4418 *
4419 * This presently has two responsibilities. We verify that no subcommands are
4420 * trying to create objects outside the new schema. We also pull out any
4421 * foreign-key constraint clauses embedded in CREATE TABLE subcommands, and
4422 * convert them to ALTER TABLE ADD CONSTRAINT commands appended to the list.
4423 * This supports forward references in foreign keys, which is required by the
4424 * SQL standard.
4425 *
4426 * We used to try to re-order the commands in a way that would work even if
4427 * the user-written order would not, but that's too hard (perhaps impossible)
4428 * to do correctly with not-yet-parse-analyzed commands. Now we'll just
4429 * execute the elements in the order given, except for foreign keys.
4430 *
4431 * "schemaName" is the name of the schema that will be used for the creation
4432 * of the objects listed. It may be obtained from the schema name defined
4433 * in the statement or a role specification.
4434 *
4435 * The result is a list of parse nodes that still need to be analyzed ---
4436 * but we can't analyze the later commands until we've executed the earlier
4437 * ones, because of possible inter-object references.
4438 *
4439 * Note it's important that we not modify the input data structure. We create
4440 * a new result List, and we copy any CREATE TABLE subcommands that we might
4441 * modify.
4442 */
4443List *
4445 const char *schemaName)
4446{
4447 List *elements = NIL;
4448 List *fk_elements = NIL;
4449 ListCell *lc;
4450
4451 /*
4452 * Run through each schema element in the schema element list. Check
4453 * target schema names, and collect the list of actions to be done.
4454 */
4455 foreach(lc, schemaElts)
4456 {
4457 Node *element = lfirst(lc);
4458
4459 switch (nodeTag(element))
4460 {
4461 case T_CreateSeqStmt:
4462 {
4464
4465 checkSchemaNameRV(pstate, schemaName, elp->sequence);
4466 elements = lappend(elements, element);
4467 }
4468 break;
4469
4470 case T_CreateStmt:
4471 {
4473
4474 checkSchemaNameRV(pstate, schemaName, elp->relation);
4475 /* Pull out any foreign key clauses, add to fk_elements */
4477 elp,
4478 &fk_elements);
4479 elements = lappend(elements, elp);
4480 }
4481 break;
4482
4483 case T_ViewStmt:
4484 {
4486
4487 checkSchemaNameRV(pstate, schemaName, elp->view);
4488 elements = lappend(elements, element);
4489 }
4490 break;
4491
4492 case T_IndexStmt:
4493 {
4495
4496 checkSchemaNameRV(pstate, schemaName, elp->relation);
4497 elements = lappend(elements, element);
4498 }
4499 break;
4500
4501 case T_CreateTrigStmt:
4502 {
4504
4505 checkSchemaNameRV(pstate, schemaName, elp->relation);
4506 elements = lappend(elements, element);
4507 }
4508 break;
4509
4510 case T_CreateDomainStmt:
4511 {
4513
4514 checkSchemaNameList(schemaName, elp->domainname);
4515 elements = lappend(elements, element);
4516 }
4517 break;
4518
4520 {
4522
4524 elements = lappend(elements, element);
4525 }
4526 break;
4527
4528 /*
4529 * CREATE TYPE can produce a DefineStmt, but also
4530 * CreateEnumStmt, CreateRangeStmt, and CompositeTypeStmt.
4531 * Allowing DefineStmt also provides support for several other
4532 * commands: currently, CREATE AGGREGATE, CREATE COLLATION,
4533 * CREATE OPERATOR, and text search objects.
4534 */
4535
4536 case T_DefineStmt:
4537 {
4539
4541 elements = lappend(elements, element);
4542 }
4543 break;
4544
4545 case T_CreateEnumStmt:
4546 {
4548
4550 elements = lappend(elements, element);
4551 }
4552 break;
4553
4554 case T_CreateRangeStmt:
4555 {
4557
4559 elements = lappend(elements, element);
4560 }
4561 break;
4562
4564 {
4566
4567 checkSchemaNameRV(pstate, schemaName, elp->typevar);
4568 elements = lappend(elements, element);
4569 }
4570 break;
4571
4572 case T_GrantStmt:
4573 elements = lappend(elements, element);
4574 break;
4575
4576 default:
4577 elog(ERROR, "unrecognized node type: %d",
4578 (int) nodeTag(element));
4579 }
4580 }
4581
4582 return list_concat(elements, fk_elements);
4583}
4584
4585/*
4586 * checkSchemaNameRV
4587 * Check schema name in an element of a CREATE SCHEMA command,
4588 * where the element's name is given by a RangeVar
4589 *
4590 * It's okay if the command doesn't specify a target schema name, because
4591 * CreateSchemaCommand will set up the default creation schema to be the
4592 * new schema. But if a target schema name is given, it had better match.
4593 * We also have to check that the command doesn't say CREATE TEMP, since
4594 * that would likewise put the object into the wrong schema.
4595 */
4596static void
4598 RangeVar *relation)
4599{
4600 if (relation->schemaname != NULL &&
4601 strcmp(context_schema, relation->schemaname) != 0)
4602 ereport(ERROR,
4604 errmsg("CREATE specifies a schema (%s) "
4605 "different from the one being created (%s)",
4606 relation->schemaname, context_schema),
4607 parser_errposition(pstate, relation->location)));
4608
4609 if (relation->relpersistence == RELPERSISTENCE_TEMP)
4610 {
4611 /* spell this error the same as in RangeVarAdjustRelationPersistence */
4612 ereport(ERROR,
4614 errmsg("cannot create temporary relation in non-temporary schema"),
4615 parser_errposition(pstate, relation->location)));
4616 }
4617}
4618
4619/*
4620 * checkSchemaNameList
4621 * Check schema name in an element of a CREATE SCHEMA command,
4622 * where the element's name is given by a List
4623 *
4624 * Much as above, but we don't have to worry about TEMP.
4625 * Sadly, this also means we don't have a parse location to report.
4626 */
4627static void
4629{
4630 char *obj_schema;
4631 char *obj_name;
4632
4634 if (obj_schema != NULL &&
4636 ereport(ERROR,
4638 errmsg("CREATE specifies a schema (%s) "
4639 "different from the one being created (%s)",
4641}
4642
4643/*
4644 * transformCreateSchemaCreateTable
4645 * Process one CreateStmt for transformCreateSchemaStmtElements.
4646 *
4647 * We remove any foreign-key clauses in the statement and convert them into
4648 * ALTER TABLE commands, which we append to *fk_elements.
4649 */
4650static CreateStmt *
4653 List **fk_elements)
4654{
4656 List *newElts = NIL;
4657 ListCell *lc;
4658
4659 /*
4660 * Flat-copy the CreateStmt node, allowing us to replace its tableElts
4661 * list without damaging the input data structure. Most sub-nodes will be
4662 * shared with the input, though.
4663 */
4665 memcpy(newstmt, stmt, sizeof(CreateStmt));
4666
4667 /* Scan for foreign-key constraints */
4668 foreach(lc, stmt->tableElts)
4669 {
4670 Node *element = lfirst(lc);
4673
4674 if (IsA(element, Constraint))
4675 {
4676 Constraint *constr = (Constraint *) element;
4677
4678 if (constr->contype != CONSTR_FOREIGN)
4679 {
4680 /* Other constraint types pass through unchanged */
4681 newElts = lappend(newElts, constr);
4682 continue;
4683 }
4684
4685 /* Make it into an ALTER TABLE ADD CONSTRAINT command */
4687 altercmd->subtype = AT_AddConstraint;
4688 altercmd->name = NULL;
4689 altercmd->def = (Node *) copyObject(constr);
4690
4692 alterstmt->relation = copyObject(stmt->relation);
4693 alterstmt->cmds = list_make1(altercmd);
4694 alterstmt->objtype = OBJECT_TABLE;
4695
4697 }
4698 else if (IsA(element, ColumnDef))
4699 {
4700 ColumnDef *entry = (ColumnDef *) element;
4703 bool afterFK = false;
4704
4705 /*
4706 * We must preprocess the list of column constraints to attach
4707 * attributes such as DEFERRED to the appropriate constraint node.
4708 * Do this on a copy. (But execution of the CreateStmt will run
4709 * transformConstraintAttrs on the copy, so we are nonetheless
4710 * relying on transformConstraintAttrs to be idempotent.)
4711 */
4714
4715 /* Scan the column constraints ... */
4717 {
4718 switch (colconstr->contype)
4719 {
4720 case CONSTR_FOREIGN:
4721 /* colconstr is already a copy, OK to modify */
4722 colconstr->fk_attrs = list_make1(makeString(entry->colname));
4723
4724 /* Make it into an ALTER TABLE ADD CONSTRAINT command */
4726 altercmd->subtype = AT_AddConstraint;
4727 altercmd->name = NULL;
4728 altercmd->def = (Node *) colconstr;
4729
4731 alterstmt->relation = copyObject(stmt->relation);
4732 alterstmt->cmds = list_make1(altercmd);
4733 alterstmt->objtype = OBJECT_TABLE;
4734
4736
4737 /* Remove the Constraint node from entryconstraints */
4740
4741 /*
4742 * Immediately-following attribute constraints should
4743 * be dropped, too.
4744 */
4745 afterFK = true;
4746 break;
4747
4748 /*
4749 * Column constraint lists separate a Constraint node
4750 * from its attributes (e.g. NOT ENFORCED); so a
4751 * column-level foreign key constraint may be
4752 * represented by multiple Constraint nodes. After
4753 * transformConstraintAttrs, the foreign key
4754 * Constraint node contains all required information,
4755 * making it okay to put into *fk_elements as a
4756 * stand-alone Constraint. But since we removed the
4757 * foreign key Constraint node from entryconstraints,
4758 * we must remove any dependent attribute nodes too,
4759 * else the later re-execution of
4760 * transformConstraintAttrs will misbehave.
4761 */
4768 if (afterFK)
4771 colconstr);
4772 break;
4773
4774 default:
4775 /* Any following constraint attributes are unrelated */
4776 afterFK = false;
4777 break;
4778 }
4779 }
4780
4781 /* Now make a modified ColumnDef to put into newElts */
4783 memcpy(newentry, entry, sizeof(ColumnDef));
4784 newentry->constraints = entryconstraints;
4786 }
4787 else
4788 {
4789 /* Other node types pass through unchanged */
4791 }
4792 }
4793
4794 newstmt->tableElts = newElts;
4795 return newstmt;
4796}
4797
4798/*
4799 * transformPartitionCmd
4800 * Analyze the ATTACH/DETACH/SPLIT PARTITION command
4801 *
4802 * In case of the ATTACH/SPLIT PARTITION command, cxt->partbound is set to the
4803 * transformed value of bound.
4804 */
4805static void
4807{
4808 Relation parentRel = cxt->rel;
4809
4810 switch (parentRel->rd_rel->relkind)
4811 {
4813 /* transform the partition bound, if any */
4815 if (bound != NULL)
4817 bound);
4818 break;
4820
4821 /*
4822 * A partitioned index cannot have a partition bound set. ALTER
4823 * INDEX prevents that with its grammar, but not ALTER TABLE.
4824 */
4825 if (bound != NULL)
4826 ereport(ERROR,
4828 errmsg("\"%s\" is not a partitioned table",
4830 break;
4831 case RELKIND_RELATION:
4832 /* the table must be partitioned */
4833 ereport(ERROR,
4835 errmsg("table \"%s\" is not partitioned",
4837 break;
4838 case RELKIND_INDEX:
4839 /* the index must be partitioned */
4840 ereport(ERROR,
4842 errmsg("index \"%s\" is not partitioned",
4844 break;
4845 default:
4846 /* parser shouldn't let this case through */
4847 elog(ERROR, "\"%s\" is not a partitioned table or index",
4849 break;
4850 }
4851}
4852
4853/*
4854 * transformPartitionBound
4855 *
4856 * Transform a partition bound specification
4857 */
4861{
4864 char strategy = get_partition_strategy(key);
4865 int partnatts = get_partition_natts(key);
4866 List *partexprs = get_partition_exprs(key);
4867
4868 /* Avoid scribbling on input */
4870
4871 if (spec->is_default)
4872 {
4873 /*
4874 * Hash partitioning does not support a default partition; there's no
4875 * use case for it (since the set of partitions to create is perfectly
4876 * defined), and if users do get into it accidentally, it's hard to
4877 * back out from it afterwards.
4878 */
4879 if (strategy == PARTITION_STRATEGY_HASH)
4880 ereport(ERROR,
4882 errmsg("a hash-partitioned table may not have a default partition")));
4883
4884 /*
4885 * In case of the default partition, parser had no way to identify the
4886 * partition strategy. Assign the parent's strategy to the default
4887 * partition bound spec.
4888 */
4889 result_spec->strategy = strategy;
4890
4891 return result_spec;
4892 }
4893
4894 if (strategy == PARTITION_STRATEGY_HASH)
4895 {
4896 if (spec->strategy != PARTITION_STRATEGY_HASH)
4897 ereport(ERROR,
4899 errmsg("invalid bound specification for a hash partition"),
4900 parser_errposition(pstate, exprLocation((Node *) spec))));
4901
4902 if (spec->modulus <= 0)
4903 ereport(ERROR,
4905 errmsg("modulus for hash partition must be an integer value greater than zero")));
4906
4907 Assert(spec->remainder >= 0);
4908
4909 if (spec->remainder >= spec->modulus)
4910 ereport(ERROR,
4912 errmsg("remainder for hash partition must be less than modulus")));
4913 }
4914 else if (strategy == PARTITION_STRATEGY_LIST)
4915 {
4916 ListCell *cell;
4917 char *colname;
4918 Oid coltype;
4920 Oid partcollation;
4921
4922 if (spec->strategy != PARTITION_STRATEGY_LIST)
4923 ereport(ERROR,
4925 errmsg("invalid bound specification for a list partition"),
4926 parser_errposition(pstate, exprLocation((Node *) spec))));
4927
4928 /* Get the only column's name in case we need to output an error */
4929 if (key->partattrs[0] != 0)
4930 colname = get_attname(RelationGetRelid(parent),
4931 key->partattrs[0], false);
4932 else
4933 colname = deparse_expression((Node *) linitial(partexprs),
4935 RelationGetRelid(parent)),
4936 false, false);
4937 /* Need its type data too */
4938 coltype = get_partition_col_typid(key, 0);
4940 partcollation = get_partition_col_collation(key, 0);
4941
4942 result_spec->listdatums = NIL;
4943 foreach(cell, spec->listdatums)
4944 {
4945 Node *expr = lfirst(cell);
4946 Const *value;
4947 ListCell *cell2;
4948 bool duplicate;
4949
4950 value = transformPartitionBoundValue(pstate, expr,
4951 colname, coltype, coltypmod,
4952 partcollation);
4953
4954 /* Don't add to the result if the value is a duplicate */
4955 duplicate = false;
4956 foreach(cell2, result_spec->listdatums)
4957 {
4959
4960 if (equal(value, value2))
4961 {
4962 duplicate = true;
4963 break;
4964 }
4965 }
4966 if (duplicate)
4967 continue;
4968
4969 result_spec->listdatums = lappend(result_spec->listdatums,
4970 value);
4971 }
4972 }
4973 else if (strategy == PARTITION_STRATEGY_RANGE)
4974 {
4975 if (spec->strategy != PARTITION_STRATEGY_RANGE)
4976 ereport(ERROR,
4978 errmsg("invalid bound specification for a range partition"),
4979 parser_errposition(pstate, exprLocation((Node *) spec))));
4980
4981 if (list_length(spec->lowerdatums) != partnatts)
4982 ereport(ERROR,
4984 errmsg("FROM must specify exactly one value per partitioning column")));
4985 if (list_length(spec->upperdatums) != partnatts)
4986 ereport(ERROR,
4988 errmsg("TO must specify exactly one value per partitioning column")));
4989
4990 /*
4991 * Convert raw parse nodes into PartitionRangeDatum nodes and perform
4992 * any necessary validation.
4993 */
4994 result_spec->lowerdatums =
4995 transformPartitionRangeBounds(pstate, spec->lowerdatums,
4996 parent);
4997 result_spec->upperdatums =
4998 transformPartitionRangeBounds(pstate, spec->upperdatums,
4999 parent);
5000 }
5001 else
5002 elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
5003
5004 return result_spec;
5005}
5006
5007/*
5008 * transformPartitionRangeBounds
5009 * This converts the expressions for range partition bounds from the raw
5010 * grammar representation to PartitionRangeDatum structs
5011 */
5012static List *
5014 Relation parent)
5015{
5016 List *result = NIL;
5018 List *partexprs = get_partition_exprs(key);
5019 ListCell *lc;
5020 int i,
5021 j;
5022
5023 j = 0;
5024 foreach(lc, blist)
5025 {
5026 Node *expr = lfirst(lc);
5028
5030
5031 /*
5032 * Infinite range bounds -- "minvalue" and "maxvalue" -- get passed in
5033 * as ColumnRefs.
5034 */
5035 if (IsA(expr, ColumnRef))
5036 {
5037 ColumnRef *cref = (ColumnRef *) expr;
5038 char *cname = NULL;
5039
5040 /*
5041 * There should be a single field named either "minvalue" or
5042 * "maxvalue".
5043 */
5044 if (list_length(cref->fields) == 1 &&
5045 IsA(linitial(cref->fields), String))
5046 cname = strVal(linitial(cref->fields));
5047
5048 if (cname == NULL)
5049 {
5050 /*
5051 * ColumnRef is not in the desired single-field-name form. For
5052 * consistency between all partition strategies, let the
5053 * expression transformation report any errors rather than
5054 * doing it ourselves.
5055 */
5056 }
5057 else if (strcmp("minvalue", cname) == 0)
5058 {
5061 prd->value = NULL;
5062 }
5063 else if (strcmp("maxvalue", cname) == 0)
5064 {
5067 prd->value = NULL;
5068 }
5069 }
5070
5071 if (prd == NULL)
5072 {
5073 char *colname;
5074 Oid coltype;
5076 Oid partcollation;
5077 Const *value;
5078
5079 /* Get the column's name in case we need to output an error */
5080 if (key->partattrs[i] != 0)
5081 colname = get_attname(RelationGetRelid(parent),
5082 key->partattrs[i], false);
5083 else
5084 {
5085 colname = deparse_expression((Node *) list_nth(partexprs, j),
5087 RelationGetRelid(parent)),
5088 false, false);
5089 ++j;
5090 }
5091
5092 /* Need its type data too */
5093 coltype = get_partition_col_typid(key, i);
5095 partcollation = get_partition_col_collation(key, i);
5096
5097 value = transformPartitionBoundValue(pstate, expr,
5098 colname,
5099 coltype, coltypmod,
5100 partcollation);
5101 if (value->constisnull)
5102 ereport(ERROR,
5104 errmsg("cannot specify NULL in range bound")));
5107 prd->value = (Node *) value;
5108 }
5109
5110 prd->location = exprLocation(expr);
5111
5113 }
5114
5115 /*
5116 * Once we see MINVALUE or MAXVALUE for one column, the remaining columns
5117 * must be the same.
5118 */
5120
5121 return result;
5122}
5123
5124/*
5125 * validateInfiniteBounds
5126 *
5127 * Check that a MAXVALUE or MINVALUE specification in a partition bound is
5128 * followed only by more of the same.
5129 */
5130static void
5132{
5133 ListCell *lc;
5135
5136 foreach(lc, blist)
5137 {
5139
5140 if (kind == prd->kind)
5141 continue;
5142
5143 switch (kind)
5144 {
5146 kind = prd->kind;
5147 break;
5148
5150 ereport(ERROR,
5152 errmsg("every bound following MAXVALUE must also be MAXVALUE"),
5153 parser_errposition(pstate, exprLocation((Node *) prd))));
5154 break;
5155
5157 ereport(ERROR,
5159 errmsg("every bound following MINVALUE must also be MINVALUE"),
5160 parser_errposition(pstate, exprLocation((Node *) prd))));
5161 break;
5162 }
5163 }
5164}
5165
5166/*
5167 * Transform one entry in a partition bound spec, producing a constant.
5168 */
5169static Const *
5171 const char *colName, Oid colType, int32 colTypmod,
5173{
5174 Node *value;
5175
5176 /* Transform raw parsetree */
5178
5179 /*
5180 * transformExpr() should have already rejected column references,
5181 * subqueries, aggregates, window functions, and SRFs, based on the
5182 * EXPR_KIND_ of a partition bound expression.
5183 */
5185
5186 /*
5187 * Coerce to the correct type. This might cause an explicit coercion step
5188 * to be added on top of the expression, which must be evaluated before
5189 * returning the result to the caller.
5190 */
5193 colType,
5194 colTypmod,
5197 -1);
5198
5199 if (value == NULL)
5200 ereport(ERROR,
5202 errmsg("specified value cannot be cast to type %s for column \"%s\"",
5205
5206 /*
5207 * Evaluate the expression, if needed, assigning the partition key's data
5208 * type and collation to the resulting Const node.
5209 */
5210 if (!IsA(value, Const))
5211 {
5216 if (!IsA(value, Const))
5217 elog(ERROR, "could not evaluate partition bound expression");
5218 }
5219 else
5220 {
5221 /*
5222 * If the expression is already a Const, as is often the case, we can
5223 * skip the rather expensive steps above. But we still have to insert
5224 * the right collation, since coerce_to_target_type doesn't handle
5225 * that.
5226 */
5227 ((Const *) value)->constcollid = partCollation;
5228 }
5229
5230 /*
5231 * Attach original expression's parse location to the Const, so that
5232 * that's what will be reported for any later errors related to this
5233 * partition bound.
5234 */
5235 ((Const *) value)->location = exprLocation(val);
5236
5237 return (Const *) value;
5238}
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:3902
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
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:894
#define InvalidSubTransactionId
Definition c.h:801
#define Assert(condition)
Definition c.h:1002
int16_t int16
Definition c.h:678
int32_t int32
Definition c.h:679
#define pg_fallthrough
Definition c.h:220
#define OidIsValid(objectId)
Definition c.h:917
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
Expr * evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, Oid result_collation)
Definition clauses.c:5743
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:875
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:31
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
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:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
Definition indexcmds.c:2644
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2381
long val
Definition informix.c:689
static struct @175 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:2242
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1084
bool type_is_range(Oid typid)
Definition lsyscache.c:3004
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1196
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2266
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3372
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1053
Oid getBaseType(Oid typid)
Definition lsyscache.c:2837
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
Oid get_atttype(Oid relid, AttrNumber attnum)
Definition lsyscache.c:1139
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition lsyscache.c:2199
bool type_is_multirange(Oid typid)
Definition lsyscache.c:3014
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:1910
void pfree(void *pointer)
Definition mcxt.c:1619
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
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3373
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:1403
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define copyObject(obj)
Definition nodes.h:230
#define nodeTag(nodeptr)
Definition nodes.h:137
@ CMD_UTILITY
Definition nodes.h:278
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
@ CMD_SELECT
Definition nodes.h:273
@ CMD_NOTHING
Definition nodes.h:280
#define makeNode(_type_)
Definition nodes.h:159
#define castNode(_type_, nodeptr)
Definition nodes.h:180
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:75
@ EXPR_KIND_INDEX_EXPRESSION
Definition parse_node.h:73
@ EXPR_KIND_PARTITION_BOUND
Definition parse_node.h:80
@ EXPR_KIND_INDEX_PREDICATE
Definition parse_node.h:74
@ EXPR_KIND_ALTER_COL_TRANSFORM
Definition parse_node.h:76
@ 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)
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(ParseState *pstate, List *schemaElts, const char *schemaName)
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
static CreateStmt * transformCreateSchemaCreateTable(ParseState *pstate, CreateStmt *stmt, List **fk_elements)
void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)
static void transformConstraintAttrs(ParseState *pstate, List *constraintList)
static void transformIndexConstraints(CreateStmtContext *cxt)
static List * get_collation(Oid collation, Oid actual_datatype)
static IndexStmt * transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
static void checkSchemaNameRV(ParseState *pstate, const char *context_schema, RangeVar *relation)
AlterTableStmt * transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, const char *queryString, List **beforeStmts, List **afterStmts)
static void transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
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)
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)
static void checkSchemaNameList(const char *context_schema, List *qualified_name)
#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:921
@ PARTITION_STRATEGY_LIST
Definition parsenodes.h:919
@ PARTITION_STRATEGY_RANGE
Definition parsenodes.h:920
@ 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:970
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition parsenodes.h:973
@ PARTITION_RANGE_DATUM_VALUE
Definition parsenodes.h:972
@ PARTITION_RANGE_DATUM_MINVALUE
Definition parsenodes.h:971
@ 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:806
@ CREATE_TABLE_LIKE_GENERATED
Definition parsenodes.h:810
@ CREATE_TABLE_LIKE_IDENTITY
Definition parsenodes.h:811
@ CREATE_TABLE_LIKE_COMPRESSION
Definition parsenodes.h:807
@ CREATE_TABLE_LIKE_STORAGE
Definition parsenodes.h:814
@ CREATE_TABLE_LIKE_INDEXES
Definition parsenodes.h:812
@ CREATE_TABLE_LIKE_DEFAULTS
Definition parsenodes.h:809
@ CREATE_TABLE_LIKE_STATISTICS
Definition parsenodes.h:813
@ CREATE_TABLE_LIKE_CONSTRAINTS
Definition parsenodes.h:808
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition analyze.c:335
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:271
Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok)
Definition pg_depend.c:1149
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1192
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:435
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:423
#define list_make1(x1)
Definition pg_list.h:244
#define for_each_cell(cell, lst, initcell)
Definition pg_list.h:470
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define linitial(l)
Definition pg_list.h:178
#define list_make3(x1, x2, x3)
Definition pg_list.h:248
#define foreach_node(type, var, lst)
Definition pg_list.h:528
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:375
#define lfirst_oid(lc)
Definition pg_list.h:174
#define list_make2(x1, x2)
Definition pg_list.h:246
static ListCell * list_last_cell(const List *list)
Definition pg_list.h:320
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:7010
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:759
@ COERCE_EXPLICIT_CALL
Definition primnodes.h:757
@ COERCION_ASSIGNMENT
Definition primnodes.h:738
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:510
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4848
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5222
List * RelationGetStatExtList(Relation relation)
Definition relcache.c:4989
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5109
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:4072
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition ruleutils.c:4009
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition relation.c:138
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
DropBehavior behavior
AlterTableType subtype
char identity
Definition parsenodes.h:782
List * constraints
Definition parsenodes.h:788
Node * cooked_default
Definition parsenodes.h:781
char * colname
Definition parsenodes.h:771
TypeName * typeName
Definition parsenodes.h:772
char generated
Definition parsenodes.h:785
bool is_from_type
Definition parsenodes.h:777
Node * raw_default
Definition parsenodes.h:780
char storage
Definition parsenodes.h:778
char * compression
Definition parsenodes.h:773
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:862
Node * expr
Definition parsenodes.h:830
Definition pg_list.h:54
Definition nodes.h:133
const char * p_sourcetext
Definition parse_node.h:214
List * p_rteperminfos
Definition parse_node.h:216
List * p_rtable
Definition parse_node.h:215
char * relname
Definition primnodes.h:84
char relpersistence
Definition primnodes.h:90
ParseLoc location
Definition primnodes.h:96
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:290
Definition type.h:97
Definition c.h:874
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
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:7284
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:1161
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:240
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:1949
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