aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/plan/planner.c12
-rw-r--r--src/backend/utils/cache/lsyscache.c68
-rw-r--r--src/include/utils/lsyscache.h2
-rw-r--r--src/test/regress/expected/btree_index.out19
-rw-r--r--src/test/regress/sql/btree_index.sql22
5 files changed, 121 insertions, 2 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 65a9b0d802a..db00a593a65 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -6306,10 +6306,18 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
* Currently, parallel workers can't access the leader's temporary tables.
* Furthermore, any index predicate or index expressions must be parallel
* safe.
+ *
+ * Fetch the list of expressions and predicates directly from the
+ * catalogs. Retrieving this information from the relcache would cause
+ * the expressions and predicates to be flattened, losing properties that
+ * can be important to check if parallel workers can be used. For
+ * example, immutable parallel-unsafe functions, that cannot be used in
+ * parallel workers, would be changed to Const nodes, that are safe in
+ * parallel workers.
*/
if (heap->rd_rel->relpersistence == RELPERSISTENCE_TEMP ||
- !is_parallel_safe(root, (Node *) RelationGetIndexExpressions(index)) ||
- !is_parallel_safe(root, (Node *) RelationGetIndexPredicate(index)))
+ !is_parallel_safe(root, (Node *) get_index_expressions(indexOid)) ||
+ !is_parallel_safe(root, (Node *) get_index_predicate(indexOid)))
{
parallel_workers = 0;
goto done;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 13f8dafa308..db6b8a36ec9 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3256,6 +3256,74 @@ get_index_column_opclass(Oid index_oid, int attno)
}
/*
+ * get_index_expressions
+ *
+ * Given the index OID, its a List of its expressions or NIL if none.
+ */
+List *
+get_index_expressions(Oid index_oid)
+{
+ List *result;
+ HeapTuple tuple;
+ Datum exprDatum;
+ bool isnull;
+ char *exprString;
+
+ tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for index %u", index_oid);
+
+ exprDatum = SysCacheGetAttr(INDEXRELID, tuple,
+ Anum_pg_index_indexprs, &isnull);
+ if (isnull)
+ {
+ ReleaseSysCache(tuple);
+ return NIL;
+ }
+
+ exprString = TextDatumGetCString(exprDatum);
+ result = (List *) stringToNode(exprString);
+ pfree(exprString);
+ ReleaseSysCache(tuple);
+
+ return result;
+}
+
+/*
+ * get_index_predicate
+ *
+ * Given the index OID, return a List of its predicate or NIL if none.
+ */
+List *
+get_index_predicate(Oid index_oid)
+{
+ List *result;
+ HeapTuple tuple;
+ Datum predDatum;
+ bool isnull;
+ char *predString;
+
+ tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for index %u", index_oid);
+
+ predDatum = SysCacheGetAttr(INDEXRELID, tuple,
+ Anum_pg_index_indpred, &isnull);
+ if (isnull)
+ {
+ ReleaseSysCache(tuple);
+ return NIL;
+ }
+
+ predString = TextDatumGetCString(predDatum);
+ result = (List *) stringToNode(predString);
+ pfree(predString);
+ ReleaseSysCache(tuple);
+
+ return result;
+}
+
+/*
* get_index_isreplident
*
* Given the index OID, return pg_index.indisreplident.
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 53d4a2d1093..32ca83736eb 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -182,6 +182,8 @@ extern char *get_namespace_name_or_temp(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
extern Oid get_range_collation(Oid rangeOid);
extern Oid get_index_column_opclass(Oid index_oid, int attno);
+extern List *get_index_expressions(Oid index_oid);
+extern List *get_index_predicate(Oid index_oid);
extern bool get_index_isreplident(Oid index_oid);
extern bool get_index_isvalid(Oid index_oid);
extern bool get_index_isclustered(Oid index_oid);
diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out
index f567117a466..8d0240f79be 100644
--- a/src/test/regress/expected/btree_index.out
+++ b/src/test/regress/expected/btree_index.out
@@ -330,3 +330,22 @@ VACUUM delete_test_table;
-- The vacuum above should've turned the leaf page into a fast root. We just
-- need to insert some rows to cause the fast root page to split.
INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
+-- Test with index expression and predicate that include a parallel unsafe
+-- function.
+CREATE FUNCTION para_unsafe_f() RETURNS int IMMUTABLE PARALLEL UNSAFE
+AS $$
+BEGIN
+ RETURN 0;
+EXCEPTION WHEN OTHERS THEN
+ RETURN 1;
+END$$ LANGUAGE plpgsql;
+CREATE TABLE btree_para_bld(i int);
+ALTER TABLE btree_para_bld SET (parallel_workers = 4);
+SET max_parallel_maintenance_workers TO 4;
+-- With parallel-unsafe expression
+CREATE INDEX ON btree_para_bld((i + para_unsafe_f()));
+-- With parallel-unsafe predicate
+CREATE INDEX ON btree_para_bld(i) WHERE i > para_unsafe_f();
+RESET max_parallel_maintenance_workers;
+DROP TABLE btree_para_bld;
+DROP FUNCTION para_unsafe_f;
diff --git a/src/test/regress/sql/btree_index.sql b/src/test/regress/sql/btree_index.sql
index 558dcae0ec7..c80165c6ee7 100644
--- a/src/test/regress/sql/btree_index.sql
+++ b/src/test/regress/sql/btree_index.sql
@@ -160,3 +160,25 @@ VACUUM delete_test_table;
-- The vacuum above should've turned the leaf page into a fast root. We just
-- need to insert some rows to cause the fast root page to split.
INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
+
+-- Test with index expression and predicate that include a parallel unsafe
+-- function.
+CREATE FUNCTION para_unsafe_f() RETURNS int IMMUTABLE PARALLEL UNSAFE
+AS $$
+BEGIN
+ RETURN 0;
+EXCEPTION WHEN OTHERS THEN
+ RETURN 1;
+END$$ LANGUAGE plpgsql;
+
+CREATE TABLE btree_para_bld(i int);
+ALTER TABLE btree_para_bld SET (parallel_workers = 4);
+SET max_parallel_maintenance_workers TO 4;
+-- With parallel-unsafe expression
+CREATE INDEX ON btree_para_bld((i + para_unsafe_f()));
+-- With parallel-unsafe predicate
+CREATE INDEX ON btree_para_bld(i) WHERE i > para_unsafe_f();
+
+RESET max_parallel_maintenance_workers;
+DROP TABLE btree_para_bld;
+DROP FUNCTION para_unsafe_f;