美文网首页PostgreSQL程序猿阵线联盟-汇总各类技术干货程序员
PostgreSQL 源码解读(20)- 查询语句#5(查询树Q

PostgreSQL 源码解读(20)- 查询语句#5(查询树Q

作者: EthanHe | 来源:发表于2018-08-16 14:30 被阅读25次

    本文简单介绍了PG查询优化重写后生成的查询树Query的详细结构,查询重写优化的输入是上一节介绍的解析树Parsetree。

    一、查询树结构

    查询语句:

    testdb=# select * from (
    testdb(# select t_dwxx.dwmc,t_grxx.grbh,t_grxx.xm,t_jfxx.ny,t_jfxx.je
    testdb(# from t_dwxx inner join t_grxx on t_dwxx.dwbh = t_grxx.dwbh
    testdb(# inner join t_jfxx on t_grxx.grbh = t_jfxx.grbh
    testdb(# where t_dwxx.dwbh IN ('1001')
    testdb(# union all
    testdb(# select t_dwxx.dwmc,t_grxx.grbh,t_grxx.xm,t_jfxx.ny,t_jfxx.je
    testdb(# from t_dwxx inner join t_grxx on t_dwxx.dwbh = t_grxx.dwbh
    testdb(# inner join t_jfxx on t_grxx.grbh = t_jfxx.grbh
    testdb(# where t_dwxx.dwbh IN ('1002') 
    testdb(# ) as ret
    testdb-# order by ret.grbh
    testdb-# limit 4;
    

    跟踪分析:

    (gdb) b exec_simple_query
    Breakpoint 1 at 0x84cad8: file postgres.c, line 893.
    (gdb) c
    Continuing.
    1047            querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
    (gdb) 
    1050            plantree_list = pg_plan_queries(querytree_list,
    (gdb) p *querytree_list
    $1 = {type = T_List, length = 1, head = 0x170c858, tail = 0x170c858}
    (gdb)  p *(Node *)(querytree_list->head->data.ptr_value)
    $2 = {type = T_Query}
    (gdb) p *(Query *)(querytree_list->head->data.ptr_value)
    $3 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true, 
      utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false, 
      hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, 
      hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x170be68, jointree = 0x170c7d8, 
      targetList = 0x170c428, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0, 
      groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0, 
      sortClause = 0x170c6b8, limitOffset = 0x0, limitCount = 0x170c788, rowMarks = 0x0, setOperations = 0x0, 
      constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 455}
    (gdb) set $query=(Query *)(querytree_list->head->data.ptr_value)
    

    Query->rtable

    #---------------------->rtable
    (gdb) set $rtable=$query->rtable
    (gdb) p *$rtable
    $8 = {type = T_List, length = 3, head = 0x170be48, tail = 0x170f6b0}
    (gdb) p *(Node *)($rtable->head->data.ptr_value)
    $9 = {type = T_RangeTblEntry}
    (gdb) p *(RangeTblEntry *)($rtable->head->data.ptr_value)
    $10 = {type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '\000', tablesample = 0x0, 
      subquery = 0x1667500, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, 
      functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, 
      ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, 
      enrname = 0x0, enrtuples = 0, alias = 0x1666d40, eref = 0x170bc18, lateral = false, inh = true, 
      inFromCl = true, requiredPerms = 2, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x0, 
      updatedCols = 0x0, securityQuals = 0x0}
    (gdb) set $rte=(RangeTblEntry *)($rtable->head->data.ptr_value)
    (gdb) p *$rte->subquery
    $12 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true, 
      utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false, 
      hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, 
      hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x16fe4e8, jointree = 0x170bbe8, 
      targetList = 0x170b358, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0, 
      groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0, 
      sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, rowMarks = 0x0, setOperations = 0x1667610, 
      constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 0}
    (gdb) p *$rte->alias
    $13 = {type = T_Alias, aliasname = 0x1666d28 "ret", colnames = 0x0}
    (gdb) p *$rte->eref
    $14 = {type = T_Alias, aliasname = 0x170bc48 "ret", colnames = 0x170bcb8}
    (gdb) p *$rte->eref->colnames
    $15 = {type = T_List, length = 5, head = 0x170bc98, tail = 0x170be28}
    (gdb) p *(Node *)$rte->eref->colnames->head->data.ptr_value
    $16 = {type = T_String}
    (gdb) p *(Value *)$rte->eref->colnames->head->data.ptr_value
    $17 = {type = T_String, val = {ival = 24165472, str = 0x170bc60 "dwmc"}}
    ---->subquery
    (gdb) p *(RangeTblEntry *)$rte->subquery->rtable->head->data.ptr_value
    $26 = {type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '\000', tablesample = 0x0, 
      subquery = 0x16faf98, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, 
      functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, 
      ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, 
      enrname = 0x0, enrtuples = 0, alias = 0x16fe240, eref = 0x16fe290, lateral = false, inh = false, 
      inFromCl = false, requiredPerms = 0, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x0, 
      updatedCols = 0x0, securityQuals = 0x0}
    (gdb) set $rte_sq_rte=((RangeTblEntry *)$rte->subquery->rtable->head->data.ptr_value)
    (gdb) p *(RangeTblEntry *)$rte_sq_rte->subquery->rtable->head->data.ptr_value
    $30 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26754, relkind = 114 'r', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, 
      funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, 
      self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, 
      enrtuples = 0, alias = 0x0, eref = 0x16677c0, lateral = false, inh = true, inFromCl = true, 
      requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16fbda8, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) set $rte_sq_rte_sq_rte=(RangeTblEntry *)$rte_sq_rte->subquery->rtable->head->data.ptr_value
    (gdb) p *$rte_sq_rte_sq_rte
    $42 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26754, relkind = 114 'r', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, 
      funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, 
      self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, 
      enrtuples = 0, alias = 0x0, eref = 0x16677c0, lateral = false, inh = true, inFromCl = true, 
      requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16fbda8, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) set $rte_sq_rte_sq_rtable=$rte_sq_rte->subquery->rtable
    (gdb) p *(RangeTblEntry *)($rte_sq_rte_sq_rtable->head->data.ptr_value)
    $60 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26754, relkind = 114 'r', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, 
      funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, 
      self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, 
      enrtuples = 0, alias = 0x0, eref = 0x16677c0, lateral = false, inh = true, inFromCl = true, 
      requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16fbda8, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) p *(RangeTblEntry *)($rte_sq_rte_sq_rtable->head->next->data.ptr_value)
    $61 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26757, relkind = 114 'r', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, 
      funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, 
      self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, 
      enrtuples = 0, alias = 0x0, eref = 0x16fb4f0, lateral = false, inh = true, inFromCl = true, 
      requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16fbe10, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) p *(RangeTblEntry *)($rte_sq_rte_sq_rtable->head->next->next->data.ptr_value)
    $62 = {type = T_RangeTblEntry, rtekind = RTE_JOIN, relid = 0, relkind = 0 '\000', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x16fbff8, 
      functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, 
      ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, 
      enrname = 0x0, enrtuples = 0, alias = 0x0, eref = 0x16fc318, lateral = false, inh = false, inFromCl = true, 
      requiredPerms = 0, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) p *(RangeTblEntry *)($rte_sq_rte_sq_rtable->head->next->next->next->data.ptr_value)
    $63 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 26760, relkind = 114 'r', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0, 
      funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0, 
      self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0, 
      enrtuples = 0, alias = 0x0, eref = 0x16fc678, lateral = false, inh = true, inFromCl = true, 
      requiredPerms = 2, checkAsUser = 0, selectedCols = 0x16fd1d0, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    (gdb) p *(RangeTblEntry *)($rte_sq_rte_sq_rtable->tail->data.ptr_value)
    $64 = {type = T_RangeTblEntry, rtekind = RTE_JOIN, relid = 0, relkind = 0 '\000', tablesample = 0x0, 
      subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x16fd3b8, 
      functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, 
      ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, 
      enrname = 0x0, enrtuples = 0, alias = 0x0, eref = 0x16fd798, lateral = false, inh = false, inFromCl = true, 
      requiredPerms = 0, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x0, updatedCols = 0x0, 
      securityQuals = 0x0}
    
    
    (gdb) p *(FromExpr *)($rte_sq_rte->subquery->jointree)
    $44 = {type = T_FromExpr, fromlist = 0x16fda18, quals = 0x16fe0f0}
    (gdb) set $rtesq2_jointree=(FromExpr *)($rte_sq_rte->subquery->jointree)
    (gdb) p *$rtesq2_jointree->fromlist
    $48 = {type = T_List, length = 1, head = 0x16fd9f8, tail = 0x16fd9f8}
    (gdb) p *(Node *)$rtesq2_jointree->fromlist->head->data.ptr_value
    $49 = {type = T_JoinExpr}
    (gdb) set $tmpvar=(JoinExpr *)$rtesq2_jointree->fromlist->head->data.ptr_value
    (gdb) p *$tmpvar
    $3 = {type = T_JoinExpr, jointype = JOIN_INNER, isNatural = false, larg = 0x2b68730, rarg = 0x2c215e8, usingClause = 0x0, quals = 0x2c28130, alias = 0x0, rtindex = 5}
    (gdb) p *$tmpvar->larg
    $4 = {type = T_JoinExpr}
    (gdb) p *(JoinExpr *)$tmpvar->larg
    $5 = {type = T_JoinExpr, jointype = JOIN_INNER, isNatural = false, larg = 0x2c1e848, rarg = 0x2c1ebd8, 
      usingClause = 0x0, quals = 0x2c20c48, alias = 0x0, rtindex = 3}
    (gdb) p *(JoinExpr *)$tmpvar->rarg
    $6 = {type = T_RangeTblRef, jointype = JOIN_SEMI, isNatural = 8, larg = 0x2b66de0, rarg = 0x636d7764, 
      usingClause = 0x10, quals = 0x2b66de0, alias = 0xda, rtindex = 46274048}
    (gdb) p *(JoinExpr *)$tmpvar->quals
    $7 = {type = T_OpExpr, jointype = 98, isNatural = 67, larg = 0x0, rarg = 0x64, usingClause = 0x2c27fb8, 
      quals = 0xa9, alias = 0x0, rtindex = 0}
    (gdb) p *((JoinExpr *)$tmpvar->larg)->larg
    $8 = {type = T_RangeTblRef}
    (gdb) p *(RangeTblRef *)((JoinExpr *)$tmpvar->larg)->larg
    $9 = {type = T_RangeTblRef, rtindex = 1}
    (gdb) p *(RangeTblRef *)((JoinExpr *)$tmpvar->larg)->rarg
    $10 = {type = T_RangeTblRef, rtindex = 2}
    (gdb) p *(RangeTblRef *)((JoinExpr *)$tmpvar->larg)->quals
    $11 = {type = T_OpExpr, rtindex = 98}
    (gdb) p *(Node *)((JoinExpr *)$tmpvar->larg)->quals
    $12 = {type = T_OpExpr}
    (gdb) p *(OpExpr *)((JoinExpr *)$tmpvar->larg)->quals
    $13 = {xpr = {type = T_OpExpr}, opno = 98, opfuncid = 67, opresulttype = 16, opretset = false, opcollid = 0, 
      inputcollid = 100, args = 0x2c20b88, location = 122}
      (gdb) p *((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args
    $72 = {type = T_List, length = 2, head = 0x2c20bd8, tail = 0x2c20bb8}
    (gdb) p *(Node *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->head->data.ptr_value
    $73 = {type = T_RelabelType}
    (gdb) p *(RelabelType *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->head->data.ptr_value
    $74 = {xpr = {type = T_RelabelType}, arg = 0x2c1f1d8, resulttype = 25, resulttypmod = -1, resultcollid = 100, 
      relabelformat = COERCE_IMPLICIT_CAST, location = -1}
    (gdb) p *((RelabelType *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->head->data.ptr_value))->arg
    Junk after end of expression.
    (gdb) p *((RelabelType *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->head->data.ptr_value)->arg
    $75 = {type = T_Var}
    (gdb) p *(Var *)((RelabelType *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->head->data.ptr_value)->arg
    $76 = {xpr = {type = T_Var}, varno = 1, varattno = 2, vartype = 1043, vartypmod = 14, varcollid = 100, 
      varlevelsup = 0, varnoold = 1, varoattno = 2, location = 110}
    (gdb) p *(Var *)((RelabelType *)((OpExpr *)((JoinExpr *)$tmpvar->larg)->quals)->args->tail->data.ptr_value)->arg
    $77 = {xpr = {type = T_Var}, varno = 2, varattno = 1, vartype = 1043, vartypmod = 14, varcollid = 100, 
      varlevelsup = 0, varnoold = 2, varoattno = 1, location = 124}
    (gdb) p *(RangeTblRef *)((JoinExpr *)$tmpvar)->rarg
    $24 = {type = T_RangeTblRef, rtindex = 4}
    (gdb) set $rtesq2_targetList=($rte_sq_rte->subquery->targetList)
    (gdb) p *$rtesq2_targetList
    $30 = {type = T_List, length = 5, head = 0x2c28840, tail = 0x2c28b70}
    (gdb) p *(Node *)$rtesq2_targetList->head->data.ptr_value
    $32 = {type = T_TargetEntry}
    (gdb) p *(TargetEntry *)$rtesq2_targetList->head->data.ptr_value
    $33 = {xpr = {type = T_TargetEntry}, expr = 0x2c28770, resno = 1, resname = 0x2b67be8 "dwmc", 
      ressortgroupref = 0, resorigtbl = 26754, resorigcol = 1, resjunk = false}
    (gdb) p *$rte->subquery->rtable
    $34 = {type = T_List, length = 2, head = 0x2c2a200, tail = 0x2c2d5f8}
    (gdb) set $rte_sq_rte2=((RangeTblEntry *)$rte->subquery->rtable->head->next->data.ptr_value)
    #分析过程类似于rte1
    (gdb) p *$rte_sq_rte2
    $35 = {type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '\000', tablesample = 0x0, 
      subquery = 0x2c211b8, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, 
      functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, 
      ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, 
      enrname = 0x0, enrtuples = 0, alias = 0x2c2d370, eref = 0x2c2d3c0, lateral = false, inh = false, 
      inFromCl = false, requiredPerms = 0, checkAsUser = 0, selectedCols = 0x0, insertedCols = 0x0, 
      updatedCols = 0x0, securityQuals = 0x0}
    (gdb) 
    (gdb) p *(FromExpr *)$rte->subquery->jointree
    $41 = {type = T_FromExpr, fromlist = 0x0, quals = 0x0}
    (gdb) p *$rte->subquery->targetList
    $45 = {type = T_List, length = 5, head = 0x2c2ddb8, tail = 0x2c2e328}
    (gdb) p *(Node *)$rte->subquery->targetList->head->data.ptr_value
    $46 = {type = T_TargetEntry}
    (gdb) p *(TargetEntry *)$rte->subquery->targetList->head->data.ptr_value
    $47 = {xpr = {type = T_TargetEntry}, expr = 0x2c2dd18, resno = 1, resname = 0x2c2dd00 "dwmc", 
      ressortgroupref = 0, resorigtbl = 0, resorigcol = 0, resjunk = false}
    
    

    Query->jointree

    #---------------------->jointree
    (gdb) p *$query->jointree
    $50 = {type = T_FromExpr, fromlist = 0x2c2e9c0, quals = 0x0}
    (gdb) p *$query->jointree->fromlist
    $51 = {type = T_List, length = 1, head = 0x2c2e9a0, tail = 0x2c2e9a0}
    (gdb) p *(Node *)$query->jointree->fromlist->head->data.ptr_value
    $52 = {type = T_RangeTblRef}
    (gdb) 
    
    

    Query->targetList

    #---------------------->targetList
    (gdb) p *$query->targetList
    $54 = {type = T_List, length = 5, head = 0x2c2ee88, tail = 0x2c2f078}
    (gdb) p *(TargetEntry *)$query->targetList->head->data.ptr_value
    $55 = {xpr = {type = T_TargetEntry}, expr = 0x2c2ea78, resno = 1, resname = 0x2c2e9f0 "dwmc", 
      ressortgroupref = 0, resorigtbl = 0, resorigcol = 0, resjunk = false}
    (gdb) 
    (gdb)
    

    Query->sortClause

    #---------------------->sortClause
    (gdb) p *(Node *)$query->sortClause->head->data.ptr_value
    $57 = {type = T_SortGroupClause}
    (gdb) p *(SortGroupClause *)$query->sortClause->head->data.ptr_value
    $58 = {type = T_SortGroupClause, tleSortGroupRef = 1, eqop = 98, sortop = 664, nulls_first = false, 
      hashable = true}
    

    Query->limitCount

    #---------------------->limitCount
    (gdb) p *$query->limitCount
    $59 = {type = T_FuncExpr}
    (gdb) p *(FuncExpr *)$query->limitCount
    $60 = {xpr = {type = T_FuncExpr}, funcid = 481, funcresulttype = 20, funcretset = false, 
      funcvariadic = false, funcformat = COERCE_IMPLICIT_CAST, funccollid = 0, inputcollid = 0, args = 0x2c2fa68, 
      location = -1}
    (gdb) 
    
    

    SQL语句最终的查询树结构如下:


    查询树

    注意:RangeTblRef中的rtindex指向的是rtable链表RangeTblEntry的Index。

    二、数据结构

    RangeTblEntry

    /*--------------------
      * RangeTblEntry -
      *    A range table is a List of RangeTblEntry nodes.
      *
      *    A range table entry may represent a plain relation, a sub-select in
      *    FROM, or the result of a JOIN clause.  (Only explicit JOIN syntax
      *    produces an RTE, not the implicit join resulting from multiple FROM
      *    items.  This is because we only need the RTE to deal with SQL features
      *    like outer joins and join-output-column aliasing.)  Other special
      *    RTE types also exist, as indicated by RTEKind.
      *
      *    Note that we consider RTE_RELATION to cover anything that has a pg_class
      *    entry.  relkind distinguishes the sub-cases.
      *
      *    alias is an Alias node representing the AS alias-clause attached to the
      *    FROM expression, or NULL if no clause.
      *
      *    eref is the table reference name and column reference names (either
      *    real or aliases).  Note that system columns (OID etc) are not included
      *    in the column list.
      *    eref->aliasname is required to be present, and should generally be used
      *    to identify the RTE for error messages etc.
      *
      *    In RELATION RTEs, the colnames in both alias and eref are indexed by
      *    physical attribute number; this means there must be colname entries for
      *    dropped columns.  When building an RTE we insert empty strings ("") for
      *    dropped columns.  Note however that a stored rule may have nonempty
      *    colnames for columns dropped since the rule was created (and for that
      *    matter the colnames might be out of date due to column renamings).
      *    The same comments apply to FUNCTION RTEs when a function's return type
      *    is a named composite type.
      *
      *    In JOIN RTEs, the colnames in both alias and eref are one-to-one with
      *    joinaliasvars entries.  A JOIN RTE will omit columns of its inputs when
      *    those columns are known to be dropped at parse time.  Again, however,
      *    a stored rule might contain entries for columns dropped since the rule
      *    was created.  (This is only possible for columns not actually referenced
      *    in the rule.)  When loading a stored rule, we replace the joinaliasvars
      *    items for any such columns with null pointers.  (We can't simply delete
      *    them from the joinaliasvars list, because that would affect the attnums
      *    of Vars referencing the rest of the list.)
      *
      *    inh is true for relation references that should be expanded to include
      *    inheritance children, if the rel has any.  This *must* be false for
      *    RTEs other than RTE_RELATION entries.
      *
      *    inFromCl marks those range variables that are listed in the FROM clause.
      *    It's false for RTEs that are added to a query behind the scenes, such
      *    as the NEW and OLD variables for a rule, or the subqueries of a UNION.
      *    This flag is not used anymore during parsing, since the parser now uses
      *    a separate "namespace" data structure to control visibility, but it is
      *    needed by ruleutils.c to determine whether RTEs should be shown in
      *    decompiled queries.
      *
      *    requiredPerms and checkAsUser specify run-time access permissions
      *    checks to be performed at query startup.  The user must have *all*
      *    of the permissions that are OR'd together in requiredPerms (zero
      *    indicates no permissions checking).  If checkAsUser is not zero,
      *    then do the permissions checks using the access rights of that user,
      *    not the current effective user ID.  (This allows rules to act as
      *    setuid gateways.)  Permissions checks only apply to RELATION RTEs.
      *
      *    For SELECT/INSERT/UPDATE permissions, if the user doesn't have
      *    table-wide permissions then it is sufficient to have the permissions
      *    on all columns identified in selectedCols (for SELECT) and/or
      *    insertedCols and/or updatedCols (INSERT with ON CONFLICT DO UPDATE may
      *    have all 3).  selectedCols, insertedCols and updatedCols are bitmapsets,
      *    which cannot have negative integer members, so we subtract
      *    FirstLowInvalidHeapAttributeNumber from column numbers before storing
      *    them in these fields.  A whole-row Var reference is represented by
      *    setting the bit for InvalidAttrNumber.
      *
      *    securityQuals is a list of security barrier quals (boolean expressions),
      *    to be tested in the listed order before returning a row from the
      *    relation.  It is always NIL in parser output.  Entries are added by the
      *    rewriter to implement security-barrier views and/or row-level security.
      *    Note that the planner turns each boolean expression into an implicitly
      *    AND'ed sublist, as is its usual habit with qualification expressions.
      *--------------------
      */
     typedef enum RTEKind
     {
         RTE_RELATION,               /* ordinary relation reference */
         RTE_SUBQUERY,               /* subquery in FROM */
         RTE_JOIN,                   /* join */
         RTE_FUNCTION,               /* function in FROM */
         RTE_TABLEFUNC,              /* TableFunc(.., column list) */
         RTE_VALUES,                 /* VALUES (<exprlist>), (<exprlist>), ... */
         RTE_CTE,                    /* common table expr (WITH list element) */
         RTE_NAMEDTUPLESTORE         /* tuplestore, e.g. for AFTER triggers */
     } RTEKind;
     
     typedef struct RangeTblEntry
     {
         NodeTag     type;
     
         RTEKind     rtekind;        /* see above */
     
         /*
          * XXX the fields applicable to only some rte kinds should be merged into
          * a union.  I didn't do this yet because the diffs would impact a lot of
          * code that is being actively worked on.  FIXME someday.
          */
     
         /*
          * Fields valid for a plain relation RTE (else zero):
          *
          * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate
          * that the tuple format of the tuplestore is the same as the referenced
          * relation.  This allows plans referencing AFTER trigger transition
          * tables to be invalidated if the underlying table is altered.
          */
         Oid         relid;          /* OID of the relation */
         char        relkind;        /* relation kind (see pg_class.relkind) */
         struct TableSampleClause *tablesample;  /* sampling info, or NULL */
     
         /*
          * Fields valid for a subquery RTE (else NULL):
          */
         Query      *subquery;       /* the sub-query */
         bool        security_barrier;   /* is from security_barrier view? */
     
         /*
          * Fields valid for a join RTE (else NULL/zero):
          *
          * joinaliasvars is a list of (usually) Vars corresponding to the columns
          * of the join result.  An alias Var referencing column K of the join
          * result can be replaced by the K'th element of joinaliasvars --- but to
          * simplify the task of reverse-listing aliases correctly, we do not do
          * that until planning time.  In detail: an element of joinaliasvars can
          * be a Var of one of the join's input relations, or such a Var with an
          * implicit coercion to the join's output column type, or a COALESCE
          * expression containing the two input column Vars (possibly coerced).
          * Within a Query loaded from a stored rule, it is also possible for
          * joinaliasvars items to be null pointers, which are placeholders for
          * (necessarily unreferenced) columns dropped since the rule was made.
          * Also, once planning begins, joinaliasvars items can be almost anything,
          * as a result of subquery-flattening substitutions.
          */
         JoinType    jointype;       /* type of join */
         List       *joinaliasvars;  /* list of alias-var expansions */
     
         /*
          * Fields valid for a function RTE (else NIL/zero):
          *
          * When funcordinality is true, the eref->colnames list includes an alias
          * for the ordinality column.  The ordinality column is otherwise
          * implicit, and must be accounted for "by hand" in places such as
          * expandRTE().
          */
         List       *functions;      /* list of RangeTblFunction nodes */
         bool        funcordinality; /* is this called WITH ORDINALITY? */
     
         /*
          * Fields valid for a TableFunc RTE (else NULL):
          */
         TableFunc  *tablefunc;
     
         /*
          * Fields valid for a values RTE (else NIL):
          */
         List       *values_lists;   /* list of expression lists */
     
         /*
          * Fields valid for a CTE RTE (else NULL/zero):
          */
         char       *ctename;        /* name of the WITH list item */
         Index       ctelevelsup;    /* number of query levels up */
         bool        self_reference; /* is this a recursive self-reference? */
     
         /*
          * Fields valid for table functions, values, CTE and ENR RTEs (else NIL):
          *
          * We need these for CTE RTEs so that the types of self-referential
          * columns are well-defined.  For VALUES RTEs, storing these explicitly
          * saves having to re-determine the info by scanning the values_lists. For
          * ENRs, we store the types explicitly here (we could get the information
          * from the catalogs if 'relid' was supplied, but we'd still need these
          * for TupleDesc-based ENRs, so we might as well always store the type
          * info here).
          *
          * For ENRs only, we have to consider the possibility of dropped columns.
          * A dropped column is included in these lists, but it will have zeroes in
          * all three lists (as well as an empty-string entry in eref).  Testing
          * for zero coltype is the standard way to detect a dropped column.
          */
         List       *coltypes;       /* OID list of column type OIDs */
         List       *coltypmods;     /* integer list of column typmods */
         List       *colcollations;  /* OID list of column collation OIDs */
     
         /*
          * Fields valid for ENR RTEs (else NULL/zero):
          */
         char       *enrname;        /* name of ephemeral named relation */
         double      enrtuples;      /* estimated or actual from caller */
     
         /*
          * Fields valid in all RTEs:
          */
         Alias      *alias;          /* user-written alias clause, if any */
         Alias      *eref;           /* expanded reference names */
         bool        lateral;        /* subquery, function, or values is LATERAL? */
         bool        inh;            /* inheritance requested? */
         bool        inFromCl;       /* present in FROM clause? */
         AclMode     requiredPerms;  /* bitmask of required access permissions */
         Oid         checkAsUser;    /* if valid, check access as this role */
         Bitmapset  *selectedCols;   /* columns needing SELECT permission */
         Bitmapset  *insertedCols;   /* columns needing INSERT permission */
         Bitmapset  *updatedCols;    /* columns needing UPDATE permission */
         List       *securityQuals;  /* security barrier quals to apply, if any */
     } RangeTblEntry;
    
    

    FromExpr/JoinExpr

     /*
      * RangeTblRef - reference to an entry in the query's rangetable
      *
      * We could use direct pointers to the RT entries and skip having these
      * nodes, but multiple pointers to the same node in a querytree cause
      * lots of headaches, so it seems better to store an index into the RT.
      */
     typedef struct RangeTblRef
     {
         NodeTag     type;
         int         rtindex;
     } RangeTblRef;
     
     /*----------
      * JoinExpr - for SQL JOIN expressions
      *
      * isNatural, usingClause, and quals are interdependent.  The user can write
      * only one of NATURAL, USING(), or ON() (this is enforced by the grammar).
      * If he writes NATURAL then parse analysis generates the equivalent USING()
      * list, and from that fills in "quals" with the right equality comparisons.
      * If he writes USING() then "quals" is filled with equality comparisons.
      * If he writes ON() then only "quals" is set.  Note that NATURAL/USING
      * are not equivalent to ON() since they also affect the output column list.
      *
      * alias is an Alias node representing the AS alias-clause attached to the
      * join expression, or NULL if no clause.  NB: presence or absence of the
      * alias has a critical impact on semantics, because a join with an alias
      * restricts visibility of the tables/columns inside it.
      *
      * During parse analysis, an RTE is created for the Join, and its index
      * is filled into rtindex.  This RTE is present mainly so that Vars can
      * be created that refer to the outputs of the join.  The planner sometimes
      * generates JoinExprs internally; these can have rtindex = 0 if there are
      * no join alias variables referencing such joins.
      *----------
      */
     typedef struct JoinExpr
     {
         NodeTag     type;
         JoinType    jointype;       /* type of join */
         bool        isNatural;      /* Natural join? Will need to shape table */
         Node       *larg;           /* left subtree */
         Node       *rarg;           /* right subtree */
         List       *usingClause;    /* USING clause, if any (list of String) */
         Node       *quals;          /* qualifiers on join, if any */
         Alias      *alias;          /* user-written alias clause, if any */
         int         rtindex;        /* RT index assigned for join, or 0 */
     } JoinExpr;
     
     /*----------
      * FromExpr - represents a FROM ... WHERE ... construct
      *
      * This is both more flexible than a JoinExpr (it can have any number of
      * children, including zero) and less so --- we don't need to deal with
      * aliases and so on.  The output column set is implicitly just the union
      * of the outputs of the children.
      *----------
      */
     typedef struct FromExpr
     {
         NodeTag     type;
         List       *fromlist;       /* List of join subtrees */
         Node       *quals;          /* qualifiers on join, if any */
     } FromExpr;
     
    

    TargetEntry

     
     /*--------------------
      * TargetEntry -
      *     a target entry (used in query target lists)
      *
      * Strictly speaking, a TargetEntry isn't an expression node (since it can't
      * be evaluated by ExecEvalExpr).  But we treat it as one anyway, since in
      * very many places it's convenient to process a whole query targetlist as a
      * single expression tree.
      *
      * In a SELECT's targetlist, resno should always be equal to the item's
      * ordinal position (counting from 1).  However, in an INSERT or UPDATE
      * targetlist, resno represents the attribute number of the destination
      * column for the item; so there may be missing or out-of-order resnos.
      * It is even legal to have duplicated resnos; consider
      *      UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ...
      * The two meanings come together in the executor, because the planner
      * transforms INSERT/UPDATE tlists into a normalized form with exactly
      * one entry for each column of the destination table.  Before that's
      * happened, however, it is risky to assume that resno == position.
      * Generally get_tle_by_resno() should be used rather than list_nth()
      * to fetch tlist entries by resno, and only in SELECT should you assume
      * that resno is a unique identifier.
      *
      * resname is required to represent the correct column name in non-resjunk
      * entries of top-level SELECT targetlists, since it will be used as the
      * column title sent to the frontend.  In most other contexts it is only
      * a debugging aid, and may be wrong or even NULL.  (In particular, it may
      * be wrong in a tlist from a stored rule, if the referenced column has been
      * renamed by ALTER TABLE since the rule was made.  Also, the planner tends
      * to store NULL rather than look up a valid name for tlist entries in
      * non-toplevel plan nodes.)  In resjunk entries, resname should be either
      * a specific system-generated name (such as "ctid") or NULL; anything else
      * risks confusing ExecGetJunkAttribute!
      *
      * ressortgroupref is used in the representation of ORDER BY, GROUP BY, and
      * DISTINCT items.  Targetlist entries with ressortgroupref=0 are not
      * sort/group items.  If ressortgroupref>0, then this item is an ORDER BY,
      * GROUP BY, and/or DISTINCT target value.  No two entries in a targetlist
      * may have the same nonzero ressortgroupref --- but there is no particular
      * meaning to the nonzero values, except as tags.  (For example, one must
      * not assume that lower ressortgroupref means a more significant sort key.)
      * The order of the associated SortGroupClause lists determine the semantics.
      *
      * resorigtbl/resorigcol identify the source of the column, if it is a
      * simple reference to a column of a base table (or view).  If it is not
      * a simple reference, these fields are zeroes.
      *
      * If resjunk is true then the column is a working column (such as a sort key)
      * that should be removed from the final output of the query.  Resjunk columns
      * must have resnos that cannot duplicate any regular column's resno.  Also
      * note that there are places that assume resjunk columns come after non-junk
      * columns.
      *--------------------
      */
     typedef struct TargetEntry
     {
         Expr        xpr;
         Expr       *expr;           /* expression to evaluate */
         AttrNumber  resno;          /* attribute number (see notes above) */
         char       *resname;        /* name of the column (could be NULL) */
         Index       ressortgroupref;    /* nonzero if referenced by a sort/group
                                          * clause */
         Oid         resorigtbl;     /* OID of column's source table */
         AttrNumber  resorigcol;     /* column's number in source table */
         bool        resjunk;        /* set to true to eliminate the attribute from
                                      * final target list */
     } TargetEntry;
    
    

    OpExpr

    /*
      * OpExpr - expression node for an operator invocation
      *
      * Semantically, this is essentially the same as a function call.
      *
      * Note that opfuncid is not necessarily filled in immediately on creation
      * of the node.  The planner makes sure it is valid before passing the node
      * tree to the executor, but during parsing/planning opfuncid can be 0.
      */
     typedef struct OpExpr
     {
         Expr        xpr;
         Oid         opno;           /* PG_OPERATOR OID of the operator */
         Oid         opfuncid;       /* PG_PROC OID of underlying function */
         Oid         opresulttype;   /* PG_TYPE OID of result value */
         bool        opretset;       /* true if operator returns set */
         Oid         opcollid;       /* OID of collation of result */
         Oid         inputcollid;    /* OID of collation that operator should use */
         List       *args;           /* arguments to the operator (1 or 2) */
         int         location;       /* token location, or -1 if unknown */
     } OpExpr;
    
    

    三、小结

    1、Query树结构:一棵树关键的信息包括rtable(相关的数据表或子查询等)、jointree(连接树信息)、targetList(输出的目标字段等信息)等;
    2、数据结构:重要的数据结构包括RangeTblEntry、FromExpr、JoinExpr等。

    相关文章

      网友评论

        本文标题:PostgreSQL 源码解读(20)- 查询语句#5(查询树Q

        本文链接:https://www.haomeiwen.com/subject/erpwbftx.html