Merge lp:~mmcm/akiban-server/pipeline-branch-lookup-nested into lp:~akiban-technologies/akiban-server/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
Reviewer Review Type Date Requested Status
Nathan Williams Approve
Review via email: mp+176825@code.launchpad.net

Description of the change

Add lookahead option to BranchLookup_Nested. Also add a list of outputRowTypes for consistenty with GroupLookup.

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.
Revision history for this message
Nathan Williams (nwilliams) wrote :

Looks as described.

review: Approve

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

Subscribers

People subscribed via source and target branches