diff options
author | Robert Haas <rhaas@postgresql.org> | 2011-07-18 11:02:48 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2011-07-18 11:04:43 -0400 |
commit | 367bc426a1c22b9f6badb06cd41fc438fd034639 (patch) | |
tree | eb518f0e9399e0857f0e5f79c10750e1bfdaf909 /src/backend/commands/tablecmds.c | |
parent | 8f8a273c4d2433de57f6f0356f44ab47b7387641 (diff) | |
download | postgresql-367bc426a1c22b9f6badb06cd41fc438fd034639.tar.gz postgresql-367bc426a1c22b9f6badb06cd41fc438fd034639.zip |
Avoid index rebuild for no-rewrite ALTER TABLE .. ALTER TYPE.
Noah Misch. Review and minor cosmetic changes by me.
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 114 |
1 files changed, 82 insertions, 32 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 295a1ff6e63..82bb756c75e 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -347,7 +347,9 @@ static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno); static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); -static void ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode); +static void ATPostAlterTypeParse(Oid oldId, char *cmd, + List **wqueue, LOCKMODE lockmode, bool rewrite); +static void TryReuseIndex(Oid oldId, IndexStmt *stmt); static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode); static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode); @@ -5232,37 +5234,52 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, bool check_rights; bool skip_build; bool quiet; + Oid new_index; Assert(IsA(stmt, IndexStmt)); /* suppress schema rights check when rebuilding existing index */ check_rights = !is_rebuild; - /* skip index build if phase 3 will have to rewrite table anyway */ - skip_build = tab->rewrite; + /* skip index build if phase 3 will do it or we're reusing an old one */ + skip_build = tab->rewrite || OidIsValid(stmt->oldNode); /* suppress notices when rebuilding existing index */ quiet = is_rebuild; /* The IndexStmt has already been through transformIndexStmt */ - DefineIndex(stmt->relation, /* relation */ - stmt->idxname, /* index name */ - InvalidOid, /* no predefined OID */ - stmt->accessMethod, /* am name */ - stmt->tableSpace, - stmt->indexParams, /* parameters */ - (Expr *) stmt->whereClause, - stmt->options, - stmt->excludeOpNames, - stmt->unique, - stmt->primary, - stmt->isconstraint, - stmt->deferrable, - stmt->initdeferred, - true, /* is_alter_table */ - check_rights, - skip_build, - quiet, - false); + new_index = DefineIndex(stmt->relation, /* relation */ + stmt->idxname, /* index name */ + InvalidOid, /* no predefined OID */ + stmt->oldNode, + stmt->accessMethod, /* am name */ + stmt->tableSpace, + stmt->indexParams, /* parameters */ + (Expr *) stmt->whereClause, + stmt->options, + stmt->excludeOpNames, + stmt->unique, + stmt->primary, + stmt->isconstraint, + stmt->deferrable, + stmt->initdeferred, + true, /* is_alter_table */ + check_rights, + skip_build, + quiet, + false); + + /* + * If TryReuseIndex() stashed a relfilenode for us, we used it for the new + * index instead of building from scratch. The DROP of the old edition of + * this index will have scheduled the storage for deletion at commit, so + * cancel that pending deletion. + */ + if (OidIsValid(stmt->oldNode)) + { + Relation irel = index_open(new_index, NoLock); + RelationPreserveStorage(irel->rd_node, true); + index_close(irel, NoLock); + } } /* @@ -7389,7 +7406,8 @@ static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) { ObjectAddress obj; - ListCell *l; + ListCell *def_item; + ListCell *oid_item; /* * Re-parse the index and constraint definitions, and attach them to the @@ -7399,10 +7417,14 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) * that before dropping. It's safe because the parser won't actually look * at the catalogs to detect the existing entry. */ - foreach(l, tab->changedIndexDefs) - ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode); - foreach(l, tab->changedConstraintDefs) - ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode); + forboth(oid_item, tab->changedConstraintOids, + def_item, tab->changedConstraintDefs) + ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), + wqueue, lockmode, tab->rewrite); + forboth(oid_item, tab->changedIndexOids, + def_item, tab->changedIndexDefs) + ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), + wqueue, lockmode, tab->rewrite); /* * Now we can drop the existing constraints and indexes --- constraints @@ -7412,18 +7434,18 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) * should be okay to use DROP_RESTRICT here, since nothing else should be * depending on these objects. */ - foreach(l, tab->changedConstraintOids) + foreach(oid_item, tab->changedConstraintOids) { obj.classId = ConstraintRelationId; - obj.objectId = lfirst_oid(l); + obj.objectId = lfirst_oid(oid_item); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } - foreach(l, tab->changedIndexOids) + foreach(oid_item, tab->changedIndexOids) { obj.classId = RelationRelationId; - obj.objectId = lfirst_oid(l); + obj.objectId = lfirst_oid(oid_item); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } @@ -7435,7 +7457,8 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) } static void -ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) +ATPostAlterTypeParse(Oid oldId, char *cmd, + List **wqueue, LOCKMODE lockmode, bool rewrite) { List *raw_parsetree_list; List *querytree_list; @@ -7482,6 +7505,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) IndexStmt *stmt = (IndexStmt *) stm; AlterTableCmd *newcmd; + if (!rewrite) + TryReuseIndex(oldId, stmt); + rel = relation_openrv(stmt->relation, lockmode); tab = ATGetQueueEntry(wqueue, rel); newcmd = makeNode(AlterTableCmd); @@ -7506,6 +7532,10 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) switch (cmd->subtype) { case AT_AddIndex: + Assert(IsA(cmd->def, IndexStmt)); + if (!rewrite) + TryReuseIndex(get_constraint_index(oldId), + (IndexStmt *) cmd->def); cmd->subtype = AT_ReAddIndex; tab->subcmds[AT_PASS_OLD_INDEX] = lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd); @@ -7529,6 +7559,26 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) } } +/* + * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible() + * for the real analysis, then mutates the IndexStmt based on that verdict. +*/ +static void +TryReuseIndex(Oid oldId, IndexStmt *stmt) +{ + + if (CheckIndexCompatible(oldId, + stmt->relation, + stmt->accessMethod, + stmt->indexParams, + stmt->excludeOpNames)) + { + Relation irel = index_open(oldId, NoLock); + stmt->oldNode = irel->rd_node.relNode; + index_close(irel, NoLock); + } +} + /* * ALTER TABLE OWNER |