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