/* 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).
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;
+ Form_pg_index indexStruct = index->rd_index;
+ int i;
+ int numAtts;
+
+ /* check the number of keys, and copy attr numbers into the IndexInfo */
+ numAtts = indexStruct->indnatts;
+ if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
+ elog(ERROR, "invalid indnatts %d for index %u",
+ numAtts, RelationGetRelid(index));
+
+ /*
+ * Create the node, using dummy index expressions, and pretending there is
+ * no predicate.
+ */
+ ii = makeIndexInfo(indexStruct->indnatts,
+ indexStruct->indnkeyatts,
+ index->rd_rel->relam,
+ RelationGetDummyIndexExpressions(index),
+ NIL,
+ indexStruct->indisunique,
+ indexStruct->indisready,
+ false);
+
+ /* fill in attribute numbers */
+ for (i = 0; i < numAtts; i++)
+ ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
+
+ /* We ignore the exclusion constraint if any */
+
+ return ii;
+}
+
/*
* CompareIndexInfo
* Return whether the properties of two indexes (in different tables)
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, NULL))
+ 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
*
extern IndexInfo *BuildIndexInfo(Relation index);
+extern IndexInfo *BuildDummyIndexInfo(Relation index);
+
extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2,
Oid *opfamilies1, Oid *opfamilies2,
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
^
-- 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);
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);