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