Hi hackers,

While working with cursors that reference plans with CustomScanStates nodes, I encountered a segfault which originates from search_plan_tree(). The query plan is the result of a simple SELECT statement into which I inject a Custom Scan node at the root to do some post-processing before returning rows. This plan is referenced by a second plan with a Tid Scan which originates from a query of the form DELETE FROM foo WHERE CURRENT OF my_cursor;

search_plan_tree() assumes that CustomScanState::ScanState::ss_currentRelation is never NULL. In my understanding that only holds for CustomScanState nodes which are at the bottom of the plan and actually read from a relation. CustomScanState nodes which are not at the bottom don't have ss_currentRelation set. I believe for such nodes, instead search_plan_tree() should recurse into CustomScanState::custom_ps.

I attached a patch. Any thoughts?

Best regards,
David
Swarm64

diff --git a/src/backend/executor/execCurrent.c 
b/src/backend/executor/execCurrent.c
index f89319fcd8..0d5f09402b 100644
--- a/src/backend/executor/execCurrent.c
+++ b/src/backend/executor/execCurrent.c
@@ -326,7 +326,6 @@ search_plan_tree(PlanState *node, Oid table_oid,
                case T_BitmapHeapScanState:
                case T_TidScanState:
                case T_ForeignScanState:
-               case T_CustomScanState:
                        {
                                ScanState  *sstate = (ScanState *) node;
 
@@ -335,6 +334,39 @@ search_plan_tree(PlanState *node, Oid table_oid,
                                break;
                        }
 
+
+                       /*
+                        * Custom scan nodes can be leaf nodes or inner nodes 
and therfore need special treatment.
+                        */
+               case T_CustomScanState:
+                       {
+                               CustomScanState *css = 
castNode(CustomScanState, node);
+                               ScanState       *sstate = (ScanState *) node;
+
+                               if (sstate->ss_currentRelation == NULL) /* 
inner node */
+                               {
+                                       ListCell *lc;
+
+                                       foreach (lc, sstate->custom_ps)
+                                       {
+                                               ScanState *elem = 
search_plan_tree((PlanState *)lfirst(lc), table_oid, pending_rescan);
+
+                                               if (!elem)
+                                                       continue;
+                                               if (result)
+                                                       return NULL;    /* 
multiple matches */
+                                               result = elem;
+                                       }
+                               }
+                               else /* leaf node */
+                               {
+                                       if 
(RelationGetRelid(sstate->ss_currentRelation) == table_oid)
+                                               result = sstate;
+                               }
+
+                               break;
+                       }
+
                        /*
                         * For Append, we must look through the members; watch 
out for
                         * multiple matches (possible if it was from UNION ALL)

Reply via email to