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