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-2021, 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/htup_details.h"
27 #include "access/relation.h"
28 #include "access/reloptions.h"
29 #include "access/table.h"
30 #include "access/toast_compression.h"
31 #include "catalog/dependency.h"
32 #include "catalog/heap.h"
33 #include "catalog/index.h"
34 #include "catalog/namespace.h"
35 #include "catalog/pg_am.h"
36 #include "catalog/pg_collation.h"
37 #include "catalog/pg_constraint.h"
38 #include "catalog/pg_opclass.h"
39 #include "catalog/pg_operator.h"
40 #include "catalog/pg_statistic_ext.h"
41 #include "catalog/pg_type.h"
42 #include "commands/comment.h"
43 #include "commands/defrem.h"
44 #include "commands/sequence.h"
45 #include "commands/tablecmds.h"
46 #include "commands/tablespace.h"
47 #include "miscadmin.h"
48 #include "nodes/makefuncs.h"
49 #include "nodes/nodeFuncs.h"
50 #include "optimizer/optimizer.h"
51 #include "parser/analyze.h"
52 #include "parser/parse_clause.h"
53 #include "parser/parse_coerce.h"
54 #include "parser/parse_collate.h"
55 #include "parser/parse_expr.h"
56 #include "parser/parse_relation.h"
57 #include "parser/parse_target.h"
58 #include "parser/parse_type.h"
59 #include "parser/parse_utilcmd.h"
60 #include "parser/parser.h"
61 #include "rewrite/rewriteManip.h"
62 #include "utils/acl.h"
63 #include "utils/builtins.h"
64 #include "utils/lsyscache.h"
65 #include "utils/partcache.h"
66 #include "utils/rel.h"
67 #include "utils/ruleutils.h"
68 #include "utils/syscache.h"
69 #include "utils/typcache.h"
70
71
72 /* State shared by transformCreateStmt and its subroutines */
73 typedef struct
74 {
75 ParseState *pstate; /* overall parser state */
76 const char *stmtType; /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
77 RangeVar *relation; /* relation to create */
78 Relation rel; /* opened/locked rel, if ALTER */
79 List *inhRelations; /* relations to inherit from */
80 bool isforeign; /* true if CREATE/ALTER FOREIGN TABLE */
81 bool isalter; /* true if altering existing table */
82 List *columns; /* ColumnDef items */
83 List *ckconstraints; /* CHECK constraints */
84 List *fkconstraints; /* FOREIGN KEY constraints */
85 List *ixconstraints; /* index-creating constraints */
86 List *likeclauses; /* LIKE clauses that need post-processing */
87 List *extstats; /* cloned extended statistics */
88 List *blist; /* "before list" of things to do before
89 * creating the table */
90 List *alist; /* "after list" of things to do after creating
91 * the table */
92 IndexStmt *pkey; /* PRIMARY KEY index, if any */
93 bool ispartitioned; /* true if table is partitioned */
94 PartitionBoundSpec *partbound; /* transformed FOR VALUES */
95 bool ofType; /* true if statement contains OF typename */
96 } CreateStmtContext;
97
98 /* State shared by transformCreateSchemaStmt and its subroutines */
99 typedef struct
100 {
101 const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
102 char *schemaname; /* name of schema */
103 RoleSpec *authrole; /* owner of schema */
104 List *sequences; /* CREATE SEQUENCE items */
105 List *tables; /* CREATE TABLE items */
106 List *views; /* CREATE VIEW items */
107 List *indexes; /* CREATE INDEX items */
108 List *triggers; /* CREATE TRIGGER items */
109 List *grants; /* GRANT items */
110 } CreateSchemaStmtContext;
111
112
113 static void transformColumnDefinition(CreateStmtContext *cxt,
114 ColumnDef *column);
115 static void transformTableConstraint(CreateStmtContext *cxt,
116 Constraint *constraint);
117 static void transformTableLikeClause(CreateStmtContext *cxt,
118 TableLikeClause *table_like_clause);
119 static void transformOfType(CreateStmtContext *cxt,
120 TypeName *ofTypename);
121 static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
122 Oid heapRelid, Oid source_statsid);
123 static List *get_collation(Oid collation, Oid actual_datatype);
124 static List *get_opclass(Oid opclass, Oid actual_datatype);
125 static void transformIndexConstraints(CreateStmtContext *cxt);
126 static IndexStmt *transformIndexConstraint(Constraint *constraint,
127 CreateStmtContext *cxt);
128 static void transformExtendedStatistics(CreateStmtContext *cxt);
129 static void transformFKConstraints(CreateStmtContext *cxt,
130 bool skipValidation,
131 bool isAddConstraint);
132 static void transformCheckConstraints(CreateStmtContext *cxt,
133 bool skipValidation);
134 static void transformConstraintAttrs(CreateStmtContext *cxt,
135 List *constraintList);
136 static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
137 static void setSchemaName(char *context_schema, char **stmt_schema_name);
138 static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
139 static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
140 Relation parent);
141 static void validateInfiniteBounds(ParseState *pstate, List *blist);
142 static Const *transformPartitionBoundValue(ParseState *pstate, Node *con,
143 const char *colName, Oid colType, int32 colTypmod,
144 Oid partCollation);
145
146
147 /*
148 * transformCreateStmt -
149 * parse analysis for CREATE TABLE
150 *
151 * Returns a List of utility commands to be done in sequence. One of these
152 * will be the transformed CreateStmt, but there may be additional actions
153 * to be done before and after the actual DefineRelation() call.
154 * In addition to normal utility commands such as AlterTableStmt and
155 * IndexStmt, the result list may contain TableLikeClause(s), representing
156 * the need to perform additional parse analysis after DefineRelation().
157 *
158 * SQL allows constraints to be scattered all over, so thumb through
159 * the columns and collect all constraints into one place.
160 * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
161 * then expand those into multiple IndexStmt blocks.
162 * - thomas 1997-12-02
163 */
164 List *
transformCreateStmt(CreateStmt * stmt,const char * queryString)165 transformCreateStmt(CreateStmt *stmt, const char *queryString)
166 {
167 ParseState *pstate;
168 CreateStmtContext cxt;
169 List *result;
170 List *save_alist;
171 ListCell *elements;
172 Oid namespaceid;
173 Oid existing_relid;
174 ParseCallbackState pcbstate;
175
176 /* Set up pstate */
177 pstate = make_parsestate(NULL);
178 pstate->p_sourcetext = queryString;
179
180 /*
181 * Look up the creation namespace. This also checks permissions on the
182 * target namespace, locks it against concurrent drops, checks for a
183 * preexisting relation in that namespace with the same name, and updates
184 * stmt->relation->relpersistence if the selected namespace is temporary.
185 */
186 setup_parser_errposition_callback(&pcbstate, pstate,
187 stmt->relation->location);
188 namespaceid =
189 RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
190 &existing_relid);
191 cancel_parser_errposition_callback(&pcbstate);
192
193 /*
194 * If the relation already exists and the user specified "IF NOT EXISTS",
195 * bail out with a NOTICE.
196 */
197 if (stmt->if_not_exists && OidIsValid(existing_relid))
198 {
199 ereport(NOTICE,
200 (errcode(ERRCODE_DUPLICATE_TABLE),
201 errmsg("relation \"%s\" already exists, skipping",
202 stmt->relation->relname)));
203 return NIL;
204 }
205
206 /*
207 * If the target relation name isn't schema-qualified, make it so. This
208 * prevents some corner cases in which added-on rewritten commands might
209 * think they should apply to other relations that have the same name and
210 * are earlier in the search path. But a local temp table is effectively
211 * specified to be in pg_temp, so no need for anything extra in that case.
212 */
213 if (stmt->relation->schemaname == NULL
214 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
215 stmt->relation->schemaname = get_namespace_name(namespaceid);
216
217 /* Set up CreateStmtContext */
218 cxt.pstate = pstate;
219 if (IsA(stmt, CreateForeignTableStmt))
220 {
221 cxt.stmtType = "CREATE FOREIGN TABLE";
222 cxt.isforeign = true;
223 }
224 else
225 {
226 cxt.stmtType = "CREATE TABLE";
227 cxt.isforeign = false;
228 }
229 cxt.relation = stmt->relation;
230 cxt.rel = NULL;
231 cxt.inhRelations = stmt->inhRelations;
232 cxt.isalter = false;
233 cxt.columns = NIL;
234 cxt.ckconstraints = NIL;
235 cxt.fkconstraints = NIL;
236 cxt.ixconstraints = NIL;
237 cxt.likeclauses = NIL;
238 cxt.extstats = NIL;
239 cxt.blist = NIL;
240 cxt.alist = NIL;
241 cxt.pkey = NULL;
242 cxt.ispartitioned = stmt->partspec != NULL;
243 cxt.partbound = stmt->partbound;
244 cxt.ofType = (stmt->ofTypename != NULL);
245
246 Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
247
248 if (stmt->ofTypename)
249 transformOfType(&cxt, stmt->ofTypename);
250
251 if (stmt->partspec)
252 {
253 if (stmt->inhRelations && !stmt->partbound)
254 ereport(ERROR,
255 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
256 errmsg("cannot create partitioned table as inheritance child")));
257 }
258
259 /*
260 * Run through each primary element in the table creation clause. Separate
261 * column defs from constraints, and do preliminary analysis.
262 */
263 foreach(elements, stmt->tableElts)
264 {
265 Node *element = lfirst(elements);
266
267 switch (nodeTag(element))
268 {
269 case T_ColumnDef:
270 transformColumnDefinition(&cxt, (ColumnDef *) element);
271 break;
272
273 case T_Constraint:
274 transformTableConstraint(&cxt, (Constraint *) element);
275 break;
276
277 case T_TableLikeClause:
278 transformTableLikeClause(&cxt, (TableLikeClause *) element);
279 break;
280
281 default:
282 elog(ERROR, "unrecognized node type: %d",
283 (int) nodeTag(element));
284 break;
285 }
286 }
287
288 /*
289 * Transfer anything we already have in cxt.alist into save_alist, to keep
290 * it separate from the output of transformIndexConstraints. (This may
291 * not be necessary anymore, but we'll keep doing it to preserve the
292 * historical order of execution of the alist commands.)
293 */
294 save_alist = cxt.alist;
295 cxt.alist = NIL;
296
297 Assert(stmt->constraints == NIL);
298
299 /*
300 * Postprocess constraints that give rise to index definitions.
301 */
302 transformIndexConstraints(&cxt);
303
304 /*
305 * Re-consideration of LIKE clauses should happen after creation of
306 * indexes, but before creation of foreign keys. This order is critical
307 * because a LIKE clause may attempt to create a primary key. If there's
308 * also a pkey in the main CREATE TABLE list, creation of that will not
309 * check for a duplicate at runtime (since index_check_primary_key()
310 * expects that we rejected dups here). Creation of the LIKE-generated
311 * pkey behaves like ALTER TABLE ADD, so it will check, but obviously that
312 * only works if it happens second. On the other hand, we want to make
313 * pkeys before foreign key constraints, in case the user tries to make a
314 * self-referential FK.
315 */
316 cxt.alist = list_concat(cxt.alist, cxt.likeclauses);
317
318 /*
319 * Postprocess foreign-key constraints.
320 */
321 transformFKConstraints(&cxt, true, false);
322
323 /*
324 * Postprocess check constraints.
325 *
326 * For regular tables all constraints can be marked valid immediately,
327 * because the table is new therefore empty. Not so for foreign tables.
328 */
329 transformCheckConstraints(&cxt, !cxt.isforeign);
330
331 /*
332 * Postprocess extended statistics.
333 */
334 transformExtendedStatistics(&cxt);
335
336 /*
337 * Output results.
338 */
339 stmt->tableElts = cxt.columns;
340 stmt->constraints = cxt.ckconstraints;
341
342 result = lappend(cxt.blist, stmt);
343 result = list_concat(result, cxt.alist);
344 result = list_concat(result, save_alist);
345
346 return result;
347 }
348
349 /*
350 * generateSerialExtraStmts
351 * Generate CREATE SEQUENCE and ALTER SEQUENCE ... OWNED BY statements
352 * to create the sequence for a serial or identity column.
353 *
354 * This includes determining the name the sequence will have. The caller
355 * can ask to get back the name components by passing non-null pointers
356 * for snamespace_p and sname_p.
357 */
358 static void
generateSerialExtraStmts(CreateStmtContext * cxt,ColumnDef * column,Oid seqtypid,List * seqoptions,bool for_identity,bool col_exists,char ** snamespace_p,char ** sname_p)359 generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
360 Oid seqtypid, List *seqoptions,
361 bool for_identity, bool col_exists,
362 char **snamespace_p, char **sname_p)
363 {
364 ListCell *option;
365 DefElem *nameEl = NULL;
366 Oid snamespaceid;
367 char *snamespace;
368 char *sname;
369 CreateSeqStmt *seqstmt;
370 AlterSeqStmt *altseqstmt;
371 List *attnamelist;
372 int nameEl_idx = -1;
373
374 /*
375 * Determine namespace and name to use for the sequence.
376 *
377 * First, check if a sequence name was passed in as an option. This is
378 * used by pg_dump. Else, generate a name.
379 *
380 * Although we use ChooseRelationName, it's not guaranteed that the
381 * selected sequence name won't conflict; given sufficiently long field
382 * names, two different serial columns in the same table could be assigned
383 * the same sequence name, and we'd not notice since we aren't creating
384 * the sequence quite yet. In practice this seems quite unlikely to be a
385 * problem, especially since few people would need two serial columns in
386 * one table.
387 */
388 foreach(option, seqoptions)
389 {
390 DefElem *defel = lfirst_node(DefElem, option);
391
392 if (strcmp(defel->defname, "sequence_name") == 0)
393 {
394 if (nameEl)
395 ereport(ERROR,
396 (errcode(ERRCODE_SYNTAX_ERROR),
397 errmsg("conflicting or redundant options")));
398 nameEl = defel;
399 nameEl_idx = foreach_current_index(option);
400 }
401 }
402
403 if (nameEl)
404 {
405 RangeVar *rv = makeRangeVarFromNameList(castNode(List, nameEl->arg));
406
407 snamespace = rv->schemaname;
408 if (!snamespace)
409 {
410 /* Given unqualified SEQUENCE NAME, select namespace */
411 if (cxt->rel)
412 snamespaceid = RelationGetNamespace(cxt->rel);
413 else
414 snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
415 snamespace = get_namespace_name(snamespaceid);
416 }
417 sname = rv->relname;
418 /* Remove the SEQUENCE NAME item from seqoptions */
419 seqoptions = list_delete_nth_cell(seqoptions, nameEl_idx);
420 }
421 else
422 {
423 if (cxt->rel)
424 snamespaceid = RelationGetNamespace(cxt->rel);
425 else
426 {
427 snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
428 RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
429 }
430 snamespace = get_namespace_name(snamespaceid);
431 sname = ChooseRelationName(cxt->relation->relname,
432 column->colname,
433 "seq",
434 snamespaceid,
435 false);
436 }
437
438 ereport(DEBUG1,
439 (errmsg_internal("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
440 cxt->stmtType, sname,
441 cxt->relation->relname, column->colname)));
442
443 /*
444 * Build a CREATE SEQUENCE command to create the sequence object, and add
445 * it to the list of things to be done before this CREATE/ALTER TABLE.
446 */
447 seqstmt = makeNode(CreateSeqStmt);
448 seqstmt->for_identity = for_identity;
449 seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
450 seqstmt->options = seqoptions;
451
452 /*
453 * If a sequence data type was specified, add it to the options. Prepend
454 * to the list rather than append; in case a user supplied their own AS
455 * clause, the "redundant options" error will point to their occurrence,
456 * not our synthetic one.
457 */
458 if (seqtypid)
459 seqstmt->options = lcons(makeDefElem("as",
460 (Node *) makeTypeNameFromOid(seqtypid, -1),
461 -1),
462 seqstmt->options);
463
464 /*
465 * If this is ALTER ADD COLUMN, make sure the sequence will be owned by
466 * the table's owner. The current user might be someone else (perhaps a
467 * superuser, or someone who's only a member of the owning role), but the
468 * SEQUENCE OWNED BY mechanisms will bleat unless table and sequence have
469 * exactly the same owning role.
470 */
471 if (cxt->rel)
472 seqstmt->ownerId = cxt->rel->rd_rel->relowner;
473 else
474 seqstmt->ownerId = InvalidOid;
475
476 cxt->blist = lappend(cxt->blist, seqstmt);
477
478 /*
479 * Store the identity sequence name that we decided on. ALTER TABLE ...
480 * ADD COLUMN ... IDENTITY needs this so that it can fill the new column
481 * with values from the sequence, while the association of the sequence
482 * with the table is not set until after the ALTER TABLE.
483 */
484 column->identitySequence = seqstmt->sequence;
485
486 /*
487 * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
488 * owned by this column, and add it to the appropriate list of things to
489 * be done along with this CREATE/ALTER TABLE. In a CREATE or ALTER ADD
490 * COLUMN, it must be done after the statement because we don't know the
491 * column's attnum yet. But if we do have the attnum (in AT_AddIdentity),
492 * we can do the marking immediately, which improves some ALTER TABLE
493 * behaviors.
494 */
495 altseqstmt = makeNode(AlterSeqStmt);
496 altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
497 attnamelist = list_make3(makeString(snamespace),
498 makeString(cxt->relation->relname),
499 makeString(column->colname));
500 altseqstmt->options = list_make1(makeDefElem("owned_by",
501 (Node *) attnamelist, -1));
502 altseqstmt->for_identity = for_identity;
503
504 if (col_exists)
505 cxt->blist = lappend(cxt->blist, altseqstmt);
506 else
507 cxt->alist = lappend(cxt->alist, altseqstmt);
508
509 if (snamespace_p)
510 *snamespace_p = snamespace;
511 if (sname_p)
512 *sname_p = sname;
513 }
514
515 /*
516 * transformColumnDefinition -
517 * transform a single ColumnDef within CREATE TABLE
518 * Also used in ALTER TABLE ADD COLUMN
519 */
520 static void
transformColumnDefinition(CreateStmtContext * cxt,ColumnDef * column)521 transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
522 {
523 bool is_serial;
524 bool saw_nullable;
525 bool saw_default;
526 bool saw_identity;
527 bool saw_generated;
528 ListCell *clist;
529
530 cxt->columns = lappend(cxt->columns, column);
531
532 /* Check for SERIAL pseudo-types */
533 is_serial = false;
534 if (column->typeName
535 && list_length(column->typeName->names) == 1
536 && !column->typeName->pct_type)
537 {
538 char *typname = strVal(linitial(column->typeName->names));
539
540 if (strcmp(typname, "smallserial") == 0 ||
541 strcmp(typname, "serial2") == 0)
542 {
543 is_serial = true;
544 column->typeName->names = NIL;
545 column->typeName->typeOid = INT2OID;
546 }
547 else if (strcmp(typname, "serial") == 0 ||
548 strcmp(typname, "serial4") == 0)
549 {
550 is_serial = true;
551 column->typeName->names = NIL;
552 column->typeName->typeOid = INT4OID;
553 }
554 else if (strcmp(typname, "bigserial") == 0 ||
555 strcmp(typname, "serial8") == 0)
556 {
557 is_serial = true;
558 column->typeName->names = NIL;
559 column->typeName->typeOid = INT8OID;
560 }
561
562 /*
563 * We have to reject "serial[]" explicitly, because once we've set
564 * typeid, LookupTypeName won't notice arrayBounds. We don't need any
565 * special coding for serial(typmod) though.
566 */
567 if (is_serial && column->typeName->arrayBounds != NIL)
568 ereport(ERROR,
569 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
570 errmsg("array of serial is not implemented"),
571 parser_errposition(cxt->pstate,
572 column->typeName->location)));
573 }
574
575 /* Do necessary work on the column type declaration */
576 if (column->typeName)
577 transformColumnType(cxt, column);
578
579 /* Special actions for SERIAL pseudo-types */
580 if (is_serial)
581 {
582 char *snamespace;
583 char *sname;
584 char *qstring;
585 A_Const *snamenode;
586 TypeCast *castnode;
587 FuncCall *funccallnode;
588 Constraint *constraint;
589
590 generateSerialExtraStmts(cxt, column,
591 column->typeName->typeOid, NIL,
592 false, false,
593 &snamespace, &sname);
594
595 /*
596 * Create appropriate constraints for SERIAL. We do this in full,
597 * rather than shortcutting, so that we will detect any conflicting
598 * constraints the user wrote (like a different DEFAULT).
599 *
600 * Create an expression tree representing the function call
601 * nextval('sequencename'). We cannot reduce the raw tree to cooked
602 * form until after the sequence is created, but there's no need to do
603 * so.
604 */
605 qstring = quote_qualified_identifier(snamespace, sname);
606 snamenode = makeNode(A_Const);
607 snamenode->val.type = T_String;
608 snamenode->val.val.str = qstring;
609 snamenode->location = -1;
610 castnode = makeNode(TypeCast);
611 castnode->typeName = SystemTypeName("regclass");
612 castnode->arg = (Node *) snamenode;
613 castnode->location = -1;
614 funccallnode = makeFuncCall(SystemFuncName("nextval"),
615 list_make1(castnode),
616 COERCE_EXPLICIT_CALL,
617 -1);
618 constraint = makeNode(Constraint);
619 constraint->contype = CONSTR_DEFAULT;
620 constraint->location = -1;
621 constraint->raw_expr = (Node *) funccallnode;
622 constraint->cooked_expr = NULL;
623 column->constraints = lappend(column->constraints, constraint);
624
625 constraint = makeNode(Constraint);
626 constraint->contype = CONSTR_NOTNULL;
627 constraint->location = -1;
628 column->constraints = lappend(column->constraints, constraint);
629 }
630
631 /* Process column constraints, if any... */
632 transformConstraintAttrs(cxt, column->constraints);
633
634 saw_nullable = false;
635 saw_default = false;
636 saw_identity = false;
637 saw_generated = false;
638
639 foreach(clist, column->constraints)
640 {
641 Constraint *constraint = lfirst_node(Constraint, clist);
642
643 switch (constraint->contype)
644 {
645 case CONSTR_NULL:
646 if (saw_nullable && column->is_not_null)
647 ereport(ERROR,
648 (errcode(ERRCODE_SYNTAX_ERROR),
649 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
650 column->colname, cxt->relation->relname),
651 parser_errposition(cxt->pstate,
652 constraint->location)));
653 column->is_not_null = false;
654 saw_nullable = true;
655 break;
656
657 case CONSTR_NOTNULL:
658 if (saw_nullable && !column->is_not_null)
659 ereport(ERROR,
660 (errcode(ERRCODE_SYNTAX_ERROR),
661 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
662 column->colname, cxt->relation->relname),
663 parser_errposition(cxt->pstate,
664 constraint->location)));
665 column->is_not_null = true;
666 saw_nullable = true;
667 break;
668
669 case CONSTR_DEFAULT:
670 if (saw_default)
671 ereport(ERROR,
672 (errcode(ERRCODE_SYNTAX_ERROR),
673 errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
674 column->colname, cxt->relation->relname),
675 parser_errposition(cxt->pstate,
676 constraint->location)));
677 column->raw_default = constraint->raw_expr;
678 Assert(constraint->cooked_expr == NULL);
679 saw_default = true;
680 break;
681
682 case CONSTR_IDENTITY:
683 {
684 Type ctype;
685 Oid typeOid;
686
687 if (cxt->ofType)
688 ereport(ERROR,
689 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
690 errmsg("identity columns are not supported on typed tables")));
691 if (cxt->partbound)
692 ereport(ERROR,
693 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
694 errmsg("identity columns are not supported on partitions")));
695
696 ctype = typenameType(cxt->pstate, column->typeName, NULL);
697 typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid;
698 ReleaseSysCache(ctype);
699
700 if (saw_identity)
701 ereport(ERROR,
702 (errcode(ERRCODE_SYNTAX_ERROR),
703 errmsg("multiple identity specifications for column \"%s\" of table \"%s\"",
704 column->colname, cxt->relation->relname),
705 parser_errposition(cxt->pstate,
706 constraint->location)));
707
708 generateSerialExtraStmts(cxt, column,
709 typeOid, constraint->options,
710 true, false,
711 NULL, NULL);
712
713 column->identity = constraint->generated_when;
714 saw_identity = true;
715
716 /* An identity column is implicitly NOT NULL */
717 if (saw_nullable && !column->is_not_null)
718 ereport(ERROR,
719 (errcode(ERRCODE_SYNTAX_ERROR),
720 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
721 column->colname, cxt->relation->relname),
722 parser_errposition(cxt->pstate,
723 constraint->location)));
724 column->is_not_null = true;
725 saw_nullable = true;
726 break;
727 }
728
729 case CONSTR_GENERATED:
730 if (cxt->ofType)
731 ereport(ERROR,
732 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
733 errmsg("generated columns are not supported on typed tables")));
734 if (cxt->partbound)
735 ereport(ERROR,
736 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
737 errmsg("generated columns are not supported on partitions")));
738
739 if (saw_generated)
740 ereport(ERROR,
741 (errcode(ERRCODE_SYNTAX_ERROR),
742 errmsg("multiple generation clauses specified for column \"%s\" of table \"%s\"",
743 column->colname, cxt->relation->relname),
744 parser_errposition(cxt->pstate,
745 constraint->location)));
746 column->generated = ATTRIBUTE_GENERATED_STORED;
747 column->raw_default = constraint->raw_expr;
748 Assert(constraint->cooked_expr == NULL);
749 saw_generated = true;
750 break;
751
752 case CONSTR_CHECK:
753 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
754 break;
755
756 case CONSTR_PRIMARY:
757 if (cxt->isforeign)
758 ereport(ERROR,
759 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
760 errmsg("primary key constraints are not supported on foreign tables"),
761 parser_errposition(cxt->pstate,
762 constraint->location)));
763 /* FALL THRU */
764
765 case CONSTR_UNIQUE:
766 if (cxt->isforeign)
767 ereport(ERROR,
768 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
769 errmsg("unique constraints are not supported on foreign tables"),
770 parser_errposition(cxt->pstate,
771 constraint->location)));
772 if (constraint->keys == NIL)
773 constraint->keys = list_make1(makeString(column->colname));
774 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
775 break;
776
777 case CONSTR_EXCLUSION:
778 /* grammar does not allow EXCLUDE as a column constraint */
779 elog(ERROR, "column exclusion constraints are not supported");
780 break;
781
782 case CONSTR_FOREIGN:
783 if (cxt->isforeign)
784 ereport(ERROR,
785 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
786 errmsg("foreign key constraints are not supported on foreign tables"),
787 parser_errposition(cxt->pstate,
788 constraint->location)));
789
790 /*
791 * Fill in the current attribute's name and throw it into the
792 * list of FK constraints to be processed later.
793 */
794 constraint->fk_attrs = list_make1(makeString(column->colname));
795 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
796 break;
797
798 case CONSTR_ATTR_DEFERRABLE:
799 case CONSTR_ATTR_NOT_DEFERRABLE:
800 case CONSTR_ATTR_DEFERRED:
801 case CONSTR_ATTR_IMMEDIATE:
802 /* transformConstraintAttrs took care of these */
803 break;
804
805 default:
806 elog(ERROR, "unrecognized constraint type: %d",
807 constraint->contype);
808 break;
809 }
810
811 if (saw_default && saw_identity)
812 ereport(ERROR,
813 (errcode(ERRCODE_SYNTAX_ERROR),
814 errmsg("both default and identity specified for column \"%s\" of table \"%s\"",
815 column->colname, cxt->relation->relname),
816 parser_errposition(cxt->pstate,
817 constraint->location)));
818
819 if (saw_default && saw_generated)
820 ereport(ERROR,
821 (errcode(ERRCODE_SYNTAX_ERROR),
822 errmsg("both default and generation expression specified for column \"%s\" of table \"%s\"",
823 column->colname, cxt->relation->relname),
824 parser_errposition(cxt->pstate,
825 constraint->location)));
826
827 if (saw_identity && saw_generated)
828 ereport(ERROR,
829 (errcode(ERRCODE_SYNTAX_ERROR),
830 errmsg("both identity and generation expression specified for column \"%s\" of table \"%s\"",
831 column->colname, cxt->relation->relname),
832 parser_errposition(cxt->pstate,
833 constraint->location)));
834 }
835
836 /*
837 * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
838 * per-column foreign data wrapper options to this column after creation.
839 */
840 if (column->fdwoptions != NIL)
841 {
842 AlterTableStmt *stmt;
843 AlterTableCmd *cmd;
844
845 cmd = makeNode(AlterTableCmd);
846 cmd->subtype = AT_AlterColumnGenericOptions;
847 cmd->name = column->colname;
848 cmd->def = (Node *) column->fdwoptions;
849 cmd->behavior = DROP_RESTRICT;
850 cmd->missing_ok = false;
851
852 stmt = makeNode(AlterTableStmt);
853 stmt->relation = cxt->relation;
854 stmt->cmds = NIL;
855 stmt->objtype = OBJECT_FOREIGN_TABLE;
856 stmt->cmds = lappend(stmt->cmds, cmd);
857
858 cxt->alist = lappend(cxt->alist, stmt);
859 }
860 }
861
862 /*
863 * transformTableConstraint
864 * transform a Constraint node within CREATE TABLE or ALTER TABLE
865 */
866 static void
transformTableConstraint(CreateStmtContext * cxt,Constraint * constraint)867 transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
868 {
869 switch (constraint->contype)
870 {
871 case CONSTR_PRIMARY:
872 if (cxt->isforeign)
873 ereport(ERROR,
874 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
875 errmsg("primary key constraints are not supported on foreign tables"),
876 parser_errposition(cxt->pstate,
877 constraint->location)));
878 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
879 break;
880
881 case CONSTR_UNIQUE:
882 if (cxt->isforeign)
883 ereport(ERROR,
884 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
885 errmsg("unique constraints are not supported on foreign tables"),
886 parser_errposition(cxt->pstate,
887 constraint->location)));
888 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
889 break;
890
891 case CONSTR_EXCLUSION:
892 if (cxt->isforeign)
893 ereport(ERROR,
894 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
895 errmsg("exclusion constraints are not supported on foreign tables"),
896 parser_errposition(cxt->pstate,
897 constraint->location)));
898 if (cxt->ispartitioned)
899 ereport(ERROR,
900 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
901 errmsg("exclusion constraints are not supported on partitioned tables"),
902 parser_errposition(cxt->pstate,
903 constraint->location)));
904 cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
905 break;
906
907 case CONSTR_CHECK:
908 cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
909 break;
910
911 case CONSTR_FOREIGN:
912 if (cxt->isforeign)
913 ereport(ERROR,
914 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
915 errmsg("foreign key constraints are not supported on foreign tables"),
916 parser_errposition(cxt->pstate,
917 constraint->location)));
918 cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
919 break;
920
921 case CONSTR_NULL:
922 case CONSTR_NOTNULL:
923 case CONSTR_DEFAULT:
924 case CONSTR_ATTR_DEFERRABLE:
925 case CONSTR_ATTR_NOT_DEFERRABLE:
926 case CONSTR_ATTR_DEFERRED:
927 case CONSTR_ATTR_IMMEDIATE:
928 elog(ERROR, "invalid context for constraint type %d",
929 constraint->contype);
930 break;
931
932 default:
933 elog(ERROR, "unrecognized constraint type: %d",
934 constraint->contype);
935 break;
936 }
937 }
938
939 /*
940 * transformTableLikeClause
941 *
942 * Change the LIKE <srctable> portion of a CREATE TABLE statement into
943 * column definitions that recreate the user defined column portions of
944 * <srctable>. Also, if there are any LIKE options that we can't fully
945 * process at this point, add the TableLikeClause to cxt->likeclauses, which
946 * will cause utility.c to call expandTableLikeClause() after the new
947 * table has been created.
948 */
949 static void
transformTableLikeClause(CreateStmtContext * cxt,TableLikeClause * table_like_clause)950 transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
951 {
952 AttrNumber parent_attno;
953 Relation relation;
954 TupleDesc tupleDesc;
955 AclResult aclresult;
956 char *comment;
957 ParseCallbackState pcbstate;
958
959 setup_parser_errposition_callback(&pcbstate, cxt->pstate,
960 table_like_clause->relation->location);
961
962 /* we could support LIKE in many cases, but worry about it another day */
963 if (cxt->isforeign)
964 ereport(ERROR,
965 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
966 errmsg("LIKE is not supported for creating foreign tables")));
967
968 /* Open the relation referenced by the LIKE clause */
969 relation = relation_openrv(table_like_clause->relation, AccessShareLock);
970
971 if (relation->rd_rel->relkind != RELKIND_RELATION &&
972 relation->rd_rel->relkind != RELKIND_VIEW &&
973 relation->rd_rel->relkind != RELKIND_MATVIEW &&
974 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
975 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
976 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
977 ereport(ERROR,
978 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
979 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
980 RelationGetRelationName(relation))));
981
982 cancel_parser_errposition_callback(&pcbstate);
983
984 /*
985 * Check for privileges
986 */
987 if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
988 {
989 aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
990 ACL_USAGE);
991 if (aclresult != ACLCHECK_OK)
992 aclcheck_error(aclresult, OBJECT_TYPE,
993 RelationGetRelationName(relation));
994 }
995 else
996 {
997 aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
998 ACL_SELECT);
999 if (aclresult != ACLCHECK_OK)
1000 aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
1001 RelationGetRelationName(relation));
1002 }
1003
1004 tupleDesc = RelationGetDescr(relation);
1005
1006 /*
1007 * Insert the copied attributes into the cxt for the new table definition.
1008 * We must do this now so that they appear in the table in the relative
1009 * position where the LIKE clause is, as required by SQL99.
1010 */
1011 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1012 parent_attno++)
1013 {
1014 Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
1015 parent_attno - 1);
1016 char *attributeName = NameStr(attribute->attname);
1017 ColumnDef *def;
1018
1019 /*
1020 * Ignore dropped columns in the parent.
1021 */
1022 if (attribute->attisdropped)
1023 continue;
1024
1025 /*
1026 * Create a new column, which is marked as NOT inherited.
1027 *
1028 * For constraints, ONLY the NOT NULL constraint is inherited by the
1029 * new column definition per SQL99.
1030 */
1031 def = makeNode(ColumnDef);
1032 def->colname = pstrdup(attributeName);
1033 def->typeName = makeTypeNameFromOid(attribute->atttypid,
1034 attribute->atttypmod);
1035 def->inhcount = 0;
1036 def->is_local = true;
1037 def->is_not_null = attribute->attnotnull;
1038 def->is_from_type = false;
1039 def->storage = 0;
1040 def->raw_default = NULL;
1041 def->cooked_default = NULL;
1042 def->collClause = NULL;
1043 def->collOid = attribute->attcollation;
1044 def->constraints = NIL;
1045 def->location = -1;
1046
1047 /*
1048 * Add to column list
1049 */
1050 cxt->columns = lappend(cxt->columns, def);
1051
1052 /*
1053 * Although we don't transfer the column's default/generation
1054 * expression now, we need to mark it GENERATED if appropriate.
1055 */
1056 if (attribute->atthasdef && attribute->attgenerated &&
1057 (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED))
1058 def->generated = attribute->attgenerated;
1059
1060 /*
1061 * Copy identity if requested
1062 */
1063 if (attribute->attidentity &&
1064 (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY))
1065 {
1066 Oid seq_relid;
1067 List *seq_options;
1068
1069 /*
1070 * find sequence owned by old column; extract sequence parameters;
1071 * build new create sequence command
1072 */
1073 seq_relid = getIdentitySequence(RelationGetRelid(relation), attribute->attnum, false);
1074 seq_options = sequence_options(seq_relid);
1075 generateSerialExtraStmts(cxt, def,
1076 InvalidOid, seq_options,
1077 true, false,
1078 NULL, NULL);
1079 def->identity = attribute->attidentity;
1080 }
1081
1082 /* Likewise, copy storage if requested */
1083 if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE)
1084 def->storage = attribute->attstorage;
1085 else
1086 def->storage = 0;
1087
1088 /* Likewise, copy compression if requested */
1089 if ((table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) != 0
1090 && CompressionMethodIsValid(attribute->attcompression))
1091 def->compression =
1092 pstrdup(GetCompressionMethodName(attribute->attcompression));
1093 else
1094 def->compression = NULL;
1095
1096 /* Likewise, copy comment if requested */
1097 if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
1098 (comment = GetComment(attribute->attrelid,
1099 RelationRelationId,
1100 attribute->attnum)) != NULL)
1101 {
1102 CommentStmt *stmt = makeNode(CommentStmt);
1103
1104 stmt->objtype = OBJECT_COLUMN;
1105 stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1106 makeString(cxt->relation->relname),
1107 makeString(def->colname));
1108 stmt->comment = comment;
1109
1110 cxt->alist = lappend(cxt->alist, stmt);
1111 }
1112 }
1113
1114 /*
1115 * We cannot yet deal with defaults, CHECK constraints, or indexes, since
1116 * we don't yet know what column numbers the copied columns will have in
1117 * the finished table. If any of those options are specified, add the
1118 * LIKE clause to cxt->likeclauses so that expandTableLikeClause will be
1119 * called after we do know that. Also, remember the relation OID so that
1120 * expandTableLikeClause is certain to open the same table.
1121 */
1122 if (table_like_clause->options &
1123 (CREATE_TABLE_LIKE_DEFAULTS |
1124 CREATE_TABLE_LIKE_GENERATED |
1125 CREATE_TABLE_LIKE_CONSTRAINTS |
1126 CREATE_TABLE_LIKE_INDEXES))
1127 {
1128 table_like_clause->relationOid = RelationGetRelid(relation);
1129 cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause);
1130 }
1131
1132 /*
1133 * We may copy extended statistics if requested, since the representation
1134 * of CreateStatsStmt doesn't depend on column numbers.
1135 */
1136 if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS)
1137 {
1138 List *parent_extstats;
1139 ListCell *l;
1140
1141 parent_extstats = RelationGetStatExtList(relation);
1142
1143 foreach(l, parent_extstats)
1144 {
1145 Oid parent_stat_oid = lfirst_oid(l);
1146 CreateStatsStmt *stats_stmt;
1147
1148 stats_stmt = generateClonedExtStatsStmt(cxt->relation,
1149 RelationGetRelid(relation),
1150 parent_stat_oid);
1151
1152 /* Copy comment on statistics object, if requested */
1153 if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
1154 {
1155 comment = GetComment(parent_stat_oid, StatisticExtRelationId, 0);
1156
1157 /*
1158 * We make use of CreateStatsStmt's stxcomment option, so as
1159 * not to need to know now what name the statistics will have.
1160 */
1161 stats_stmt->stxcomment = comment;
1162 }
1163
1164 cxt->extstats = lappend(cxt->extstats, stats_stmt);
1165 }
1166
1167 list_free(parent_extstats);
1168 }
1169
1170 /*
1171 * Close the parent rel, but keep our AccessShareLock on it until xact
1172 * commit. That will prevent someone else from deleting or ALTERing the
1173 * parent before we can run expandTableLikeClause.
1174 */
1175 table_close(relation, NoLock);
1176 }
1177
1178 /*
1179 * expandTableLikeClause
1180 *
1181 * Process LIKE options that require knowing the final column numbers
1182 * assigned to the new table's columns. This executes after we have
1183 * run DefineRelation for the new table. It returns a list of utility
1184 * commands that should be run to generate indexes etc.
1185 */
1186 List *
expandTableLikeClause(RangeVar * heapRel,TableLikeClause * table_like_clause)1187 expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
1188 {
1189 List *result = NIL;
1190 List *atsubcmds = NIL;
1191 AttrNumber parent_attno;
1192 Relation relation;
1193 Relation childrel;
1194 TupleDesc tupleDesc;
1195 TupleConstr *constr;
1196 AttrMap *attmap;
1197 char *comment;
1198
1199 /*
1200 * Open the relation referenced by the LIKE clause. We should still have
1201 * the table lock obtained by transformTableLikeClause (and this'll throw
1202 * an assertion failure if not). Hence, no need to recheck privileges
1203 * etc. We must open the rel by OID not name, to be sure we get the same
1204 * table.
1205 */
1206 if (!OidIsValid(table_like_clause->relationOid))
1207 elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause");
1208
1209 relation = relation_open(table_like_clause->relationOid, NoLock);
1210
1211 tupleDesc = RelationGetDescr(relation);
1212 constr = tupleDesc->constr;
1213
1214 /*
1215 * Open the newly-created child relation; we have lock on that too.
1216 */
1217 childrel = relation_openrv(heapRel, NoLock);
1218
1219 /*
1220 * Construct a map from the LIKE relation's attnos to the child rel's.
1221 * This re-checks type match etc, although it shouldn't be possible to
1222 * have a failure since both tables are locked.
1223 */
1224 attmap = build_attrmap_by_name(RelationGetDescr(childrel),
1225 tupleDesc);
1226
1227 /*
1228 * Process defaults, if required.
1229 */
1230 if ((table_like_clause->options &
1231 (CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_GENERATED)) &&
1232 constr != NULL)
1233 {
1234 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
1235 parent_attno++)
1236 {
1237 Form_pg_attribute attribute = TupleDescAttr(tupleDesc,
1238 parent_attno - 1);
1239
1240 /*
1241 * Ignore dropped columns in the parent.
1242 */
1243 if (attribute->attisdropped)
1244 continue;
1245
1246 /*
1247 * Copy default, if present and it should be copied. We have
1248 * separate options for plain default expressions and GENERATED
1249 * defaults.
1250 */
1251 if (attribute->atthasdef &&
1252 (attribute->attgenerated ?
1253 (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) :
1254 (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS)))
1255 {
1256 Node *this_default = NULL;
1257 AttrDefault *attrdef = constr->defval;
1258 AlterTableCmd *atsubcmd;
1259 bool found_whole_row;
1260
1261 /* Find default in constraint structure */
1262 for (int i = 0; i < constr->num_defval; i++)
1263 {
1264 if (attrdef[i].adnum == parent_attno)
1265 {
1266 this_default = stringToNode(attrdef[i].adbin);
1267 break;
1268 }
1269 }
1270 if (this_default == NULL)
1271 elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
1272 parent_attno, RelationGetRelationName(relation));
1273
1274 atsubcmd = makeNode(AlterTableCmd);
1275 atsubcmd->subtype = AT_CookedColumnDefault;
1276 atsubcmd->num = attmap->attnums[parent_attno - 1];
1277 atsubcmd->def = map_variable_attnos(this_default,
1278 1, 0,
1279 attmap,
1280 InvalidOid,
1281 &found_whole_row);
1282
1283 /*
1284 * Prevent this for the same reason as for constraints below.
1285 * Note that defaults cannot contain any vars, so it's OK that
1286 * the error message refers to generated columns.
1287 */
1288 if (found_whole_row)
1289 ereport(ERROR,
1290 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1291 errmsg("cannot convert whole-row table reference"),
1292 errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
1293 NameStr(attribute->attname),
1294 RelationGetRelationName(relation))));
1295
1296 atsubcmds = lappend(atsubcmds, atsubcmd);
1297 }
1298 }
1299 }
1300
1301 /*
1302 * Copy CHECK constraints if requested, being careful to adjust attribute
1303 * numbers so they match the child.
1304 */
1305 if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
1306 constr != NULL)
1307 {
1308 int ccnum;
1309
1310 for (ccnum = 0; ccnum < constr->num_check; ccnum++)
1311 {
1312 char *ccname = constr->check[ccnum].ccname;
1313 char *ccbin = constr->check[ccnum].ccbin;
1314 bool ccnoinherit = constr->check[ccnum].ccnoinherit;
1315 Node *ccbin_node;
1316 bool found_whole_row;
1317 Constraint *n;
1318 AlterTableCmd *atsubcmd;
1319
1320 ccbin_node = map_variable_attnos(stringToNode(ccbin),
1321 1, 0,
1322 attmap,
1323 InvalidOid, &found_whole_row);
1324
1325 /*
1326 * We reject whole-row variables because the whole point of LIKE
1327 * is that the new table's rowtype might later diverge from the
1328 * parent's. So, while translation might be possible right now,
1329 * it wouldn't be possible to guarantee it would work in future.
1330 */
1331 if (found_whole_row)
1332 ereport(ERROR,
1333 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1334 errmsg("cannot convert whole-row table reference"),
1335 errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1336 ccname,
1337 RelationGetRelationName(relation))));
1338
1339 n = makeNode(Constraint);
1340 n->contype = CONSTR_CHECK;
1341 n->conname = pstrdup(ccname);
1342 n->location = -1;
1343 n->is_no_inherit = ccnoinherit;
1344 n->raw_expr = NULL;
1345 n->cooked_expr = nodeToString(ccbin_node);
1346
1347 /* We can skip validation, since the new table should be empty. */
1348 n->skip_validation = true;
1349 n->initially_valid = true;
1350
1351 atsubcmd = makeNode(AlterTableCmd);
1352 atsubcmd->subtype = AT_AddConstraint;
1353 atsubcmd->def = (Node *) n;
1354 atsubcmds = lappend(atsubcmds, atsubcmd);
1355
1356 /* Copy comment on constraint */
1357 if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
1358 (comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
1359 n->conname, false),
1360 ConstraintRelationId,
1361 0)) != NULL)
1362 {
1363 CommentStmt *stmt = makeNode(CommentStmt);
1364
1365 stmt->objtype = OBJECT_TABCONSTRAINT;
1366 stmt->object = (Node *) list_make3(makeString(heapRel->schemaname),
1367 makeString(heapRel->relname),
1368 makeString(n->conname));
1369 stmt->comment = comment;
1370
1371 result = lappend(result, stmt);
1372 }
1373 }
1374 }
1375
1376 /*
1377 * If we generated any ALTER TABLE actions above, wrap them into a single
1378 * ALTER TABLE command. Stick it at the front of the result, so it runs
1379 * before any CommentStmts we made above.
1380 */
1381 if (atsubcmds)
1382 {
1383 AlterTableStmt *atcmd = makeNode(AlterTableStmt);
1384
1385 atcmd->relation = copyObject(heapRel);
1386 atcmd->cmds = atsubcmds;
1387 atcmd->objtype = OBJECT_TABLE;
1388 atcmd->missing_ok = false;
1389 result = lcons(atcmd, result);
1390 }
1391
1392 /*
1393 * Process indexes if required.
1394 */
1395 if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
1396 relation->rd_rel->relhasindex)
1397 {
1398 List *parent_indexes;
1399 ListCell *l;
1400
1401 parent_indexes = RelationGetIndexList(relation);
1402
1403 foreach(l, parent_indexes)
1404 {
1405 Oid parent_index_oid = lfirst_oid(l);
1406 Relation parent_index;
1407 IndexStmt *index_stmt;
1408
1409 parent_index = index_open(parent_index_oid, AccessShareLock);
1410
1411 /* Build CREATE INDEX statement to recreate the parent_index */
1412 index_stmt = generateClonedIndexStmt(heapRel,
1413 parent_index,
1414 attmap,
1415 NULL);
1416
1417 /* Copy comment on index, if requested */
1418 if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
1419 {
1420 comment = GetComment(parent_index_oid, RelationRelationId, 0);
1421
1422 /*
1423 * We make use of IndexStmt's idxcomment option, so as not to
1424 * need to know now what name the index will have.
1425 */
1426 index_stmt->idxcomment = comment;
1427 }
1428
1429 result = lappend(result, index_stmt);
1430
1431 index_close(parent_index, AccessShareLock);
1432 }
1433 }
1434
1435 /* Done with child rel */
1436 table_close(childrel, NoLock);
1437
1438 /*
1439 * Close the parent rel, but keep our AccessShareLock on it until xact
1440 * commit. That will prevent someone else from deleting or ALTERing the
1441 * parent before the child is committed.
1442 */
1443 table_close(relation, NoLock);
1444
1445 return result;
1446 }
1447
1448 static void
transformOfType(CreateStmtContext * cxt,TypeName * ofTypename)1449 transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
1450 {
1451 HeapTuple tuple;
1452 TupleDesc tupdesc;
1453 int i;
1454 Oid ofTypeId;
1455
1456 AssertArg(ofTypename);
1457
1458 tuple = typenameType(NULL, ofTypename, NULL);
1459 check_of_type(tuple);
1460 ofTypeId = ((Form_pg_type) GETSTRUCT(tuple))->oid;
1461 ofTypename->typeOid = ofTypeId; /* cached for later */
1462
1463 tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
1464 for (i = 0; i < tupdesc->natts; i++)
1465 {
1466 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1467 ColumnDef *n;
1468
1469 if (attr->attisdropped)
1470 continue;
1471
1472 n = makeNode(ColumnDef);
1473 n->colname = pstrdup(NameStr(attr->attname));
1474 n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod);
1475 n->inhcount = 0;
1476 n->is_local = true;
1477 n->is_not_null = false;
1478 n->is_from_type = true;
1479 n->storage = 0;
1480 n->raw_default = NULL;
1481 n->cooked_default = NULL;
1482 n->collClause = NULL;
1483 n->collOid = attr->attcollation;
1484 n->constraints = NIL;
1485 n->location = -1;
1486 cxt->columns = lappend(cxt->columns, n);
1487 }
1488 DecrTupleDescRefCount(tupdesc);
1489
1490 ReleaseSysCache(tuple);
1491 }
1492
1493 /*
1494 * Generate an IndexStmt node using information from an already existing index
1495 * "source_idx".
1496 *
1497 * heapRel is stored into the IndexStmt's relation field, but we don't use it
1498 * otherwise; some callers pass NULL, if they don't need it to be valid.
1499 * (The target relation might not exist yet, so we mustn't try to access it.)
1500 *
1501 * Attribute numbers in expression Vars are adjusted according to attmap.
1502 *
1503 * If constraintOid isn't NULL, we store the OID of any constraint associated
1504 * with the index there.
1505 *
1506 * Unlike transformIndexConstraint, we don't make any effort to force primary
1507 * key columns to be NOT NULL. The larger cloning process this is part of
1508 * should have cloned their NOT NULL status separately (and DefineIndex will
1509 * complain if that fails to happen).
1510 */
1511 IndexStmt *
generateClonedIndexStmt(RangeVar * heapRel,Relation source_idx,const AttrMap * attmap,Oid * constraintOid)1512 generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
1513 const AttrMap *attmap,
1514 Oid *constraintOid)
1515 {
1516 Oid source_relid = RelationGetRelid(source_idx);
1517 HeapTuple ht_idxrel;
1518 HeapTuple ht_idx;
1519 HeapTuple ht_am;
1520 Form_pg_class idxrelrec;
1521 Form_pg_index idxrec;
1522 Form_pg_am amrec;
1523 oidvector *indcollation;
1524 oidvector *indclass;
1525 IndexStmt *index;
1526 List *indexprs;
1527 ListCell *indexpr_item;
1528 Oid indrelid;
1529 int keyno;
1530 Oid keycoltype;
1531 Datum datum;
1532 bool isnull;
1533
1534 if (constraintOid)
1535 *constraintOid = InvalidOid;
1536
1537 /*
1538 * Fetch pg_class tuple of source index. We can't use the copy in the
1539 * relcache entry because it doesn't include optional fields.
1540 */
1541 ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(source_relid));
1542 if (!HeapTupleIsValid(ht_idxrel))
1543 elog(ERROR, "cache lookup failed for relation %u", source_relid);
1544 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1545
1546 /* Fetch pg_index tuple for source index from relcache entry */
1547 ht_idx = source_idx->rd_indextuple;
1548 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1549 indrelid = idxrec->indrelid;
1550
1551 /* Fetch the pg_am tuple of the index' access method */
1552 ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1553 if (!HeapTupleIsValid(ht_am))
1554 elog(ERROR, "cache lookup failed for access method %u",
1555 idxrelrec->relam);
1556 amrec = (Form_pg_am) GETSTRUCT(ht_am);
1557
1558 /* Extract indcollation from the pg_index tuple */
1559 datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1560 Anum_pg_index_indcollation, &isnull);
1561 Assert(!isnull);
1562 indcollation = (oidvector *) DatumGetPointer(datum);
1563
1564 /* Extract indclass from the pg_index tuple */
1565 datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1566 Anum_pg_index_indclass, &isnull);
1567 Assert(!isnull);
1568 indclass = (oidvector *) DatumGetPointer(datum);
1569
1570 /* Begin building the IndexStmt */
1571 index = makeNode(IndexStmt);
1572 index->relation = heapRel;
1573 index->accessMethod = pstrdup(NameStr(amrec->amname));
1574 if (OidIsValid(idxrelrec->reltablespace))
1575 index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
1576 else
1577 index->tableSpace = NULL;
1578 index->excludeOpNames = NIL;
1579 index->idxcomment = NULL;
1580 index->indexOid = InvalidOid;
1581 index->oldNode = InvalidOid;
1582 index->oldCreateSubid = InvalidSubTransactionId;
1583 index->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
1584 index->unique = idxrec->indisunique;
1585 index->primary = idxrec->indisprimary;
1586 index->transformed = true; /* don't need transformIndexStmt */
1587 index->concurrent = false;
1588 index->if_not_exists = false;
1589 index->reset_default_tblspc = false;
1590
1591 /*
1592 * We don't try to preserve the name of the source index; instead, just
1593 * let DefineIndex() choose a reasonable name. (If we tried to preserve
1594 * the name, we'd get duplicate-relation-name failures unless the source
1595 * table was in a different schema.)
1596 */
1597 index->idxname = NULL;
1598
1599 /*
1600 * If the index is marked PRIMARY or has an exclusion condition, it's
1601 * certainly from a constraint; else, if it's not marked UNIQUE, it
1602 * certainly isn't. If it is or might be from a constraint, we have to
1603 * fetch the pg_constraint record.
1604 */
1605 if (index->primary || index->unique || idxrec->indisexclusion)
1606 {
1607 Oid constraintId = get_index_constraint(source_relid);
1608
1609 if (OidIsValid(constraintId))
1610 {
1611 HeapTuple ht_constr;
1612 Form_pg_constraint conrec;
1613
1614 if (constraintOid)
1615 *constraintOid = constraintId;
1616
1617 ht_constr = SearchSysCache1(CONSTROID,
1618 ObjectIdGetDatum(constraintId));
1619 if (!HeapTupleIsValid(ht_constr))
1620 elog(ERROR, "cache lookup failed for constraint %u",
1621 constraintId);
1622 conrec = (Form_pg_constraint) GETSTRUCT(ht_constr);
1623
1624 index->isconstraint = true;
1625 index->deferrable = conrec->condeferrable;
1626 index->initdeferred = conrec->condeferred;
1627
1628 /* If it's an exclusion constraint, we need the operator names */
1629 if (idxrec->indisexclusion)
1630 {
1631 Datum *elems;
1632 int nElems;
1633 int i;
1634
1635 Assert(conrec->contype == CONSTRAINT_EXCLUSION);
1636 /* Extract operator OIDs from the pg_constraint tuple */
1637 datum = SysCacheGetAttr(CONSTROID, ht_constr,
1638 Anum_pg_constraint_conexclop,
1639 &isnull);
1640 if (isnull)
1641 elog(ERROR, "null conexclop for constraint %u",
1642 constraintId);
1643
1644 deconstruct_array(DatumGetArrayTypeP(datum),
1645 OIDOID, sizeof(Oid), true, TYPALIGN_INT,
1646 &elems, NULL, &nElems);
1647
1648 for (i = 0; i < nElems; i++)
1649 {
1650 Oid operid = DatumGetObjectId(elems[i]);
1651 HeapTuple opertup;
1652 Form_pg_operator operform;
1653 char *oprname;
1654 char *nspname;
1655 List *namelist;
1656
1657 opertup = SearchSysCache1(OPEROID,
1658 ObjectIdGetDatum(operid));
1659 if (!HeapTupleIsValid(opertup))
1660 elog(ERROR, "cache lookup failed for operator %u",
1661 operid);
1662 operform = (Form_pg_operator) GETSTRUCT(opertup);
1663 oprname = pstrdup(NameStr(operform->oprname));
1664 /* For simplicity we always schema-qualify the op name */
1665 nspname = get_namespace_name(operform->oprnamespace);
1666 namelist = list_make2(makeString(nspname),
1667 makeString(oprname));
1668 index->excludeOpNames = lappend(index->excludeOpNames,
1669 namelist);
1670 ReleaseSysCache(opertup);
1671 }
1672 }
1673
1674 ReleaseSysCache(ht_constr);
1675 }
1676 else
1677 index->isconstraint = false;
1678 }
1679 else
1680 index->isconstraint = false;
1681
1682 /* Get the index expressions, if any */
1683 datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1684 Anum_pg_index_indexprs, &isnull);
1685 if (!isnull)
1686 {
1687 char *exprsString;
1688
1689 exprsString = TextDatumGetCString(datum);
1690 indexprs = (List *) stringToNode(exprsString);
1691 }
1692 else
1693 indexprs = NIL;
1694
1695 /* Build the list of IndexElem */
1696 index->indexParams = NIL;
1697 index->indexIncludingParams = NIL;
1698
1699 indexpr_item = list_head(indexprs);
1700 for (keyno = 0; keyno < idxrec->indnkeyatts; keyno++)
1701 {
1702 IndexElem *iparam;
1703 AttrNumber attnum = idxrec->indkey.values[keyno];
1704 Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
1705 keyno);
1706 int16 opt = source_idx->rd_indoption[keyno];
1707
1708 iparam = makeNode(IndexElem);
1709
1710 if (AttributeNumberIsValid(attnum))
1711 {
1712 /* Simple index column */
1713 char *attname;
1714
1715 attname = get_attname(indrelid, attnum, false);
1716 keycoltype = get_atttype(indrelid, attnum);
1717
1718 iparam->name = attname;
1719 iparam->expr = NULL;
1720 }
1721 else
1722 {
1723 /* Expressional index */
1724 Node *indexkey;
1725 bool found_whole_row;
1726
1727 if (indexpr_item == NULL)
1728 elog(ERROR, "too few entries in indexprs list");
1729 indexkey = (Node *) lfirst(indexpr_item);
1730 indexpr_item = lnext(indexprs, indexpr_item);
1731
1732 /* Adjust Vars to match new table's column numbering */
1733 indexkey = map_variable_attnos(indexkey,
1734 1, 0,
1735 attmap,
1736 InvalidOid, &found_whole_row);
1737
1738 /* As in expandTableLikeClause, reject whole-row variables */
1739 if (found_whole_row)
1740 ereport(ERROR,
1741 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1742 errmsg("cannot convert whole-row table reference"),
1743 errdetail("Index \"%s\" contains a whole-row table reference.",
1744 RelationGetRelationName(source_idx))));
1745
1746 iparam->name = NULL;
1747 iparam->expr = indexkey;
1748
1749 keycoltype = exprType(indexkey);
1750 }
1751
1752 /* Copy the original index column name */
1753 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1754
1755 /* Add the collation name, if non-default */
1756 iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
1757
1758 /* Add the operator class name, if non-default */
1759 iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
1760 iparam->opclassopts =
1761 untransformRelOptions(get_attoptions(source_relid, keyno + 1));
1762
1763 iparam->ordering = SORTBY_DEFAULT;
1764 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
1765
1766 /* Adjust options if necessary */
1767 if (source_idx->rd_indam->amcanorder)
1768 {
1769 /*
1770 * If it supports sort ordering, copy DESC and NULLS opts. Don't
1771 * set non-default settings unnecessarily, though, so as to
1772 * improve the chance of recognizing equivalence to constraint
1773 * indexes.
1774 */
1775 if (opt & INDOPTION_DESC)
1776 {
1777 iparam->ordering = SORTBY_DESC;
1778 if ((opt & INDOPTION_NULLS_FIRST) == 0)
1779 iparam->nulls_ordering = SORTBY_NULLS_LAST;
1780 }
1781 else
1782 {
1783 if (opt & INDOPTION_NULLS_FIRST)
1784 iparam->nulls_ordering = SORTBY_NULLS_FIRST;
1785 }
1786 }
1787
1788 index->indexParams = lappend(index->indexParams, iparam);
1789 }
1790
1791 /* Handle included columns separately */
1792 for (keyno = idxrec->indnkeyatts; keyno < idxrec->indnatts; keyno++)
1793 {
1794 IndexElem *iparam;
1795 AttrNumber attnum = idxrec->indkey.values[keyno];
1796 Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
1797 keyno);
1798
1799 iparam = makeNode(IndexElem);
1800
1801 if (AttributeNumberIsValid(attnum))
1802 {
1803 /* Simple index column */
1804 char *attname;
1805
1806 attname = get_attname(indrelid, attnum, false);
1807
1808 iparam->name = attname;
1809 iparam->expr = NULL;
1810 }
1811 else
1812 ereport(ERROR,
1813 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1814 errmsg("expressions are not supported in included columns")));
1815
1816 /* Copy the original index column name */
1817 iparam->indexcolname = pstrdup(NameStr(attr->attname));
1818
1819 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
1820 }
1821 /* Copy reloptions if any */
1822 datum = SysCacheGetAttr(RELOID, ht_idxrel,
1823 Anum_pg_class_reloptions, &isnull);
1824 if (!isnull)
1825 index->options = untransformRelOptions(datum);
1826
1827 /* If it's a partial index, decompile and append the predicate */
1828 datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1829 Anum_pg_index_indpred, &isnull);
1830 if (!isnull)
1831 {
1832 char *pred_str;
1833 Node *pred_tree;
1834 bool found_whole_row;
1835
1836 /* Convert text string to node tree */
1837 pred_str = TextDatumGetCString(datum);
1838 pred_tree = (Node *) stringToNode(pred_str);
1839
1840 /* Adjust Vars to match new table's column numbering */
1841 pred_tree = map_variable_attnos(pred_tree,
1842 1, 0,
1843 attmap,
1844 InvalidOid, &found_whole_row);
1845
1846 /* As in expandTableLikeClause, reject whole-row variables */
1847 if (found_whole_row)
1848 ereport(ERROR,
1849 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1850 errmsg("cannot convert whole-row table reference"),
1851 errdetail("Index \"%s\" contains a whole-row table reference.",
1852 RelationGetRelationName(source_idx))));
1853
1854 index->whereClause = pred_tree;
1855 }
1856
1857 /* Clean up */
1858 ReleaseSysCache(ht_idxrel);
1859 ReleaseSysCache(ht_am);
1860
1861 return index;
1862 }
1863
1864 /*
1865 * Generate a CreateStatsStmt node using information from an already existing
1866 * extended statistic "source_statsid", for the rel identified by heapRel and
1867 * heapRelid.
1868 */
1869 static CreateStatsStmt *
generateClonedExtStatsStmt(RangeVar * heapRel,Oid heapRelid,Oid source_statsid)1870 generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
1871 Oid source_statsid)
1872 {
1873 HeapTuple ht_stats;
1874 Form_pg_statistic_ext statsrec;
1875 CreateStatsStmt *stats;
1876 List *stat_types = NIL;
1877 List *def_names = NIL;
1878 bool isnull;
1879 Datum datum;
1880 ArrayType *arr;
1881 char *enabled;
1882 int i;
1883
1884 Assert(OidIsValid(heapRelid));
1885 Assert(heapRel != NULL);
1886
1887 /*
1888 * Fetch pg_statistic_ext tuple of source statistics object.
1889 */
1890 ht_stats = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(source_statsid));
1891 if (!HeapTupleIsValid(ht_stats))
1892 elog(ERROR, "cache lookup failed for statistics object %u", source_statsid);
1893 statsrec = (Form_pg_statistic_ext) GETSTRUCT(ht_stats);
1894
1895 /* Determine which statistics types exist */
1896 datum = SysCacheGetAttr(STATEXTOID, ht_stats,
1897 Anum_pg_statistic_ext_stxkind, &isnull);
1898 Assert(!isnull);
1899 arr = DatumGetArrayTypeP(datum);
1900 if (ARR_NDIM(arr) != 1 ||
1901 ARR_HASNULL(arr) ||
1902 ARR_ELEMTYPE(arr) != CHAROID)
1903 elog(ERROR, "stxkind is not a 1-D char array");
1904 enabled = (char *) ARR_DATA_PTR(arr);
1905 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1906 {
1907 if (enabled[i] == STATS_EXT_NDISTINCT)
1908 stat_types = lappend(stat_types, makeString("ndistinct"));
1909 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1910 stat_types = lappend(stat_types, makeString("dependencies"));
1911 else if (enabled[i] == STATS_EXT_MCV)
1912 stat_types = lappend(stat_types, makeString("mcv"));
1913 else if (enabled[i] == STATS_EXT_EXPRESSIONS)
1914 /* expression stats are not exposed to users */
1915 continue;
1916 else
1917 elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
1918 }
1919
1920 /* Determine which columns the statistics are on */
1921 for (i = 0; i < statsrec->stxkeys.dim1; i++)
1922 {
1923 StatsElem *selem = makeNode(StatsElem);
1924 AttrNumber attnum = statsrec->stxkeys.values[i];
1925
1926 selem->name = get_attname(heapRelid, attnum, false);
1927 selem->expr = NULL;
1928
1929 def_names = lappend(def_names, selem);
1930 }
1931
1932 /*
1933 * Now handle expressions, if there are any. The order (with respect to
1934 * regular attributes) does not really matter for extended stats, so we
1935 * simply append them after simple column references.
1936 *
1937 * XXX Some places during build/estimation treat expressions as if they
1938 * are before attributes, but for the CREATE command that's entirely
1939 * irrelevant.
1940 */
1941 datum = SysCacheGetAttr(STATEXTOID, ht_stats,
1942 Anum_pg_statistic_ext_stxexprs, &isnull);
1943
1944 if (!isnull)
1945 {
1946 ListCell *lc;
1947 List *exprs = NIL;
1948 char *exprsString;
1949
1950 exprsString = TextDatumGetCString(datum);
1951 exprs = (List *) stringToNode(exprsString);
1952
1953 foreach(lc, exprs)
1954 {
1955 StatsElem *selem = makeNode(StatsElem);
1956
1957 selem->name = NULL;
1958 selem->expr = (Node *) lfirst(lc);
1959
1960 def_names = lappend(def_names, selem);
1961 }
1962
1963 pfree(exprsString);
1964 }
1965
1966 /* finally, build the output node */
1967 stats = makeNode(CreateStatsStmt);
1968 stats->defnames = NULL;
1969 stats->stat_types = stat_types;
1970 stats->exprs = def_names;
1971 stats->relations = list_make1(heapRel);
1972 stats->stxcomment = NULL;
1973 stats->transformed = true; /* don't need transformStatsStmt again */
1974 stats->if_not_exists = false;
1975
1976 /* Clean up */
1977 ReleaseSysCache(ht_stats);
1978
1979 return stats;
1980 }
1981
1982 /*
1983 * get_collation - fetch qualified name of a collation
1984 *
1985 * If collation is InvalidOid or is the default for the given actual_datatype,
1986 * then the return value is NIL.
1987 */
1988 static List *
get_collation(Oid collation,Oid actual_datatype)1989 get_collation(Oid collation, Oid actual_datatype)
1990 {
1991 List *result;
1992 HeapTuple ht_coll;
1993 Form_pg_collation coll_rec;
1994 char *nsp_name;
1995 char *coll_name;
1996
1997 if (!OidIsValid(collation))
1998 return NIL; /* easy case */
1999 if (collation == get_typcollation(actual_datatype))
2000 return NIL; /* just let it default */
2001
2002 ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
2003 if (!HeapTupleIsValid(ht_coll))
2004 elog(ERROR, "cache lookup failed for collation %u", collation);
2005 coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
2006
2007 /* For simplicity, we always schema-qualify the name */
2008 nsp_name = get_namespace_name(coll_rec->collnamespace);
2009 coll_name = pstrdup(NameStr(coll_rec->collname));
2010 result = list_make2(makeString(nsp_name), makeString(coll_name));
2011
2012 ReleaseSysCache(ht_coll);
2013 return result;
2014 }
2015
2016 /*
2017 * get_opclass - fetch qualified name of an index operator class
2018 *
2019 * If the opclass is the default for the given actual_datatype, then
2020 * the return value is NIL.
2021 */
2022 static List *
get_opclass(Oid opclass,Oid actual_datatype)2023 get_opclass(Oid opclass, Oid actual_datatype)
2024 {
2025 List *result = NIL;
2026 HeapTuple ht_opc;
2027 Form_pg_opclass opc_rec;
2028
2029 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
2030 if (!HeapTupleIsValid(ht_opc))
2031 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2032 opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
2033
2034 if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
2035 {
2036 /* For simplicity, we always schema-qualify the name */
2037 char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
2038 char *opc_name = pstrdup(NameStr(opc_rec->opcname));
2039
2040 result = list_make2(makeString(nsp_name), makeString(opc_name));
2041 }
2042
2043 ReleaseSysCache(ht_opc);
2044 return result;
2045 }
2046
2047
2048 /*
2049 * transformIndexConstraints
2050 * Handle UNIQUE, PRIMARY KEY, EXCLUDE constraints, which create indexes.
2051 * We also merge in any index definitions arising from
2052 * LIKE ... INCLUDING INDEXES.
2053 */
2054 static void
transformIndexConstraints(CreateStmtContext * cxt)2055 transformIndexConstraints(CreateStmtContext *cxt)
2056 {
2057 IndexStmt *index;
2058 List *indexlist = NIL;
2059 List *finalindexlist = NIL;
2060 ListCell *lc;
2061
2062 /*
2063 * Run through the constraints that need to generate an index. For PRIMARY
2064 * KEY, mark each column as NOT NULL and create an index. For UNIQUE or
2065 * EXCLUDE, create an index as for PRIMARY KEY, but do not insist on NOT
2066 * NULL.
2067 */
2068 foreach(lc, cxt->ixconstraints)
2069 {
2070 Constraint *constraint = lfirst_node(Constraint, lc);
2071
2072 Assert(constraint->contype == CONSTR_PRIMARY ||
2073 constraint->contype == CONSTR_UNIQUE ||
2074 constraint->contype == CONSTR_EXCLUSION);
2075
2076 index = transformIndexConstraint(constraint, cxt);
2077
2078 indexlist = lappend(indexlist, index);
2079 }
2080
2081 /*
2082 * Scan the index list and remove any redundant index specifications. This
2083 * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
2084 * strict reading of SQL would suggest raising an error instead, but that
2085 * strikes me as too anal-retentive. - tgl 2001-02-14
2086 *
2087 * XXX in ALTER TABLE case, it'd be nice to look for duplicate
2088 * pre-existing indexes, too.
2089 */
2090 if (cxt->pkey != NULL)
2091 {
2092 /* Make sure we keep the PKEY index in preference to others... */
2093 finalindexlist = list_make1(cxt->pkey);
2094 }
2095
2096 foreach(lc, indexlist)
2097 {
2098 bool keep = true;
2099 ListCell *k;
2100
2101 index = lfirst(lc);
2102
2103 /* if it's pkey, it's already in finalindexlist */
2104 if (index == cxt->pkey)
2105 continue;
2106
2107 foreach(k, finalindexlist)
2108 {
2109 IndexStmt *priorindex = lfirst(k);
2110
2111 if (equal(index->indexParams, priorindex->indexParams) &&
2112 equal(index->indexIncludingParams, priorindex->indexIncludingParams) &&
2113 equal(index->whereClause, priorindex->whereClause) &&
2114 equal(index->excludeOpNames, priorindex->excludeOpNames) &&
2115 strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
2116 index->deferrable == priorindex->deferrable &&
2117 index->initdeferred == priorindex->initdeferred)
2118 {
2119 priorindex->unique |= index->unique;
2120
2121 /*
2122 * If the prior index is as yet unnamed, and this one is
2123 * named, then transfer the name to the prior index. This
2124 * ensures that if we have named and unnamed constraints,
2125 * we'll use (at least one of) the names for the index.
2126 */
2127 if (priorindex->idxname == NULL)
2128 priorindex->idxname = index->idxname;
2129 keep = false;
2130 break;
2131 }
2132 }
2133
2134 if (keep)
2135 finalindexlist = lappend(finalindexlist, index);
2136 }
2137
2138 /*
2139 * Now append all the IndexStmts to cxt->alist. If we generated an ALTER
2140 * TABLE SET NOT NULL statement to support a primary key, it's already in
2141 * cxt->alist.
2142 */
2143 cxt->alist = list_concat(cxt->alist, finalindexlist);
2144 }
2145
2146 /*
2147 * transformIndexConstraint
2148 * Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
2149 * transformIndexConstraints.
2150 *
2151 * We return an IndexStmt. For a PRIMARY KEY constraint, we additionally
2152 * produce NOT NULL constraints, either by marking ColumnDefs in cxt->columns
2153 * as is_not_null or by adding an ALTER TABLE SET NOT NULL command to
2154 * cxt->alist.
2155 */
2156 static IndexStmt *
transformIndexConstraint(Constraint * constraint,CreateStmtContext * cxt)2157 transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
2158 {
2159 IndexStmt *index;
2160 List *notnullcmds = NIL;
2161 ListCell *lc;
2162
2163 index = makeNode(IndexStmt);
2164
2165 index->unique = (constraint->contype != CONSTR_EXCLUSION);
2166 index->primary = (constraint->contype == CONSTR_PRIMARY);
2167 if (index->primary)
2168 {
2169 if (cxt->pkey != NULL)
2170 ereport(ERROR,
2171 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
2172 errmsg("multiple primary keys for table \"%s\" are not allowed",
2173 cxt->relation->relname),
2174 parser_errposition(cxt->pstate, constraint->location)));
2175 cxt->pkey = index;
2176
2177 /*
2178 * In ALTER TABLE case, a primary index might already exist, but
2179 * DefineIndex will check for it.
2180 */
2181 }
2182 index->isconstraint = true;
2183 index->deferrable = constraint->deferrable;
2184 index->initdeferred = constraint->initdeferred;
2185
2186 if (constraint->conname != NULL)
2187 index->idxname = pstrdup(constraint->conname);
2188 else
2189 index->idxname = NULL; /* DefineIndex will choose name */
2190
2191 index->relation = cxt->relation;
2192 index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
2193 index->options = constraint->options;
2194 index->tableSpace = constraint->indexspace;
2195 index->whereClause = constraint->where_clause;
2196 index->indexParams = NIL;
2197 index->indexIncludingParams = NIL;
2198 index->excludeOpNames = NIL;
2199 index->idxcomment = NULL;
2200 index->indexOid = InvalidOid;
2201 index->oldNode = InvalidOid;
2202 index->oldCreateSubid = InvalidSubTransactionId;
2203 index->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
2204 index->transformed = false;
2205 index->concurrent = false;
2206 index->if_not_exists = false;
2207 index->reset_default_tblspc = constraint->reset_default_tblspc;
2208
2209 /*
2210 * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
2211 * verify it's usable, then extract the implied column name list. (We
2212 * will not actually need the column name list at runtime, but we need it
2213 * now to check for duplicate column entries below.)
2214 */
2215 if (constraint->indexname != NULL)
2216 {
2217 char *index_name = constraint->indexname;
2218 Relation heap_rel = cxt->rel;
2219 Oid index_oid;
2220 Relation index_rel;
2221 Form_pg_index index_form;
2222 oidvector *indclass;
2223 Datum indclassDatum;
2224 bool isnull;
2225 int i;
2226
2227 /* Grammar should not allow this with explicit column list */
2228 Assert(constraint->keys == NIL);
2229
2230 /* Grammar should only allow PRIMARY and UNIQUE constraints */
2231 Assert(constraint->contype == CONSTR_PRIMARY ||
2232 constraint->contype == CONSTR_UNIQUE);
2233
2234 /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
2235 if (!cxt->isalter)
2236 ereport(ERROR,
2237 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2238 errmsg("cannot use an existing index in CREATE TABLE"),
2239 parser_errposition(cxt->pstate, constraint->location)));
2240
2241 /* Look for the index in the same schema as the table */
2242 index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
2243
2244 if (!OidIsValid(index_oid))
2245 ereport(ERROR,
2246 (errcode(ERRCODE_UNDEFINED_OBJECT),
2247 errmsg("index \"%s\" does not exist", index_name),
2248 parser_errposition(cxt->pstate, constraint->location)));
2249
2250 /* Open the index (this will throw an error if it is not an index) */
2251 index_rel = index_open(index_oid, AccessShareLock);
2252 index_form = index_rel->rd_index;
2253
2254 /* Check that it does not have an associated constraint already */
2255 if (OidIsValid(get_index_constraint(index_oid)))
2256 ereport(ERROR,
2257 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2258 errmsg("index \"%s\" is already associated with a constraint",
2259 index_name),
2260 parser_errposition(cxt->pstate, constraint->location)));
2261
2262 /* Perform validity checks on the index */
2263 if (index_form->indrelid != RelationGetRelid(heap_rel))
2264 ereport(ERROR,
2265 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2266 errmsg("index \"%s\" does not belong to table \"%s\"",
2267 index_name, RelationGetRelationName(heap_rel)),
2268 parser_errposition(cxt->pstate, constraint->location)));
2269
2270 if (!index_form->indisvalid)
2271 ereport(ERROR,
2272 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2273 errmsg("index \"%s\" is not valid", index_name),
2274 parser_errposition(cxt->pstate, constraint->location)));
2275
2276 if (!index_form->indisunique)
2277 ereport(ERROR,
2278 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2279 errmsg("\"%s\" is not a unique index", index_name),
2280 errdetail("Cannot create a primary key or unique constraint using such an index."),
2281 parser_errposition(cxt->pstate, constraint->location)));
2282
2283 if (RelationGetIndexExpressions(index_rel) != NIL)
2284 ereport(ERROR,
2285 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2286 errmsg("index \"%s\" contains expressions", index_name),
2287 errdetail("Cannot create a primary key or unique constraint using such an index."),
2288 parser_errposition(cxt->pstate, constraint->location)));
2289
2290 if (RelationGetIndexPredicate(index_rel) != NIL)
2291 ereport(ERROR,
2292 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2293 errmsg("\"%s\" is a partial index", index_name),
2294 errdetail("Cannot create a primary key or unique constraint using such an index."),
2295 parser_errposition(cxt->pstate, constraint->location)));
2296
2297 /*
2298 * It's probably unsafe to change a deferred index to non-deferred. (A
2299 * non-constraint index couldn't be deferred anyway, so this case
2300 * should never occur; no need to sweat, but let's check it.)
2301 */
2302 if (!index_form->indimmediate && !constraint->deferrable)
2303 ereport(ERROR,
2304 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2305 errmsg("\"%s\" is a deferrable index", index_name),
2306 errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
2307 parser_errposition(cxt->pstate, constraint->location)));
2308
2309 /*
2310 * Insist on it being a btree. That's the only kind that supports
2311 * uniqueness at the moment anyway; but we must have an index that
2312 * exactly matches what you'd get from plain ADD CONSTRAINT syntax,
2313 * else dump and reload will produce a different index (breaking
2314 * pg_upgrade in particular).
2315 */
2316 if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
2317 ereport(ERROR,
2318 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2319 errmsg("index \"%s\" is not a btree", index_name),
2320 parser_errposition(cxt->pstate, constraint->location)));
2321
2322 /* Must get indclass the hard way */
2323 indclassDatum = SysCacheGetAttr(INDEXRELID, index_rel->rd_indextuple,
2324 Anum_pg_index_indclass, &isnull);
2325 Assert(!isnull);
2326 indclass = (oidvector *) DatumGetPointer(indclassDatum);
2327
2328 for (i = 0; i < index_form->indnatts; i++)
2329 {
2330 int16 attnum = index_form->indkey.values[i];
2331 const FormData_pg_attribute *attform;
2332 char *attname;
2333 Oid defopclass;
2334
2335 /*
2336 * We shouldn't see attnum == 0 here, since we already rejected
2337 * expression indexes. If we do, SystemAttributeDefinition will
2338 * throw an error.
2339 */
2340 if (attnum > 0)
2341 {
2342 Assert(attnum <= heap_rel->rd_att->natts);
2343 attform = TupleDescAttr(heap_rel->rd_att, attnum - 1);
2344 }
2345 else
2346 attform = SystemAttributeDefinition(attnum);
2347 attname = pstrdup(NameStr(attform->attname));
2348
2349 if (i < index_form->indnkeyatts)
2350 {
2351 /*
2352 * Insist on default opclass, collation, and sort options.
2353 * While the index would still work as a constraint with
2354 * non-default settings, it might not provide exactly the same
2355 * uniqueness semantics as you'd get from a normally-created
2356 * constraint; and there's also the dump/reload problem
2357 * mentioned above.
2358 */
2359 Datum attoptions =
2360 get_attoptions(RelationGetRelid(index_rel), i + 1);
2361
2362 defopclass = GetDefaultOpClass(attform->atttypid,
2363 index_rel->rd_rel->relam);
2364 if (indclass->values[i] != defopclass ||
2365 attform->attcollation != index_rel->rd_indcollation[i] ||
2366 attoptions != (Datum) 0 ||
2367 index_rel->rd_indoption[i] != 0)
2368 ereport(ERROR,
2369 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2370 errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
2371 errdetail("Cannot create a primary key or unique constraint using such an index."),
2372 parser_errposition(cxt->pstate, constraint->location)));
2373
2374 constraint->keys = lappend(constraint->keys, makeString(attname));
2375 }
2376 else
2377 constraint->including = lappend(constraint->including, makeString(attname));
2378 }
2379
2380 /* Close the index relation but keep the lock */
2381 relation_close(index_rel, NoLock);
2382
2383 index->indexOid = index_oid;
2384 }
2385
2386 /*
2387 * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
2388 * IndexElems and operator names. We have to break that apart into
2389 * separate lists.
2390 */
2391 if (constraint->contype == CONSTR_EXCLUSION)
2392 {
2393 foreach(lc, constraint->exclusions)
2394 {
2395 List *pair = (List *) lfirst(lc);
2396 IndexElem *elem;
2397 List *opname;
2398
2399 Assert(list_length(pair) == 2);
2400 elem = linitial_node(IndexElem, pair);
2401 opname = lsecond_node(List, pair);
2402
2403 index->indexParams = lappend(index->indexParams, elem);
2404 index->excludeOpNames = lappend(index->excludeOpNames, opname);
2405 }
2406 }
2407
2408 /*
2409 * For UNIQUE and PRIMARY KEY, we just have a list of column names.
2410 *
2411 * Make sure referenced keys exist. If we are making a PRIMARY KEY index,
2412 * also make sure they are NOT NULL.
2413 */
2414 else
2415 {
2416 foreach(lc, constraint->keys)
2417 {
2418 char *key = strVal(lfirst(lc));
2419 bool found = false;
2420 bool forced_not_null = false;
2421 ColumnDef *column = NULL;
2422 ListCell *columns;
2423 IndexElem *iparam;
2424
2425 /* Make sure referenced column exists. */
2426 foreach(columns, cxt->columns)
2427 {
2428 column = castNode(ColumnDef, lfirst(columns));
2429 if (strcmp(column->colname, key) == 0)
2430 {
2431 found = true;
2432 break;
2433 }
2434 }
2435 if (found)
2436 {
2437 /*
2438 * column is defined in the new table. For PRIMARY KEY, we
2439 * can apply the NOT NULL constraint cheaply here ... unless
2440 * the column is marked is_from_type, in which case marking it
2441 * here would be ineffective (see MergeAttributes).
2442 */
2443 if (constraint->contype == CONSTR_PRIMARY &&
2444 !column->is_from_type)
2445 {
2446 column->is_not_null = true;
2447 forced_not_null = true;
2448 }
2449 }
2450 else if (SystemAttributeByName(key) != NULL)
2451 {
2452 /*
2453 * column will be a system column in the new table, so accept
2454 * it. System columns can't ever be null, so no need to worry
2455 * about PRIMARY/NOT NULL constraint.
2456 */
2457 found = true;
2458 }
2459 else if (cxt->inhRelations)
2460 {
2461 /* try inherited tables */
2462 ListCell *inher;
2463
2464 foreach(inher, cxt->inhRelations)
2465 {
2466 RangeVar *inh = castNode(RangeVar, lfirst(inher));
2467 Relation rel;
2468 int count;
2469
2470 rel = table_openrv(inh, AccessShareLock);
2471 /* check user requested inheritance from valid relkind */
2472 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2473 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2474 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2475 ereport(ERROR,
2476 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2477 errmsg("inherited relation \"%s\" is not a table or foreign table",
2478 inh->relname)));
2479 for (count = 0; count < rel->rd_att->natts; count++)
2480 {
2481 Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
2482 count);
2483 char *inhname = NameStr(inhattr->attname);
2484
2485 if (inhattr->attisdropped)
2486 continue;
2487 if (strcmp(key, inhname) == 0)
2488 {
2489 found = true;
2490
2491 /*
2492 * It's tempting to set forced_not_null if the
2493 * parent column is already NOT NULL, but that
2494 * seems unsafe because the column's NOT NULL
2495 * marking might disappear between now and
2496 * execution. Do the runtime check to be safe.
2497 */
2498 break;
2499 }
2500 }
2501 table_close(rel, NoLock);
2502 if (found)
2503 break;
2504 }
2505 }
2506
2507 /*
2508 * In the ALTER TABLE case, don't complain about index keys not
2509 * created in the command; they may well exist already.
2510 * DefineIndex will complain about them if not.
2511 */
2512 if (!found && !cxt->isalter)
2513 ereport(ERROR,
2514 (errcode(ERRCODE_UNDEFINED_COLUMN),
2515 errmsg("column \"%s\" named in key does not exist", key),
2516 parser_errposition(cxt->pstate, constraint->location)));
2517
2518 /* Check for PRIMARY KEY(foo, foo) */
2519 foreach(columns, index->indexParams)
2520 {
2521 iparam = (IndexElem *) lfirst(columns);
2522 if (iparam->name && strcmp(key, iparam->name) == 0)
2523 {
2524 if (index->primary)
2525 ereport(ERROR,
2526 (errcode(ERRCODE_DUPLICATE_COLUMN),
2527 errmsg("column \"%s\" appears twice in primary key constraint",
2528 key),
2529 parser_errposition(cxt->pstate, constraint->location)));
2530 else
2531 ereport(ERROR,
2532 (errcode(ERRCODE_DUPLICATE_COLUMN),
2533 errmsg("column \"%s\" appears twice in unique constraint",
2534 key),
2535 parser_errposition(cxt->pstate, constraint->location)));
2536 }
2537 }
2538
2539 /* OK, add it to the index definition */
2540 iparam = makeNode(IndexElem);
2541 iparam->name = pstrdup(key);
2542 iparam->expr = NULL;
2543 iparam->indexcolname = NULL;
2544 iparam->collation = NIL;
2545 iparam->opclass = NIL;
2546 iparam->opclassopts = NIL;
2547 iparam->ordering = SORTBY_DEFAULT;
2548 iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
2549 index->indexParams = lappend(index->indexParams, iparam);
2550
2551 /*
2552 * For a primary-key column, also create an item for ALTER TABLE
2553 * SET NOT NULL if we couldn't ensure it via is_not_null above.
2554 */
2555 if (constraint->contype == CONSTR_PRIMARY && !forced_not_null)
2556 {
2557 AlterTableCmd *notnullcmd = makeNode(AlterTableCmd);
2558
2559 notnullcmd->subtype = AT_SetNotNull;
2560 notnullcmd->name = pstrdup(key);
2561 notnullcmds = lappend(notnullcmds, notnullcmd);
2562 }
2563 }
2564 }
2565
2566 /*
2567 * Add included columns to index definition. This is much like the
2568 * simple-column-name-list code above, except that we don't worry about
2569 * NOT NULL marking; included columns in a primary key should not be
2570 * forced NOT NULL. We don't complain about duplicate columns, either,
2571 * though maybe we should?
2572 */
2573 foreach(lc, constraint->including)
2574 {
2575 char *key = strVal(lfirst(lc));
2576 bool found = false;
2577 ColumnDef *column = NULL;
2578 ListCell *columns;
2579 IndexElem *iparam;
2580
2581 foreach(columns, cxt->columns)
2582 {
2583 column = lfirst_node(ColumnDef, columns);
2584 if (strcmp(column->colname, key) == 0)
2585 {
2586 found = true;
2587 break;
2588 }
2589 }
2590
2591 if (!found)
2592 {
2593 if (SystemAttributeByName(key) != NULL)
2594 {
2595 /*
2596 * column will be a system column in the new table, so accept
2597 * it.
2598 */
2599 found = true;
2600 }
2601 else if (cxt->inhRelations)
2602 {
2603 /* try inherited tables */
2604 ListCell *inher;
2605
2606 foreach(inher, cxt->inhRelations)
2607 {
2608 RangeVar *inh = lfirst_node(RangeVar, inher);
2609 Relation rel;
2610 int count;
2611
2612 rel = table_openrv(inh, AccessShareLock);
2613 /* check user requested inheritance from valid relkind */
2614 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2615 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
2616 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2617 ereport(ERROR,
2618 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2619 errmsg("inherited relation \"%s\" is not a table or foreign table",
2620 inh->relname)));
2621 for (count = 0; count < rel->rd_att->natts; count++)
2622 {
2623 Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
2624 count);
2625 char *inhname = NameStr(inhattr->attname);
2626
2627 if (inhattr->attisdropped)
2628 continue;
2629 if (strcmp(key, inhname) == 0)
2630 {
2631 found = true;
2632 break;
2633 }
2634 }
2635 table_close(rel, NoLock);
2636 if (found)
2637 break;
2638 }
2639 }
2640 }
2641
2642 /*
2643 * In the ALTER TABLE case, don't complain about index keys not
2644 * created in the command; they may well exist already. DefineIndex
2645 * will complain about them if not.
2646 */
2647 if (!found && !cxt->isalter)
2648 ereport(ERROR,
2649 (errcode(ERRCODE_UNDEFINED_COLUMN),
2650 errmsg("column \"%s\" named in key does not exist", key),
2651 parser_errposition(cxt->pstate, constraint->location)));
2652
2653 /* OK, add it to the index definition */
2654 iparam = makeNode(IndexElem);
2655 iparam->name = pstrdup(key);
2656 iparam->expr = NULL;
2657 iparam->indexcolname = NULL;
2658 iparam->collation = NIL;
2659 iparam->opclass = NIL;
2660 iparam->opclassopts = NIL;
2661 index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
2662 }
2663
2664 /*
2665 * If we found anything that requires run-time SET NOT NULL, build a full
2666 * ALTER TABLE command for that and add it to cxt->alist.
2667 */
2668 if (notnullcmds)
2669 {
2670 AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
2671
2672 alterstmt->relation = copyObject(cxt->relation);
2673 alterstmt->cmds = notnullcmds;
2674 alterstmt->objtype = OBJECT_TABLE;
2675 alterstmt->missing_ok = false;
2676
2677 cxt->alist = lappend(cxt->alist, alterstmt);
2678 }
2679
2680 return index;
2681 }
2682
2683 /*
2684 * transformExtendedStatistics
2685 * Handle extended statistic objects
2686 *
2687 * Right now, there's nothing to do here, so we just append the list to
2688 * the existing "after" list.
2689 */
2690 static void
transformExtendedStatistics(CreateStmtContext * cxt)2691 transformExtendedStatistics(CreateStmtContext *cxt)
2692 {
2693 cxt->alist = list_concat(cxt->alist, cxt->extstats);
2694 }
2695
2696 /*
2697 * transformCheckConstraints
2698 * handle CHECK constraints
2699 *
2700 * Right now, there's nothing to do here when called from ALTER TABLE,
2701 * but the other constraint-transformation functions are called in both
2702 * the CREATE TABLE and ALTER TABLE paths, so do the same here, and just
2703 * don't do anything if we're not authorized to skip validation.
2704 */
2705 static void
transformCheckConstraints(CreateStmtContext * cxt,bool skipValidation)2706 transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
2707 {
2708 ListCell *ckclist;
2709
2710 if (cxt->ckconstraints == NIL)
2711 return;
2712
2713 /*
2714 * If creating a new table (but not a foreign table), we can safely skip
2715 * validation of check constraints, and nonetheless mark them valid. (This
2716 * will override any user-supplied NOT VALID flag.)
2717 */
2718 if (skipValidation)
2719 {
2720 foreach(ckclist, cxt->ckconstraints)
2721 {
2722 Constraint *constraint = (Constraint *) lfirst(ckclist);
2723
2724 constraint->skip_validation = true;
2725 constraint->initially_valid = true;
2726 }
2727 }
2728 }
2729
2730 /*
2731 * transformFKConstraints
2732 * handle FOREIGN KEY constraints
2733 */
2734 static void
transformFKConstraints(CreateStmtContext * cxt,bool skipValidation,bool isAddConstraint)2735 transformFKConstraints(CreateStmtContext *cxt,
2736 bool skipValidation, bool isAddConstraint)
2737 {
2738 ListCell *fkclist;
2739
2740 if (cxt->fkconstraints == NIL)
2741 return;
2742
2743 /*
2744 * If CREATE TABLE or adding a column with NULL default, we can safely
2745 * skip validation of FK constraints, and nonetheless mark them valid.
2746 * (This will override any user-supplied NOT VALID flag.)
2747 */
2748 if (skipValidation)
2749 {
2750 foreach(fkclist, cxt->fkconstraints)
2751 {
2752 Constraint *constraint = (Constraint *) lfirst(fkclist);
2753
2754 constraint->skip_validation = true;
2755 constraint->initially_valid = true;
2756 }
2757 }
2758
2759 /*
2760 * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
2761 * CONSTRAINT command to execute after the basic command is complete. (If
2762 * called from ADD CONSTRAINT, that routine will add the FK constraints to
2763 * its own subcommand list.)
2764 *
2765 * Note: the ADD CONSTRAINT command must also execute after any index
2766 * creation commands. Thus, this should run after
2767 * transformIndexConstraints, so that the CREATE INDEX commands are
2768 * already in cxt->alist. See also the handling of cxt->likeclauses.
2769 */
2770 if (!isAddConstraint)
2771 {
2772 AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
2773
2774 alterstmt->relation = cxt->relation;
2775 alterstmt->cmds = NIL;
2776 alterstmt->objtype = OBJECT_TABLE;
2777
2778 foreach(fkclist, cxt->fkconstraints)
2779 {
2780 Constraint *constraint = (Constraint *) lfirst(fkclist);
2781 AlterTableCmd *altercmd = makeNode(AlterTableCmd);
2782
2783 altercmd->subtype = AT_AddConstraint;
2784 altercmd->name = NULL;
2785 altercmd->def = (Node *) constraint;
2786 alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
2787 }
2788
2789 cxt->alist = lappend(cxt->alist, alterstmt);
2790 }
2791 }
2792
2793 /*
2794 * transformIndexStmt - parse analysis for CREATE INDEX and ALTER TABLE
2795 *
2796 * Note: this is a no-op for an index not using either index expressions or
2797 * a predicate expression. There are several code paths that create indexes
2798 * without bothering to call this, because they know they don't have any
2799 * such expressions to deal with.
2800 *
2801 * To avoid race conditions, it's important that this function rely only on
2802 * the passed-in relid (and not on stmt->relation) to determine the target
2803 * relation.
2804 */
2805 IndexStmt *
transformIndexStmt(Oid relid,IndexStmt * stmt,const char * queryString)2806 transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
2807 {
2808 ParseState *pstate;
2809 ParseNamespaceItem *nsitem;
2810 ListCell *l;
2811 Relation rel;
2812
2813 /* Nothing to do if statement already transformed. */
2814 if (stmt->transformed)
2815 return stmt;
2816
2817 /* Set up pstate */
2818 pstate = make_parsestate(NULL);
2819 pstate->p_sourcetext = queryString;
2820
2821 /*
2822 * Put the parent table into the rtable so that the expressions can refer
2823 * to its fields without qualification. Caller is responsible for locking
2824 * relation, but we still need to open it.
2825 */
2826 rel = relation_open(relid, NoLock);
2827 nsitem = addRangeTableEntryForRelation(pstate, rel,
2828 AccessShareLock,
2829 NULL, false, true);
2830
2831 /* no to join list, yes to namespaces */
2832 addNSItemToQuery(pstate, nsitem, false, true, true);
2833
2834 /* take care of the where clause */
2835 if (stmt->whereClause)
2836 {
2837 stmt->whereClause = transformWhereClause(pstate,
2838 stmt->whereClause,
2839 EXPR_KIND_INDEX_PREDICATE,
2840 "WHERE");
2841 /* we have to fix its collations too */
2842 assign_expr_collations(pstate, stmt->whereClause);
2843 }
2844
2845 /* take care of any index expressions */
2846 foreach(l, stmt->indexParams)
2847 {
2848 IndexElem *ielem = (IndexElem *) lfirst(l);
2849
2850 if (ielem->expr)
2851 {
2852 /* Extract preliminary index col name before transforming expr */
2853 if (ielem->indexcolname == NULL)
2854 ielem->indexcolname = FigureIndexColname(ielem->expr);
2855
2856 /* Now do parse transformation of the expression */
2857 ielem->expr = transformExpr(pstate, ielem->expr,
2858 EXPR_KIND_INDEX_EXPRESSION);
2859
2860 /* We have to fix its collations too */
2861 assign_expr_collations(pstate, ielem->expr);
2862
2863 /*
2864 * transformExpr() should have already rejected subqueries,
2865 * aggregates, window functions, and SRFs, based on the EXPR_KIND_
2866 * for an index expression.
2867 *
2868 * DefineIndex() will make more checks.
2869 */
2870 }
2871 }
2872
2873 /*
2874 * Check that only the base rel is mentioned. (This should be dead code
2875 * now that add_missing_from is history.)
2876 */
2877 if (list_length(pstate->p_rtable) != 1)
2878 ereport(ERROR,
2879 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2880 errmsg("index expressions and predicates can refer only to the table being indexed")));
2881
2882 free_parsestate(pstate);
2883
2884 /* Close relation */
2885 table_close(rel, NoLock);
2886
2887 /* Mark statement as successfully transformed */
2888 stmt->transformed = true;
2889
2890 return stmt;
2891 }
2892
2893 /*
2894 * transformStatsStmt - parse analysis for CREATE STATISTICS
2895 *
2896 * To avoid race conditions, it's important that this function relies only on
2897 * the passed-in relid (and not on stmt->relation) to determine the target
2898 * relation.
2899 */
2900 CreateStatsStmt *
transformStatsStmt(Oid relid,CreateStatsStmt * stmt,const char * queryString)2901 transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
2902 {
2903 ParseState *pstate;
2904 ParseNamespaceItem *nsitem;
2905 ListCell *l;
2906 Relation rel;
2907
2908 /* Nothing to do if statement already transformed. */
2909 if (stmt->transformed)
2910 return stmt;
2911
2912 /* Set up pstate */
2913 pstate = make_parsestate(NULL);
2914 pstate->p_sourcetext = queryString;
2915
2916 /*
2917 * Put the parent table into the rtable so that the expressions can refer
2918 * to its fields without qualification. Caller is responsible for locking
2919 * relation, but we still need to open it.
2920 */
2921 rel = relation_open(relid, NoLock);
2922 nsitem = addRangeTableEntryForRelation(pstate, rel,
2923 AccessShareLock,
2924 NULL, false, true);
2925
2926 /* no to join list, yes to namespaces */
2927 addNSItemToQuery(pstate, nsitem, false, true, true);
2928
2929 /* take care of any expressions */
2930 foreach(l, stmt->exprs)
2931 {
2932 StatsElem *selem = (StatsElem *) lfirst(l);
2933
2934 if (selem->expr)
2935 {
2936 /* Now do parse transformation of the expression */
2937 selem->expr = transformExpr(pstate, selem->expr,
2938 EXPR_KIND_STATS_EXPRESSION);
2939
2940 /* We have to fix its collations too */
2941 assign_expr_collations(pstate, selem->expr);
2942 }
2943 }
2944
2945 /*
2946 * Check that only the base rel is mentioned. (This should be dead code
2947 * now that add_missing_from is history.)
2948 */
2949 if (list_length(pstate->p_rtable) != 1)
2950 ereport(ERROR,
2951 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2952 errmsg("statistics expressions can refer only to the table being referenced")));
2953
2954 free_parsestate(pstate);
2955
2956 /* Close relation */
2957 table_close(rel, NoLock);
2958
2959 /* Mark statement as successfully transformed */
2960 stmt->transformed = true;
2961
2962 return stmt;
2963 }
2964
2965
2966 /*
2967 * transformRuleStmt -
2968 * transform a CREATE RULE Statement. The action is a list of parse
2969 * trees which is transformed into a list of query trees, and we also
2970 * transform the WHERE clause if any.
2971 *
2972 * actions and whereClause are output parameters that receive the
2973 * transformed results.
2974 */
2975 void
transformRuleStmt(RuleStmt * stmt,const char * queryString,List ** actions,Node ** whereClause)2976 transformRuleStmt(RuleStmt *stmt, const char *queryString,
2977 List **actions, Node **whereClause)
2978 {
2979 Relation rel;
2980 ParseState *pstate;
2981 ParseNamespaceItem *oldnsitem;
2982 ParseNamespaceItem *newnsitem;
2983
2984 /*
2985 * To avoid deadlock, make sure the first thing we do is grab
2986 * AccessExclusiveLock on the target relation. This will be needed by
2987 * DefineQueryRewrite(), and we don't want to grab a lesser lock
2988 * beforehand.
2989 */
2990 rel = table_openrv(stmt->relation, AccessExclusiveLock);
2991
2992 if (rel->rd_rel->relkind == RELKIND_MATVIEW)
2993 ereport(ERROR,
2994 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2995 errmsg("rules on materialized views are not supported")));
2996
2997 /* Set up pstate */
2998 pstate = make_parsestate(NULL);
2999 pstate->p_sourcetext = queryString;
3000
3001 /*
3002 * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
3003 * Set up their ParseNamespaceItems in the main pstate for use in parsing
3004 * the rule qualification.
3005 */
3006 oldnsitem = addRangeTableEntryForRelation(pstate, rel,
3007 AccessShareLock,
3008 makeAlias("old", NIL),
3009 false, false);
3010 newnsitem = addRangeTableEntryForRelation(pstate, rel,
3011 AccessShareLock,
3012 makeAlias("new", NIL),
3013 false, false);
3014 /* Must override addRangeTableEntry's default access-check flags */
3015 oldnsitem->p_rte->requiredPerms = 0;
3016 newnsitem->p_rte->requiredPerms = 0;
3017
3018 /*
3019 * They must be in the namespace too for lookup purposes, but only add the
3020 * one(s) that are relevant for the current kind of rule. In an UPDATE
3021 * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
3022 * there's no need to be so picky for INSERT & DELETE. We do not add them
3023 * to the joinlist.
3024 */
3025 switch (stmt->event)
3026 {
3027 case CMD_SELECT:
3028 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3029 break;
3030 case CMD_UPDATE:
3031 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3032 addNSItemToQuery(pstate, newnsitem, false, true, true);
3033 break;
3034 case CMD_INSERT:
3035 addNSItemToQuery(pstate, newnsitem, false, true, true);
3036 break;
3037 case CMD_DELETE:
3038 addNSItemToQuery(pstate, oldnsitem, false, true, true);
3039 break;
3040 default:
3041 elog(ERROR, "unrecognized event type: %d",
3042 (int) stmt->event);
3043 break;
3044 }
3045
3046 /* take care of the where clause */
3047 *whereClause = transformWhereClause(pstate,
3048 stmt->whereClause,
3049 EXPR_KIND_WHERE,
3050 "WHERE");
3051 /* we have to fix its collations too */
3052 assign_expr_collations(pstate, *whereClause);
3053
3054 /* this is probably dead code without add_missing_from: */
3055 if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
3056 ereport(ERROR,
3057 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3058 errmsg("rule WHERE condition cannot contain references to other relations")));
3059
3060 /*
3061 * 'instead nothing' rules with a qualification need a query rangetable so
3062 * the rewrite handler can add the negated rule qualification to the
3063 * original query. We create a query with the new command type CMD_NOTHING
3064 * here that is treated specially by the rewrite system.
3065 */
3066 if (stmt->actions == NIL)
3067 {
3068 Query *nothing_qry = makeNode(Query);
3069
3070 nothing_qry->commandType = CMD_NOTHING;
3071 nothing_qry->rtable = pstate->p_rtable;
3072 nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
3073
3074 *actions = list_make1(nothing_qry);
3075 }
3076 else
3077 {
3078 ListCell *l;
3079 List *newactions = NIL;
3080
3081 /*
3082 * transform each statement, like parse_sub_analyze()
3083 */
3084 foreach(l, stmt->actions)
3085 {
3086 Node *action = (Node *) lfirst(l);
3087 ParseState *sub_pstate = make_parsestate(NULL);
3088 Query *sub_qry,
3089 *top_subqry;
3090 bool has_old,
3091 has_new;
3092
3093 /*
3094 * Since outer ParseState isn't parent of inner, have to pass down
3095 * the query text by hand.
3096 */
3097 sub_pstate->p_sourcetext = queryString;
3098
3099 /*
3100 * Set up OLD/NEW in the rtable for this statement. The entries
3101 * are added only to relnamespace, not varnamespace, because we
3102 * don't want them to be referred to by unqualified field names
3103 * nor "*" in the rule actions. We decide later whether to put
3104 * them in the joinlist.
3105 */
3106 oldnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
3107 AccessShareLock,
3108 makeAlias("old", NIL),
3109 false, false);
3110 newnsitem = addRangeTableEntryForRelation(sub_pstate, rel,
3111 AccessShareLock,
3112 makeAlias("new", NIL),
3113 false, false);
3114 oldnsitem->p_rte->requiredPerms = 0;
3115 newnsitem->p_rte->requiredPerms = 0;
3116 addNSItemToQuery(sub_pstate, oldnsitem, false, true, false);
3117 addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
3118
3119 /* Transform the rule action statement */
3120 top_subqry = transformStmt(sub_pstate, action);
3121
3122 /*
3123 * We cannot support utility-statement actions (eg NOTIFY) with
3124 * nonempty rule WHERE conditions, because there's no way to make
3125 * the utility action execute conditionally.
3126 */
3127 if (top_subqry->commandType == CMD_UTILITY &&
3128 *whereClause != NULL)
3129 ereport(ERROR,
3130 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3131 errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
3132
3133 /*
3134 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
3135 * into the SELECT, and that's what we need to look at. (Ugly
3136 * kluge ... try to fix this when we redesign querytrees.)
3137 */
3138 sub_qry = getInsertSelectQuery(top_subqry, NULL);
3139
3140 /*
3141 * If the sub_qry is a setop, we cannot attach any qualifications
3142 * to it, because the planner won't notice them. This could
3143 * perhaps be relaxed someday, but for now, we may as well reject
3144 * such a rule immediately.
3145 */
3146 if (sub_qry->setOperations != NULL && *whereClause != NULL)
3147 ereport(ERROR,
3148 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3149 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3150
3151 /*
3152 * Validate action's use of OLD/NEW, qual too
3153 */
3154 has_old =
3155 rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
3156 rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
3157 has_new =
3158 rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
3159 rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
3160
3161 switch (stmt->event)
3162 {
3163 case CMD_SELECT:
3164 if (has_old)
3165 ereport(ERROR,
3166 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3167 errmsg("ON SELECT rule cannot use OLD")));
3168 if (has_new)
3169 ereport(ERROR,
3170 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3171 errmsg("ON SELECT rule cannot use NEW")));
3172 break;
3173 case CMD_UPDATE:
3174 /* both are OK */
3175 break;
3176 case CMD_INSERT:
3177 if (has_old)
3178 ereport(ERROR,
3179 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3180 errmsg("ON INSERT rule cannot use OLD")));
3181 break;
3182 case CMD_DELETE:
3183 if (has_new)
3184 ereport(ERROR,
3185 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3186 errmsg("ON DELETE rule cannot use NEW")));
3187 break;
3188 default:
3189 elog(ERROR, "unrecognized event type: %d",
3190 (int) stmt->event);
3191 break;
3192 }
3193
3194 /*
3195 * OLD/NEW are not allowed in WITH queries, because they would
3196 * amount to outer references for the WITH, which we disallow.
3197 * However, they were already in the outer rangetable when we
3198 * analyzed the query, so we have to check.
3199 *
3200 * Note that in the INSERT...SELECT case, we need to examine the
3201 * CTE lists of both top_subqry and sub_qry.
3202 *
3203 * Note that we aren't digging into the body of the query looking
3204 * for WITHs in nested sub-SELECTs. A WITH down there can
3205 * legitimately refer to OLD/NEW, because it'd be an
3206 * indirect-correlated outer reference.
3207 */
3208 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3209 PRS2_OLD_VARNO, 0) ||
3210 rangeTableEntry_used((Node *) sub_qry->cteList,
3211 PRS2_OLD_VARNO, 0))
3212 ereport(ERROR,
3213 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3214 errmsg("cannot refer to OLD within WITH query")));
3215 if (rangeTableEntry_used((Node *) top_subqry->cteList,
3216 PRS2_NEW_VARNO, 0) ||
3217 rangeTableEntry_used((Node *) sub_qry->cteList,
3218 PRS2_NEW_VARNO, 0))
3219 ereport(ERROR,
3220 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3221 errmsg("cannot refer to NEW within WITH query")));
3222
3223 /*
3224 * For efficiency's sake, add OLD to the rule action's jointree
3225 * only if it was actually referenced in the statement or qual.
3226 *
3227 * For INSERT, NEW is not really a relation (only a reference to
3228 * the to-be-inserted tuple) and should never be added to the
3229 * jointree.
3230 *
3231 * For UPDATE, we treat NEW as being another kind of reference to
3232 * OLD, because it represents references to *transformed* tuples
3233 * of the existing relation. It would be wrong to enter NEW
3234 * separately in the jointree, since that would cause a double
3235 * join of the updated relation. It's also wrong to fail to make
3236 * a jointree entry if only NEW and not OLD is mentioned.
3237 */
3238 if (has_old || (has_new && stmt->event == CMD_UPDATE))
3239 {
3240 RangeTblRef *rtr;
3241
3242 /*
3243 * If sub_qry is a setop, manipulating its jointree will do no
3244 * good at all, because the jointree is dummy. (This should be
3245 * a can't-happen case because of prior tests.)
3246 */
3247 if (sub_qry->setOperations != NULL)
3248 ereport(ERROR,
3249 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3250 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
3251 /* hackishly add OLD to the already-built FROM clause */
3252 rtr = makeNode(RangeTblRef);
3253 rtr->rtindex = oldnsitem->p_rtindex;
3254 sub_qry->jointree->fromlist =
3255 lappend(sub_qry->jointree->fromlist, rtr);
3256 }
3257
3258 newactions = lappend(newactions, top_subqry);
3259
3260 free_parsestate(sub_pstate);
3261 }
3262
3263 *actions = newactions;
3264 }
3265
3266 free_parsestate(pstate);
3267
3268 /* Close relation, but keep the exclusive lock */
3269 table_close(rel, NoLock);
3270 }
3271
3272
3273 /*
3274 * transformAlterTableStmt -
3275 * parse analysis for ALTER TABLE
3276 *
3277 * Returns the transformed AlterTableStmt. There may be additional actions
3278 * to be done before and after the transformed statement, which are returned
3279 * in *beforeStmts and *afterStmts as lists of utility command parsetrees.
3280 *
3281 * To avoid race conditions, it's important that this function rely only on
3282 * the passed-in relid (and not on stmt->relation) to determine the target
3283 * relation.
3284 */
3285 AlterTableStmt *
transformAlterTableStmt(Oid relid,AlterTableStmt * stmt,const char * queryString,List ** beforeStmts,List ** afterStmts)3286 transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
3287 const char *queryString,
3288 List **beforeStmts, List **afterStmts)
3289 {
3290 Relation rel;
3291 TupleDesc tupdesc;
3292 ParseState *pstate;
3293 CreateStmtContext cxt;
3294 List *save_alist;
3295 ListCell *lcmd,
3296 *l;
3297 List *newcmds = NIL;
3298 bool skipValidation = true;
3299 AlterTableCmd *newcmd;
3300 ParseNamespaceItem *nsitem;
3301
3302 /* Caller is responsible for locking the relation */
3303 rel = relation_open(relid, NoLock);
3304 tupdesc = RelationGetDescr(rel);
3305
3306 /* Set up pstate */
3307 pstate = make_parsestate(NULL);
3308 pstate->p_sourcetext = queryString;
3309 nsitem = addRangeTableEntryForRelation(pstate,
3310 rel,
3311 AccessShareLock,
3312 NULL,
3313 false,
3314 true);
3315 addNSItemToQuery(pstate, nsitem, false, true, true);
3316
3317 /* Set up CreateStmtContext */
3318 cxt.pstate = pstate;
3319 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3320 {
3321 cxt.stmtType = "ALTER FOREIGN TABLE";
3322 cxt.isforeign = true;
3323 }
3324 else
3325 {
3326 cxt.stmtType = "ALTER TABLE";
3327 cxt.isforeign = false;
3328 }
3329 cxt.relation = stmt->relation;
3330 cxt.rel = rel;
3331 cxt.inhRelations = NIL;
3332 cxt.isalter = true;
3333 cxt.columns = NIL;
3334 cxt.ckconstraints = NIL;
3335 cxt.fkconstraints = NIL;
3336 cxt.ixconstraints = NIL;
3337 cxt.likeclauses = NIL;
3338 cxt.extstats = NIL;
3339 cxt.blist = NIL;
3340 cxt.alist = NIL;
3341 cxt.pkey = NULL;
3342 cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
3343 cxt.partbound = NULL;
3344 cxt.ofType = false;
3345
3346 /*
3347 * Transform ALTER subcommands that need it (most don't). These largely
3348 * re-use code from CREATE TABLE.
3349 */
3350 foreach(lcmd, stmt->cmds)
3351 {
3352 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3353
3354 switch (cmd->subtype)
3355 {
3356 case AT_AddColumn:
3357 case AT_AddColumnRecurse:
3358 {
3359 ColumnDef *def = castNode(ColumnDef, cmd->def);
3360
3361 transformColumnDefinition(&cxt, def);
3362
3363 /*
3364 * If the column has a non-null default, we can't skip
3365 * validation of foreign keys.
3366 */
3367 if (def->raw_default != NULL)
3368 skipValidation = false;
3369
3370 /*
3371 * All constraints are processed in other ways. Remove the
3372 * original list
3373 */
3374 def->constraints = NIL;
3375
3376 newcmds = lappend(newcmds, cmd);
3377 break;
3378 }
3379
3380 case AT_AddConstraint:
3381 case AT_AddConstraintRecurse:
3382
3383 /*
3384 * The original AddConstraint cmd node doesn't go to newcmds
3385 */
3386 if (IsA(cmd->def, Constraint))
3387 {
3388 transformTableConstraint(&cxt, (Constraint *) cmd->def);
3389 if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
3390 skipValidation = false;
3391 }
3392 else
3393 elog(ERROR, "unrecognized node type: %d",
3394 (int) nodeTag(cmd->def));
3395 break;
3396
3397 case AT_AlterColumnType:
3398 {
3399 ColumnDef *def = castNode(ColumnDef, cmd->def);
3400 AttrNumber attnum;
3401
3402 /*
3403 * For ALTER COLUMN TYPE, transform the USING clause if
3404 * one was specified.
3405 */
3406 if (def->raw_default)
3407 {
3408 def->cooked_default =
3409 transformExpr(pstate, def->raw_default,
3410 EXPR_KIND_ALTER_COL_TRANSFORM);
3411 }
3412
3413 /*
3414 * For identity column, create ALTER SEQUENCE command to
3415 * change the data type of the sequence.
3416 */
3417 attnum = get_attnum(relid, cmd->name);
3418 if (attnum == InvalidAttrNumber)
3419 ereport(ERROR,
3420 (errcode(ERRCODE_UNDEFINED_COLUMN),
3421 errmsg("column \"%s\" of relation \"%s\" does not exist",
3422 cmd->name, RelationGetRelationName(rel))));
3423
3424 if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
3425 {
3426 Oid seq_relid = getIdentitySequence(relid, attnum, false);
3427 Oid typeOid = typenameTypeId(pstate, def->typeName);
3428 AlterSeqStmt *altseqstmt = makeNode(AlterSeqStmt);
3429
3430 altseqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
3431 get_rel_name(seq_relid),
3432 -1);
3433 altseqstmt->options = list_make1(makeDefElem("as", (Node *) makeTypeNameFromOid(typeOid, -1), -1));
3434 altseqstmt->for_identity = true;
3435 cxt.blist = lappend(cxt.blist, altseqstmt);
3436 }
3437
3438 newcmds = lappend(newcmds, cmd);
3439 break;
3440 }
3441
3442 case AT_AddIdentity:
3443 {
3444 Constraint *def = castNode(Constraint, cmd->def);
3445 ColumnDef *newdef = makeNode(ColumnDef);
3446 AttrNumber attnum;
3447
3448 newdef->colname = cmd->name;
3449 newdef->identity = def->generated_when;
3450 cmd->def = (Node *) newdef;
3451
3452 attnum = get_attnum(relid, cmd->name);
3453 if (attnum == InvalidAttrNumber)
3454 ereport(ERROR,
3455 (errcode(ERRCODE_UNDEFINED_COLUMN),
3456 errmsg("column \"%s\" of relation \"%s\" does not exist",
3457 cmd->name, RelationGetRelationName(rel))));
3458
3459 generateSerialExtraStmts(&cxt, newdef,
3460 get_atttype(relid, attnum),
3461 def->options, true, true,
3462 NULL, NULL);
3463
3464 newcmds = lappend(newcmds, cmd);
3465 break;
3466 }
3467
3468 case AT_SetIdentity:
3469 {
3470 /*
3471 * Create an ALTER SEQUENCE statement for the internal
3472 * sequence of the identity column.
3473 */
3474 ListCell *lc;
3475 List *newseqopts = NIL;
3476 List *newdef = NIL;
3477 AttrNumber attnum;
3478 Oid seq_relid;
3479
3480 /*
3481 * Split options into those handled by ALTER SEQUENCE and
3482 * those for ALTER TABLE proper.
3483 */
3484 foreach(lc, castNode(List, cmd->def))
3485 {
3486 DefElem *def = lfirst_node(DefElem, lc);
3487
3488 if (strcmp(def->defname, "generated") == 0)
3489 newdef = lappend(newdef, def);
3490 else
3491 newseqopts = lappend(newseqopts, def);
3492 }
3493
3494 attnum = get_attnum(relid, cmd->name);
3495 if (attnum == InvalidAttrNumber)
3496 ereport(ERROR,
3497 (errcode(ERRCODE_UNDEFINED_COLUMN),
3498 errmsg("column \"%s\" of relation \"%s\" does not exist",
3499 cmd->name, RelationGetRelationName(rel))));
3500
3501 seq_relid = getIdentitySequence(relid, attnum, true);
3502
3503 if (seq_relid)
3504 {
3505 AlterSeqStmt *seqstmt;
3506
3507 seqstmt = makeNode(AlterSeqStmt);
3508 seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
3509 get_rel_name(seq_relid), -1);
3510 seqstmt->options = newseqopts;
3511 seqstmt->for_identity = true;
3512 seqstmt->missing_ok = false;
3513
3514 cxt.blist = lappend(cxt.blist, seqstmt);
3515 }
3516
3517 /*
3518 * If column was not an identity column, we just let the
3519 * ALTER TABLE command error out later. (There are cases
3520 * this fails to cover, but we'll need to restructure
3521 * where creation of the sequence dependency linkage
3522 * happens before we can fix it.)
3523 */
3524
3525 cmd->def = (Node *) newdef;
3526 newcmds = lappend(newcmds, cmd);
3527 break;
3528 }
3529
3530 case AT_AttachPartition:
3531 case AT_DetachPartition:
3532 {
3533 PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
3534
3535 transformPartitionCmd(&cxt, partcmd);
3536 /* assign transformed value of the partition bound */
3537 partcmd->bound = cxt.partbound;
3538 }
3539
3540 newcmds = lappend(newcmds, cmd);
3541 break;
3542
3543 default:
3544
3545 /*
3546 * Currently, we shouldn't actually get here for subcommand
3547 * types that don't require transformation; but if we do, just
3548 * emit them unchanged.
3549 */
3550 newcmds = lappend(newcmds, cmd);
3551 break;
3552 }
3553 }
3554
3555 /*
3556 * Transfer anything we already have in cxt.alist into save_alist, to keep
3557 * it separate from the output of transformIndexConstraints.
3558 */
3559 save_alist = cxt.alist;
3560 cxt.alist = NIL;
3561
3562 /* Postprocess constraints */
3563 transformIndexConstraints(&cxt);
3564 transformFKConstraints(&cxt, skipValidation, true);
3565 transformCheckConstraints(&cxt, false);
3566
3567 /*
3568 * Push any index-creation commands into the ALTER, so that they can be
3569 * scheduled nicely by tablecmds.c. Note that tablecmds.c assumes that
3570 * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
3571 * subcommand has already been through transformIndexStmt.
3572 */
3573 foreach(l, cxt.alist)
3574 {
3575 Node *istmt = (Node *) lfirst(l);
3576
3577 /*
3578 * We assume here that cxt.alist contains only IndexStmts and possibly
3579 * ALTER TABLE SET NOT NULL statements generated from primary key
3580 * constraints. We absorb the subcommands of the latter directly.
3581 */
3582 if (IsA(istmt, IndexStmt))
3583 {
3584 IndexStmt *idxstmt = (IndexStmt *) istmt;
3585
3586 idxstmt = transformIndexStmt(relid, idxstmt, queryString);
3587 newcmd = makeNode(AlterTableCmd);
3588 newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex;
3589 newcmd->def = (Node *) idxstmt;
3590 newcmds = lappend(newcmds, newcmd);
3591 }
3592 else if (IsA(istmt, AlterTableStmt))
3593 {
3594 AlterTableStmt *alterstmt = (AlterTableStmt *) istmt;
3595
3596 newcmds = list_concat(newcmds, alterstmt->cmds);
3597 }
3598 else
3599 elog(ERROR, "unexpected stmt type %d", (int) nodeTag(istmt));
3600 }
3601 cxt.alist = NIL;
3602
3603 /* Append any CHECK or FK constraints to the commands list */
3604 foreach(l, cxt.ckconstraints)
3605 {
3606 newcmd = makeNode(AlterTableCmd);
3607 newcmd->subtype = AT_AddConstraint;
3608 newcmd->def = (Node *) lfirst(l);
3609 newcmds = lappend(newcmds, newcmd);
3610 }
3611 foreach(l, cxt.fkconstraints)
3612 {
3613 newcmd = makeNode(AlterTableCmd);
3614 newcmd->subtype = AT_AddConstraint;
3615 newcmd->def = (Node *) lfirst(l);
3616 newcmds = lappend(newcmds, newcmd);
3617 }
3618
3619 /* Append extended statistics objects */
3620 transformExtendedStatistics(&cxt);
3621
3622 /* Close rel */
3623 relation_close(rel, NoLock);
3624
3625 /*
3626 * Output results.
3627 */
3628 stmt->cmds = newcmds;
3629
3630 *beforeStmts = cxt.blist;
3631 *afterStmts = list_concat(cxt.alist, save_alist);
3632
3633 return stmt;
3634 }
3635
3636
3637 /*
3638 * Preprocess a list of column constraint clauses
3639 * to attach constraint attributes to their primary constraint nodes
3640 * and detect inconsistent/misplaced constraint attributes.
3641 *
3642 * NOTE: currently, attributes are only supported for FOREIGN KEY, UNIQUE,
3643 * EXCLUSION, and PRIMARY KEY constraints, but someday they ought to be
3644 * supported for other constraint types.
3645 */
3646 static void
transformConstraintAttrs(CreateStmtContext * cxt,List * constraintList)3647 transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList)
3648 {
3649 Constraint *lastprimarycon = NULL;
3650 bool saw_deferrability = false;
3651 bool saw_initially = false;
3652 ListCell *clist;
3653
3654 #define SUPPORTS_ATTRS(node) \
3655 ((node) != NULL && \
3656 ((node)->contype == CONSTR_PRIMARY || \
3657 (node)->contype == CONSTR_UNIQUE || \
3658 (node)->contype == CONSTR_EXCLUSION || \
3659 (node)->contype == CONSTR_FOREIGN))
3660
3661 foreach(clist, constraintList)
3662 {
3663 Constraint *con = (Constraint *) lfirst(clist);
3664
3665 if (!IsA(con, Constraint))
3666 elog(ERROR, "unrecognized node type: %d",
3667 (int) nodeTag(con));
3668 switch (con->contype)
3669 {
3670 case CONSTR_ATTR_DEFERRABLE:
3671 if (!SUPPORTS_ATTRS(lastprimarycon))
3672 ereport(ERROR,
3673 (errcode(ERRCODE_SYNTAX_ERROR),
3674 errmsg("misplaced DEFERRABLE clause"),
3675 parser_errposition(cxt->pstate, con->location)));
3676 if (saw_deferrability)
3677 ereport(ERROR,
3678 (errcode(ERRCODE_SYNTAX_ERROR),
3679 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
3680 parser_errposition(cxt->pstate, con->location)));
3681 saw_deferrability = true;
3682 lastprimarycon->deferrable = true;
3683 break;
3684
3685 case CONSTR_ATTR_NOT_DEFERRABLE:
3686 if (!SUPPORTS_ATTRS(lastprimarycon))
3687 ereport(ERROR,
3688 (errcode(ERRCODE_SYNTAX_ERROR),
3689 errmsg("misplaced NOT DEFERRABLE clause"),
3690 parser_errposition(cxt->pstate, con->location)));
3691 if (saw_deferrability)
3692 ereport(ERROR,
3693 (errcode(ERRCODE_SYNTAX_ERROR),
3694 errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
3695 parser_errposition(cxt->pstate, con->location)));
3696 saw_deferrability = true;
3697 lastprimarycon->deferrable = false;
3698 if (saw_initially &&
3699 lastprimarycon->initdeferred)
3700 ereport(ERROR,
3701 (errcode(ERRCODE_SYNTAX_ERROR),
3702 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
3703 parser_errposition(cxt->pstate, con->location)));
3704 break;
3705
3706 case CONSTR_ATTR_DEFERRED:
3707 if (!SUPPORTS_ATTRS(lastprimarycon))
3708 ereport(ERROR,
3709 (errcode(ERRCODE_SYNTAX_ERROR),
3710 errmsg("misplaced INITIALLY DEFERRED clause"),
3711 parser_errposition(cxt->pstate, con->location)));
3712 if (saw_initially)
3713 ereport(ERROR,
3714 (errcode(ERRCODE_SYNTAX_ERROR),
3715 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
3716 parser_errposition(cxt->pstate, con->location)));
3717 saw_initially = true;
3718 lastprimarycon->initdeferred = true;
3719
3720 /*
3721 * If only INITIALLY DEFERRED appears, assume DEFERRABLE
3722 */
3723 if (!saw_deferrability)
3724 lastprimarycon->deferrable = true;
3725 else if (!lastprimarycon->deferrable)
3726 ereport(ERROR,
3727 (errcode(ERRCODE_SYNTAX_ERROR),
3728 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
3729 parser_errposition(cxt->pstate, con->location)));
3730 break;
3731
3732 case CONSTR_ATTR_IMMEDIATE:
3733 if (!SUPPORTS_ATTRS(lastprimarycon))
3734 ereport(ERROR,
3735 (errcode(ERRCODE_SYNTAX_ERROR),
3736 errmsg("misplaced INITIALLY IMMEDIATE clause"),
3737 parser_errposition(cxt->pstate, con->location)));
3738 if (saw_initially)
3739 ereport(ERROR,
3740 (errcode(ERRCODE_SYNTAX_ERROR),
3741 errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
3742 parser_errposition(cxt->pstate, con->location)));
3743 saw_initially = true;
3744 lastprimarycon->initdeferred = false;
3745 break;
3746
3747 default:
3748 /* Otherwise it's not an attribute */
3749 lastprimarycon = con;
3750 /* reset flags for new primary node */
3751 saw_deferrability = false;
3752 saw_initially = false;
3753 break;
3754 }
3755 }
3756 }
3757
3758 /*
3759 * Special handling of type definition for a column
3760 */
3761 static void
transformColumnType(CreateStmtContext * cxt,ColumnDef * column)3762 transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
3763 {
3764 /*
3765 * All we really need to do here is verify that the type is valid,
3766 * including any collation spec that might be present.
3767 */
3768 Type ctype = typenameType(cxt->pstate, column->typeName, NULL);
3769
3770 if (column->collClause)
3771 {
3772 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
3773
3774 LookupCollation(cxt->pstate,
3775 column->collClause->collname,
3776 column->collClause->location);
3777 /* Complain if COLLATE is applied to an uncollatable type */
3778 if (!OidIsValid(typtup->typcollation))
3779 ereport(ERROR,
3780 (errcode(ERRCODE_DATATYPE_MISMATCH),
3781 errmsg("collations are not supported by type %s",
3782 format_type_be(typtup->oid)),
3783 parser_errposition(cxt->pstate,
3784 column->collClause->location)));
3785 }
3786
3787 ReleaseSysCache(ctype);
3788 }
3789
3790
3791 /*
3792 * transformCreateSchemaStmt -
3793 * analyzes the CREATE SCHEMA statement
3794 *
3795 * Split the schema element list into individual commands and place
3796 * them in the result list in an order such that there are no forward
3797 * references (e.g. GRANT to a table created later in the list). Note
3798 * that the logic we use for determining forward references is
3799 * presently quite incomplete.
3800 *
3801 * SQL also allows constraints to make forward references, so thumb through
3802 * the table columns and move forward references to a posterior alter-table
3803 * command.
3804 *
3805 * The result is a list of parse nodes that still need to be analyzed ---
3806 * but we can't analyze the later commands until we've executed the earlier
3807 * ones, because of possible inter-object references.
3808 *
3809 * Note: this breaks the rules a little bit by modifying schema-name fields
3810 * within passed-in structs. However, the transformation would be the same
3811 * if done over, so it should be all right to scribble on the input to this
3812 * extent.
3813 */
3814 List *
transformCreateSchemaStmt(CreateSchemaStmt * stmt)3815 transformCreateSchemaStmt(CreateSchemaStmt *stmt)
3816 {
3817 CreateSchemaStmtContext cxt;
3818 List *result;
3819 ListCell *elements;
3820
3821 cxt.stmtType = "CREATE SCHEMA";
3822 cxt.schemaname = stmt->schemaname;
3823 cxt.authrole = (RoleSpec *) stmt->authrole;
3824 cxt.sequences = NIL;
3825 cxt.tables = NIL;
3826 cxt.views = NIL;
3827 cxt.indexes = NIL;
3828 cxt.triggers = NIL;
3829 cxt.grants = NIL;
3830
3831 /*
3832 * Run through each schema element in the schema element list. Separate
3833 * statements by type, and do preliminary analysis.
3834 */
3835 foreach(elements, stmt->schemaElts)
3836 {
3837 Node *element = lfirst(elements);
3838
3839 switch (nodeTag(element))
3840 {
3841 case T_CreateSeqStmt:
3842 {
3843 CreateSeqStmt *elp = (CreateSeqStmt *) element;
3844
3845 setSchemaName(cxt.schemaname, &elp->sequence->schemaname);
3846 cxt.sequences = lappend(cxt.sequences, element);
3847 }
3848 break;
3849
3850 case T_CreateStmt:
3851 {
3852 CreateStmt *elp = (CreateStmt *) element;
3853
3854 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
3855
3856 /*
3857 * XXX todo: deal with constraints
3858 */
3859 cxt.tables = lappend(cxt.tables, element);
3860 }
3861 break;
3862
3863 case T_ViewStmt:
3864 {
3865 ViewStmt *elp = (ViewStmt *) element;
3866
3867 setSchemaName(cxt.schemaname, &elp->view->schemaname);
3868
3869 /*
3870 * XXX todo: deal with references between views
3871 */
3872 cxt.views = lappend(cxt.views, element);
3873 }
3874 break;
3875
3876 case T_IndexStmt:
3877 {
3878 IndexStmt *elp = (IndexStmt *) element;
3879
3880 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
3881 cxt.indexes = lappend(cxt.indexes, element);
3882 }
3883 break;
3884
3885 case T_CreateTrigStmt:
3886 {
3887 CreateTrigStmt *elp = (CreateTrigStmt *) element;
3888
3889 setSchemaName(cxt.schemaname, &elp->relation->schemaname);
3890 cxt.triggers = lappend(cxt.triggers, element);
3891 }
3892 break;
3893
3894 case T_GrantStmt:
3895 cxt.grants = lappend(cxt.grants, element);
3896 break;
3897
3898 default:
3899 elog(ERROR, "unrecognized node type: %d",
3900 (int) nodeTag(element));
3901 }
3902 }
3903
3904 result = NIL;
3905 result = list_concat(result, cxt.sequences);
3906 result = list_concat(result, cxt.tables);
3907 result = list_concat(result, cxt.views);
3908 result = list_concat(result, cxt.indexes);
3909 result = list_concat(result, cxt.triggers);
3910 result = list_concat(result, cxt.grants);
3911
3912 return result;
3913 }
3914
3915 /*
3916 * setSchemaName
3917 * Set or check schema name in an element of a CREATE SCHEMA command
3918 */
3919 static void
setSchemaName(char * context_schema,char ** stmt_schema_name)3920 setSchemaName(char *context_schema, char **stmt_schema_name)
3921 {
3922 if (*stmt_schema_name == NULL)
3923 *stmt_schema_name = context_schema;
3924 else if (strcmp(context_schema, *stmt_schema_name) != 0)
3925 ereport(ERROR,
3926 (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
3927 errmsg("CREATE specifies a schema (%s) "
3928 "different from the one being created (%s)",
3929 *stmt_schema_name, context_schema)));
3930 }
3931
3932 /*
3933 * transformPartitionCmd
3934 * Analyze the ATTACH/DETACH PARTITION command
3935 *
3936 * In case of the ATTACH PARTITION command, cxt->partbound is set to the
3937 * transformed value of cmd->bound.
3938 */
3939 static void
transformPartitionCmd(CreateStmtContext * cxt,PartitionCmd * cmd)3940 transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
3941 {
3942 Relation parentRel = cxt->rel;
3943
3944 switch (parentRel->rd_rel->relkind)
3945 {
3946 case RELKIND_PARTITIONED_TABLE:
3947 /* transform the partition bound, if any */
3948 Assert(RelationGetPartitionKey(parentRel) != NULL);
3949 if (cmd->bound != NULL)
3950 cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
3951 cmd->bound);
3952 break;
3953 case RELKIND_PARTITIONED_INDEX:
3954
3955 /*
3956 * A partitioned index cannot have a partition bound set. ALTER
3957 * INDEX prevents that with its grammar, but not ALTER TABLE.
3958 */
3959 if (cmd->bound != NULL)
3960 ereport(ERROR,
3961 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3962 errmsg("\"%s\" is not a partitioned table",
3963 RelationGetRelationName(parentRel))));
3964 break;
3965 case RELKIND_RELATION:
3966 /* the table must be partitioned */
3967 ereport(ERROR,
3968 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3969 errmsg("table \"%s\" is not partitioned",
3970 RelationGetRelationName(parentRel))));
3971 break;
3972 case RELKIND_INDEX:
3973 /* the index must be partitioned */
3974 ereport(ERROR,
3975 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3976 errmsg("index \"%s\" is not partitioned",
3977 RelationGetRelationName(parentRel))));
3978 break;
3979 default:
3980 /* parser shouldn't let this case through */
3981 elog(ERROR, "\"%s\" is not a partitioned table or index",
3982 RelationGetRelationName(parentRel));
3983 break;
3984 }
3985 }
3986
3987 /*
3988 * transformPartitionBound
3989 *
3990 * Transform a partition bound specification
3991 */
3992 PartitionBoundSpec *
transformPartitionBound(ParseState * pstate,Relation parent,PartitionBoundSpec * spec)3993 transformPartitionBound(ParseState *pstate, Relation parent,
3994 PartitionBoundSpec *spec)
3995 {
3996 PartitionBoundSpec *result_spec;
3997 PartitionKey key = RelationGetPartitionKey(parent);
3998 char strategy = get_partition_strategy(key);
3999 int partnatts = get_partition_natts(key);
4000 List *partexprs = get_partition_exprs(key);
4001
4002 /* Avoid scribbling on input */
4003 result_spec = copyObject(spec);
4004
4005 if (spec->is_default)
4006 {
4007 /*
4008 * Hash partitioning does not support a default partition; there's no
4009 * use case for it (since the set of partitions to create is perfectly
4010 * defined), and if users do get into it accidentally, it's hard to
4011 * back out from it afterwards.
4012 */
4013 if (strategy == PARTITION_STRATEGY_HASH)
4014 ereport(ERROR,
4015 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4016 errmsg("a hash-partitioned table may not have a default partition")));
4017
4018 /*
4019 * In case of the default partition, parser had no way to identify the
4020 * partition strategy. Assign the parent's strategy to the default
4021 * partition bound spec.
4022 */
4023 result_spec->strategy = strategy;
4024
4025 return result_spec;
4026 }
4027
4028 if (strategy == PARTITION_STRATEGY_HASH)
4029 {
4030 if (spec->strategy != PARTITION_STRATEGY_HASH)
4031 ereport(ERROR,
4032 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4033 errmsg("invalid bound specification for a hash partition"),
4034 parser_errposition(pstate, exprLocation((Node *) spec))));
4035
4036 if (spec->modulus <= 0)
4037 ereport(ERROR,
4038 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4039 errmsg("modulus for hash partition must be an integer value greater than zero")));
4040
4041 Assert(spec->remainder >= 0);
4042
4043 if (spec->remainder >= spec->modulus)
4044 ereport(ERROR,
4045 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4046 errmsg("remainder for hash partition must be less than modulus")));
4047 }
4048 else if (strategy == PARTITION_STRATEGY_LIST)
4049 {
4050 ListCell *cell;
4051 char *colname;
4052 Oid coltype;
4053 int32 coltypmod;
4054 Oid partcollation;
4055
4056 if (spec->strategy != PARTITION_STRATEGY_LIST)
4057 ereport(ERROR,
4058 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4059 errmsg("invalid bound specification for a list partition"),
4060 parser_errposition(pstate, exprLocation((Node *) spec))));
4061
4062 /* Get the only column's name in case we need to output an error */
4063 if (key->partattrs[0] != 0)
4064 colname = get_attname(RelationGetRelid(parent),
4065 key->partattrs[0], false);
4066 else
4067 colname = deparse_expression((Node *) linitial(partexprs),
4068 deparse_context_for(RelationGetRelationName(parent),
4069 RelationGetRelid(parent)),
4070 false, false);
4071 /* Need its type data too */
4072 coltype = get_partition_col_typid(key, 0);
4073 coltypmod = get_partition_col_typmod(key, 0);
4074 partcollation = get_partition_col_collation(key, 0);
4075
4076 result_spec->listdatums = NIL;
4077 foreach(cell, spec->listdatums)
4078 {
4079 Node *expr = lfirst(cell);
4080 Const *value;
4081 ListCell *cell2;
4082 bool duplicate;
4083
4084 value = transformPartitionBoundValue(pstate, expr,
4085 colname, coltype, coltypmod,
4086 partcollation);
4087
4088 /* Don't add to the result if the value is a duplicate */
4089 duplicate = false;
4090 foreach(cell2, result_spec->listdatums)
4091 {
4092 Const *value2 = castNode(Const, lfirst(cell2));
4093
4094 if (equal(value, value2))
4095 {
4096 duplicate = true;
4097 break;
4098 }
4099 }
4100 if (duplicate)
4101 continue;
4102
4103 result_spec->listdatums = lappend(result_spec->listdatums,
4104 value);
4105 }
4106 }
4107 else if (strategy == PARTITION_STRATEGY_RANGE)
4108 {
4109 if (spec->strategy != PARTITION_STRATEGY_RANGE)
4110 ereport(ERROR,
4111 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4112 errmsg("invalid bound specification for a range partition"),
4113 parser_errposition(pstate, exprLocation((Node *) spec))));
4114
4115 if (list_length(spec->lowerdatums) != partnatts)
4116 ereport(ERROR,
4117 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4118 errmsg("FROM must specify exactly one value per partitioning column")));
4119 if (list_length(spec->upperdatums) != partnatts)
4120 ereport(ERROR,
4121 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
4122 errmsg("TO must specify exactly one value per partitioning column")));
4123
4124 /*
4125 * Convert raw parse nodes into PartitionRangeDatum nodes and perform
4126 * any necessary validation.
4127 */
4128 result_spec->lowerdatums =
4129 transformPartitionRangeBounds(pstate, spec->lowerdatums,
4130 parent);
4131 result_spec->upperdatums =
4132 transformPartitionRangeBounds(pstate, spec->upperdatums,
4133 parent);
4134 }
4135 else
4136 elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
4137
4138 return result_spec;
4139 }
4140
4141 /*
4142 * transformPartitionRangeBounds
4143 * This converts the expressions for range partition bounds from the raw
4144 * grammar representation to PartitionRangeDatum structs
4145 */
4146 static List *
transformPartitionRangeBounds(ParseState * pstate,List * blist,Relation parent)4147 transformPartitionRangeBounds(ParseState *pstate, List *blist,
4148 Relation parent)
4149 {
4150 List *result = NIL;
4151 PartitionKey key = RelationGetPartitionKey(parent);
4152 List *partexprs = get_partition_exprs(key);
4153 ListCell *lc;
4154 int i,
4155 j;
4156
4157 i = j = 0;
4158 foreach(lc, blist)
4159 {
4160 Node *expr = lfirst(lc);
4161 PartitionRangeDatum *prd = NULL;
4162
4163 /*
4164 * Infinite range bounds -- "minvalue" and "maxvalue" -- get passed in
4165 * as ColumnRefs.
4166 */
4167 if (IsA(expr, ColumnRef))
4168 {
4169 ColumnRef *cref = (ColumnRef *) expr;
4170 char *cname = NULL;
4171
4172 /*
4173 * There should be a single field named either "minvalue" or
4174 * "maxvalue".
4175 */
4176 if (list_length(cref->fields) == 1 &&
4177 IsA(linitial(cref->fields), String))
4178 cname = strVal(linitial(cref->fields));
4179
4180 if (cname == NULL)
4181 {
4182 /*
4183 * ColumnRef is not in the desired single-field-name form. For
4184 * consistency between all partition strategies, let the
4185 * expression transformation report any errors rather than
4186 * doing it ourselves.
4187 */
4188 }
4189 else if (strcmp("minvalue", cname) == 0)
4190 {
4191 prd = makeNode(PartitionRangeDatum);
4192 prd->kind = PARTITION_RANGE_DATUM_MINVALUE;
4193 prd->value = NULL;
4194 }
4195 else if (strcmp("maxvalue", cname) == 0)
4196 {
4197 prd = makeNode(PartitionRangeDatum);
4198 prd->kind = PARTITION_RANGE_DATUM_MAXVALUE;
4199 prd->value = NULL;
4200 }
4201 }
4202
4203 if (prd == NULL)
4204 {
4205 char *colname;
4206 Oid coltype;
4207 int32 coltypmod;
4208 Oid partcollation;
4209 Const *value;
4210
4211 /* Get the column's name in case we need to output an error */
4212 if (key->partattrs[i] != 0)
4213 colname = get_attname(RelationGetRelid(parent),
4214 key->partattrs[i], false);
4215 else
4216 {
4217 colname = deparse_expression((Node *) list_nth(partexprs, j),
4218 deparse_context_for(RelationGetRelationName(parent),
4219 RelationGetRelid(parent)),
4220 false, false);
4221 ++j;
4222 }
4223
4224 /* Need its type data too */
4225 coltype = get_partition_col_typid(key, i);
4226 coltypmod = get_partition_col_typmod(key, i);
4227 partcollation = get_partition_col_collation(key, i);
4228
4229 value = transformPartitionBoundValue(pstate, expr,
4230 colname,
4231 coltype, coltypmod,
4232 partcollation);
4233 if (value->constisnull)
4234 ereport(ERROR,
4235 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4236 errmsg("cannot specify NULL in range bound")));
4237 prd = makeNode(PartitionRangeDatum);
4238 prd->kind = PARTITION_RANGE_DATUM_VALUE;
4239 prd->value = (Node *) value;
4240 ++i;
4241 }
4242
4243 prd->location = exprLocation(expr);
4244
4245 result = lappend(result, prd);
4246 }
4247
4248 /*
4249 * Once we see MINVALUE or MAXVALUE for one column, the remaining columns
4250 * must be the same.
4251 */
4252 validateInfiniteBounds(pstate, result);
4253
4254 return result;
4255 }
4256
4257 /*
4258 * validateInfiniteBounds
4259 *
4260 * Check that a MAXVALUE or MINVALUE specification in a partition bound is
4261 * followed only by more of the same.
4262 */
4263 static void
validateInfiniteBounds(ParseState * pstate,List * blist)4264 validateInfiniteBounds(ParseState *pstate, List *blist)
4265 {
4266 ListCell *lc;
4267 PartitionRangeDatumKind kind = PARTITION_RANGE_DATUM_VALUE;
4268
4269 foreach(lc, blist)
4270 {
4271 PartitionRangeDatum *prd = castNode(PartitionRangeDatum, lfirst(lc));
4272
4273 if (kind == prd->kind)
4274 continue;
4275
4276 switch (kind)
4277 {
4278 case PARTITION_RANGE_DATUM_VALUE:
4279 kind = prd->kind;
4280 break;
4281
4282 case PARTITION_RANGE_DATUM_MAXVALUE:
4283 ereport(ERROR,
4284 (errcode(ERRCODE_DATATYPE_MISMATCH),
4285 errmsg("every bound following MAXVALUE must also be MAXVALUE"),
4286 parser_errposition(pstate, exprLocation((Node *) prd))));
4287 break;
4288
4289 case PARTITION_RANGE_DATUM_MINVALUE:
4290 ereport(ERROR,
4291 (errcode(ERRCODE_DATATYPE_MISMATCH),
4292 errmsg("every bound following MINVALUE must also be MINVALUE"),
4293 parser_errposition(pstate, exprLocation((Node *) prd))));
4294 break;
4295 }
4296 }
4297 }
4298
4299 /*
4300 * Transform one entry in a partition bound spec, producing a constant.
4301 */
4302 static Const *
transformPartitionBoundValue(ParseState * pstate,Node * val,const char * colName,Oid colType,int32 colTypmod,Oid partCollation)4303 transformPartitionBoundValue(ParseState *pstate, Node *val,
4304 const char *colName, Oid colType, int32 colTypmod,
4305 Oid partCollation)
4306 {
4307 Node *value;
4308
4309 /* Transform raw parsetree */
4310 value = transformExpr(pstate, val, EXPR_KIND_PARTITION_BOUND);
4311
4312 /*
4313 * transformExpr() should have already rejected column references,
4314 * subqueries, aggregates, window functions, and SRFs, based on the
4315 * EXPR_KIND_ of a partition bound expression.
4316 */
4317 Assert(!contain_var_clause(value));
4318
4319 /*
4320 * Coerce to the correct type. This might cause an explicit coercion step
4321 * to be added on top of the expression, which must be evaluated before
4322 * returning the result to the caller.
4323 */
4324 value = coerce_to_target_type(pstate,
4325 value, exprType(value),
4326 colType,
4327 colTypmod,
4328 COERCION_ASSIGNMENT,
4329 COERCE_IMPLICIT_CAST,
4330 -1);
4331
4332 if (value == NULL)
4333 ereport(ERROR,
4334 (errcode(ERRCODE_DATATYPE_MISMATCH),
4335 errmsg("specified value cannot be cast to type %s for column \"%s\"",
4336 format_type_be(colType), colName),
4337 parser_errposition(pstate, exprLocation(val))));
4338
4339 /*
4340 * Evaluate the expression, if needed, assigning the partition key's data
4341 * type and collation to the resulting Const node.
4342 */
4343 if (!IsA(value, Const))
4344 {
4345 assign_expr_collations(pstate, value);
4346 value = (Node *) expression_planner((Expr *) value);
4347 value = (Node *) evaluate_expr((Expr *) value, colType, colTypmod,
4348 partCollation);
4349 if (!IsA(value, Const))
4350 elog(ERROR, "could not evaluate partition bound expression");
4351 }
4352 else
4353 {
4354 /*
4355 * If the expression is already a Const, as is often the case, we can
4356 * skip the rather expensive steps above. But we still have to insert
4357 * the right collation, since coerce_to_target_type doesn't handle
4358 * that.
4359 */
4360 ((Const *) value)->constcollid = partCollation;
4361 }
4362
4363 /*
4364 * Attach original expression's parse location to the Const, so that
4365 * that's what will be reported for any later errors related to this
4366 * partition bound.
4367 */
4368 ((Const *) value)->location = exprLocation(val);
4369
4370 return (Const *) value;
4371 }
4372