Package gavo :: Package utils :: Module pgexplain
[frames] | no frames]

Source Code for Module gavo.utils.pgexplain

  1  """ 
  2  Parsing Postgres query plans (somewhat). 
  3  """ 
  4   
  5  #c Copyright 2008-2019, the GAVO project 
  6  #c 
  7  #c This program is free software, covered by the GNU GPL.  See the 
  8  #c COPYING file in the source distribution. 
  9   
 10   
 11  import re 
 12   
 13  _opKVRE = r"(?P<operation>[^\s][^(]*[^\s])\s+\((?P<keyval>[^)]*)\)" 
 14  _rootLinePat = re.compile(r"^%s"%_opKVRE) 
 15  _otherLinePat = re.compile(r"^(?P<indent>\s+)->\s+%s"%_opKVRE) 
 16  _kvPat = re.compile(r"(\w+)=([^\s]+)") 
 17   
 18   
19 -def _parseKV(kvLiteral):
20 return dict((mat.group(1), mat.group(2)) 21 for mat in _kvPat.finditer(kvLiteral))
22 23
24 -def _lexPlannerLine(inputLine):
25 """returns a triple of indent, operation, operation dict for an explain 26 output line. 27 28 The explainer output lines are usually 29 [<indent> "->" ]<operation> "(" <key-value-pairs> ")" 30 31 Lines not having this format make this function return None. 32 """ 33 mat = _rootLinePat.match(inputLine) 34 if mat: 35 return 0, mat.group("operation"), _parseKV(mat.group("keyval")) 36 mat = _otherLinePat.match(inputLine) 37 if mat: 38 return (len(mat.group("indent")), mat.group("operation"), 39 _parseKV(mat.group("keyval"))) 40 # fallthrough 41 return None
42 43
44 -def _parseVal_cost(val):
45 return tuple(map(float, val.split("..")))
46
47 -def _parseVal_rows(val):
48 return int(val)
49 50
51 -def _parseKeyedValues(kvDict):
52 """parses the values in an operation dictionary. 53 """ 54 newKV = {} 55 for key, value in kvDict.iteritems(): 56 try: 57 newKV[str(key)] = globals()["_parseVal_"+key](value) 58 except KeyError: 59 pass 60 return newKV
61 62
63 -def _getChildren(phrases, childIndent):
64 """returns the children with indented by childIndent. 65 66 A helper for _makePlannerNode. 67 """ 68 children = [] 69 while phrases and phrases[0][0]==childIndent: 70 children.append(_makePlannerNode(phrases)) 71 return tuple(children)
72 73
74 -def _makePlannerNode(phrases):
75 """returns a tuple tree for phrases. 76 77 The tree structure is explained at parseQueryPlan, phrases are results 78 of _lexPlannerTree. 79 """ 80 p = phrases.pop(0) 81 children = () 82 if phrases: 83 children = _getChildren(phrases, phrases[0][0]) 84 return (str(p[1]), 85 _parseKeyedValues(p[2]) 86 )+children
87 88
89 -def parseQueryPlan(pgPlan):
90 """returns a parsed query plan from an iterator returning postgres 91 explain lines. 92 93 pgPlan usually is a cursor resulting from an EXPLAIN query. 94 95 The returned query plan is a tuple tree containing nodes of 96 (op type, op dict, (children)), where op dict contains key-value 97 pairs for things like cost, rows, etc. 98 """ 99 phrases = [toks for toks in (_lexPlannerLine(tup[0]) for tup in pgPlan) 100 if toks] 101 return _makePlannerNode(phrases)
102