Merge lp:~mmcm/akiban-server/pipeline-branch-lookup-nested into lp:~akiban-technologies/akiban-server/trunk
- pipeline-branch-lookup-nested
- Merge into trunk
Proposed by
Mike McMahon
Status: | Merged |
---|---|
Approved by: | Nathan Williams |
Approved revision: | 2741 |
Merged at revision: | 2713 |
Proposed branch: | lp:~mmcm/akiban-server/pipeline-branch-lookup-nested |
Merge into: | lp:~akiban-technologies/akiban-server/trunk |
Prerequisite: | lp:~mmcm/akiban-server/group-lookup |
Diff against target: |
1429 lines (+651/-297) 17 files modified
src/main/java/com/akiban/qp/operator/API.java (+27/-19) src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java (+258/-45) src/main/java/com/akiban/qp/operator/IndexScan_Default.java (+24/-196) src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java (+243/-0) src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java (+13/-11) src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java (+2/-2) src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java (+24/-11) src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java (+21/-5) src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java (+31/-0) src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected (+1/-1) src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected (+1/-1) |
To merge this branch: | bzr merge lp:~mmcm/akiban-server/pipeline-branch-lookup-nested |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nathan Williams | Approve | ||
Review via email: mp+176825@code.launchpad.net |
Commit message
Description of the change
Add lookahead option to BranchLookup_
This is done by abstracting out IndexScan_Default's pipelined cursor, which keeps a pool of open cursors for bindings that it reads ahead. And then implementing a new RowCursor that wraps a GroupCursor and (1) inserts the input row where necessary and (2) filters by output row types.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/main/java/com/akiban/qp/operator/API.java' |
2 | --- src/main/java/com/akiban/qp/operator/API.java 2013-07-25 00:26:26 +0000 |
3 | +++ src/main/java/com/akiban/qp/operator/API.java 2013-07-25 00:26:27 +0000 |
4 | @@ -190,13 +190,17 @@ |
5 | UserTableRowType outputRowType, |
6 | InputPreservationOption flag) |
7 | { |
8 | + return groupLookup_Default(inputOperator, group, inputRowType, branchOutputRowTypes(outputRowType), flag, 1); |
9 | + } |
10 | + |
11 | + protected static List<UserTableRowType> branchOutputRowTypes(UserTableRowType outputRowType) { |
12 | List<UserTableRowType> outputRowTypes = new ArrayList<>(); |
13 | outputRowTypes.add(outputRowType); |
14 | Schema schema = (Schema)outputRowType.schema(); |
15 | for (RowType rowType : schema.descendentTypes(outputRowType, schema.userTableTypes())) { |
16 | outputRowTypes.add((UserTableRowType)rowType); |
17 | } |
18 | - return groupLookup_Default(inputOperator, group, inputRowType, outputRowTypes, flag, 1); |
19 | + return outputRowTypes; |
20 | } |
21 | |
22 | /** deprecated */ |
23 | @@ -206,13 +210,14 @@ |
24 | InputPreservationOption flag, |
25 | int inputBindingPosition) |
26 | { |
27 | - return new BranchLookup_Nested(group, |
28 | - inputRowType, |
29 | - inputRowType, |
30 | - null, |
31 | - outputRowType, |
32 | - flag, |
33 | - inputBindingPosition); |
34 | + return branchLookup_Nested(group, |
35 | + inputRowType, |
36 | + inputRowType, |
37 | + null, |
38 | + branchOutputRowTypes(outputRowType), |
39 | + flag, |
40 | + inputBindingPosition, |
41 | + 1); |
42 | } |
43 | |
44 | public static Operator branchLookup_Nested(Group group, |
45 | @@ -222,30 +227,33 @@ |
46 | InputPreservationOption flag, |
47 | int inputBindingPosition) |
48 | { |
49 | - return new BranchLookup_Nested(group, |
50 | - inputRowType, |
51 | - inputRowType, |
52 | - ancestorRowType, |
53 | - outputRowType, |
54 | - flag, |
55 | - inputBindingPosition); |
56 | + return branchLookup_Nested(group, |
57 | + inputRowType, |
58 | + inputRowType, |
59 | + ancestorRowType, |
60 | + branchOutputRowTypes(outputRowType), |
61 | + flag, |
62 | + inputBindingPosition, |
63 | + 1); |
64 | } |
65 | |
66 | public static Operator branchLookup_Nested(Group group, |
67 | RowType inputRowType, |
68 | RowType sourceRowType, |
69 | UserTableRowType ancestorRowType, |
70 | - UserTableRowType outputRowType, |
71 | + Collection<UserTableRowType> outputRowTypes, |
72 | InputPreservationOption flag, |
73 | - int inputBindingPosition) |
74 | + int inputBindingPosition, |
75 | + int lookaheadQuantum) |
76 | { |
77 | return new BranchLookup_Nested(group, |
78 | inputRowType, |
79 | sourceRowType, |
80 | ancestorRowType, |
81 | - outputRowType, |
82 | + outputRowTypes, |
83 | flag, |
84 | - inputBindingPosition); |
85 | + inputBindingPosition, |
86 | + lookaheadQuantum); |
87 | } |
88 | |
89 | // Limit |
90 | |
91 | === modified file 'src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java' |
92 | --- src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-17 20:41:05 +0000 |
93 | +++ src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-25 00:26:27 +0000 |
94 | @@ -25,6 +25,7 @@ |
95 | import com.akiban.qp.rowtype.RowType; |
96 | import com.akiban.qp.rowtype.UserTableRowType; |
97 | import com.akiban.qp.rowtype.*; |
98 | +import com.akiban.server.api.dml.ColumnSelector; |
99 | import com.akiban.server.explain.*; |
100 | import com.akiban.server.explain.std.LookUpOperatorExplainer; |
101 | import com.akiban.util.ArgumentValidation; |
102 | @@ -33,6 +34,11 @@ |
103 | import org.slf4j.Logger; |
104 | import org.slf4j.LoggerFactory; |
105 | |
106 | +import java.util.ArrayList; |
107 | +import java.util.Collections; |
108 | +import java.util.Comparator; |
109 | +import java.util.Collection; |
110 | +import java.util.List; |
111 | import java.util.Set; |
112 | |
113 | import static java.lang.Math.min; |
114 | @@ -53,18 +59,17 @@ |
115 | |
116 | <ul> |
117 | |
118 | - <li><b>GroupTable groupTable:</b> The group table containing the |
119 | - ancestors of interest. |
120 | + <li><b>Group group:</b> The group containing the ancestors of interest. |
121 | |
122 | <li><b>RowType inputRowType:</b> Bound row will be of this type. |
123 | |
124 | <li><b>RowType sourceRowType:</b> Branches will be located for input |
125 | - rows of this type. |
126 | + rows of this type. Possibly a subrow of inputRowType. |
127 | |
128 | <li><b>UserTableRowType ancestorRowType:</b> Identifies the table in the group at which branching occurs. |
129 | - Must be an ancestor of both inputRowType's table and outputRowType's table. |
130 | + Must be an ancestor of both inputRowType's table and outputRowTypes' tables. |
131 | |
132 | - <li><b>UserTableRowType outputRowType:</b> Type at the root of the branch to be |
133 | + <li><b>UserTableRowType outputRowTypes:</b> Types within the branch to be |
134 | retrieved. |
135 | |
136 | <li><b>API.InputPreservationOption flag:</b> Indicates whether rows of type rowType |
137 | @@ -74,17 +79,19 @@ |
138 | <li><b>int inputBindingPosition:</b> Indicates input row's position in the query context. The hkey |
139 | of this row will be used to locate ancestors. |
140 | |
141 | + <li><b>int lookaheadQuantum:</b> Number of cursors to try to keep open by looking |
142 | + ahead in bindings stream. |
143 | + |
144 | </ul> |
145 | |
146 | inputRowType may be an index row type, a user table row type, or an hkey row type. flag = KEEP_INPUT is permitted |
147 | only for user table row types. |
148 | |
149 | - The groupTable, inputRowType, and outputRowType must belong to the |
150 | + The groupTable, inputRowType, and outputRowTypes must belong to the |
151 | same group. |
152 | |
153 | ancestorRowType's table must be an ancestor of |
154 | - inputRowType's table and outputRowType's table. outputRowType's table must be the parent |
155 | - of outputRowType's table. |
156 | + inputRowType's table and outputRowTypes' tables. |
157 | |
158 | <h1>Behavior</h1> |
159 | |
160 | @@ -139,7 +146,7 @@ |
161 | getClass().getSimpleName(), |
162 | group.getRoot().getName(), |
163 | sourceRowType, |
164 | - outputRowType); |
165 | + outputRowTypes); |
166 | } |
167 | |
168 | // Operator interface |
169 | @@ -152,7 +159,14 @@ |
170 | @Override |
171 | public Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) |
172 | { |
173 | - return new Execution(context, bindingsCursor); |
174 | + if (lookaheadQuantum <= 1) { |
175 | + return new Execution(context, bindingsCursor); |
176 | + } |
177 | + else { |
178 | + return new LookaheadExecution(context, bindingsCursor, |
179 | + context.getStore(commonAncestor), |
180 | + lookaheadQuantum); |
181 | + } |
182 | } |
183 | |
184 | @Override |
185 | @@ -167,14 +181,15 @@ |
186 | RowType inputRowType, |
187 | RowType sourceRowType, |
188 | UserTableRowType ancestorRowType, |
189 | - UserTableRowType outputRowType, |
190 | + Collection<UserTableRowType> outputRowTypes, |
191 | API.InputPreservationOption flag, |
192 | - int inputBindingPosition) |
193 | + int inputBindingPosition, |
194 | + int lookaheadQuantum) |
195 | { |
196 | ArgumentValidation.notNull("group", group); |
197 | ArgumentValidation.notNull("inputRowType", inputRowType); |
198 | ArgumentValidation.notNull("sourceRowType", sourceRowType); |
199 | - ArgumentValidation.notNull("outputRowType", outputRowType); |
200 | + ArgumentValidation.notEmpty("outputRowTypes", outputRowTypes); |
201 | ArgumentValidation.notNull("flag", flag); |
202 | ArgumentValidation.isTrue("sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT", |
203 | sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT); |
204 | @@ -185,42 +200,75 @@ |
205 | } else if (sourceRowType instanceof IndexRowType) { |
206 | inputTableType = ((IndexRowType) sourceRowType).tableType(); |
207 | } else if (sourceRowType instanceof HKeyRowType) { |
208 | - Schema schema = outputRowType.schema(); |
209 | + Schema schema = outputRowTypes.iterator().next().schema(); |
210 | inputTableType = schema.userTableRowType(sourceRowType.hKey().userTable()); |
211 | } |
212 | assert inputTableType != null : sourceRowType; |
213 | UserTable inputTable = inputTableType.userTable(); |
214 | - UserTable outputTable = outputRowType.userTable(); |
215 | - ArgumentValidation.isSame("inputTable.getGroup()", |
216 | - inputTable.getGroup(), |
217 | - "outputTable.getGroup()", |
218 | - outputTable.getGroup()); |
219 | + ArgumentValidation.isSame("inputTable.getGroup()", inputTable.getGroup(), |
220 | + "group", group); |
221 | + UserTable commonAncestor; |
222 | + if (ancestorRowType == null) { |
223 | + commonAncestor = inputTable; |
224 | + } else { |
225 | + commonAncestor = ancestorRowType.userTable(); |
226 | + ArgumentValidation.isTrue("ancestorRowType.ancestorOf(inputTableType)", |
227 | + ancestorRowType.ancestorOf(inputTableType)); |
228 | + } |
229 | + for (UserTableRowType outputRowType : outputRowTypes) { |
230 | + UserTable outputTable = outputRowType.userTable(); |
231 | + ArgumentValidation.isSame("outputTable.getGroup()", outputTable.getGroup(), |
232 | + "group", group); |
233 | + if (ancestorRowType == null) { |
234 | + commonAncestor = commonAncestor(commonAncestor, outputTable); |
235 | + } |
236 | + else { |
237 | + ArgumentValidation.isTrue("ancestorRowType.ancestorOf(outputRowType)", |
238 | + ancestorRowType.ancestorOf(outputRowType)); |
239 | + } |
240 | + } |
241 | this.group = group; |
242 | this.inputRowType = inputRowType; |
243 | this.sourceRowType = sourceRowType; |
244 | - this.outputRowType = outputRowType; |
245 | + this.outputRowTypes = new ArrayList<>(outputRowTypes); |
246 | + Collections.sort(this.outputRowTypes, |
247 | + new Comparator<UserTableRowType>() |
248 | + { |
249 | + @Override |
250 | + public int compare(UserTableRowType x, UserTableRowType y) |
251 | + { |
252 | + return x.userTable().getDepth() - y.userTable().getDepth(); |
253 | + } |
254 | + }); |
255 | + this.commonAncestor = commonAncestor; |
256 | this.keepInput = flag == API.InputPreservationOption.KEEP_INPUT; |
257 | this.inputBindingPosition = inputBindingPosition; |
258 | - if (ancestorRowType == null) { |
259 | - this.commonAncestor = commonAncestor(inputTable, outputTable); |
260 | - } else { |
261 | - this.commonAncestor = ancestorRowType.userTable(); |
262 | - ArgumentValidation.isTrue("ancestorRowType.ancestorOf(inputTableType)", |
263 | - ancestorRowType.ancestorOf(inputTableType)); |
264 | - ArgumentValidation.isTrue("ancestorRowType.ancestorOf(outputRowType)", |
265 | - ancestorRowType.ancestorOf(outputRowType)); |
266 | - } |
267 | - switch (outputTable.getDepth() - commonAncestor.getDepth()) { |
268 | - case 0: |
269 | - branchRootOrdinal = -1; |
270 | - break; |
271 | - case 1: |
272 | - branchRootOrdinal = ordinal(outputTable); |
273 | - break; |
274 | - default: |
275 | - branchRootOrdinal = -1; |
276 | - ArgumentValidation.isTrue("false", false); |
277 | - break; |
278 | + this.lookaheadQuantum = lookaheadQuantum; |
279 | + // See whether there is a single branch beneath commonAncestor |
280 | + // with all output row types. |
281 | + UserTable outputTable = this.outputRowTypes.get(0).userTable(); |
282 | + boolean allOneBranch; |
283 | + if (outputTable == commonAncestor) { |
284 | + allOneBranch = false; |
285 | + } |
286 | + else { |
287 | + while (outputTable.parentTable() != commonAncestor) { |
288 | + outputTable = outputTable.parentTable(); |
289 | + } |
290 | + UserTableRowType outputTableRowType = this.outputRowTypes.get(0).schema().userTableRowType(outputTable); |
291 | + allOneBranch = true; |
292 | + for (int i = 1; i < this.outputRowTypes.size(); i++) { |
293 | + if (!outputTableRowType.ancestorOf(this.outputRowTypes.get(i))) { |
294 | + allOneBranch = false; |
295 | + break; |
296 | + } |
297 | + } |
298 | + } |
299 | + if (allOneBranch) { |
300 | + branchRootOrdinal = ordinal(outputTable); |
301 | + } |
302 | + else { |
303 | + branchRootOrdinal = -1; |
304 | } |
305 | // branchRootOrdinal = -1 means that outputTable is an ancestor of inputTable. In this case, inputPrecedesBranch |
306 | // is false. Otherwise, branchRoot's parent is the common ancestor. Find inputTable's ancestor that is also |
307 | @@ -268,11 +316,12 @@ |
308 | |
309 | private final Group group; |
310 | private final RowType inputRowType, sourceRowType; |
311 | - private final UserTableRowType outputRowType; |
312 | + private final List<UserTableRowType> outputRowTypes; |
313 | private final boolean keepInput; |
314 | // If keepInput is true, inputPrecedesBranch controls whether input row appears before the retrieved branch. |
315 | private final boolean inputPrecedesBranch; |
316 | private final int inputBindingPosition; |
317 | + private final int lookaheadQuantum; |
318 | private final UserTable commonAncestor; |
319 | private final int branchRootOrdinal; |
320 | |
321 | @@ -281,10 +330,15 @@ |
322 | { |
323 | Attributes atts = new Attributes(); |
324 | atts.put(Label.BINDING_POSITION, PrimitiveExplainer.getInstance(inputBindingPosition)); |
325 | - atts.put(Label.OUTPUT_TYPE, outputRowType.getExplainer(context)); |
326 | + for (UserTableRowType outputRowType : outputRowTypes) { |
327 | + atts.put(Label.OUTPUT_TYPE, outputRowType.getExplainer(context)); |
328 | + } |
329 | + UserTableRowType outputRowType = outputRowTypes.get(0); |
330 | UserTableRowType ancestorRowType = outputRowType.schema().userTableRowType(commonAncestor); |
331 | - if ((ancestorRowType != sourceRowType) && (ancestorRowType != outputRowType)) |
332 | + if ((ancestorRowType != sourceRowType) && (ancestorRowType != outputRowType)) { |
333 | atts.put(Label.ANCESTOR_TYPE, ancestorRowType.getExplainer(context)); |
334 | + } |
335 | + atts.put(Label.PIPELINE, PrimitiveExplainer.getInstance(lookaheadQuantum)); |
336 | return new LookUpOperatorExplainer(getName(), atts, sourceRowType, false, null, context); |
337 | } |
338 | |
339 | @@ -334,7 +388,9 @@ |
340 | row = inputRow.get(); |
341 | inputRow.release(); |
342 | } else { |
343 | - row = cursor.next(); |
344 | + do { |
345 | + row = cursor.next(); |
346 | + } while ((row != null) && !outputRowTypes.contains(row.rowType())); |
347 | if (row == null) { |
348 | if (keepInput && !inputPrecedesBranch) { |
349 | assert inputRow.isHolding(); |
350 | @@ -395,7 +451,7 @@ |
351 | { |
352 | super(context, bindingsCursor); |
353 | this.cursor = adapter().newGroupCursor(group); |
354 | - this.hKey = adapter().newHKey(outputRowType.hKey()); |
355 | + this.hKey = adapter().newHKey(outputRowTypes.get(0).hKey()); |
356 | } |
357 | |
358 | // For use by this class |
359 | @@ -416,4 +472,161 @@ |
360 | private ShareHolder<Row> inputRow = new ShareHolder<>(); |
361 | private boolean idle = true; |
362 | } |
363 | + |
364 | + private class BranchCursor implements BindingsAwareCursor |
365 | + { |
366 | + // BindingsAwareCursor interface |
367 | + |
368 | + @Override |
369 | + public void open() { |
370 | + Row rowFromBindings = bindings.getRow(inputBindingPosition); |
371 | + assert rowFromBindings.rowType() == inputRowType : rowFromBindings; |
372 | + if (inputRowType != sourceRowType) { |
373 | + rowFromBindings = rowFromBindings.subRow(sourceRowType); |
374 | + } |
375 | + computeLookupRowHKey(rowFromBindings); |
376 | + cursor.rebind(hKey, true); |
377 | + cursor.open(); |
378 | + inputRow.hold(rowFromBindings); |
379 | + } |
380 | + |
381 | + @Override |
382 | + public Row next() { |
383 | + Row row = null; |
384 | + if (keepInput && inputPrecedesBranch && inputRow.isHolding()) { |
385 | + row = inputRow.get(); |
386 | + inputRow.release(); |
387 | + } else { |
388 | + do { |
389 | + row = cursor.next(); |
390 | + } while ((row != null) && !outputRowTypes.contains(row.rowType())); |
391 | + if (row == null) { |
392 | + if (keepInput && !inputPrecedesBranch) { |
393 | + assert inputRow.isHolding(); |
394 | + row = inputRow.get(); |
395 | + inputRow.release(); |
396 | + } |
397 | + close(); |
398 | + } |
399 | + } |
400 | + return row; |
401 | + } |
402 | + |
403 | + @Override |
404 | + public void jump(Row row, ColumnSelector columnSelector) { |
405 | + cursor.jump(row, columnSelector); |
406 | + } |
407 | + |
408 | + @Override |
409 | + public void close() { |
410 | + inputRow.release(); |
411 | + cursor.close(); |
412 | + } |
413 | + |
414 | + @Override |
415 | + public void destroy() { |
416 | + close(); |
417 | + cursor.destroy(); |
418 | + } |
419 | + |
420 | + @Override |
421 | + public boolean isIdle() { |
422 | + return cursor.isIdle(); |
423 | + } |
424 | + |
425 | + @Override |
426 | + public boolean isActive() { |
427 | + return cursor.isActive(); |
428 | + } |
429 | + |
430 | + @Override |
431 | + public boolean isDestroyed() { |
432 | + return cursor.isDestroyed(); |
433 | + } |
434 | + |
435 | + @Override |
436 | + public void rebind(QueryBindings bindings) { |
437 | + this.bindings = bindings; |
438 | + } |
439 | + |
440 | + // BranchCursor interface |
441 | + public BranchCursor(StoreAdapter adapter) { |
442 | + this.cursor = adapter.newGroupCursor(group); |
443 | + this.hKey = adapter.newHKey(outputRowTypes.get(0).hKey()); |
444 | + } |
445 | + |
446 | + // For use by this class |
447 | + |
448 | + private void computeLookupRowHKey(Row row) |
449 | + { |
450 | + HKey ancestorHKey = row.ancestorHKey(commonAncestor); |
451 | + ancestorHKey.copyTo(hKey); |
452 | + if (branchRootOrdinal != -1) { |
453 | + hKey.extendWithOrdinal(branchRootOrdinal); |
454 | + } |
455 | + } |
456 | + |
457 | + // Object state |
458 | + |
459 | + private final GroupCursor cursor; |
460 | + private final HKey hKey; |
461 | + private ShareHolder<Row> inputRow = new ShareHolder<>(); |
462 | + private QueryBindings bindings; |
463 | + } |
464 | + |
465 | + private class LookaheadExecution extends LookaheadLeafCursor<BranchCursor> |
466 | + { |
467 | + // Cursor interface |
468 | + |
469 | + @Override |
470 | + public void open() { |
471 | + TAP_OPEN.in(); |
472 | + try { |
473 | + super.open(); |
474 | + } finally { |
475 | + TAP_OPEN.out(); |
476 | + } |
477 | + } |
478 | + |
479 | + @Override |
480 | + public Row next() { |
481 | + if (TAP_NEXT_ENABLED) { |
482 | + TAP_NEXT.in(); |
483 | + } |
484 | + try { |
485 | + Row row = super.next(); |
486 | + if (LOG_EXECUTION) { |
487 | + LOG.debug("BranchLookup_Nested: yield {}", row); |
488 | + } |
489 | + return row; |
490 | + } finally { |
491 | + if (TAP_NEXT_ENABLED) { |
492 | + TAP_NEXT.out(); |
493 | + } |
494 | + } |
495 | + } |
496 | + |
497 | + // LookaheadLeafCursor interface |
498 | + |
499 | + @Override |
500 | + protected BranchCursor newCursor(QueryContext context, StoreAdapter adapter) { |
501 | + return new BranchCursor(adapter); |
502 | + } |
503 | + |
504 | + @Override |
505 | + protected BranchCursor openACursor(QueryBindings bindings, boolean lookahead) { |
506 | + BranchCursor cursor = super.openACursor(bindings, lookahead); |
507 | + if (LOG_EXECUTION) { |
508 | + LOG.debug("BranchLookup_Nested: open{} using {}", lookahead ? " lookahead" : "", cursor.inputRow.get()); |
509 | + } |
510 | + return cursor; |
511 | + } |
512 | + |
513 | + // LookaheadExecution interface |
514 | + |
515 | + LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor, |
516 | + StoreAdapter adapter, int quantum) { |
517 | + super(context, bindingsCursor, adapter, quantum); |
518 | + } |
519 | + } |
520 | } |
521 | |
522 | === modified file 'src/main/java/com/akiban/qp/operator/IndexScan_Default.java' |
523 | --- src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-25 00:26:26 +0000 |
524 | +++ src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-25 00:26:27 +0000 |
525 | @@ -170,7 +170,9 @@ |
526 | return new Execution(context, bindingsCursor); |
527 | } |
528 | else { |
529 | - return new LookaheadExecution(context, bindingsCursor, lookaheadQuantum); |
530 | + return new LookaheadExecution(context, bindingsCursor, |
531 | + context.getStore((UserTable)index.rootMostTable()), |
532 | + lookaheadQuantum); |
533 | } |
534 | } |
535 | |
536 | @@ -383,17 +385,7 @@ |
537 | private final RowCursor cursor; |
538 | } |
539 | |
540 | - static final class BindingsAndCursor { |
541 | - QueryBindings bindings; |
542 | - RowCursor cursor; |
543 | - |
544 | - BindingsAndCursor(QueryBindings bindings, RowCursor cursor) { |
545 | - this.bindings = bindings; |
546 | - this.cursor = cursor; |
547 | - } |
548 | - } |
549 | - |
550 | - private class LookaheadExecution extends OperatorCursor |
551 | + private class LookaheadExecution extends LookaheadLeafCursor<BindingsAwareCursor> |
552 | { |
553 | // Cursor interface |
554 | |
555 | @@ -401,31 +393,7 @@ |
556 | public void open() { |
557 | TAP_OPEN.in(); |
558 | try { |
559 | - CursorLifecycle.checkIdle(this); |
560 | - if (currentCursor != null) { |
561 | - currentCursor.open(); |
562 | - } |
563 | - else if (pendingCursor != null) { |
564 | - currentCursor = pendingCursor; |
565 | - pendingCursor = null; |
566 | - } |
567 | - else { |
568 | - // At the very beginning, the pipeline isn't started. |
569 | - currentCursor = openACursor(currentBindings); |
570 | - } |
571 | - while (!cursorPool.isEmpty() && !bindingsExhausted) { |
572 | - QueryBindings bindings = bindingsCursor.nextBindings(); |
573 | - if (bindings == null) { |
574 | - bindingsExhausted = true; |
575 | - break; |
576 | - } |
577 | - RowCursor cursor = null; |
578 | - if (bindings.getDepth() == currentBindings.getDepth()) { |
579 | - cursor = openACursor(bindings); |
580 | - LOG.debug("IndexScan: lookahead {}", bindings); |
581 | - } |
582 | - pendingBindings.add(new BindingsAndCursor(bindings, cursor)); |
583 | - } |
584 | + super.open(); |
585 | } finally { |
586 | TAP_OPEN.out(); |
587 | } |
588 | @@ -437,11 +405,7 @@ |
589 | TAP_NEXT.in(); |
590 | } |
591 | try { |
592 | - checkQueryCancelation(); |
593 | - Row row = currentCursor.next(); |
594 | - if (row == null) { |
595 | - currentCursor.close(); |
596 | - } |
597 | + Row row = super.next(); |
598 | if (LOG_EXECUTION) { |
599 | LOG.debug("IndexScan: yield {}", row); |
600 | } |
601 | @@ -453,162 +417,26 @@ |
602 | } |
603 | } |
604 | |
605 | - @Override |
606 | - public void jump(Row row, ColumnSelector columnSelector) { |
607 | - currentCursor.jump(row, columnSelector); |
608 | - } |
609 | - |
610 | - @Override |
611 | - public void close() { |
612 | - if (currentCursor != null) { |
613 | - currentCursor.close(); |
614 | - } |
615 | - } |
616 | - |
617 | - @Override |
618 | - public void destroy() { |
619 | - CursorLifecycle.checkIdleOrActive(this); |
620 | - if (currentCursor != null) { |
621 | - currentCursor.destroy(); |
622 | - currentCursor = null; |
623 | - } |
624 | - if (pendingCursor != null) { |
625 | - pendingCursor.destroy(); |
626 | - pendingCursor = null; |
627 | - } |
628 | - recyclePending(); |
629 | - while (true) { |
630 | - RowCursor cursor = cursorPool.poll(); |
631 | - if (cursor == null) break; |
632 | - cursor.destroy(); |
633 | - } |
634 | - destroyed = true; |
635 | - } |
636 | - |
637 | - @Override |
638 | - public boolean isIdle() { |
639 | - return (currentCursor != null) ? currentCursor.isIdle() : !destroyed; |
640 | - } |
641 | - |
642 | - @Override |
643 | - public boolean isActive() { |
644 | - return ((currentCursor != null) && currentCursor.isActive()); |
645 | - } |
646 | - |
647 | - @Override |
648 | - public boolean isDestroyed() { |
649 | - return destroyed; |
650 | - } |
651 | - |
652 | - @Override |
653 | - public void openBindings() { |
654 | - recyclePending(); |
655 | - bindingsCursor.openBindings(); |
656 | - bindingsExhausted = false; |
657 | - currentCursor = pendingCursor = null; |
658 | - } |
659 | - |
660 | - @Override |
661 | - public QueryBindings nextBindings() { |
662 | - if (currentCursor != null) { |
663 | - cursorPool.add(currentCursor); |
664 | - currentCursor = null; |
665 | - } |
666 | - if (pendingCursor != null) { |
667 | - pendingCursor.close(); // Abandoning lookahead. |
668 | - cursorPool.add(pendingCursor); |
669 | - pendingCursor = null; |
670 | - } |
671 | - BindingsAndCursor bandc = pendingBindings.poll(); |
672 | - if (bandc != null) { |
673 | - currentBindings = bandc.bindings; |
674 | - pendingCursor = bandc.cursor; |
675 | - return currentBindings; |
676 | - } |
677 | - currentBindings = bindingsCursor.nextBindings(); |
678 | - if (currentBindings == null) { |
679 | - bindingsExhausted = true; |
680 | - } |
681 | - return currentBindings; |
682 | - } |
683 | - |
684 | - @Override |
685 | - public void closeBindings() { |
686 | - bindingsCursor.closeBindings(); |
687 | - recyclePending(); |
688 | - } |
689 | - |
690 | - @Override |
691 | - public void cancelBindings(QueryBindings bindings) { |
692 | - if ((currentBindings != null) && currentBindings.isAncestor(bindings)) { |
693 | - if (currentCursor != null) { |
694 | - currentCursor.close(); |
695 | - cursorPool.add(currentCursor); |
696 | - currentCursor = null; |
697 | - } |
698 | - if (pendingCursor != null) { |
699 | - pendingCursor.close(); |
700 | - cursorPool.add(pendingCursor); |
701 | - pendingCursor = null; |
702 | - } |
703 | - currentBindings = null; |
704 | - } |
705 | - while (true) { |
706 | - BindingsAndCursor bandc = pendingBindings.peek(); |
707 | - if (bandc == null) break; |
708 | - if (!bandc.bindings.isAncestor(bindings)) break; |
709 | - bandc = pendingBindings.remove(); |
710 | - if (bandc.cursor != null) { |
711 | - bandc.cursor.close(); |
712 | - cursorPool.add(bandc.cursor); |
713 | - } |
714 | - } |
715 | - bindingsCursor.cancelBindings(bindings); |
716 | - } |
717 | - |
718 | + // LookaheadLeafCursor interface |
719 | + |
720 | + @Override |
721 | + protected BindingsAwareCursor newCursor(QueryContext context, StoreAdapter adapter) { |
722 | + return (BindingsAwareCursor)adapter.newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues, true); |
723 | + } |
724 | + |
725 | + @Override |
726 | + protected BindingsAwareCursor openACursor(QueryBindings bindings, boolean lookahead) { |
727 | + if (LOG_EXECUTION) { |
728 | + LOG.debug("IndexScan: open{} for {}", lookahead ? " lookahead" : "", bindings); |
729 | + } |
730 | + return super.openACursor(bindings, lookahead); |
731 | + } |
732 | + |
733 | // LookaheadExecution interface |
734 | |
735 | LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor, |
736 | - int quantum) { |
737 | - super(context); |
738 | - this.bindingsCursor = bindingsCursor; |
739 | - this.pendingBindings = new ArrayDeque<>(quantum+1); |
740 | - this.cursorPool = new ArrayDeque<>(quantum); |
741 | - UserTable table = (UserTable)index.rootMostTable(); |
742 | - StoreAdapter adapter = adapter(table); |
743 | - for (int i = 0; i < quantum; i++) { |
744 | - RowCursor cursor = adapter.newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues, true); |
745 | - cursorPool.add(cursor); |
746 | - } |
747 | - } |
748 | - |
749 | - // For use by this class |
750 | - |
751 | - private void recyclePending() { |
752 | - while (true) { |
753 | - BindingsAndCursor bandc = pendingBindings.poll(); |
754 | - if (bandc == null) break; |
755 | - if (bandc.cursor != null) { |
756 | - bandc.cursor.close(); |
757 | - cursorPool.add(bandc.cursor); |
758 | - } |
759 | - } |
760 | - } |
761 | - |
762 | - private RowCursor openACursor(QueryBindings bindings) { |
763 | - RowCursor cursor = cursorPool.remove(); |
764 | - ((BindingsAwareCursor)cursor).rebind(bindings); |
765 | - cursor.open(); |
766 | - return cursor; |
767 | - } |
768 | - |
769 | - // Object state |
770 | - |
771 | - private final QueryBindingsCursor bindingsCursor; |
772 | - private final Queue<BindingsAndCursor> pendingBindings; |
773 | - private final Queue<RowCursor> cursorPool; |
774 | - private QueryBindings currentBindings; |
775 | - private RowCursor pendingCursor, currentCursor; |
776 | - private boolean bindingsExhausted, destroyed; |
777 | + StoreAdapter adapter, int quantum) { |
778 | + super(context, bindingsCursor, adapter, quantum); |
779 | + } |
780 | } |
781 | } |
782 | |
783 | === added file 'src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java' |
784 | --- src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java 1970-01-01 00:00:00 +0000 |
785 | +++ src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java 2013-07-25 00:26:27 +0000 |
786 | @@ -0,0 +1,243 @@ |
787 | +/** |
788 | + * Copyright (C) 2009-2013 Akiban Technologies, Inc. |
789 | + * |
790 | + * This program is free software: you can redistribute it and/or modify |
791 | + * it under the terms of the GNU Affero General Public License as published by |
792 | + * the Free Software Foundation, either version 3 of the License, or |
793 | + * (at your option) any later version. |
794 | + * |
795 | + * This program is distributed in the hope that it will be useful, |
796 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
797 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
798 | + * GNU Affero General Public License for more details. |
799 | + * |
800 | + * You should have received a copy of the GNU Affero General Public License |
801 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
802 | + */ |
803 | + |
804 | +package com.akiban.qp.operator; |
805 | + |
806 | +import com.akiban.qp.row.Row; |
807 | +import com.akiban.server.api.dml.ColumnSelector; |
808 | + |
809 | +import java.util.ArrayDeque; |
810 | +import java.util.List; |
811 | +import java.util.Queue; |
812 | + |
813 | +/** An {@link OperatorCursor} that opens a single {@link BindingsAwareCursor} |
814 | +* for each {@link QueryBindings} with lookahead. |
815 | +*/ |
816 | +public abstract class LookaheadLeafCursor<C extends BindingsAwareCursor> extends OperatorCursor |
817 | +{ |
818 | + // Cursor interface |
819 | + |
820 | + @Override |
821 | + public void open() { |
822 | + CursorLifecycle.checkIdle(this); |
823 | + if (currentCursor != null) { |
824 | + currentCursor.open(); |
825 | + } |
826 | + else if (pendingCursor != null) { |
827 | + currentCursor = pendingCursor; |
828 | + pendingCursor = null; |
829 | + } |
830 | + else { |
831 | + // At the very beginning, the pipeline isn't started. |
832 | + currentCursor = openACursor(currentBindings, false); |
833 | + } |
834 | + while (!cursorPool.isEmpty() && !bindingsExhausted) { |
835 | + QueryBindings bindings = bindingsCursor.nextBindings(); |
836 | + if (bindings == null) { |
837 | + bindingsExhausted = true; |
838 | + break; |
839 | + } |
840 | + C cursor = null; |
841 | + if (bindings.getDepth() == currentBindings.getDepth()) { |
842 | + cursor = openACursor(bindings, true); |
843 | + } |
844 | + pendingBindings.add(new BindingsAndCursor<C>(bindings, cursor)); |
845 | + } |
846 | + } |
847 | + |
848 | + @Override |
849 | + public Row next() { |
850 | + checkQueryCancelation(); |
851 | + Row row = currentCursor.next(); |
852 | + if (row == null) { |
853 | + currentCursor.close(); |
854 | + } |
855 | + return row; |
856 | + } |
857 | + |
858 | + @Override |
859 | + public void jump(Row row, ColumnSelector columnSelector) { |
860 | + currentCursor.jump(row, columnSelector); |
861 | + } |
862 | + |
863 | + @Override |
864 | + public void close() { |
865 | + if (currentCursor != null) { |
866 | + currentCursor.close(); |
867 | + } |
868 | + } |
869 | + |
870 | + @Override |
871 | + public void destroy() { |
872 | + CursorLifecycle.checkIdleOrActive(this); |
873 | + if (currentCursor != null) { |
874 | + currentCursor.destroy(); |
875 | + currentCursor = null; |
876 | + } |
877 | + if (pendingCursor != null) { |
878 | + pendingCursor.destroy(); |
879 | + pendingCursor = null; |
880 | + } |
881 | + recyclePending(); |
882 | + while (true) { |
883 | + C cursor = cursorPool.poll(); |
884 | + if (cursor == null) break; |
885 | + cursor.destroy(); |
886 | + } |
887 | + destroyed = true; |
888 | + } |
889 | + |
890 | + @Override |
891 | + public boolean isIdle() { |
892 | + return (currentCursor != null) ? currentCursor.isIdle() : !destroyed; |
893 | + } |
894 | + |
895 | + @Override |
896 | + public boolean isActive() { |
897 | + return ((currentCursor != null) && currentCursor.isActive()); |
898 | + } |
899 | + |
900 | + @Override |
901 | + public boolean isDestroyed() { |
902 | + return destroyed; |
903 | + } |
904 | + |
905 | + @Override |
906 | + public void openBindings() { |
907 | + recyclePending(); |
908 | + bindingsCursor.openBindings(); |
909 | + bindingsExhausted = false; |
910 | + currentCursor = pendingCursor = null; |
911 | + } |
912 | + |
913 | + @Override |
914 | + public QueryBindings nextBindings() { |
915 | + if (currentCursor != null) { |
916 | + cursorPool.add(currentCursor); |
917 | + currentCursor = null; |
918 | + } |
919 | + if (pendingCursor != null) { |
920 | + pendingCursor.close(); // Abandoning lookahead. |
921 | + cursorPool.add(pendingCursor); |
922 | + pendingCursor = null; |
923 | + } |
924 | + BindingsAndCursor<C> bandc = pendingBindings.poll(); |
925 | + if (bandc != null) { |
926 | + currentBindings = bandc.bindings; |
927 | + pendingCursor = bandc.cursor; |
928 | + return currentBindings; |
929 | + } |
930 | + currentBindings = bindingsCursor.nextBindings(); |
931 | + if (currentBindings == null) { |
932 | + bindingsExhausted = true; |
933 | + } |
934 | + return currentBindings; |
935 | + } |
936 | + |
937 | + @Override |
938 | + public void closeBindings() { |
939 | + bindingsCursor.closeBindings(); |
940 | + recyclePending(); |
941 | + } |
942 | + |
943 | + @Override |
944 | + public void cancelBindings(QueryBindings bindings) { |
945 | + if ((currentBindings != null) && currentBindings.isAncestor(bindings)) { |
946 | + if (currentCursor != null) { |
947 | + currentCursor.close(); |
948 | + cursorPool.add(currentCursor); |
949 | + currentCursor = null; |
950 | + } |
951 | + if (pendingCursor != null) { |
952 | + pendingCursor.close(); |
953 | + cursorPool.add(pendingCursor); |
954 | + pendingCursor = null; |
955 | + } |
956 | + currentBindings = null; |
957 | + } |
958 | + while (true) { |
959 | + BindingsAndCursor<C> bandc = pendingBindings.peek(); |
960 | + if (bandc == null) break; |
961 | + if (!bandc.bindings.isAncestor(bindings)) break; |
962 | + bandc = pendingBindings.remove(); |
963 | + if (bandc.cursor != null) { |
964 | + bandc.cursor.close(); |
965 | + cursorPool.add(bandc.cursor); |
966 | + } |
967 | + } |
968 | + bindingsCursor.cancelBindings(bindings); |
969 | + } |
970 | + |
971 | + // LookaheadLeafCursor interface |
972 | + |
973 | + LookaheadLeafCursor(QueryContext context, QueryBindingsCursor bindingsCursor, |
974 | + StoreAdapter adapter, int quantum) { |
975 | + super(context); |
976 | + this.bindingsCursor = bindingsCursor; |
977 | + this.pendingBindings = new ArrayDeque<>(quantum+1); |
978 | + this.cursorPool = new ArrayDeque<>(quantum); |
979 | + for (int i = 0; i < quantum; i++) { |
980 | + C cursor = newCursor(context, adapter); |
981 | + cursorPool.add(cursor); |
982 | + } |
983 | + } |
984 | + |
985 | + // Implemented by subclass |
986 | + |
987 | + protected abstract C newCursor(QueryContext context, StoreAdapter adapter); |
988 | + |
989 | + // Inner classes |
990 | + |
991 | + protected static final class BindingsAndCursor<C extends BindingsAwareCursor> { |
992 | + QueryBindings bindings; |
993 | + C cursor; |
994 | + |
995 | + BindingsAndCursor(QueryBindings bindings, C cursor) { |
996 | + this.bindings = bindings; |
997 | + this.cursor = cursor; |
998 | + } |
999 | + } |
1000 | + |
1001 | + // For use by this class |
1002 | + |
1003 | + protected void recyclePending() { |
1004 | + while (true) { |
1005 | + BindingsAndCursor<C> bandc = pendingBindings.poll(); |
1006 | + if (bandc == null) break; |
1007 | + if (bandc.cursor != null) { |
1008 | + bandc.cursor.close(); |
1009 | + cursorPool.add(bandc.cursor); |
1010 | + } |
1011 | + } |
1012 | + } |
1013 | + |
1014 | + protected C openACursor(QueryBindings bindings, boolean lookahead) { |
1015 | + C cursor = cursorPool.remove(); |
1016 | + cursor.rebind(bindings); |
1017 | + cursor.open(); |
1018 | + return cursor; |
1019 | + } |
1020 | + |
1021 | + // Object state |
1022 | + |
1023 | + protected final QueryBindingsCursor bindingsCursor; |
1024 | + protected final Queue<BindingsAndCursor<C>> pendingBindings; |
1025 | + protected final Queue<C> cursorPool; |
1026 | + protected QueryBindings currentBindings; |
1027 | + protected C pendingCursor, currentCursor; |
1028 | + protected boolean bindingsExhausted, destroyed; |
1029 | +} |
1030 | |
1031 | === modified file 'src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java' |
1032 | --- src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-25 00:26:26 +0000 |
1033 | +++ src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-25 00:26:27 +0000 |
1034 | @@ -1489,6 +1489,13 @@ |
1035 | protected RowStream assembleBranchLookup(BranchLookup branchLookup) { |
1036 | RowStream stream; |
1037 | Group group = branchLookup.getSource().getGroup(); |
1038 | + List<UserTableRowType> outputRowTypes = |
1039 | + new ArrayList<>(branchLookup.getTables().size()); |
1040 | + if (false) // TODO: Any way to check that this matched? |
1041 | + outputRowTypes.add(tableRowType(branchLookup.getBranch())); |
1042 | + for (TableSource table : branchLookup.getTables()) { |
1043 | + outputRowTypes.add(tableRowType(table)); |
1044 | + } |
1045 | if (branchLookup.getInput() == null) { |
1046 | // Simple version for Product_Nested. |
1047 | stream = new RowStream(); |
1048 | @@ -1498,9 +1505,10 @@ |
1049 | boundRow.getRowType(), |
1050 | tableRowType(branchLookup.getSource()), |
1051 | tableRowType(branchLookup.getAncestor()), |
1052 | - tableRowType(branchLookup.getBranch()), |
1053 | + outputRowTypes, |
1054 | flag, |
1055 | - currentBindingPosition()); |
1056 | + currentBindingPosition(), |
1057 | + rulesContext.getPipelineConfiguration().getGroupLookupLookaheadQuantum()); |
1058 | |
1059 | } |
1060 | else if (branchLookup.getInput() instanceof GroupLoopScan) { |
1061 | @@ -1513,9 +1521,10 @@ |
1062 | boundRow.getRowType(), |
1063 | boundRow.getRowType(), |
1064 | tableRowType(branchLookup.getAncestor()), |
1065 | - tableRowType(branchLookup.getBranch()), |
1066 | + outputRowTypes, |
1067 | flag, |
1068 | - rowIndex + loopBindingsOffset); |
1069 | + rowIndex + loopBindingsOffset, |
1070 | + rulesContext.getPipelineConfiguration().getGroupLookupLookaheadQuantum()); |
1071 | } |
1072 | else { |
1073 | // Ordinary inline version. |
1074 | @@ -1527,13 +1536,6 @@ |
1075 | inputRowType = tableRowType(branchLookup.getSource()); |
1076 | flag = API.InputPreservationOption.KEEP_INPUT; |
1077 | } |
1078 | - List<UserTableRowType> outputRowTypes = |
1079 | - new ArrayList<>(branchLookup.getTables().size()); |
1080 | - if (false) // TODO: Any way to check that this matched? |
1081 | - outputRowTypes.add(tableRowType(branchLookup.getBranch())); |
1082 | - for (TableSource table : branchLookup.getTables()) { |
1083 | - outputRowTypes.add(tableRowType(table)); |
1084 | - } |
1085 | stream.operator = API.groupLookup_Default(stream.operator, |
1086 | group, |
1087 | inputRowType, |
1088 | |
1089 | === modified file 'src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java' |
1090 | --- src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-13 19:25:25 +0000 |
1091 | +++ src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-25 00:26:27 +0000 |
1092 | @@ -116,9 +116,9 @@ |
1093 | } |
1094 | |
1095 | @Test(expected = IllegalArgumentException.class) |
1096 | - public void testBLNOutputRowTypeNull() |
1097 | + public void testBLNOutputRowTypesEmpty() |
1098 | { |
1099 | - branchLookup_Nested(rabc, aRowType, null, InputPreservationOption.KEEP_INPUT, 0); |
1100 | + branchLookup_Nested(rabc, aRowType, aRowType, null, Collections.<UserTableRowType>emptyList(), InputPreservationOption.KEEP_INPUT, 0, 1); |
1101 | } |
1102 | |
1103 | @Test(expected = IllegalArgumentException.class) |
1104 | |
1105 | === modified file 'src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java' |
1106 | --- src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java 2013-07-18 01:55:53 +0000 |
1107 | +++ src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java 2013-07-25 00:26:27 +0000 |
1108 | @@ -26,6 +26,7 @@ |
1109 | import org.junit.Test; |
1110 | |
1111 | import java.util.Arrays; |
1112 | +import java.util.List; |
1113 | import java.util.Set; |
1114 | |
1115 | import static com.akiban.qp.operator.API.JoinType.INNER_JOIN; |
1116 | @@ -132,9 +133,10 @@ |
1117 | RA.rowType(), |
1118 | rRowType, |
1119 | null, |
1120 | - bRowType, |
1121 | + list(bRowType), |
1122 | KEEP_INPUT, |
1123 | - 0), |
1124 | + 0, |
1125 | + 1), |
1126 | rRowType, |
1127 | bRowType, |
1128 | INNER_JOIN); |
1129 | @@ -146,8 +148,9 @@ |
1130 | RAB.rowType(), |
1131 | rRowType, |
1132 | null, |
1133 | - cRowType, |
1134 | + list(cRowType), |
1135 | KEEP_INPUT, |
1136 | + 1, |
1137 | 1), |
1138 | rRowType, |
1139 | cRowType, |
1140 | @@ -201,9 +204,10 @@ |
1141 | RA.rowType(), |
1142 | rRowType, |
1143 | null, |
1144 | - cRowType, |
1145 | + list(cRowType), |
1146 | KEEP_INPUT, |
1147 | - 0), |
1148 | + 0, |
1149 | + 1), |
1150 | rRowType, |
1151 | cRowType, |
1152 | INNER_JOIN); |
1153 | @@ -215,8 +219,9 @@ |
1154 | RAC.rowType(), |
1155 | rRowType, |
1156 | null, |
1157 | - bRowType, |
1158 | + list(bRowType), |
1159 | KEEP_INPUT, |
1160 | + 1, |
1161 | 1), |
1162 | rRowType, |
1163 | bRowType, |
1164 | @@ -265,9 +270,10 @@ |
1165 | rRowType, |
1166 | rRowType, |
1167 | null, |
1168 | - aRowType, |
1169 | + list(aRowType), |
1170 | KEEP_INPUT, |
1171 | - 0), |
1172 | + 0, |
1173 | + 1), |
1174 | rRowType, |
1175 | aRowType, |
1176 | INNER_JOIN); |
1177 | @@ -279,8 +285,9 @@ |
1178 | RA.rowType(), |
1179 | rRowType, |
1180 | null, |
1181 | - bRowType, |
1182 | + list(bRowType), |
1183 | KEEP_INPUT, |
1184 | + 1, |
1185 | 1), |
1186 | rRowType, |
1187 | bRowType, |
1188 | @@ -293,9 +300,10 @@ |
1189 | RAB.rowType(), |
1190 | rRowType, |
1191 | null, |
1192 | - cRowType, |
1193 | + list(cRowType), |
1194 | KEEP_INPUT, |
1195 | - 2), |
1196 | + 2, |
1197 | + 1), |
1198 | rRowType, |
1199 | cRowType, |
1200 | INNER_JOIN); |
1201 | @@ -337,6 +345,11 @@ |
1202 | return keepTypes; |
1203 | } |
1204 | |
1205 | + private List<UserTableRowType> list(UserTableRowType... rowTypes) |
1206 | + { |
1207 | + return Arrays.asList(rowTypes); |
1208 | + } |
1209 | + |
1210 | protected int r; |
1211 | protected int a; |
1212 | protected int c; |
1213 | |
1214 | === modified file 'src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java' |
1215 | --- src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java 2013-07-17 21:53:18 +0000 |
1216 | +++ src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java 2013-07-25 00:26:27 +0000 |
1217 | @@ -29,6 +29,7 @@ |
1218 | import org.junit.Test; |
1219 | |
1220 | import java.util.Arrays; |
1221 | +import java.util.List; |
1222 | import java.util.Collections; |
1223 | import java.util.Set; |
1224 | |
1225 | @@ -85,6 +86,10 @@ |
1226 | use(db); |
1227 | } |
1228 | |
1229 | + protected int lookaheadQuantum() { |
1230 | + return 1; |
1231 | + } |
1232 | + |
1233 | // Test assumption about ordinals |
1234 | |
1235 | @Test |
1236 | @@ -146,7 +151,7 @@ |
1237 | INNER_JOIN); |
1238 | Operator flattenCA = |
1239 | flatten_HKeyOrdered( |
1240 | - branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0), |
1241 | + branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()), |
1242 | customerRowType, |
1243 | addressRowType, |
1244 | INNER_JOIN); |
1245 | @@ -184,7 +189,7 @@ |
1246 | INNER_JOIN); |
1247 | Operator flattenCA = |
1248 | flatten_HKeyOrdered( |
1249 | - branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0), |
1250 | + branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()), |
1251 | customerRowType, |
1252 | addressRowType, |
1253 | INNER_JOIN); |
1254 | @@ -224,9 +229,10 @@ |
1255 | flattenCAOuter.rowType(), |
1256 | customerRowType, |
1257 | customerRowType, |
1258 | - addressRowType, |
1259 | + list(addressRowType), |
1260 | InputPreservationOption.KEEP_INPUT, |
1261 | - 0), |
1262 | + 0, |
1263 | + lookaheadQuantum()), |
1264 | customerRowType, |
1265 | addressRowType, |
1266 | JoinType.LEFT_JOIN); |
1267 | @@ -282,7 +288,7 @@ |
1268 | INNER_JOIN); |
1269 | Operator flattenCA = |
1270 | flatten_HKeyOrdered( |
1271 | - branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0), |
1272 | + branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()), |
1273 | customerRowType, |
1274 | addressRowType, |
1275 | INNER_JOIN); |
1276 | @@ -305,6 +311,11 @@ |
1277 | row(coaRowType, 1L, "northbridge", 101L, 1L, "ori", 1001L, 1L, "111 1001 st"), |
1278 | }; |
1279 | } |
1280 | + |
1281 | + @Override |
1282 | + public boolean reopenTopLevel() { |
1283 | + return pipelineMap(); |
1284 | + } |
1285 | }; |
1286 | testCursorLifecycle(plan, testCase); |
1287 | } |
1288 | @@ -315,4 +326,9 @@ |
1289 | keepTypes.removeAll(Schema.descendentTypes(type, keepTypes)); |
1290 | return keepTypes; |
1291 | } |
1292 | + |
1293 | + private List<UserTableRowType> list(UserTableRowType... rowTypes) |
1294 | + { |
1295 | + return Arrays.asList(rowTypes); |
1296 | + } |
1297 | } |
1298 | |
1299 | === added file 'src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java' |
1300 | --- src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java 1970-01-01 00:00:00 +0000 |
1301 | +++ src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java 2013-07-25 00:26:27 +0000 |
1302 | @@ -0,0 +1,31 @@ |
1303 | +/** |
1304 | + * Copyright (C) 2009-2013 Akiban Technologies, Inc. |
1305 | + * |
1306 | + * This program is free software: you can redistribute it and/or modify |
1307 | + * it under the terms of the GNU Affero General Public License as published by |
1308 | + * the Free Software Foundation, either version 3 of the License, or |
1309 | + * (at your option) any later version. |
1310 | + * |
1311 | + * This program is distributed in the hope that it will be useful, |
1312 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1313 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1314 | + * GNU Affero General Public License for more details. |
1315 | + * |
1316 | + * You should have received a copy of the GNU Affero General Public License |
1317 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1318 | + */ |
1319 | + |
1320 | +package com.akiban.server.test.it.qp; |
1321 | + |
1322 | +public class Product_NestedLookaheadIT extends Product_NestedIT |
1323 | +{ |
1324 | + @Override |
1325 | + protected boolean pipelineMap() { |
1326 | + return true; |
1327 | + } |
1328 | + |
1329 | + @Override |
1330 | + protected int lookaheadQuantum() { |
1331 | + return 4; |
1332 | + } |
1333 | +} |
1334 | |
1335 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected' |
1336 | --- src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected 2013-07-25 00:26:26 +0000 |
1337 | +++ src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected 2013-07-25 00:26:27 +0000 |
1338 | @@ -12,4 +12,4 @@ |
1339 | Flatten_HKeyOrdered(customers - orders INNER items) |
1340 | Flatten_HKeyOrdered(customers INNER orders) |
1341 | Select_HKeyOrdered(i2.sku == '4567') |
1342 | - BranchLookup_Nested(customers -> orders) |
1343 | \ No newline at end of file |
1344 | + BranchLookup_Nested(customers -> orders, items) |
1345 | \ No newline at end of file |
1346 | |
1347 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected' |
1348 | --- src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected 2013-07-25 00:26:26 +0000 |
1349 | +++ src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected 2013-07-25 00:26:27 +0000 |
1350 | @@ -12,4 +12,4 @@ |
1351 | Flatten_HKeyOrdered(customers - orders INNER items) |
1352 | Flatten_HKeyOrdered(customers INNER orders) |
1353 | Select_HKeyOrdered(i2.sku == '4567') |
1354 | - BranchLookup_Nested(customers -> orders) |
1355 | \ No newline at end of file |
1356 | + BranchLookup_Nested(customers -> orders, items) |
1357 | \ No newline at end of file |
1358 | |
1359 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected' |
1360 | --- src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected 2013-07-25 00:26:26 +0000 |
1361 | +++ src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected 2013-07-25 00:26:27 +0000 |
1362 | @@ -13,4 +13,4 @@ |
1363 | Filter_Default(customers - orders - items) |
1364 | Flatten_HKeyOrdered(customers - orders INNER items) |
1365 | Flatten_HKeyOrdered(customers INNER orders) |
1366 | - BranchLookup_Nested(customers -> orders) |
1367 | \ No newline at end of file |
1368 | + BranchLookup_Nested(customers -> orders, items) |
1369 | \ No newline at end of file |
1370 | |
1371 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected' |
1372 | --- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected 2013-07-25 00:26:26 +0000 |
1373 | +++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected 2013-07-25 00:26:27 +0000 |
1374 | @@ -9,4 +9,4 @@ |
1375 | Filter_Default(customers - orders - items) |
1376 | Flatten_HKeyOrdered(customers - orders INNER items) |
1377 | Flatten_HKeyOrdered(customers INNER orders) |
1378 | - BranchLookup_Nested(customers -> orders) |
1379 | \ No newline at end of file |
1380 | + BranchLookup_Nested(customers -> orders, items) |
1381 | \ No newline at end of file |
1382 | |
1383 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected' |
1384 | --- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected 2013-07-25 00:26:26 +0000 |
1385 | +++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected 2013-07-25 00:26:27 +0000 |
1386 | @@ -9,4 +9,4 @@ |
1387 | Filter_Default(customers - orders - items) |
1388 | Flatten_HKeyOrdered(customers - orders INNER items) |
1389 | Flatten_HKeyOrdered(customers INNER orders) |
1390 | - BranchLookup_Nested(customers -> orders) |
1391 | \ No newline at end of file |
1392 | + BranchLookup_Nested(customers -> orders, items) |
1393 | \ No newline at end of file |
1394 | |
1395 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected' |
1396 | --- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected 2013-07-25 00:26:26 +0000 |
1397 | +++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected 2013-07-25 00:26:27 +0000 |
1398 | @@ -9,4 +9,4 @@ |
1399 | Filter_Default(customers - orders - items) |
1400 | Flatten_HKeyOrdered(customers - orders INNER items) |
1401 | Flatten_HKeyOrdered(customers INNER orders) |
1402 | - BranchLookup_Nested(customers -> orders) |
1403 | \ No newline at end of file |
1404 | + BranchLookup_Nested(customers -> orders, items) |
1405 | \ No newline at end of file |
1406 | |
1407 | === modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected' |
1408 | --- src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected 2013-07-17 21:00:35 +0000 |
1409 | +++ src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected 2013-07-25 00:26:27 +0000 |
1410 | @@ -8,4 +8,4 @@ |
1411 | Filter_Default(customers - orders - items) |
1412 | Flatten_HKeyOrdered(customers - orders INNER items) |
1413 | Flatten_HKeyOrdered(customers INNER orders) |
1414 | - BranchLookup_Nested(customers -> orders) |
1415 | \ No newline at end of file |
1416 | + BranchLookup_Nested(customers -> orders, items) |
1417 | \ No newline at end of file |
1418 | |
1419 | === modified file 'src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected' |
1420 | --- src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected 2013-07-25 00:26:26 +0000 |
1421 | +++ src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected 2013-07-25 00:26:27 +0000 |
1422 | @@ -9,4 +9,4 @@ |
1423 | Filter_Default(test.customers - test.orders - test.items) |
1424 | Flatten_HKeyOrdered(test.customers - test.orders INNER test.items) |
1425 | Flatten_HKeyOrdered(test.customers INNER test.orders) |
1426 | - BranchLookup_Nested(test.customers -> test.orders) |
1427 | \ No newline at end of file |
1428 | + BranchLookup_Nested(test.customers -> test.orders, test.items) |
1429 | \ No newline at end of file |
Looks as described.