我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PostgreSQL 源码解读(41)- 查询语句#26(query_planner函数#4)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PostgreSQL 源码解读(41)- 查询语句#26(query_planner函数#4)

上一小节介绍了函数query_planner中子函数add_base_rels_to_query的实现逻辑,本节继续介绍其中的子函数build_base_rel_tlists/find_placeholders_in_jointree/find_lateral_references,这几个子函数的目的仍然是完善RelOptInfo结构体信息。

query_planner代码片段:

     //...
     
     build_base_rel_tlists(root, tlist);//构建"base rels"的投影列
 
     find_placeholders_in_jointree(root);//处理jointree中的PHI
 
     find_lateral_references(root);//处理jointree中Lateral依赖
 
     //...

一、重要的数据结构

PlannerInfo
PlannerInfo贯穿整个构建查询计划的全过程.
build_base_rel_tlists、find_placeholders_in_jointree和find_lateral_references函数完善了PlannerInfo->placeholder_list链表.

 
 struct AppendRelInfo;
 
 typedef struct PlannerInfo
 {
     NodeTag     type;//Node标识
 
     Query      *parse;          
 
     PlannerGlobal *glob;        
 
     Index       query_level;    
 
     struct PlannerInfo *parent_root;    
 
     
     List       *plan_params;    
     Bitmapset  *outer_params;
 
     
     
     struct RelOptInfo **simple_rel_array;   
     int         simple_rel_array_size;  
 
     
     RangeTblEntry **simple_rte_array;   
 
     
     struct AppendRelInfo **append_rel_array;//先前已介绍,在处理集合操作如UNION ALL时使用
 
     
     Relids      all_baserels;//"base rels"
 
     
     Relids      nullable_baserels;//Nullable-side端的"base rels"
 
     
     List       *join_rel_list;  
     struct HTAB *join_rel_hash; 
 
     
     List      **join_rel_level; 
     int         join_cur_level; 
 
     List       *init_plans;     
 
     List       *cte_plan_ids;   
 
     List       *multiexpr_params;   
 
     List       *eq_classes;     
 
     List       *canon_pathkeys; 
 
     List       *left_join_clauses;  
 
     List       *right_join_clauses; 
 
     List       *full_join_clauses;  
 
     List       *join_info_list; 
 
     List       *append_rel_list;    
 
     List       *rowMarks;       
 
     List       *placeholder_list;   
 
     List       *fkey_list;      
 
     List       *query_pathkeys; 
 
     List       *group_pathkeys; 
     List       *window_pathkeys;    
     List       *distinct_pathkeys;  
     List       *sort_pathkeys;  
 
     List       *part_schemes;   
 
     List       *initial_rels;   
 
     
     List       *upper_rels[UPPERREL_FINAL + 1]; 
 
     
     struct PathTarget *upper_targets[UPPERREL_FINAL + 1];//
 
     
     List       *processed_tlist;//最后需处理的投影列
 
     
     AttrNumber *grouping_map;   
     List       *minmax_aggs;    
 
     MemoryContext planner_cxt;  
 
     double      total_table_pages;  
 
     double      tuple_fraction; 
     double      limit_tuples;   
 
     Index       qual_security_level;    
     
 
     InheritanceKind inhTargetKind;  
     bool        hasJoinRTEs;    
     bool        hasLateralRTEs; 
     bool        hasDeletedRTEs; 
     bool        hasHavingQual;  
     bool        hasPseudoConstantQuals; 
     bool        hasRecursion;   
 
     
     int         wt_param_id;    
     struct Path *non_recursive_path;    
 
     
     Relids      curOuterRels;   
     List       *curOuterParams; 
 
     
     void       *join_search_private;
 
     
     bool        partColsUpdated;
 } PlannerInfo;
 

RelOptInfo
RelOptInfo结构体贯彻逻辑优化和物理优化过程的始终.
build_base_rel_tlists完善了结构体中attr_needed和reltarget变量,find_lateral_references函数完善了结构体中lateral_vars变量.


 typedef struct RelOptInfo
 {
     NodeTag     type;//节点标识
 
     RelOptKind  reloptkind;//RelOpt类型
 
     
     Relids      relids;         
 
     
     double      rows;           
 
     
     bool        consider_startup;   
     bool        consider_param_startup; 
     bool        consider_parallel;  
 
     
     struct PathTarget *reltarget;   
 
     
     List       *pathlist;       
     List       *ppilist;        
     List       *partial_pathlist;   
     struct Path *cheapest_startup_path;//代价最低的启动路径
     struct Path *cheapest_total_path;//代价最低的整体路径
     struct Path *cheapest_unique_path;//代价最低的获取唯一值的路径
     List       *cheapest_parameterized_paths;//代价最低的参数化?路径链表
 
     
     
     Relids      direct_lateral_relids;  
     Relids      lateral_relids; 
 
     
     //reloptkind=RELOPT_BASEREL时使用的数据结构
     Index       relid;          
     Oid         reltablespace;  
     RTEKind     rtekind;        
     AttrNumber  min_attr;       
     AttrNumber  max_attr;       
     Relids     *attr_needed;    
     int32      *attr_widths;    
     List       *lateral_vars;   
     Relids      lateral_referencers;    
     List       *indexlist;      
     List       *statlist;       
     BlockNumber pages;          
     double      tuples;         
     double      allvisfrac;     
     PlannerInfo *subroot;       
     List       *subplan_params; 
     int         rel_parallel_workers;   
 
     
     //FWD相关信息
     Oid         serverid;       
     Oid         userid;         
     bool        useridiscurrent;    
     
     struct FdwRoutine *fdwroutine;
     void       *fdw_private;
 
     
     //已知的,可保证唯一的Relids链表
     List       *unique_for_rels;    
     List       *non_unique_for_rels;    
 
     
     List       *baserestrictinfo;   
     QualCost    baserestrictcost;   
     Index       baserestrict_min_security;  
     List       *joininfo;       
     bool        has_eclass_joins;   
 
     
     bool        consider_partitionwise_join;    
     Relids      top_parent_relids;  
 
     
     //分区表使用
     PartitionScheme part_scheme;    
     int         nparts;         
     struct PartitionBoundInfoData *boundinfo;   
     List       *partition_qual; 
     struct RelOptInfo **part_rels;  
     List      **partexprs;      
     List      **nullable_partexprs; 
     List       *partitioned_child_rels; 
 } RelOptInfo;

二、源码解读

基本概念
PlaceHolder
PlaceHolder即占位符,常用于减少SQL的parse过程提高性能.
如JDBC中常用的PreparedStatement:

String sql = "select * from t_dwxx where dwbh = ? and dwmc = ?";
PreparedStatement pstmt = connection.preparestatement(sql);
pstmt.setstring(1,'1001');
pstmt.setstring(2,'测试');
resultset rs = ps.executequery(); 

可以认为,其中的?所代表的是占位符.

在psql中,使用set命令定义变量,在SQL语句中使用占位符:

testdb=# \set v1 '\'1001\''
testdb=# select * from t_dwxx where dwbh = :v1;
   dwmc    | dwbh |        dwdz        
-----------+------+--------------------
 X有限公司 | 1001 | 广东省广州市荔湾区
(1 row)

build_base_rel_tlists




 void
 build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
 {
     List       *tlist_vars = pull_var_clause((Node *) final_tlist,
                                              PVC_RECURSE_AGGREGATES |
                                              PVC_RECURSE_WINDOWFUNCS |
                                              PVC_INCLUDE_PLACEHOLDERS);//获取投影列
 
     if (tlist_vars != NIL)
     {
         //添加到相应的Relation's targetlist(如不存在)
         //标记其为连接或者最终输出所需要
         add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
         list_free(tlist_vars);
     }
 
     
     if (root->parse->havingQual)//如存在Having子句,顶层的Having是在查询语句的后期才执行,需保留需要的Vars
     {
         List       *having_vars = pull_var_clause(root->parse->havingQual,
                                                   PVC_RECURSE_AGGREGATES |
                                                   PVC_INCLUDE_PLACEHOLDERS);
 
         if (having_vars != NIL)
         {
             add_vars_to_targetlist(root, having_vars,
                                    bms_make_singleton(0), true);
             list_free(having_vars);
         }
     }
 }

 
 void
 add_vars_to_targetlist(PlannerInfo *root, List *vars,
                        Relids where_needed, bool create_new_ph)
 {
     ListCell   *temp;
 
     Assert(!bms_is_empty(where_needed));
 
     foreach(temp, vars)
     {
         Node       *node = (Node *) lfirst(temp);
 
         if (IsA(node, Var))
         {
             Var        *var = (Var *) node;//属性Var
             RelOptInfo *rel = find_base_rel(root, var->varno);//找到相应的RelOptInfo
             int         attno = var->varattno;//属性编号
 
             if (bms_is_subset(where_needed, rel->relids))//where_needed是否rel的子集?
                 continue;//是,继续循环
             Assert(attno >= rel->min_attr && attno <= rel->max_attr);
             attno -= rel->min_attr;
             if (rel->attr_needed[attno] == NULL)
             {
                 
                 
                 rel->reltarget->exprs = lappend(rel->reltarget->exprs,
                                                 copyObject(var));//TODO,添加到rel->reltarget->exprs 中
                 
             }
             rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
                                                       where_needed);//where_needed添加到bitmapset中
         }
         else if (IsA(node, PlaceHolderVar))
         {
             PlaceHolderVar *phv = (PlaceHolderVar *) node;
             PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
                                                             create_new_ph);
 
             phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
                                                 where_needed);//添加PHV
         }
         else
             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
     }
 }

find_placeholders_in_jointree


 
 void
 find_placeholders_in_jointree(PlannerInfo *root)
 {
     
     if (root->glob->lastPHId != 0)
     {
         
         Assert(root->parse->jointree != NULL &&
                IsA(root->parse->jointree, FromExpr));
         find_placeholders_recurse(root, (Node *) root->parse->jointree);//递归处理
     }
 }
 
 
 static void
 find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
 {
     if (jtnode == NULL)
         return;
     if (IsA(jtnode, RangeTblRef))//RTR
     {
         
     }
     else if (IsA(jtnode, FromExpr))//FromExpr
     {
         FromExpr   *f = (FromExpr *) jtnode;
         ListCell   *l;
 
         
         foreach(l, f->fromlist)
         {
             find_placeholders_recurse(root, lfirst(l));
         }
 
         
         find_placeholders_in_expr(root, f->quals);//在表达式中搜索
     }
     else if (IsA(jtnode, JoinExpr))//JoinExpr
     {
         JoinExpr   *j = (JoinExpr *) jtnode;
 
         
         find_placeholders_recurse(root, j->larg);
         find_placeholders_recurse(root, j->rarg);
 
         
         find_placeholders_in_expr(root, j->quals);//在表达式中搜索
     }
     else
         elog(ERROR, "unrecognized node type: %d",
              (int) nodeTag(jtnode));
 }
 
 
 static void
 find_placeholders_in_expr(PlannerInfo *root, Node *expr)
 {
     List       *vars;
     ListCell   *vl;
 
     
     vars = pull_var_clause(expr,
                            PVC_RECURSE_AGGREGATES |
                            PVC_RECURSE_WINDOWFUNCS |
                            PVC_INCLUDE_PLACEHOLDERS);//遍历Vars,得到PH链表
     foreach(vl, vars)
     {
         PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl);
 
         
         if (!IsA(phv, PlaceHolderVar))
             continue;
 
         
         (void) find_placeholder_info(root, phv, true);//创建PHInfo
     }
     list_free(vars);
 }

 
 PlaceHolderInfo *
 find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv,
                       bool create_new_ph)
 {
     PlaceHolderInfo *phinfo;//结果
     Relids      rels_used;
     ListCell   *lc;
 
     
     Assert(phv->phlevelsup == 0);
 
     foreach(lc, root->placeholder_list)//已存在,返回
     {
         phinfo = (PlaceHolderInfo *) lfirst(lc);
         if (phinfo->phid == phv->phid)
             return phinfo;
     }
 
     
     if (!create_new_ph)
         elog(ERROR, "too late to create a new PlaceHolderInfo");
 
     phinfo = makeNode(PlaceHolderInfo);//构建PHInfo
 
     phinfo->phid = phv->phid;
     phinfo->ph_var = copyObject(phv);
 
     
     rels_used = pull_varnos((Node *) phv->phexpr);
     phinfo->ph_lateral = bms_difference(rels_used, phv->phrels);
     if (bms_is_empty(phinfo->ph_lateral))
         phinfo->ph_lateral = NULL;  
     phinfo->ph_eval_at = bms_int_members(rels_used, phv->phrels);
     
     if (bms_is_empty(phinfo->ph_eval_at))
     {
         phinfo->ph_eval_at = bms_copy(phv->phrels);
         Assert(!bms_is_empty(phinfo->ph_eval_at));
     }
     
     phinfo->ph_needed = NULL;   
     
     phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
                                        exprTypmod((Node *) phv->phexpr));
 
     root->placeholder_list = lappend(root->placeholder_list, phinfo);//添加到优化器信息中
 
     
     find_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr);//如存在子表达式,递归进去
 
     return phinfo;
 }

find_lateral_references



 
 void
 find_lateral_references(PlannerInfo *root)
 {
     Index       rti;
 
     
     if (!root->hasLateralRTEs)
         return;
 
     
     for (rti = 1; rti < root->simple_rel_array_size; rti++)//遍历RelOptInfo
     {
         RelOptInfo *brel = root->simple_rel_array[rti];
 
         
         if (brel == NULL)
             continue;
 
         Assert(brel->relid == rti); 
 
         
 
         
         if (brel->reloptkind != RELOPT_BASEREL)
             continue;
 
         extract_lateral_references(root, brel, rti);//获取LATERAL依赖
     }
 }
 
 static void
 extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
 {
     RangeTblEntry *rte = root->simple_rte_array[rtindex];//相应的RTE
     List       *vars;
     List       *newvars;
     Relids      where_needed;
     ListCell   *lc;
 
     
     if (!rte->lateral)//非LATERAL,退出
         return;
 
     
     //获取相应的Vars
     if (rte->rtekind == RTE_RELATION)//基表
         vars = pull_vars_of_level((Node *) rte->tablesample, 0);
     else if (rte->rtekind == RTE_SUBQUERY)//子查询
         vars = pull_vars_of_level((Node *) rte->subquery, 1);
     else if (rte->rtekind == RTE_FUNCTION)//函数
         vars = pull_vars_of_level((Node *) rte->functions, 0);
     else if (rte->rtekind == RTE_TABLEFUNC)//TABLEFUNC
         vars = pull_vars_of_level((Node *) rte->tablefunc, 0);
     else if (rte->rtekind == RTE_VALUES)//VALUES
         vars = pull_vars_of_level((Node *) rte->values_lists, 0);
     else
     {
         Assert(false);
         return;                 
     }
 
     if (vars == NIL)
         return;                 
 
     
     newvars = NIL;
     foreach(lc, vars)//遍历Vars
     {
         Node       *node = (Node *) lfirst(lc);
 
         node = copyObject(node);
         if (IsA(node, Var))//Var
         {
             Var        *var = (Var *) node;
 
             
             var->varlevelsup = 0;
         }
         else if (IsA(node, PlaceHolderVar))//PHVar
         {
             PlaceHolderVar *phv = (PlaceHolderVar *) node;
             int         levelsup = phv->phlevelsup;
 
             
             if (levelsup != 0)
                 IncrementVarSublevelsUp(node, -levelsup, 0);//调整其中的表达式
 
             
             if (levelsup > 0)
                 phv->phexpr = preprocess_phv_expression(root, phv->phexpr);//预处理PHVar表达式
         }
         else
             Assert(false);
         newvars = lappend(newvars, node);//添加到新的结果Vars中
     }
 
     list_free(vars);
 
     
     where_needed = bms_make_singleton(rtindex);//获取Rel编号
 
     
     add_vars_to_targetlist(root, newvars, where_needed, true);//添加到相应的Rel中
 
     
     brel->lateral_vars = newvars;//RelOptInfo赋值
 }

 
 List *
 pull_vars_of_level(Node *node, int levelsup)
 {
     pull_vars_context context;
 
     context.vars = NIL;
     context.sublevels_up = levelsup;
 
     
     query_or_expression_tree_walker(node,
                                     pull_vars_walker,
                                     (void *) &context,
                                     0);//调用XX_walker函数遍历
 
     return context.vars;
 }
 
 static bool
 pull_vars_walker(Node *node, pull_vars_context *context)//遍历函数
 {
     if (node == NULL)
         return false;
     if (IsA(node, Var))
     {
         Var        *var = (Var *) node;
 
         if (var->varlevelsup == context->sublevels_up)
             context->vars = lappend(context->vars, var);
         return false;
     }
     if (IsA(node, PlaceHolderVar))
     {
         PlaceHolderVar *phv = (PlaceHolderVar *) node;
 
         if (phv->phlevelsup == context->sublevels_up)
             context->vars = lappend(context->vars, phv);
         
         return false;
     }
     if (IsA(node, Query))
     {
         
         bool        result;
 
         context->sublevels_up++;
         result = query_tree_walker((Query *) node, pull_vars_walker,
                                    (void *) context, 0);
         context->sublevels_up--;
         return result;
     }
     return expression_tree_walker(node, pull_vars_walker,
                                   (void *) context);
 }

公共部分


 
 List *
 pull_var_clause(Node *node, int flags)
 {
     pull_var_clause_context context;//上下文
 
     //互斥选项检测
     
     Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES))
            != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES));
     Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS))
            != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS));
     Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS))
            != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS));
 
     context.varlist = NIL;
     context.flags = flags;
 
     pull_var_clause_walker(node, &context);//调用XX_walker函数遍历,结果保存在context.varlist中
     return context.varlist;
 }
 
 static bool
 pull_var_clause_walker(Node *node, pull_var_clause_context *context)
 {
     if (node == NULL)
         return false;
     if (IsA(node, Var))//Var类型
     {
         if (((Var *) node)->varlevelsup != 0)//非本级Var
             elog(ERROR, "Upper-level Var found where not expected");
         context->varlist = lappend(context->varlist, node);//添加到结果链表中
         return false;
     }
     else if (IsA(node, Aggref))//聚合
     {
         if (((Aggref *) node)->agglevelsup != 0)
             elog(ERROR, "Upper-level Aggref found where not expected");
         if (context->flags & PVC_INCLUDE_AGGREGATES)//包含聚合
         {
             context->varlist = lappend(context->varlist, node);//添加到结果
             
             return false;
         }
         else if (context->flags & PVC_RECURSE_AGGREGATES)//递归搜索
         {
             
         }
         else
             elog(ERROR, "Aggref found where not expected");
     }
     else if (IsA(node, GroupingFunc))//分组
     {
         if (((GroupingFunc *) node)->agglevelsup != 0)
             elog(ERROR, "Upper-level GROUPING found where not expected");
         if (context->flags & PVC_INCLUDE_AGGREGATES)//包含标记
         {
             context->varlist = lappend(context->varlist, node);
             
             return false;
         }
         else if (context->flags & PVC_RECURSE_AGGREGATES)//递归标记
         {
             
             return false;//直接返回,需与GROUP BY语句一起
         }
         else
             elog(ERROR, "GROUPING found where not expected");
     }
     else if (IsA(node, WindowFunc))//窗口函数
     {
         
         if (context->flags & PVC_INCLUDE_WINDOWFUNCS)//包含标记
         {
             context->varlist = lappend(context->varlist, node);
             
             return false;
         }
         else if (context->flags & PVC_RECURSE_WINDOWFUNCS)//递归标记
         {
             
         }
         else
             elog(ERROR, "WindowFunc found where not expected");
     }
     else if (IsA(node, PlaceHolderVar))//PH
     {
         if (((PlaceHolderVar *) node)->phlevelsup != 0)
             elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
         if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
         {
             context->varlist = lappend(context->varlist, node);
             
             return false;
         }
         else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
         {
             
         }
         else
             elog(ERROR, "PlaceHolderVar found where not expected");
     }
     return expression_tree_walker(node, pull_var_clause_walker,
                                   (void *) context);//表达式解析
 }
 

三、跟踪分析

重点考察root->simple_rel_array[n]->attr_needed、root->simple_rel_array[n]->reltarget、root->placeholder_list、root->simple_rel_array[n]->lateral_vars.
启动gdb跟踪

(gdb) b build_base_rel_tlists
Breakpoint 1 at 0x76551b: file initsplan.c, line 153.
(gdb) c
Continuing.

Breakpoint 1, build_base_rel_tlists (root=0x171ae40, final_tlist=0x1734750) at initsplan.c:153
153     List       *tlist_vars = pull_var_clause((Node *) final_tlist,
(gdb) 

final_tlist是最终的输出列(投影列),一共有5个,分别是t_dwxx.dwmc/dwbh/dwdz,t_grxx.grbh,t_jfxx.je

(gdb) p *final_tlist
$1 = {type = T_List, length = 5, head = 0x1734730, tail = 0x1734a60}
(gdb) p *(Node *)final_tlist->head->data.ptr_value
$2 = {type = T_TargetEntry}
(gdb) p *(TargetEntry *)final_tlist->head->data.ptr_value
$3 = {xpr = {type = T_TargetEntry}, expr = 0x17346e0, resno = 1, resname = 0x171a5a0 "dwmc", ressortgroupref = 0, 
  resorigtbl = 16394, resorigcol = 1, resjunk = false}

跟踪函数build_base_rel_tlists

(gdb) n
158     if (tlist_vars != NIL)
(gdb) 
160         add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
#5个Vars
(gdb) p *tlist_vars
$4 = {type = T_List, length = 5, head = 0x17369e0, tail = 0x1737cb8}
(gdb) p *(Var *)tlist_vars->head->data.ptr_value
$5 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 1043, vartypmod = 104, varcollid = 100, varlevelsup = 0, 
  varnoold = 1, varoattno = 1, location = 7}

执行函数build_base_rel_tlists,检查final_rel->attr_needed和final_rel->reltarget

(gdb) finish
Run till exit from #0  build_base_rel_tlists (root=0x171ae40, final_tlist=0x1734750) at initsplan.c:160
query_planner (root=0x171ae40, tlist=0x1734750, qp_callback=0x76e97d <standard_qp_callback>, qp_extra=0x7ffe20fc33d0)
    at planmain.c:152
152     find_placeholders_in_jointree(root);

检查root内存结构

(gdb) p *root
$15 = {type = T_PlannerInfo, parse = 0x1711680, glob = 0x1732118, query_level = 1, parent_root = 0x0, plan_params = 0x0, 
  outer_params = 0x0, simple_rel_array = 0x1736578, simple_rel_array_size = 6, simple_rte_array = 0x17365c8, 
  all_baserels = 0x0, nullable_baserels = 0x0, join_rel_list = 0x0, join_rel_hash = 0x0, join_rel_level = 0x0, 
  join_cur_level = 0, init_plans = 0x0, cte_plan_ids = 0x0, multiexpr_params = 0x0, eq_classes = 0x0, canon_pathkeys = 0x0, 
  left_join_clauses = 0x0, right_join_clauses = 0x0, full_join_clauses = 0x0, join_info_list = 0x0, append_rel_list = 0x0, 
  rowMarks = 0x0, placeholder_list = 0x0, fkey_list = 0x0, query_pathkeys = 0x0, group_pathkeys = 0x0, 
  window_pathkeys = 0x0, distinct_pathkeys = 0x0, sort_pathkeys = 0x0, part_schemes = 0x0, initial_rels = 0x0, 
  upper_rels = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, upper_targets = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  processed_tlist = 0x1734750, grouping_map = 0x0, minmax_aggs = 0x0, planner_cxt = 0x165a040, total_table_pages = 0, 
  tuple_fraction = 0, limit_tuples = -1, qual_security_level = 0, inhTargetKind = INHKIND_NONE, hasJoinRTEs = true, 
  hasLateralRTEs = true, hasDeletedRTEs = false, hasHavingQual = false, hasPseudoConstantQuals = false, 
  hasRecursion = false, wt_param_id = -1, non_recursive_path = 0x0, curOuterRels = 0x0, curOuterParams = 0x0, 
  join_search_private = 0x0, partColsUpdated = false}

RelOptInfo数组,注意数组的第0(下标)个元素为NULL(无用),有用的元素下标从1开始:
第1个元素是基础关系(相应的RTE=t_dwxx),第2个元素为NULL(相应的RTE=子查询),第3个元素为基础关系(相应的RTE=t_grxx),第4个元素为基础关系(相应的RTE=t_jfxx),第5个元素为NULL(相应的RTE=连接)

(gdb) p *root->simple_rel_array[0]
Cannot access memory at address 0x0
(gdb) p *root->simple_rel_array[1]
$31 = {type = T_RelOptInfo, reloptkind = RELOPT_BASEREL, relids = 0x1736828, rows = 0, consider_startup = false, 
  consider_param_startup = false, consider_parallel = false, reltarget = 0x1736840, pathlist = 0x0, ppilist = 0x0, 
  partial_pathlist = 0x0, cheapest_startup_path = 0x0, cheapest_total_path = 0x0, cheapest_unique_path = 0x0, 
  cheapest_parameterized_paths = 0x0, direct_lateral_relids = 0x0, lateral_relids = 0x0, relid = 1, reltablespace = 0, 
  rtekind = RTE_RELATION, min_attr = -7, max_attr = 3, attr_needed = 0x1736890, attr_widths = 0x1736920, 
  lateral_vars = 0x0, lateral_referencers = 0x0, indexlist = 0x1736cc8, statlist = 0x0, pages = 1, tuples = 3, 
  allvisfrac = 0, subroot = 0x0, subplan_params = 0x0, rel_parallel_workers = -1, serverid = 0, userid = 0, 
  useridiscurrent = false, fdwroutine = 0x0, fdw_private = 0x0, unique_for_rels = 0x0, non_unique_for_rels = 0x0, 
  baserestrictinfo = 0x0, baserestrictcost = {startup = 0, per_tuple = 0}, baserestrict_min_security = 4294967295, 
  joininfo = 0x0, has_eclass_joins = false, top_parent_relids = 0x0, part_scheme = 0x0, nparts = 0, boundinfo = 0x0, 
  partition_qual = 0x0, part_rels = 0x0, partexprs = 0x0, nullable_partexprs = 0x0, partitioned_child_rels = 0x0}
(gdb) p *root->simple_rel_array[2]
Cannot access memory at address 0x0
(gdb) p *root->simple_rel_array[3]
$32 = {type = T_RelOptInfo, reloptkind = RELOPT_BASEREL, relids = 0x17377f8, rows = 0, consider_startup = false, 
  consider_param_startup = false, consider_parallel = false, reltarget = 0x1737810, pathlist = 0x0, ppilist = 0x0, 
  partial_pathlist = 0x0, cheapest_startup_path = 0x0, cheapest_total_path = 0x0, cheapest_unique_path = 0x0, 
  cheapest_parameterized_paths = 0x0, direct_lateral_relids = 0x0, lateral_relids = 0x0, relid = 3, reltablespace = 0, 
  rtekind = RTE_RELATION, min_attr = -7, max_attr = 5, attr_needed = 0x1737860, attr_widths = 0x17378f0, 
  lateral_vars = 0x0, lateral_referencers = 0x0, indexlist = 0x0, statlist = 0x0, pages = 10, tuples = 400, allvisfrac = 0, 
  subroot = 0x0, subplan_params = 0x0, rel_parallel_workers = -1, serverid = 0, userid = 0, useridiscurrent = false, 
  fdwroutine = 0x0, fdw_private = 0x0, unique_for_rels = 0x0, non_unique_for_rels = 0x0, baserestrictinfo = 0x0, 
  baserestrictcost = {startup = 0, per_tuple = 0}, baserestrict_min_security = 4294967295, joininfo = 0x0, 
  has_eclass_joins = false, top_parent_relids = 0x0, part_scheme = 0x0, nparts = 0, boundinfo = 0x0, partition_qual = 0x0, 
  part_rels = 0x0, partexprs = 0x0, nullable_partexprs = 0x0, partitioned_child_rels = 0x0}
(gdb) p *root->simple_rel_array[4]
$33 = {type = T_RelOptInfo, reloptkind = RELOPT_BASEREL, relids = 0x1737b50, rows = 0, consider_startup = false, 
  consider_param_startup = false, consider_parallel = false, reltarget = 0x1737b68, pathlist = 0x0, ppilist = 0x0, 
  partial_pathlist = 0x0, cheapest_startup_path = 0x0, cheapest_total_path = 0x0, cheapest_unique_path = 0x0, 
  cheapest_parameterized_paths = 0x0, direct_lateral_relids = 0x0, lateral_relids = 0x0, relid = 4, reltablespace = 0, 
  rtekind = RTE_RELATION, min_attr = -7, max_attr = 3, attr_needed = 0x1737bb8, attr_widths = 0x1737c48, 
  lateral_vars = 0x0, lateral_referencers = 0x0, indexlist = 0x0, statlist = 0x0, pages = 10, tuples = 720, allvisfrac = 0, 
  subroot = 0x0, subplan_params = 0x0, rel_parallel_workers = -1, serverid = 0, userid = 0, useridiscurrent = false, 
  fdwroutine = 0x0, fdw_private = 0x0, unique_for_rels = 0x0, non_unique_for_rels = 0x0, baserestrictinfo = 0x0, 
  baserestrictcost = {startup = 0, per_tuple = 0}, baserestrict_min_security = 4294967295, joininfo = 0x0, 
  has_eclass_joins = false, top_parent_relids = 0x0, part_scheme = 0x0, nparts = 0, boundinfo = 0x0, partition_qual = 0x0, 
  part_rels = 0x0, partexprs = 0x0, nullable_partexprs = 0x0, partitioned_child_rels = 0x0}
(gdb) p *root->simple_rel_array[5]
Cannot access memory at address 0x0

查看root->simple_rel_array[n]->attr_needed、root->simple_rel_array[n]->reltarget的内存结构,以第1个元素为例:

#attr_needed(类型为Relids)为NULL
(gdb) p *root->simple_rel_array[1]->attr_needed
$47 = (Relids) 0x0
#reltarget->exprs为3个Var的链表
(gdb) p *root->simple_rel_array[1]->reltarget->exprs
$38 = {type = T_List, length = 3, head = 0x1737d40, tail = 0x1737e80}
(gdb) p *(Var *)root->simple_rel_array[1]->reltarget->exprs->head->data.ptr_value
$40 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 1043, vartypmod = 104, varcollid = 100, varlevelsup = 0, 
  varnoold = 1, varoattno = 1, location = 7}

继续执行,调用函数find_placeholders_in_jointree

152     find_placeholders_in_jointree(root);
(gdb) step
find_placeholders_in_jointree (root=0x171ae40) at placeholder.c:148
148     if (root->glob->lastPHId != 0)
(gdb) n
155 }
(gdb) n
154     find_lateral_references(root);
#链表为NULL
#psql中的:v1似乎不是占位符,理解有偏差//TODO...
(gdb) p root->placeholder_list
$48 = (List *) 0x0

下面调用子函数find_lateral_references,由于RelOptInfo中的3个不为NULL的元素对应的lateral均为FALSE(只有子查询的lateral为true,但子查询对应的RelOptInfo为NULL),因此root->simple_rel_array[1/3/4/5]->lateral_vars均为NULL

四、参考资料

initsplan.c

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PostgreSQL 源码解读(41)- 查询语句#26(query_planner函数#4)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

PostgreSQL 源码解读(71)- 查询语句#56(make_one_rel函数#21-...

本节大体介绍了动态规划算法实现(standard_join_search)中的join_search_one_level->make_join_rel->populate_joinrel_with_paths->add_paths_to_j
2022-11-30

编程热搜

目录