@@ -210,6 +210,9 @@ static List *set_returning_clause_references(PlannerInfo *root,
210210static List * set_windowagg_runcondition_references (PlannerInfo * root ,
211211 List * runcondition ,
212212 Plan * plan );
213+ static bool pull_up_has_session_variables_walker (Node * node ,
214+ PlannerInfo * root );
215+ static void record_plan_variable_dependency (PlannerInfo * root , Oid varid );
213216
214217
215218/*****************************************************************************
@@ -1341,6 +1344,50 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
13411344 return plan ;
13421345}
13431346
1347+ /*
1348+ * Search usage of session variables in subqueries
1349+ */
1350+ void
1351+ pull_up_has_session_variables (PlannerInfo * root )
1352+ {
1353+ Query * query = root -> parse ;
1354+
1355+ if (query -> hasSessionVariables )
1356+ {
1357+ root -> hasSessionVariables = true;
1358+ }
1359+ else
1360+ {
1361+ (void ) query_tree_walker (query ,
1362+ pull_up_has_session_variables_walker ,
1363+ (void * ) root , 0 );
1364+ }
1365+ }
1366+
1367+ static bool
1368+ pull_up_has_session_variables_walker (Node * node , PlannerInfo * root )
1369+ {
1370+ if (node == NULL )
1371+ return false;
1372+ if (IsA (node , Query ))
1373+ {
1374+ Query * query = (Query * ) node ;
1375+
1376+ if (query -> hasSessionVariables )
1377+ {
1378+ root -> hasSessionVariables = true;
1379+ return false;
1380+ }
1381+
1382+ /* recurse into subselects */
1383+ return query_tree_walker ((Query * ) node ,
1384+ pull_up_has_session_variables_walker ,
1385+ (void * ) root , 0 );
1386+ }
1387+ return expression_tree_walker (node , pull_up_has_session_variables_walker ,
1388+ (void * ) root );
1389+ }
1390+
13441391/*
13451392 * set_indexonlyscan_references
13461393 * Do set_plan_references processing on an IndexOnlyScan
@@ -2041,8 +2088,9 @@ copyVar(Var *var)
20412088 * This is code that is common to all variants of expression-fixing.
20422089 * We must look up operator opcode info for OpExpr and related nodes,
20432090 * add OIDs from regclass Const nodes into root->glob->relationOids, and
2044- * add PlanInvalItems for user-defined functions into root->glob->invalItems.
2045- * We also fill in column index lists for GROUPING() expressions.
2091+ * add PlanInvalItems for user-defined functions and session variables into
2092+ * root->glob->invalItems. We also fill in column index lists for GROUPING()
2093+ * expressions.
20462094 *
20472095 * We assume it's okay to update opcode info in-place. So this could possibly
20482096 * scribble on the planner's input data structures, but it's OK.
@@ -2132,6 +2180,13 @@ fix_expr_common(PlannerInfo *root, Node *node)
21322180 g -> cols = cols ;
21332181 }
21342182 }
2183+ else if (IsA (node , Param ))
2184+ {
2185+ Param * p = (Param * ) node ;
2186+
2187+ if (p -> paramkind == PARAM_VARIABLE )
2188+ record_plan_variable_dependency (root , p -> paramvarid );
2189+ }
21352190}
21362191
21372192/*
@@ -2141,6 +2196,10 @@ fix_expr_common(PlannerInfo *root, Node *node)
21412196 * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
21422197 * root->multiexpr_params; otherwise no change is needed.
21432198 * Just for paranoia's sake, we make a copy of the node in either case.
2199+ *
2200+ * If it's a PARAM_VARIABLE, then we collect used session variables in
2201+ * the list root->glob->sessionVariable. Also, assign the parameter's
2202+ * "paramid" to the parameter's position in that list.
21442203 */
21452204static Node *
21462205fix_param_node (PlannerInfo * root , Param * p )
@@ -2159,6 +2218,40 @@ fix_param_node(PlannerInfo *root, Param *p)
21592218 elog (ERROR , "unexpected PARAM_MULTIEXPR ID: %d" , p -> paramid );
21602219 return copyObject (list_nth (params , colno - 1 ));
21612220 }
2221+
2222+ if (p -> paramkind == PARAM_VARIABLE )
2223+ {
2224+ int n = 0 ;
2225+ bool found = false;
2226+
2227+ /* we will modify object */
2228+ p = (Param * ) copyObject (p );
2229+
2230+ /*
2231+ * Now, we can actualize list of session variables, and we can
2232+ * complete paramid parameter.
2233+ */
2234+ foreach_oid (varid , root -> glob -> sessionVariables )
2235+ {
2236+ if (varid == p -> paramvarid )
2237+ {
2238+ p -> paramid = n ;
2239+ found = true;
2240+ break ;
2241+ }
2242+ n += 1 ;
2243+ }
2244+
2245+ if (!found )
2246+ {
2247+ root -> glob -> sessionVariables = lappend_oid (root -> glob -> sessionVariables ,
2248+ p -> paramvarid );
2249+ p -> paramid = n ;
2250+ }
2251+
2252+ return (Node * ) p ;
2253+ }
2254+
21622255 return (Node * ) copyObject (p );
21632256}
21642257
@@ -2220,7 +2313,10 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
22202313 * replacing Aggref nodes that should be replaced by initplan output Params,
22212314 * choosing the best implementation for AlternativeSubPlans,
22222315 * looking up operator opcode info for OpExpr and related nodes,
2223- * and adding OIDs from regclass Const nodes into root->glob->relationOids.
2316+ * adding OIDs from regclass Const nodes into root->glob->relationOids,
2317+ * assigning paramvarid to PARAM_VARIABLE params, and collecting the
2318+ * OIDs of session variables in the root->glob->sessionVariables list
2319+ * (paramvarid is the position of the session variable in this list).
22242320 *
22252321 * 'node': the expression to be modified
22262322 * 'rtoffset': how much to increment varnos by
@@ -2242,7 +2338,8 @@ fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
22422338 root -> multiexpr_params != NIL ||
22432339 root -> glob -> lastPHId != 0 ||
22442340 root -> minmax_aggs != NIL ||
2245- root -> hasAlternativeSubPlans )
2341+ root -> hasAlternativeSubPlans ||
2342+ root -> hasSessionVariables )
22462343 {
22472344 return fix_scan_expr_mutator (node , & context );
22482345 }
@@ -3635,6 +3732,25 @@ record_plan_type_dependency(PlannerInfo *root, Oid typid)
36353732 }
36363733}
36373734
3735+ /*
3736+ * Record dependency on a session variable. The variable can be used as a
3737+ * session variable in an expression list.
3738+ */
3739+ static void
3740+ record_plan_variable_dependency (PlannerInfo * root , Oid varid )
3741+ {
3742+ PlanInvalItem * inval_item = makeNode (PlanInvalItem );
3743+
3744+ /* paramid is still session variable id */
3745+ inval_item -> cacheId = VARIABLEOID ;
3746+ inval_item -> hashValue = GetSysCacheHashValue1 (VARIABLEOID ,
3747+ ObjectIdGetDatum (varid ));
3748+
3749+ /* append this variable to global, register dependency */
3750+ root -> glob -> invalItems = lappend (root -> glob -> invalItems ,
3751+ inval_item );
3752+ }
3753+
36383754/*
36393755 * extract_query_dependencies
36403756 * Given a rewritten, but not yet planned, query or queries
0 commit comments