This is an automated email from the ASF dual-hosted git repository.
maxyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git
The following commit(s) were added to refs/heads/main by this push:
new decaba17e63 ORCA: reject functions with prosupport in DXL translation
decaba17e63 is described below
commit decaba17e63bd30d7e35e1319bdd6d9c00f19e2f
Author: Jianghua Yang <[email protected]>
AuthorDate: Wed Aug 20 02:05:57 2025 +0000
ORCA: reject functions with prosupport in DXL translation
ORCA does not currently implement PostgreSQL's prosupport mechanism.
Support functions (prosupport) provide planner-time optimization hints
in the upstream planner, but ORCA has no equivalent logic. To avoid
incorrect query plans, functions with prosupport are now rejected during
DXL translation.
---
.../regress/expected/misc_functions_optimizer.out | 50 ++++++++++----------
src/backend/gpopt/gpdbwrappers.cpp | 25 ++++++++++
.../gpopt/translate/CTranslatorRelcacheToDXL.cpp | 17 +++++++
src/include/gpopt/gpdbwrappers.h | 6 +++
.../regress/expected/misc_functions_optimizer.out | 54 +++++++++++-----------
5 files changed, 98 insertions(+), 54 deletions(-)
diff --git
a/contrib/pax_storage/src/test/regress/expected/misc_functions_optimizer.out
b/contrib/pax_storage/src/test/regress/expected/misc_functions_optimizer.out
index 8cdcba95fb1..56138548e88 100644
--- a/contrib/pax_storage/src/test/regress/expected/misc_functions_optimizer.out
+++ b/contrib/pax_storage/src/test/regress/expected/misc_functions_optimizer.out
@@ -235,7 +235,7 @@ WHERE my_int_eq(a.unique2, 42);
-> Hash
-> Seq Scan on tenk1 a
Filter: my_int_eq(unique2, 42)
- Optimizer: Pivotal Optimizer (GPORCA)
+ Optimizer: GPORCA
(8 rows)
-- With support function that knows it's int4eq, we get a different plan
@@ -243,17 +243,16 @@ ALTER FUNCTION my_int_eq(int, int) SUPPORT
test_support_func;
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN tenk1 b ON a.unique1 = b.unique1
WHERE my_int_eq(a.unique2, 42);
- QUERY PLAN
-------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
- -> Hash Join
- Hash Cond: (b.unique1 = a.unique1)
- -> Seq Scan on tenk1 b
- -> Hash
- -> Seq Scan on tenk1 a
- Filter: my_int_eq(unique2, 42)
- Optimizer: Pivotal Optimizer (GPORCA)
-(8 rows)
+ -> Nested Loop
+ -> Seq Scan on tenk1 a
+ Filter: my_int_eq(unique2, 42)
+ -> Index Scan using tenk1_unique1 on tenk1 b
+ Index Cond: (unique1 = a.unique1)
+ Optimizer: Postgres query optimizer
+(7 rows)
-- Also test non-default rowcount estimate
CREATE FUNCTION my_gen_series(int, int) RETURNS SETOF integer
@@ -262,27 +261,26 @@ CREATE FUNCTION my_gen_series(int, int) RETURNS SETOF
integer
SUPPORT test_support_func;
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN my_gen_series(1,1000) g ON a.unique1 = g;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
-> Hash Join
- Hash Cond: (a.unique1 = my_gen_series.my_gen_series)
- -> Seq Scan on tenk1 a
+ Hash Cond: (g.g = a.unique1)
+ -> Function Scan on my_gen_series g
-> Hash
- -> Function Scan on my_gen_series
- Optimizer: Pivotal Optimizer (GPORCA)
+ -> Seq Scan on tenk1 a
+ Optimizer: Postgres query optimizer
(7 rows)
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN my_gen_series(1,5) g ON a.unique1 = g;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
- -> Hash Join
- Hash Cond: (a.unique1 = my_gen_series.my_gen_series)
- -> Seq Scan on tenk1 a
- -> Hash
- -> Function Scan on my_gen_series
- Optimizer: Pivotal Optimizer (GPORCA)
-(7 rows)
+ -> Nested Loop
+ -> Function Scan on my_gen_series g
+ -> Index Scan using tenk1_unique1 on tenk1 a
+ Index Cond: (unique1 = g.g)
+ Optimizer: Postgres query optimizer
+(6 rows)
diff --git a/src/backend/gpopt/gpdbwrappers.cpp
b/src/backend/gpopt/gpdbwrappers.cpp
index 1deb53883d5..4e636a0c653 100644
--- a/src/backend/gpopt/gpdbwrappers.cpp
+++ b/src/backend/gpopt/gpdbwrappers.cpp
@@ -49,6 +49,7 @@ extern "C" {
#include "partitioning/partdesc.h"
#include "storage/lmgr.h"
#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
}
@@ -346,6 +347,30 @@ gpdb::FuncStability(Oid funcid)
return '\0';
}
+RegProcedure
+gpdb::FuncSupport(Oid funcid)
+{
+ GP_WRAP_START;
+ {
+ /* catalog tables: pg_proc */
+ return get_func_support(funcid);
+ }
+ GP_WRAP_END;
+ return InvalidOid;
+}
+
+Oid
+gpdb::FuncNamespace(Oid funcid)
+{
+ GP_WRAP_START;
+ {
+ /* catalog tables: pg_proc */
+ return get_func_namespace(funcid);
+ }
+ GP_WRAP_END;
+ return InvalidOid;
+}
+
char
gpdb::FuncExecLocation(Oid funcid)
{
diff --git a/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp
b/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp
index d0d57338b78..469d69fb60f 100644
--- a/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp
+++ b/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp
@@ -20,6 +20,7 @@ extern "C" {
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_statistic_ext.h"
@@ -1437,6 +1438,22 @@ CTranslatorRelcacheToDXL::LookupFuncProps(
*stability = GetFuncStability(gpdb::FuncStability(func_oid));
+ RegProcedure prosupport = gpdb::FuncSupport(func_oid);
+ if (OidIsValid(prosupport))
+ {
+ /*
+ CBDB_FIXME:
+ Check if function is NOT in pg_catalog namespace
+ Functions outside pg_catalog are likely extension functions
that unsupported yet.
+ */
+ Oid func_namespace = gpdb::FuncNamespace(func_oid);
+ if (func_namespace != PG_CATALOG_NAMESPACE)
+ {
+ GPOS_RAISE(gpdxl::ExmaDXL,
gpdxl::ExmiQuery2DXLUnsupportedFeature,
+ GPOS_WSZ_LIT("extension functions
with prosupport unsupported"));
+ }
+ }
+
if (gpdb::FuncExecLocation(func_oid) != PROEXECLOCATION_ANY)
{
GPOS_RAISE(gpdxl::ExmaDXL,
gpdxl::ExmiQuery2DXLUnsupportedFeature,
diff --git a/src/include/gpopt/gpdbwrappers.h b/src/include/gpopt/gpdbwrappers.h
index fe387e471c0..261cd28b5f0 100644
--- a/src/include/gpopt/gpdbwrappers.h
+++ b/src/include/gpopt/gpdbwrappers.h
@@ -338,6 +338,12 @@ bool IsFuncNDVPreserving(Oid funcid);
// stability property of given function
char FuncStability(Oid funcid);
+// support function of given function
+RegProcedure FuncSupport(Oid funcid);
+
+// namespace of given function
+Oid FuncNamespace(Oid funcid);
+
// exec location property of given function
char FuncExecLocation(Oid funcid);
diff --git a/src/test/regress/expected/misc_functions_optimizer.out
b/src/test/regress/expected/misc_functions_optimizer.out
index f5187fad45b..e5723fea5f3 100644
--- a/src/test/regress/expected/misc_functions_optimizer.out
+++ b/src/test/regress/expected/misc_functions_optimizer.out
@@ -256,8 +256,8 @@ CREATE FUNCTION my_int_eq(int, int) RETURNS bool
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN tenk1 b ON a.unique1 = b.unique1
WHERE my_int_eq(a.unique2, 42);
- QUERY PLAN
-------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
-> Hash Join
Hash Cond: (b.unique1 = a.unique1)
@@ -265,7 +265,7 @@ WHERE my_int_eq(a.unique2, 42);
-> Hash
-> Seq Scan on tenk1 a
Filter: my_int_eq(unique2, 42)
- Optimizer: Pivotal Optimizer (GPORCA)
+ Optimizer: GPORCA
(8 rows)
-- With support function that knows it's int4eq, we get a different plan
@@ -273,17 +273,16 @@ ALTER FUNCTION my_int_eq(int, int) SUPPORT
test_support_func;
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN tenk1 b ON a.unique1 = b.unique1
WHERE my_int_eq(a.unique2, 42);
- QUERY PLAN
-------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
- -> Hash Join
- Hash Cond: (b.unique1 = a.unique1)
- -> Seq Scan on tenk1 b
- -> Hash
- -> Seq Scan on tenk1 a
- Filter: my_int_eq(unique2, 42)
- Optimizer: Pivotal Optimizer (GPORCA)
-(8 rows)
+ -> Nested Loop
+ -> Seq Scan on tenk1 a
+ Filter: my_int_eq(unique2, 42)
+ -> Index Scan using tenk1_unique1 on tenk1 b
+ Index Cond: (unique1 = a.unique1)
+ Optimizer: Postgres query optimizer
+(7 rows)
-- Also test non-default rowcount estimate
CREATE FUNCTION my_gen_series(int, int) RETURNS SETOF integer
@@ -292,27 +291,26 @@ CREATE FUNCTION my_gen_series(int, int) RETURNS SETOF
integer
SUPPORT test_support_func;
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN my_gen_series(1,1000) g ON a.unique1 = g;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
-> Hash Join
- Hash Cond: (a.unique1 = my_gen_series.my_gen_series)
- -> Seq Scan on tenk1 a
+ Hash Cond: (g.g = a.unique1)
+ -> Function Scan on my_gen_series g
-> Hash
- -> Function Scan on my_gen_series
- Optimizer: Pivotal Optimizer (GPORCA)
+ -> Seq Scan on tenk1 a
+ Optimizer: Postgres query optimizer
(7 rows)
EXPLAIN (COSTS OFF)
SELECT * FROM tenk1 a JOIN my_gen_series(1,10) g ON a.unique1 = g;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
- -> Hash Join
- Hash Cond: (a.unique1 = my_gen_series.my_gen_series)
- -> Seq Scan on tenk1 a
- -> Hash
- -> Function Scan on my_gen_series
- Optimizer: Pivotal Optimizer (GPORCA)
-(7 rows)
+ -> Nested Loop
+ -> Function Scan on my_gen_series g
+ -> Index Scan using tenk1_unique1 on tenk1 a
+ Index Cond: (unique1 = g.g)
+ Optimizer: Postgres query optimizer
+(6 rows)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]