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