Coverage Report

Created: 2026-09-28 06:55

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