Skip to content

Commit a86a8ce

Browse files
authored
Merge pull request github#12302 from MathiasVP/recursive-join-order-metric
QL: Extend the join-order badness query to recursive predicates
2 parents bb692a7 + f0fe6fb commit a86a8ce

File tree

4 files changed

+447
-41
lines changed

4 files changed

+447
-41
lines changed

ql/ql/src/codeql_ql/StructuredLogs.qll

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ class Array extends JSON::Array {
7777
*
7878
* This is needed because the evaluator log is padded with -1s in some cases.
7979
*/
80-
private float getRanked(Array a, int i) {
80+
pragma[nomagic]
81+
private float getRankedFloat(Array a, int i) {
8182
result = rank[i + 1](int j, float f | f = a.getFloat(j) and f >= 0 | f order by j)
8283
}
8384

@@ -137,10 +138,10 @@ module EvaluatorLog {
137138

138139
string getRAReference() { result = this.getString("raReference") }
139140

140-
float getCount(int i) { result = getRanked(this.getArray("counts"), i) }
141+
float getCount(int i) { result = getRankedFloat(this.getArray("counts"), i) }
141142

142143
float getDuplicationPercentage(int i) {
143-
result = getRanked(this.getArray("duplicationPercentages"), i)
144+
result = getRankedFloat(this.getArray("duplicationPercentages"), i)
144145
}
145146

146147
float getResultSize() { result = this.getFloat("resultSize") }
@@ -250,6 +251,11 @@ module KindPredicatesLog {
250251

251252
int getMillis() { result = this.getNumber("millis") }
252253

254+
PipeLineRuns getPipelineRuns() { result = this.getArray("pipelineRuns") }
255+
256+
pragma[nomagic]
257+
float getDeltaSize(int i) { result = getRankedFloat(this.getArray("deltaSizes"), i) }
258+
253259
predicate hasCompletionTime(
254260
int year, string month, int day, int hours, int minute, int second, int millisecond
255261
) {
@@ -271,9 +277,7 @@ module KindPredicatesLog {
271277

272278
float getResultSize() { result = this.getFloat("resultSize") }
273279

274-
Array getRA(string ordering) { result = this.getObject("ra").getArray(ordering) }
275-
276-
string getAnOrdering() { exists(this.getRA(result)) }
280+
string getAnOrdering() { exists(this.getRA().getPipeLine(result)) }
277281

278282
override string toString() {
279283
if exists(this.getPredicateName())
@@ -307,6 +311,8 @@ module KindPredicatesLog {
307311
RA() { evt.getObject("ra") = this }
308312

309313
PipeLine getPipeLine(string name) { result = this.getArray(name) }
314+
315+
PipeLine getPipeLine() { result = this.getPipeLine("pipeline") }
310316
}
311317

312318
class SentinelEmpty extends SummaryEvent {
@@ -341,12 +347,12 @@ module KindPredicatesLog {
341347

342348
Array getCounts() { result = this.getArray("counts") }
343349

344-
float getCount(int i) { result = getRanked(this.getArray("counts"), i) }
350+
float getCount(int i) { result = getRankedFloat(this.getArray("counts"), i) }
345351

346352
Array getDuplicationPercentage() { result = this.getArray("duplicationPercentages") }
347353

348354
float getDuplicationPercentage(int i) {
349-
result = getRanked(this.getArray("duplicationPercentages"), i)
355+
result = getRankedFloat(this.getArray("duplicationPercentages"), i)
350356
}
351357
}
352358

@@ -391,10 +397,14 @@ module KindPredicatesLog {
391397
}
392398

393399
/** Gets the `index`'th event that's evaluated by `recursive`. */
394-
private InLayer layerEventRank(ComputeRecursive recursive, int index) {
400+
private SummaryEvent layerEventRank(ComputeRecursive recursive, int index) {
395401
result =
396-
rank[index + 1](InLayer cand, int startline, string filepath |
397-
cand.getComputeRecursiveEvent() = recursive and
402+
rank[index + 1](SummaryEvent cand, int startline, string filepath |
403+
(
404+
cand = recursive
405+
or
406+
cand.(InLayer).getComputeRecursiveEvent() = recursive
407+
) and
398408
cand.hasLocationInfo(filepath, startline, _, _, _)
399409
|
400410
cand order by filepath, startline
@@ -405,15 +415,13 @@ module KindPredicatesLog {
405415
* Gets the first predicate that's evaluated in an iteration
406416
* of the SCC computation rooted at `recursive`.
407417
*/
408-
private InLayer firstPredicate(ComputeRecursive recursive) {
409-
result = layerEventRank(recursive, 0)
410-
}
418+
SummaryEvent firstPredicate(ComputeRecursive recursive) { result = layerEventRank(recursive, 0) }
411419

412420
/**
413421
* Gets the last predicate that's evaluated in an iteration
414422
* of the SCC computation rooted at `recursive`.
415423
*/
416-
private InLayer lastPredicate(ComputeRecursive recursive) {
424+
SummaryEvent lastPredicate(ComputeRecursive recursive) {
417425
exists(int n |
418426
result = layerEventRank(recursive, n) and
419427
not exists(layerEventRank(recursive, n + 1))
@@ -424,7 +432,7 @@ module KindPredicatesLog {
424432
* Holds if the predicate represented by `next` was evaluated after the
425433
* predicate represented by `prev` in the SCC computation rooted at `recursive`.
426434
*/
427-
predicate successor(ComputeRecursive recursive, InLayer prev, InLayer next) {
435+
predicate successor(ComputeRecursive recursive, SummaryEvent prev, InLayer next) {
428436
exists(int index |
429437
layerEventRank(recursive, index) = prev and
430438
layerEventRank(recursive, index + 1) = next
@@ -503,6 +511,8 @@ module KindPredicatesLog {
503511

504512
class ComputeRecursive extends SummaryEvent {
505513
ComputeRecursive() { evaluationStrategy = "COMPUTE_RECURSIVE" }
514+
515+
Depencencies getDependencies() { result = this.getObject("dependencies") }
506516
}
507517

508518
class InLayer extends SummaryEvent {
@@ -515,12 +525,8 @@ module KindPredicatesLog {
515525
Array getPredicateIterationMillis() { result = this.getArray("predicateIterationMillis") }
516526

517527
float getPredicateIterationMillis(int i) {
518-
result = getRanked(this.getArray("predicateIterationMillis"), i)
528+
result = getRankedFloat(this.getArray("predicateIterationMillis"), i)
519529
}
520-
521-
PipeLineRuns getPipelineRuns() { result = this.getArray("pipelineRuns") }
522-
523-
float getDeltaSize(int i) { result = getRanked(this.getArray("deltaSizes"), i) }
524530
}
525531

526532
class ComputedExtensional extends SummaryEvent {

ql/ql/src/experimental/RA.qll

Lines changed: 176 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,71 @@ module RAParser<RApredicate Predicate> {
2626
result = str.trim().regexpCapture("return r([0-9]+)", 1).toInt()
2727
}
2828

29+
bindingset[str]
30+
private predicate parseScan(string str, int arity, int lhs, string rhs) {
31+
exists(string r, string trimmed |
32+
r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+SCAN\\s+([0-9a-zA-Z:#_]+)\\s.*" and
33+
trimmed = str.trim()
34+
|
35+
arity = trimmed.regexpCapture(r, 1).toInt() and
36+
lhs = trimmed.regexpCapture(r, 2).toInt() and
37+
rhs = trimmed.regexpCapture(r, 3)
38+
)
39+
}
40+
41+
bindingset[str]
42+
private predicate parseJoin(string str, int arity, int lhs, string left, string right) {
43+
exists(string r, string trimmed |
44+
r =
45+
"\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+JOIN\\s+([0-9a-zA-Z:#_]+)\\s+WITH\\s+([0-9a-zA-Z:#_]+)\\s.*" and
46+
trimmed = str.trim()
47+
|
48+
arity = trimmed.regexpCapture(r, 1).toInt() and
49+
lhs = trimmed.regexpCapture(r, 2).toInt() and
50+
left = trimmed.regexpCapture(r, 3) and
51+
right = trimmed.regexpCapture(r, 4)
52+
)
53+
}
54+
55+
bindingset[str]
56+
private predicate parseSelect(string str, int arity, int lhs, string rhs) {
57+
exists(string r, string trimmed |
58+
r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+SELECT\\s+([0-9a-zA-Z:#_]+).*" and
59+
trimmed = str.trim()
60+
|
61+
arity = trimmed.regexpCapture(r, 1).toInt() and
62+
lhs = trimmed.regexpCapture(r, 2).toInt() and
63+
rhs = trimmed.regexpCapture(r, 3)
64+
)
65+
}
66+
67+
bindingset[str]
68+
private predicate parseAntiJoin(string str, int arity, int lhs, string left, string right) {
69+
exists(string r, string trimmed |
70+
r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+([0-9a-zA-Z:#_]+)\\s+AND\\s+NOT\\s+([0-9a-zA-Z:#_]+).*" and
71+
trimmed = str.trim()
72+
|
73+
arity = trimmed.regexpCapture(r, 1).toInt() and
74+
lhs = trimmed.regexpCapture(r, 2).toInt() and
75+
left = trimmed.regexpCapture(r, 3) and
76+
right = trimmed.regexpCapture(r, 4)
77+
)
78+
}
79+
2980
private newtype TRA =
3081
TReturn(Predicate p, int line, int v) { v = parseReturn(p.getLineOfRA(line)) } or
82+
TScan(Predicate p, int line, int arity, int lhs, string rhs) {
83+
parseScan(p.getLineOfRA(line), arity, lhs, rhs)
84+
} or
85+
TJoin(Predicate p, int line, int arity, int lhs, string left, string right) {
86+
parseJoin(p.getLineOfRA(line), arity, lhs, left, right)
87+
} or
88+
TSelect(Predicate p, int line, int arity, int lhs, string rhs) {
89+
parseSelect(p.getLineOfRA(line), arity, lhs, rhs)
90+
} or
91+
TAntiJoin(Predicate p, int line, int arity, int lhs, string left, string right) {
92+
parseAntiJoin(p.getLineOfRA(line), arity, lhs, left, right)
93+
} or
3194
TUnknown(Predicate p, int line, int lhs, int arity, string rhs) {
3295
rhs = parseRaExpr(p, line, arity, lhs)
3396
}
@@ -90,12 +153,12 @@ module RAParser<RApredicate Predicate> {
90153
}
91154

92155
class RAReturnExpr extends RAExpr, TReturn {
93-
RAReturnExpr() { this = TReturn(p, line, res) }
94-
95156
Predicate p;
96157
int line;
97158
int res;
98159

160+
RAReturnExpr() { this = TReturn(p, line, res) }
161+
99162
override Predicate getPredicate() { result = p }
100163

101164
override int getLine() { result = line }
@@ -108,4 +171,115 @@ module RAParser<RApredicate Predicate> {
108171

109172
override string getARhsPredicate() { none() }
110173
}
174+
175+
class RAScanExpr extends RAExpr, TScan {
176+
Predicate p;
177+
int line;
178+
int arity;
179+
int lhs;
180+
string rhs;
181+
182+
RAScanExpr() { this = TScan(p, line, arity, lhs, rhs) }
183+
184+
override Predicate getPredicate() { result = p }
185+
186+
override int getLine() { result = line }
187+
188+
override int getLhs() { result = lhs }
189+
190+
override int getArity() { result = arity }
191+
192+
override int getARhsVariable() { isVariable(rhs, result) }
193+
194+
override string getARhsPredicate() {
195+
result = rhs and
196+
not isVariable(result, _)
197+
}
198+
}
199+
200+
bindingset[s]
201+
private predicate isVariable(string s, int n) { n = s.regexpCapture("r(\\d+)", 1).toInt() }
202+
203+
class RAJoinExpr extends RAExpr, TJoin {
204+
Predicate p;
205+
int line;
206+
int arity;
207+
int lhs;
208+
string left;
209+
string right;
210+
211+
RAJoinExpr() { this = TJoin(p, line, arity, lhs, left, right) }
212+
213+
override Predicate getPredicate() { result = p }
214+
215+
override int getLine() { result = line }
216+
217+
override int getLhs() { result = lhs }
218+
219+
override int getArity() { result = arity }
220+
221+
// Note: We could return reasonable values here sometimes.
222+
override int getARhsVariable() { isVariable([left, right], result) }
223+
224+
// Note: We could return reasonable values here sometimes.
225+
override string getARhsPredicate() {
226+
result = [left, right] and
227+
not isVariable(result, _)
228+
}
229+
}
230+
231+
class RaSelectExpr extends RAExpr, TSelect {
232+
Predicate p;
233+
int line;
234+
int arity;
235+
int lhs;
236+
string rhs;
237+
238+
RaSelectExpr() { this = TSelect(p, line, arity, lhs, rhs) }
239+
240+
override Predicate getPredicate() { result = p }
241+
242+
override int getLine() { result = line }
243+
244+
override int getLhs() { result = lhs }
245+
246+
override int getArity() { result = arity }
247+
248+
// Note: We could return reasonable values here sometimes.
249+
override int getARhsVariable() { isVariable(rhs, result) }
250+
251+
// Note: We could return reasonable values here sometimes.
252+
override string getARhsPredicate() {
253+
result = rhs and
254+
not isVariable(result, _)
255+
}
256+
}
257+
258+
class RaAntiJoinExpr extends RAExpr, TAntiJoin {
259+
Predicate p;
260+
int line;
261+
int arity;
262+
int lhs;
263+
string left;
264+
string right;
265+
266+
RaAntiJoinExpr() { this = TAntiJoin(p, line, arity, lhs, left, right) }
267+
268+
override Predicate getPredicate() { result = p }
269+
270+
override int getLine() { result = line }
271+
272+
override int getLhs() { result = lhs }
273+
274+
override int getArity() { result = arity }
275+
276+
// Note: We could return reasonable values here sometimes.
277+
override int getARhsVariable() { isVariable([left, right], result) }
278+
279+
// Note: We could return reasonable values here sometimes.
280+
override string getARhsPredicate() {
281+
result = [left, right] and
282+
not isVariable(result, _)
283+
}
284+
}
111285
}

0 commit comments

Comments
 (0)