1 """
2 Parsing Postgres query plans (somewhat).
3 """
4
5
6
7
8
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
20 return dict((mat.group(1), mat.group(2))
21 for mat in _kvPat.finditer(kvLiteral))
22
23
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
41 return None
42
43
45 return tuple(map(float, val.split("..")))
46
49
50
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
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
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
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