diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5790f87..6f5ffb3 100644 *** a/src/backend/catalog/index.c --- b/src/backend/catalog/index.c *************** *** 1420,1425 **** index_build(Relation heapRelation, --- 1420,1435 ---- procedure = indexRelation->rd_am->ambuild; Assert(RegProcedureIsValid(procedure)); + if (indexInfo->ii_ToastForRelName != NULL) + ereport(DEBUG1, + (errmsg("building TOAST index for table \"%s\"", + indexInfo->ii_ToastForRelName))); + else + ereport(DEBUG1, + (errmsg("building index \"%s\" on table \"%s\"", + RelationGetRelationName(indexRelation), + RelationGetRelationName(heapRelation)))); + /* * Switch to the table owner's userid, so that any index functions are run * as that user. Also lock down security-restricted operations and *************** *** 2412,2418 **** IndexGetRelation(Oid indexId) * reindex_index - This routine is used to recreate a single index */ void ! reindex_index(Oid indexId, bool skip_constraint_checks) { Relation iRel, heapRelation, --- 2422,2429 ---- * reindex_index - This routine is used to recreate a single index */ void ! reindex_index(Oid indexId, const char *toastFor, ! bool skip_constraint_checks) { Relation iRel, heapRelation, *************** *** 2470,2475 **** reindex_index(Oid indexId, bool skip_constraint_checks) --- 2481,2489 ---- indexInfo->ii_ExclusionStrats = NULL; } + /* Pass the name of relation this TOAST index serves, if any. */ + indexInfo->ii_ToastForRelName = toastFor; + /* We'll build a new physical relation for the index */ RelationSetNewRelfilenode(iRel, InvalidTransactionId); *************** *** 2529,2534 **** reindex_index(Oid indexId, bool skip_constraint_checks) --- 2543,2551 ---- * reindex_relation - This routine is used to recreate all indexes * of a relation (and optionally its toast relation too, if any). * + * If this is a TOAST relation, toastFor may bear the parent relation name, + * facilitating improved messages. + * * If heap_rebuilt is true, then the relation was just completely rebuilt by * an operation such as VACUUM FULL or CLUSTER, and therefore its indexes are * inconsistent with it. This makes things tricky if the relation is a system *************** *** 2548,2554 **** reindex_index(Oid indexId, bool skip_constraint_checks) * CommandCounterIncrement will occur after each index rebuild. */ bool ! reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt) { Relation rel; Oid toast_relid; --- 2565,2572 ---- * CommandCounterIncrement will occur after each index rebuild. */ bool ! reindex_relation(Oid relid, const char *toastFor, ! bool toast_too, bool heap_rebuilt) { Relation rel; Oid toast_relid; *************** *** 2625,2631 **** reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt) if (is_pg_class) RelationSetIndexList(rel, doneIndexes, InvalidOid); ! reindex_index(indexOid, heap_rebuilt); CommandCounterIncrement(); --- 2643,2649 ---- if (is_pg_class) RelationSetIndexList(rel, doneIndexes, InvalidOid); ! reindex_index(indexOid, toastFor, heap_rebuilt); CommandCounterIncrement(); *************** *** 2648,2658 **** reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt) if (is_pg_class) RelationSetIndexList(rel, indexIds, ClassOidIndexId); - /* - * Close rel, but continue to hold the lock. - */ - heap_close(rel, NoLock); - result = (indexIds != NIL); /* --- 2666,2671 ---- *************** *** 2660,2666 **** reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt) * still hold the lock on the master table. */ if (toast_too && OidIsValid(toast_relid)) ! result |= reindex_relation(toast_relid, false, false); return result; } --- 2673,2685 ---- * still hold the lock on the master table. */ if (toast_too && OidIsValid(toast_relid)) ! result |= reindex_relation(toast_relid, RelationGetRelationName(rel), ! false, false); ! ! /* ! * Close rel, but continue to hold the lock. ! */ ! heap_close(rel, NoLock); return result; } diff --git a/src/backend/catalog/tindex 142beae..031471b 100644 *** a/src/backend/catalog/toasting.c --- b/src/backend/catalog/toasting.c *************** *** 36,43 **** extern Oid binary_upgrade_next_toast_pg_class_oid; Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid; ! static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, ! Datum reloptions); static bool needs_toast_table(Relation rel); --- 36,43 ---- Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid; ! static bool create_toast_table(Relation rel, const char *finalRelName, ! Oid toastOid, Oid toastIndexOid, Datum reloptions); static bool needs_toast_table(Relation rel); *************** *** 46,51 **** static bool needs_toast_table(Relation rel); --- 46,54 ---- * If the table needs a toast table, and doesn't already have one, * then create a toast table for it. * + * make_new_heap fills finalRelName, so messages display the permanent table + * name, not the rewrite-temporary name. Most callers should pass NULL. + * * reloptions for the toast table can be passed, too. Pass (Datum) 0 * for default reloptions. * *************** *** 54,60 **** static bool needs_toast_table(Relation rel); * to end with CommandCounterIncrement if it makes any changes. */ void ! AlterTableCreateToastTable(Oid relOid, Datum reloptions) { Relation rel; --- 57,64 ---- * to end with CommandCounterIncrement if it makes any changes. */ void ! AlterTableCreateToastTable(Oid relOid, const char *finalRelName, ! Datum reloptions) { Relation rel; *************** *** 66,72 **** AlterTableCreateToastTable(Oid relOid, Datum reloptions) rel = heap_open(relOid, AccessExclusiveLock); /* create_toast_table does all the work */ ! (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions); heap_close(rel, NoLock); } --- 70,77 ---- rel = heap_open(relOid, AccessExclusiveLock); /* create_toast_table does all the work */ ! (void) create_toast_table(rel, finalRelName, ! InvalidOid, InvalidOid, reloptions); heap_close(rel, NoLock); } *************** *** 92,98 **** BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) relName))); /* create_toast_table does all the work */ ! if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0)) elog(ERROR, "\"%s\" does not require a toast table", relName); --- 97,103 ---- relName))); /* create_toast_table does all the work */ ! if (!create_toast_table(rel, NULL, toastOid, toastIndexOid, (Datum) 0)) elog(ERROR, "\"%s\" does not require a toast table", relName); *************** *** 104,114 **** BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) * create_toast_table --- internal workhorse * * rel is already opened and exclusive-locked * toastOid and toastIndexOid are normally InvalidOid, but during * bootstrap they can be nonzero to specify hand-assigned OIDs */ static bool ! create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions) { Oid relOid = RelationGetRelid(rel); HeapTuple reltup; --- 109,121 ---- * create_toast_table --- internal workhorse * * rel is already opened and exclusive-locked + * finalRelName is normally NULL; make_new_heap overrides it * toastOid and toastIndexOid are normally InvalidOid, but during * bootstrap they can be nonzero to specify hand-assigned OIDs */ static bool ! create_toast_table(Relation rel, const char *finalRelName, ! Oid toastOid, Oid toastIndexOid, Datum reloptions) { Oid relOid = RelationGetRelid(rel); HeapTuple reltup; *************** *** 255,260 **** create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio --- 262,269 ---- indexInfo->ii_ExclusionOps = NULL; indexInfo->ii_ExclusionProcs = NULL; indexInfo->ii_ExclusionStrats = NULL; + indexInfo->ii_ToastForRelName + = finalRelName != NULL ? finalRelName : RelationGetRelationName(rel); indexInfo->ii_Unique = true; indexInfo->ii_ReadyForInserts = true; indexInfo->ii_Concurrent = false; diff --git a/src/backend/commands/cluindex 19c3cf9..25f5a3d 100644 *** a/src/backend/commands/cluster.c --- b/src/backend/commands/cluster.c *************** *** 681,687 **** make_new_heap(Oid OIDOldHeap, Oid NewTableSpace) if (isNull) reloptions = (Datum) 0; ! AlterTableCreateToastTable(OIDNewHeap, reloptions); ReleaseSysCache(tuple); } --- 681,688 ---- if (isNull) reloptions = (Datum) 0; ! AlterTableCreateToastTable(OIDNewHeap, RelationGetRelationName(OldHeap), ! reloptions); ReleaseSysCache(tuple); } *************** *** 1395,1401 **** finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, * so no chance to reclaim disk space before commit. We do not need a * final CommandCounterIncrement() because reindex_relation does it. */ ! reindex_relation(OIDOldHeap, false, true); /* Destroy new heap with old filenode */ object.classId = RelationRelationId; --- 1396,1402 ---- * so no chance to reclaim disk space before commit. We do not need a * final CommandCounterIncrement() because reindex_relation does it. */ ! reindex_relation(OIDOldHeap, NULL, false, true); /* Destroy new heap with old filenode */ object.classId = RelationRelationId; diff --git a/src/backend/commands/indindex f809a26..b84e2b2 100644 *** a/src/backend/commands/indexcmds.c --- b/src/backend/commands/indexcmds.c *************** *** 1597,1603 **** ReindexIndex(RangeVar *indexRelation) ReleaseSysCache(tuple); ! reindex_index(indOid, false); } /* --- 1597,1603 ---- ReleaseSysCache(tuple); ! reindex_index(indOid, NULL, false); } /* *************** *** 1629,1635 **** ReindexTable(RangeVar *relation) ReleaseSysCache(tuple); ! if (!reindex_relation(heapOid, true, false)) ereport(NOTICE, (errmsg("table \"%s\" has no indexes", relation->relname))); --- 1629,1635 ---- ReleaseSysCache(tuple); ! if (!reindex_relation(heapOid, NULL, true, false)) ereport(NOTICE, (errmsg("table \"%s\" has no indexes", relation->relname))); *************** *** 1742,1748 **** ReindexDatabase(const char *databaseName, bool do_system, bool do_user) StartTransactionCommand(); /* functions in indexes may want a snapshot set */ PushActiveSnapshot(GetTransactionSnapshot()); ! if (reindex_relation(relid, true, false)) ereport(NOTICE, (errmsg("table \"%s.%s\" was reindexed", get_namespace_name(get_rel_namespace(relid)), --- 1742,1748 ---- StartTransactionCommand(); /* functions in indexes may want a snapshot set */ PushActiveSnapshot(GetTransactionSnapshot()); ! if (reindex_relation(relid, NULL, true, false)) ereport(NOTICE, (errmsg("table \"%s.%s\" was reindexed", get_namespace_name(get_rel_namespace(relid)), diff --git a/src/backend/commands/tableindex f3bd565..7c4488e 100644 *** a/src/backend/commands/tablecmds.c --- b/src/backend/commands/tablecmds.c *************** *** 1076,1082 **** ExecuteTruncate(TruncateStmt *stmt) /* * Reconstruct the indexes to match, and we're done. */ ! reindex_relation(heap_relid, true, false); } } --- 1076,1082 ---- /* * Reconstruct the indexes to match, and we're done. */ ! reindex_relation(heap_relid, NULL, true, false); } } *************** *** 2981,2987 **** ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode) (tab->subcmds[AT_PASS_ADD_COL] || tab->subcmds[AT_PASS_ALTER_TYPE] || tab->subcmds[AT_PASS_COL_ATTRS])) ! AlterTableCreateToastTable(tab->relid, (Datum) 0); } } --- 2981,2987 ---- (tab->subcmds[AT_PASS_ADD_COL] || tab->subcmds[AT_PASS_ALTER_TYPE] || tab->subcmds[AT_PASS_COL_ATTRS])) ! AlterTableCreateToastTable(tab->relid, NULL, (Datum) 0); } } *************** *** 3443,3448 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) --- 3443,3457 ---- List *dropped_attrs = NIL; ListCell *lc; + if (newrel) + ereport(DEBUG1, + (errmsg("rewriting table \"%s\"", + RelationGetRelationName(oldrel)))); + else + ereport(DEBUG1, + (errmsg("verifying table \"%s\"", + RelationGetRelationName(oldrel)))); + econtext = GetPerTupleExprContext(estate); /* *************** *** 3836,3841 **** ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, --- 3845,3854 ---- * Eventually, we'd like to propagate the check or rewrite operation * into other such tables, but for now, just error out if we find any. * + * CHECK, NOT NULL and DEFAULT constraints and the "oid" system column do + * not (currently) follow the row type, so they require no attention here. + * The non-propagation of DEFAULT and NOT NULL make ADD COLUMN safe, too. + * * Caller should provide either a table name or a type name (not both) to * report in the error message, if any. * *************** *** 5789,5794 **** validateForeignKeyConstraint(Constraint *fkconstraint, --- 5802,5811 ---- HeapTuple tuple; Trigger trig; + ereport(DEBUG1, + (errmsg("validating foreign key constraint \"%s\"", + fkconstraint->conname))); + /* * Build a trigger call structure; we'll need it either way. */ diff --git a/src/backend/executor/execMindex 600f7e0..56b10a3 100644 *** a/src/backend/executor/execMain.c --- b/src/backend/executor/execMain.c *************** *** 2307,2313 **** OpenIntoRel(QueryDesc *queryDesc) (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true); ! AlterTableCreateToastTable(intoRelationId, reloptions); /* * And open the constructed table for writing. --- 2307,2313 ---- (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true); ! AlterTableCreateToastTable(intoRelationId, NULL, reloptions); /* * And open the constructed table for writing. diff --git a/src/backend/tcop/utility.index 9500037..e6416e4 100644 *** a/src/backend/tcop/utility.c --- b/src/backend/tcop/utility.c *************** *** 540,546 **** standard_ProcessUtility(Node *parsetree, (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); ! AlterTableCreateToastTable(relOid, toast_options); } else if (IsA(stmt, CreateForeignTableStmt)) { --- 540,546 ---- (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); ! AlterTableCreateToastTable(relOid, NULL, toast_options); } else if (IsA(stmt, CreateForeignTableStmt)) { diff --git a/src/include/catalog/index 2804c63..12656fa 100644 *** a/src/include/catalog/index.h --- b/src/include/catalog/index.h *************** *** 70,77 **** extern double IndexBuildHeapScan(Relation heapRelation, extern void validate_index(Oid heapId, Oid indexId, Snapshot snapshot); ! extern void reindex_index(Oid indexId, bool skip_constraint_checks); ! extern bool reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt); extern bool ReindexIsProcessingHeap(Oid heapOid); extern bool ReindexIsProcessingIndex(Oid indexOid); --- 70,79 ---- extern void validate_index(Oid heapId, Oid indexId, Snapshot snapshot); ! extern void reindex_index(Oid indexId, const char *toastFor, ! bool skip_constraint_checks); ! extern bool reindex_relation(Oid relid, const char *toastFor, ! bool toast_too, bool heap_rebuilt); extern bool ReindexIsProcessingHeap(Oid heapOid); extern bool ReindexIsProcessingIndex(Oid indexOid); diff --git a/src/include/catalog/tindex de3623a..7bd2bdd 100644 *** a/src/include/catalog/toasting.h --- b/src/include/catalog/toasting.h *************** *** 17,23 **** /* * toasting.c prototypes */ ! extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions); extern void BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid); --- 17,24 ---- /* * toasting.c prototypes */ ! extern void AlterTableCreateToastTable(Oid relOid, const char *finalRelName, ! Datum reloptions); extern void BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid); diff --git a/src/include/nodes/execnoindex 546b581..46d9d1a 100644 *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 64,69 **** typedef struct IndexInfo --- 64,70 ---- Oid *ii_ExclusionOps; /* array with one entry per column */ Oid *ii_ExclusionProcs; /* array with one entry per column */ uint16 *ii_ExclusionStrats; /* array with one entry per column */ + const char *ii_ToastForRelName; /* TOAST index only: name of main rel */ bool ii_Unique; bool ii_ReadyForInserts; bool ii_Concurrent; diff --git a/src/test/regress/GNUmakindex 15b9ec4..c33ecb9 100644 diff --git a/src/test/regress/expecindex 3d126bb..282de46 100644 *** a/src/test/regress/expected/alter_table.out --- b/src/test/regress/expected/alter_table.out *************** *** 1477,1482 **** create table tab1 (a int, b text); --- 1477,1648 ---- create table tab2 (x int, y tab1); alter table tab1 alter column b type varchar; -- fails ERROR: cannot alter table "tab1" because column "tab2"."y" uses its rowtype + alter table tab1 add check (b <> 'foo'); + alter table tab1 add c int not null; + alter table tab1 add d int not null default 1; -- fails + ERROR: cannot alter table "tab1" because column "tab2"."y" uses its rowtype + alter table tab1 drop a; + alter table tab1 set with oids; -- fails + ERROR: cannot alter table "tab1" because column "tab2"."y" uses its rowtype + -- + -- ALTER COLUMN ... SET DATA TYPE optimizations + -- + SET client_min_messages = debug1; -- Track rewrites. + -- Model a type change that throws the semantics of dependent expressions. + CREATE DOMAIN trickint AS int; + CREATE FUNCTION touchy_f(trickint) RETURNS int4 LANGUAGE sql AS 'SELECT 100'; + CREATE FUNCTION touchy_f(int4) RETURNS int4 LANGUAGE sql AS 'SELECT $1'; + CREATE DOMAIN lendom AS varchar(8); + CREATE DOMAIN checkdom AS text CHECK (VALUE LIKE '<%'); + CREATE TABLE parent (keycol numeric PRIMARY KEY); + DEBUG: building TOAST index for table "parent" + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "parent_pkey" for table "parent" + DEBUG: building index "parent_pkey" on table "parent" + INSERT INTO parent VALUES (0.12), (1.12); + CREATE TABLE t ( + integral int4 NOT NULL, + rational numeric(9,4) UNIQUE NOT NULL REFERENCES parent, + string varchar(4) NOT NULL, + strarr varchar(2)[] NOT NULL, + CHECK (touchy_f(integral) < 10), + EXCLUDE (integral WITH =) + ); + DEBUG: building TOAST index for table "t" + NOTICE: CREATE TABLE / UNIQUE will create implicit index "t_rational_key" for table "t" + DEBUG: building index "t_rational_key" on table "t" + NOTICE: CREATE TABLE / EXCLUDE will create implicit index "t_integral_excl" for table "t" + DEBUG: building index "t_integral_excl" on table "t" + CREATE INDEX ON t USING gin (strarr); + DEBUG: building index "t_strarr_idx" on table "t" + INSERT INTO t VALUES (1, 0.12, '', '{ab,cd}'), (2, 1.12, '', '{ef,gh}'); + -- Comments "rewrite", "verify" and "noop" signify whether ATRewriteTables + -- rewrites, scans or does nothing to the table proper. An "-e" suffix denotes + -- an error outcome. + ALTER TABLE t ALTER integral TYPE trickint; -- verify-e + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + ERROR: check constraint "t_integral_check" is violated by some row + ALTER TABLE t DROP CONSTRAINT t_integral_check; + ALTER TABLE t ALTER integral TYPE abstime USING integral::abstime; -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + ALTER TABLE t ALTER integral TYPE oid USING integral::int4; -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + ALTER TABLE t ALTER integral TYPE regtype; -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + ALTER TABLE t ALTER rational TYPE numeric(7,4); -- verify + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: validating foreign key constraint "t_rational_fkey" + ALTER TABLE t ALTER rational TYPE numeric(8,4); -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: validating foreign key constraint "t_rational_fkey" + ALTER TABLE t ALTER rational TYPE numeric(8,1); -- rewrite-e + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: validating foreign key constraint "t_rational_fkey" + ERROR: insert or update on table "t" violates foreign key constraint "t_rational_fkey" + DETAIL: Key (rational)=(0.1) is not present in table "parent". + ALTER TABLE t ALTER string TYPE varchar(6); -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + ALTER TABLE t ALTER string TYPE lendom; -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + ALTER TABLE t ALTER string TYPE xml USING string::xml; -- verify + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + ALTER TABLE t ALTER string TYPE checkdom; -- verify + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + ALTER TABLE t ALTER string TYPE text USING 'foo'::varchar; -- rewrite + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + ALTER TABLE t ALTER strarr TYPE varchar(4)[]; -- noop + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: building index "t_strarr_idx" on table "t" + ALTER TABLE t ADD CONSTRAINT u0 UNIQUE (integral), -- build index exactly once + ALTER integral TYPE int8; -- rewrite + NOTICE: ALTER TABLE / ADD UNIQUE will create implicit index "u0" for table "t" + DEBUG: building TOAST index for table "t" + DEBUG: rewriting table "t" + DEBUG: building index "t_rational_key" on table "t" + DEBUG: building index "t_strarr_idx" on table "t" + DEBUG: building index "t_integral_excl" on table "t" + DEBUG: building index "u0" on table "t" + -- Data and catalog end state. We omit the columns that bear unstable OIDs. + SELECT * FROM t ORDER BY 1; + integral | rational | string | strarr + ----------+----------+--------+--------- + 1 | 0.1200 | foo | {ab,cd} + 2 | 1.1200 | foo | {ef,gh} + (2 rows) + + SELECT relname, indclass FROM pg_index JOIN pg_class c ON c.oid = indexrelid + WHERE indrelid = 't'::regclass ORDER BY 1; + relname | indclass + -----------------+---------- + t_integral_excl | 10029 + t_rational_key | 10037 + t_strarr_idx | 10103 + u0 | 10029 + (4 rows) + + SELECT relname, attname, atttypid, atttypmod + FROM pg_attribute JOIN pg_class c ON c.oid = attrelid + WHERE attnum > 0 AND + attrelid IN (SELECT indexrelid FROM pg_index WHERE indrelid = 't'::regclass) + ORDER BY 1, 2; + relname | attname | atttypid | atttypmod + -----------------+----------+----------+----------- + t_integral_excl | integral | 20 | -1 + t_rational_key | rational | 1700 | 524296 + t_strarr_idx | strarr | 1043 | -1 + u0 | integral | 20 | -1 + (4 rows) + + -- Done. Retain the table under a less-generic name. + ALTER TABLE t RENAME TO alter_type_test; + RESET client_min_messages; -- -- lock levels -- diff --git a/src/test/regress/expected/big_alternew file mode 100644 index 0000000..1609c01 diff --git a/src/test/regress/sql/alter_table.sql b/index 4895768..8e5090e 100644 *** a/src/test/regress/sql/alter_table.sql --- b/src/test/regress/sql/alter_table.sql *************** *** 1094,1099 **** drop table another; --- 1094,1166 ---- create table tab1 (a int, b text); create table tab2 (x int, y tab1); alter table tab1 alter column b type varchar; -- fails + alter table tab1 add check (b <> 'foo'); + alter table tab1 add c int not null; + alter table tab1 add d int not null default 1; -- fails + alter table tab1 drop a; + alter table tab1 set with oids; -- fails + + -- + -- ALTER COLUMN ... SET DATA TYPE optimizations + -- + SET client_min_messages = debug1; -- Track rewrites. + + -- Model a type change that throws the semantics of dependent expressions. + CREATE DOMAIN trickint AS int; + CREATE FUNCTION touchy_f(trickint) RETURNS int4 LANGUAGE sql AS 'SELECT 100'; + CREATE FUNCTION touchy_f(int4) RETURNS int4 LANGUAGE sql AS 'SELECT $1'; + CREATE DOMAIN lendom AS varchar(8); + CREATE DOMAIN checkdom AS text CHECK (VALUE LIKE '<%'); + + CREATE TABLE parent (keycol numeric PRIMARY KEY); + INSERT INTO parent VALUES (0.12), (1.12); + + CREATE TABLE t ( + integral int4 NOT NULL, + rational numeric(9,4) UNIQUE NOT NULL REFERENCES parent, + string varchar(4) NOT NULL, + strarr varchar(2)[] NOT NULL, + CHECK (touchy_f(integral) < 10), + EXCLUDE (integral WITH =) + ); + CREATE INDEX ON t USING gin (strarr); + INSERT INTO t VALUES (1, 0.12, '', '{ab,cd}'), (2, 1.12, '', '{ef,gh}'); + + -- Comments "rewrite", "verify" and "noop" signify whether ATRewriteTables + -- rewrites, scans or does nothing to the table proper. An "-e" suffix denotes + -- an error outcome. + ALTER TABLE t ALTER integral TYPE trickint; -- verify-e + ALTER TABLE t DROP CONSTRAINT t_integral_check; + ALTER TABLE t ALTER integral TYPE abstime USING integral::abstime; -- noop + ALTER TABLE t ALTER integral TYPE oid USING integral::int4; -- noop + ALTER TABLE t ALTER integral TYPE regtype; -- noop + ALTER TABLE t ALTER rational TYPE numeric(7,4); -- verify + ALTER TABLE t ALTER rational TYPE numeric(8,4); -- noop + ALTER TABLE t ALTER rational TYPE numeric(8,1); -- rewrite-e + ALTER TABLE t ALTER string TYPE varchar(6); -- noop + ALTER TABLE t ALTER string TYPE lendom; -- noop + ALTER TABLE t ALTER string TYPE xml USING string::xml; -- verify + ALTER TABLE t ALTER string TYPE checkdom; -- verify + ALTER TABLE t ALTER string TYPE text USING 'foo'::varchar; -- rewrite + ALTER TABLE t ALTER strarr TYPE varchar(4)[]; -- noop + ALTER TABLE t ADD CONSTRAINT u0 UNIQUE (integral), -- build index exactly once + ALTER integral TYPE int8; -- rewrite + + -- Data and catalog end state. We omit the columns that bear unstable OIDs. + SELECT * FROM t ORDER BY 1; + + SELECT relname, indclass FROM pg_index JOIN pg_class c ON c.oid = indexrelid + WHERE indrelid = 't'::regclass ORDER BY 1; + + SELECT relname, attname, atttypid, atttypmod + FROM pg_attribute JOIN pg_class c ON c.oid = attrelid + WHERE attnum > 0 AND + attrelid IN (SELECT indexrelid FROM pg_index WHERE indrelid = 't'::regclass) + ORDER BY 1, 2; + + -- Done. Retain the table under a less-generic name. + ALTER TABLE t RENAME TO alter_type_test; + RESET client_min_messages; -- -- lock levels diff --git a/src/test/regress/sql/big_alternew file mode 100644 index 0000000..3824d96