PostgreSQL 原始碼解讀(20)- 查詢語句#5(查詢樹Query詳解)
本文簡單介紹了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等。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6906/viewspace-2374896/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL 原始碼解讀(43)- 查詢語句#28(query_planner函式#5)SQL原始碼函式
- PostgreSQL 原始碼解讀(19)- 查詢語句#4(ParseTree詳解)SQL原始碼
- PostgreSQL 原始碼解讀(24)- 查詢語句#9(查詢重寫)SQL原始碼
- PostgreSQL 原始碼解讀(23)- 查詢語句#8(PlannedStmt與QUERY P...SQL原始碼
- PostgreSQL 原始碼解讀(29)- 查詢語句#14(查詢優化-上拉子查詢)SQL原始碼優化
- PostgreSQL 原始碼解讀(46)- 查詢語句#31(query_planner函式#7)SQL原始碼函式
- PostgreSQL 原始碼解讀(47)- 查詢語句#32(query_planner函式#8)SQL原始碼函式
- PostgreSQL 原始碼解讀(48)- 查詢語句#33(query_planner函式#9)SQL原始碼函式
- PostgreSQL 原始碼解讀(41)- 查詢語句#26(query_planner函式#4)SQL原始碼函式
- PostgreSQL 原始碼解讀(40)- 查詢語句#25(query_planner函式#3)SQL原始碼函式
- PostgreSQL 原始碼解讀(45)- 查詢語句#30(query_planner函式#6)SQL原始碼函式
- PostgreSQL 原始碼解讀(38)- 查詢語句#23(query_planner函式#1)SQL原始碼函式
- PostgreSQL 原始碼解讀(39)- 查詢語句#24(query_planner函式#2)SQL原始碼函式
- PostgreSQL 原始碼解讀(25)- 查詢語句#10(查詢優化概覽)SQL原始碼優化
- PostgreSQL 原始碼解讀(17)- 查詢語句#2(查詢優化基礎)SQL原始碼優化
- PostgreSQL 原始碼解讀(21)- 查詢語句#6(PlannedStmt詳解-跟蹤分析)SQL原始碼
- PostgreSQL 原始碼解讀(18)- 查詢語句#3(SQL Parse)SQL原始碼
- PostgreSQL 原始碼解讀(36)- 查詢語句#21(查詢優化-消除外連線)SQL原始碼優化
- PostgreSQL 原始碼解讀(37)- 查詢語句#22(查詢優化-grouping_plan...SQL原始碼優化
- PostgreSQL 原始碼解讀(83)- 查詢語句#68(PortalStart函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(42)- 查詢語句#27(等價類)SQL原始碼
- PostgreSQL 原始碼解讀(74)- 查詢語句#59(Review - subquery_...SQL原始碼View
- PostgreSQL 原始碼解讀(75)- 查詢語句#60(Review - standard_...SQL原始碼View
- PostgreSQL 原始碼解讀(97)- 查詢語句#79(ExecHashJoin函式#5-H...SQL原始碼函式
- PostgreSQL 原始碼解讀(22)- 查詢語句#7(PlannedStmt結構詳解-日誌分析)SQL原始碼
- PostgreSQL 原始碼解讀(35)- 查詢語句#20(查詢優化-簡化Having和Grou...SQL原始碼優化
- PostgreSQL 原始碼解讀(90)- 查詢語句#75(ExecHashJoin函式#1)SQL原始碼函式
- PostgreSQL 原始碼解讀(91)- 查詢語句#76(ExecHashJoin函式#2)SQL原始碼函式
- PostgreSQL 原始碼解讀(93)- 查詢語句#77(ExecHashJoin函式#3)SQL原始碼函式
- PostgreSQL 原始碼解讀(81)- 查詢語句#66(Review - exec_simp...SQL原始碼View
- PostgreSQL 原始碼解讀(84)- 查詢語句#69(PortalStart->InitP...SQL原始碼
- PostgreSQL 原始碼解讀(85)- 查詢語句#70(PortalRun->InitPla...SQL原始碼
- PostgreSQL 原始碼解讀(86)- 查詢語句#71(PortalRun->PortalR...SQL原始碼
- PostgreSQL 原始碼解讀(50)- 查詢語句#35(Optimizer Review#1)SQL原始碼View
- PostgreSQL 原始碼解讀(51)- 查詢語句#36(Optimizer Review#2)SQL原始碼View
- PostgreSQL 原始碼解讀(26)- 查詢語句#11(查詢優化-上拉子連結#1)SQL原始碼優化
- PostgreSQL 原始碼解讀(27)- 查詢語句#12(查詢優化-上拉子連結#2)SQL原始碼優化
- PostgreSQL 原始碼解讀(28)- 查詢語句#13(查詢優化-上拉子連結#3)SQL原始碼優化