diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index ac9df9eefe7..4d61e8e071c 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2795,8 +2795,15 @@ RelationTruncateIndexes(Relation heapRelation) /* Open the index relation; use exclusive lock, just to be sure */ currentIndex = index_open(indexId, AccessExclusiveLock); - /* Fetch info needed for index_build */ - indexInfo = BuildIndexInfo(currentIndex); + /* + * Fetch info needed for index_build. Since we know there are no + * tuples that actually need indexing, we can use a dummy IndexInfo. + * This is slightly cheaper to build, but the real point is to avoid + * possibly running user-defined code in index expressions or + * predicates. We might be getting invoked during ON COMMIT + * processing, and we don't want to run any such code then. + */ + indexInfo = BuildDummyIndexInfo(currentIndex); /* * Now truncate the actual file (and discard buffers). diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index a6b56d31007..942d43db892 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1706,6 +1706,69 @@ BuildIndexInfo(Relation index) return ii; } +/* ---------------- + * BuildDummyIndexInfo + * Construct a dummy IndexInfo record for an open index + * + * This differs from the real BuildIndexInfo in that it will never run any + * user-defined code that might exist in index expressions or predicates. + * Instead of the real index expressions, we return null constants that have + * the right types/typmods/collations. Predicates and exclusion clauses are + * just ignored. This is sufficient for the purpose of truncating an index, + * since we will not need to actually evaluate the expressions or predicates; + * the only thing that's likely to be done with the data is construction of + * a tupdesc describing the index's rowtype. + * ---------------- + */ +IndexInfo * +BuildDummyIndexInfo(Relation index) +{ + IndexInfo *ii = makeNode(IndexInfo); + Form_pg_index indexStruct = index->rd_index; + int i; + int numKeys; + + /* check the number of keys, and copy attr numbers into the IndexInfo */ + numKeys = indexStruct->indnatts; + if (numKeys < 1 || numKeys > INDEX_MAX_KEYS) + elog(ERROR, "invalid indnatts %d for index %u", + numKeys, RelationGetRelid(index)); + ii->ii_NumIndexAttrs = numKeys; + for (i = 0; i < numKeys; i++) + ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i]; + + /* fetch dummy expressions for expressional indexes */ + ii->ii_Expressions = RelationGetDummyIndexExpressions(index); + ii->ii_ExpressionsState = NIL; + + /* pretend there is no predicate */ + ii->ii_Predicate = NIL; + ii->ii_PredicateState = NULL; + + /* We ignore the exclusion constraint if any */ + ii->ii_ExclusionOps = NULL; + ii->ii_ExclusionProcs = NULL; + ii->ii_ExclusionStrats = NULL; + + /* other info */ + ii->ii_Unique = indexStruct->indisunique; + ii->ii_ReadyForInserts = IndexIsReady(indexStruct); + /* assume not doing speculative insertion for now */ + ii->ii_UniqueOps = NULL; + ii->ii_UniqueProcs = NULL; + ii->ii_UniqueStrats = NULL; + + /* initialize index-build state to default */ + ii->ii_Concurrent = false; + ii->ii_BrokenHotChain = false; + + /* set up for possible use by index AM */ + ii->ii_AmCache = NULL; + ii->ii_Context = CurrentMemoryContext; + + return ii; +} + /* ---------------- * BuildSpeculativeIndexInfo * Add extra state to IndexInfo record diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 24e830a39c1..b6720184633 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -65,6 +65,7 @@ #include "commands/policy.h" #include "commands/trigger.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/prep.h" @@ -4816,6 +4817,57 @@ RelationGetIndexExpressions(Relation relation) return result; } +/* + * RelationGetDummyIndexExpressions -- get dummy expressions for an index + * + * Return a list of dummy expressions (just Const nodes) with the same + * types/typmods/collations as the index's real expressions. This is + * useful in situations where we don't want to run any user-defined code. + */ +List * +RelationGetDummyIndexExpressions(Relation relation) +{ + List *result; + Datum exprsDatum; + bool isnull; + char *exprsString; + List *rawExprs; + ListCell *lc; + + /* Quick exit if there is nothing to do. */ + if (relation->rd_indextuple == NULL || + heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs)) + return NIL; + + /* Extract raw node tree(s) from index tuple. */ + exprsDatum = heap_getattr(relation->rd_indextuple, + Anum_pg_index_indexprs, + GetPgIndexDescriptor(), + &isnull); + Assert(!isnull); + exprsString = TextDatumGetCString(exprsDatum); + rawExprs = (List *) stringToNode(exprsString); + pfree(exprsString); + + /* Construct null Consts; the typlen and typbyval are arbitrary. */ + result = NIL; + foreach(lc, rawExprs) + { + Node *rawExpr = (Node *) lfirst(lc); + + result = lappend(result, + makeConst(exprType(rawExpr), + exprTypmod(rawExpr), + exprCollation(rawExpr), + 1, + (Datum) 0, + true, + true)); + } + + return result; +} + /* * RelationGetIndexPredicate -- get the index predicate for an index * diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index ebca7740eae..7c56182c723 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -82,6 +82,8 @@ extern void index_drop(Oid indexId, bool concurrent); extern IndexInfo *BuildIndexInfo(Relation index); +extern IndexInfo *BuildDummyIndexInfo(Relation index); + extern void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii); extern void FormIndexDatum(IndexInfo *indexInfo, diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 3c53cefe4b4..e2207ccd3d0 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -44,6 +44,7 @@ extern Oid RelationGetOidIndex(Relation relation); extern Oid RelationGetPrimaryKeyIndex(Relation relation); extern Oid RelationGetReplicaIndex(Relation relation); extern List *RelationGetIndexExpressions(Relation relation); +extern List *RelationGetDummyIndexExpressions(Relation relation); extern List *RelationGetIndexPredicate(Relation relation); typedef enum IndexAttrBitmapKind diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out index 5e089ef0503..47d58e829a3 100644 --- a/src/test/regress/expected/temp.out +++ b/src/test/regress/expected/temp.out @@ -49,6 +49,8 @@ LINE 1: SELECT * FROM temptest; ^ -- Test ON COMMIT DELETE ROWS CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS; +-- while we're here, verify successful truncation of index with SQL function +CREATE INDEX ON temptest(bit_length('')); BEGIN; INSERT INTO temptest VALUES (1); INSERT INTO temptest VALUES (2); diff --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql index f8d2a285c3c..e72618fa7f7 100644 --- a/src/test/regress/sql/temp.sql +++ b/src/test/regress/sql/temp.sql @@ -55,6 +55,9 @@ SELECT * FROM temptest; CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS; +-- while we're here, verify successful truncation of index with SQL function +CREATE INDEX ON temptest(bit_length('')); + BEGIN; INSERT INTO temptest VALUES (1); INSERT INTO temptest VALUES (2);