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