This is an automated email from the ASF dual-hosted git repository.

yjhjstz 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 0d40460eed2 ORCA: prevent crashes with extension prosupport functions 
in NULL rtable queries
0d40460eed2 is described below

commit 0d40460eed20572a248791de84992a454c59626f
Author: Jianghua Yang <yjhj...@gmail.com>
AuthorDate: Fri Sep 12 14:49:35 2025 +0000

    ORCA: prevent crashes with extension prosupport functions in NULL rtable 
queries
    
    Add query_contains_support_functions() to detect extension prosupport 
functions
    before GPORCA planning and fall back to standard planner when rtable is 
NULL.
    
    The issue occurs during constant folding when extension prosupport functions
    (e.g., from pg_search) expect a valid rtable but encounter NULL rtable in
    sublink scenarios. This causes crashes in eval_const_expressions_mutator.
---
 src/backend/optimizer/plan/orca.c | 127 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/src/backend/optimizer/plan/orca.c 
b/src/backend/optimizer/plan/orca.c
index dc6a88e73c6..97f63f7a334 100644
--- a/src/backend/optimizer/plan/orca.c
+++ b/src/backend/optimizer/plan/orca.c
@@ -25,6 +25,7 @@
 #include "cdb/cdbplan.h"
 #include "cdb/cdbvars.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "optimizer/orca.h"
@@ -37,8 +38,13 @@
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "portability/instr_time.h"
+#include "utils/elog.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/syscache.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_namespace.h"
 
 /* GPORCA entry point */
 extern PlannedStmt * GPOPTOptimizedPlan(Query *parse, bool 
*had_unexpected_failure, OptimizerOptions *opts);
@@ -81,6 +87,110 @@ log_optimizer(PlannedStmt *plan, bool fUnexpectedFailure)
        }
 }
 
+/*
+ * support_functions_check_context
+ *             Context structure for checking support functions, similar to 
eval_const_expressions_context
+ */
+typedef struct
+{
+       PlannerInfo *root;
+       bool            recurse_queries;                /* recurse into query 
structures */
+       bool            recurse_sublink_testexpr; /* recurse into sublink test 
expressions */
+} support_functions_check_context;
+
+/*
+ * check_support_functions_walker
+ *             Walker function to check if a query tree contains functions 
with support functions
+ *             Uses the same traversal pattern as 
eval_const_expressions_mutator but as a walker
+ */
+static bool
+check_support_functions_walker(Node *node, support_functions_check_context 
*context)
+{
+       if (node == NULL)
+               return false;
+
+       if (IsA(node, Query))
+       {
+               Query *query = (Query *) node;
+
+               if (context->recurse_queries)
+               {
+                       /* Recurse into Query structures like fold_constants 
does */
+                       return query_tree_walker(query, 
check_support_functions_walker, context, 0);
+               }
+               return false;
+       }
+
+       /* Handle SubLink like eval_const_expressions_mutator does */
+       if (IsA(node, SubLink) && !context->recurse_sublink_testexpr)
+       {
+               SubLink *sublink = (SubLink *) node;
+
+               /*
+                * Also invoke the walker on the sublink's Query node, so it
+                * can recurse into the sub-query if it wants to.
+                */
+               return query_tree_walker((Query *) sublink->subselect, 
check_support_functions_walker, context, 0);
+       }
+
+       /* Check both FuncExpr and OpExpr nodes for prosupport functions */
+       if (IsA(node, FuncExpr) || IsA(node, OpExpr))
+       {
+               HeapTuple       proctup;
+               Form_pg_proc procform;
+               bool            has_support = false;
+               Oid                     funcid;
+               const char      *exprtype;
+
+               /* Extract function OID from either FuncExpr or OpExpr */
+               if (IsA(node, FuncExpr))
+               {
+                       FuncExpr *funcexpr = (FuncExpr *) node;
+                       funcid = funcexpr->funcid;
+                       exprtype = "FuncExpr";
+               }
+               else /* OpExpr */
+               {
+                       OpExpr *opexpr = (OpExpr *) node;
+                       funcid = opexpr->opfuncid;
+                       exprtype = "OpExpr";
+               }
+
+               proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+               if (HeapTupleIsValid(proctup))
+               {
+                       procform = (Form_pg_proc) GETSTRUCT(proctup);
+                       has_support = OidIsValid(procform->prosupport);
+                       /* Skip pg_catalog namespace support functions - they 
are safe */
+                       if (has_support && procform->pronamespace != 
PG_CATALOG_NAMESPACE)
+                       {
+                               elog(DEBUG1, "Found %s with non-pg_catalog 
prosupport function, falling back to standard planner", exprtype);
+                               ReleaseSysCache(proctup);
+                               return true;
+                       }
+                       ReleaseSysCache(proctup);
+               }
+       }
+
+       return expression_tree_walker(node, check_support_functions_walker, 
context);
+}
+
+/*
+ * query_contains_support_functions
+ *             Check if a query contains function calls that have support 
functions
+ */
+static bool
+query_contains_support_functions(Query *query)
+{
+       support_functions_check_context context;
+
+       context.root = NULL;  /* We don't need PlannerInfo for this check */
+       context.recurse_queries = true; /* recurse into query structures */
+       context.recurse_sublink_testexpr = false; /* do not recurse into 
sublink test expressions */
+
+       /* Use the same traversal pattern as fold_constants but with a walker */
+       return query_or_expression_tree_walker((Node *) query, 
check_support_functions_walker, &context, 0);
+}
 
 /*
  * optimize_query
@@ -140,6 +250,23 @@ optimize_query(Query *parse, int cursorOptions, 
ParamListInfo boundParams, Optim
        /*
         * Pre-process the Query tree before calling optimizer.
         *
+        * Check if rtable is NULL and query contains support functions.
+        * If both conditions are true, fall back to standard planner to avoid
+        * crashes in extension support functions that expect valid rtable.
+        * 
+        * Performance note: This check does not significantly impact 
performance
+        * since pqueryCopy->rtable is non-NULL for most queries. The rtable is
+        * typically only NULL when the query contains sublinks, which is 
uncommon.
+        * The query_contains_support_functions() traversal only occurs in these
+        * rare cases.
+        */
+       if (pqueryCopy->rtable == NULL && 
query_contains_support_functions(pqueryCopy))
+       {
+               elog(DEBUG1, "Query rtable is NULL and contains support 
functions, falling back to standard planner");
+               return NULL;
+       }
+
+       /*
         * Constant folding will add dependencies to functions or relations in
         * glob->invalItems, for any functions that are inlined or eliminated
         * away. (We will find dependencies to other objects later, after 
planning).


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cloudberry.apache.org
For additional commands, e-mail: commits-h...@cloudberry.apache.org

Reply via email to