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
=== modified file 'src/main/java/com/akiban/qp/operator/API.java'
--- src/main/java/com/akiban/qp/operator/API.java 2013-07-25 00:26:26 +0000
+++ src/main/java/com/akiban/qp/operator/API.java 2013-07-25 00:26:27 +0000
@@ -190,13 +190,17 @@
190 UserTableRowType outputRowType,190 UserTableRowType outputRowType,
191 InputPreservationOption flag)191 InputPreservationOption flag)
192 {192 {
193 return groupLookup_Default(inputOperator, group, inputRowType, branchOutputRowTypes(outputRowType), flag, 1);
194 }
195
196 protected static List<UserTableRowType> branchOutputRowTypes(UserTableRowType outputRowType) {
193 List<UserTableRowType> outputRowTypes = new ArrayList<>();197 List<UserTableRowType> outputRowTypes = new ArrayList<>();
194 outputRowTypes.add(outputRowType);198 outputRowTypes.add(outputRowType);
195 Schema schema = (Schema)outputRowType.schema();199 Schema schema = (Schema)outputRowType.schema();
196 for (RowType rowType : schema.descendentTypes(outputRowType, schema.userTableTypes())) {200 for (RowType rowType : schema.descendentTypes(outputRowType, schema.userTableTypes())) {
197 outputRowTypes.add((UserTableRowType)rowType);201 outputRowTypes.add((UserTableRowType)rowType);
198 }202 }
199 return groupLookup_Default(inputOperator, group, inputRowType, outputRowTypes, flag, 1);203 return outputRowTypes;
200 }204 }
201205
202 /** deprecated */206 /** deprecated */
@@ -206,13 +210,14 @@
206 InputPreservationOption flag,210 InputPreservationOption flag,
207 int inputBindingPosition)211 int inputBindingPosition)
208 {212 {
209 return new BranchLookup_Nested(group,213 return branchLookup_Nested(group,
210 inputRowType, 214 inputRowType,
211 inputRowType,215 inputRowType,
212 null,216 null,
213 outputRowType,217 branchOutputRowTypes(outputRowType),
214 flag,218 flag,
215 inputBindingPosition);219 inputBindingPosition,
220 1);
216 }221 }
217222
218 public static Operator branchLookup_Nested(Group group,223 public static Operator branchLookup_Nested(Group group,
@@ -222,30 +227,33 @@
222 InputPreservationOption flag,227 InputPreservationOption flag,
223 int inputBindingPosition)228 int inputBindingPosition)
224 {229 {
225 return new BranchLookup_Nested(group,230 return branchLookup_Nested(group,
226 inputRowType, 231 inputRowType,
227 inputRowType,232 inputRowType,
228 ancestorRowType,233 ancestorRowType,
229 outputRowType,234 branchOutputRowTypes(outputRowType),
230 flag,235 flag,
231 inputBindingPosition);236 inputBindingPosition,
237 1);
232 }238 }
233239
234 public static Operator branchLookup_Nested(Group group,240 public static Operator branchLookup_Nested(Group group,
235 RowType inputRowType,241 RowType inputRowType,
236 RowType sourceRowType,242 RowType sourceRowType,
237 UserTableRowType ancestorRowType,243 UserTableRowType ancestorRowType,
238 UserTableRowType outputRowType,244 Collection<UserTableRowType> outputRowTypes,
239 InputPreservationOption flag,245 InputPreservationOption flag,
240 int inputBindingPosition)246 int inputBindingPosition,
247 int lookaheadQuantum)
241 {248 {
242 return new BranchLookup_Nested(group,249 return new BranchLookup_Nested(group,
243 inputRowType, 250 inputRowType,
244 sourceRowType,251 sourceRowType,
245 ancestorRowType,252 ancestorRowType,
246 outputRowType,253 outputRowTypes,
247 flag,254 flag,
248 inputBindingPosition);255 inputBindingPosition,
256 lookaheadQuantum);
249 }257 }
250258
251 // Limit259 // Limit
252260
=== modified file 'src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java'
--- src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-17 20:41:05 +0000
+++ src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-25 00:26:27 +0000
@@ -25,6 +25,7 @@
25import com.akiban.qp.rowtype.RowType;25import com.akiban.qp.rowtype.RowType;
26import com.akiban.qp.rowtype.UserTableRowType;26import com.akiban.qp.rowtype.UserTableRowType;
27import com.akiban.qp.rowtype.*;27import com.akiban.qp.rowtype.*;
28import com.akiban.server.api.dml.ColumnSelector;
28import com.akiban.server.explain.*;29import com.akiban.server.explain.*;
29import com.akiban.server.explain.std.LookUpOperatorExplainer;30import com.akiban.server.explain.std.LookUpOperatorExplainer;
30import com.akiban.util.ArgumentValidation;31import com.akiban.util.ArgumentValidation;
@@ -33,6 +34,11 @@
33import org.slf4j.Logger;34import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;35import org.slf4j.LoggerFactory;
3536
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.Collection;
41import java.util.List;
36import java.util.Set;42import java.util.Set;
3743
38import static java.lang.Math.min;44import static java.lang.Math.min;
@@ -53,18 +59,17 @@
5359
54 <ul>60 <ul>
5561
56 <li><b>GroupTable groupTable:</b> The group table containing the62 <li><b>Group group:</b> The group containing the ancestors of interest.
57 ancestors of interest.
5863
59 <li><b>RowType inputRowType:</b> Bound row will be of this type.64 <li><b>RowType inputRowType:</b> Bound row will be of this type.
60 65
61 <li><b>RowType sourceRowType:</b> Branches will be located for input66 <li><b>RowType sourceRowType:</b> Branches will be located for input
62 rows of this type.67 rows of this type. Possibly a subrow of inputRowType.
63 68
64 <li><b>UserTableRowType ancestorRowType:</b> Identifies the table in the group at which branching occurs.69 <li><b>UserTableRowType ancestorRowType:</b> Identifies the table in the group at which branching occurs.
65 Must be an ancestor of both inputRowType's table and outputRowType's table.70 Must be an ancestor of both inputRowType's table and outputRowTypes' tables.
6671
67 <li><b>UserTableRowType outputRowType:</b> Type at the root of the branch to be72 <li><b>UserTableRowType outputRowTypes:</b> Types within the branch to be
68 retrieved.73 retrieved.
6974
70 <li><b>API.InputPreservationOption flag:</b> Indicates whether rows of type rowType75 <li><b>API.InputPreservationOption flag:</b> Indicates whether rows of type rowType
@@ -74,17 +79,19 @@
74 <li><b>int inputBindingPosition:</b> Indicates input row's position in the query context. The hkey79 <li><b>int inputBindingPosition:</b> Indicates input row's position in the query context. The hkey
75 of this row will be used to locate ancestors.80 of this row will be used to locate ancestors.
7681
82 <li><b>int lookaheadQuantum:</b> Number of cursors to try to keep open by looking
83 ahead in bindings stream.
84
77 </ul>85 </ul>
7886
79 inputRowType may be an index row type, a user table row type, or an hkey row type. flag = KEEP_INPUT is permitted87 inputRowType may be an index row type, a user table row type, or an hkey row type. flag = KEEP_INPUT is permitted
80 only for user table row types.88 only for user table row types.
8189
82 The groupTable, inputRowType, and outputRowType must belong to the90 The groupTable, inputRowType, and outputRowTypes must belong to the
83 same group.91 same group.
84 92
85 ancestorRowType's table must be an ancestor of93 ancestorRowType's table must be an ancestor of
86 inputRowType's table and outputRowType's table. outputRowType's table must be the parent94 inputRowType's table and outputRowTypes' tables.
87 of outputRowType's table.
8895
89 <h1>Behavior</h1>96 <h1>Behavior</h1>
9097
@@ -139,7 +146,7 @@
139 getClass().getSimpleName(),146 getClass().getSimpleName(),
140 group.getRoot().getName(),147 group.getRoot().getName(),
141 sourceRowType,148 sourceRowType,
142 outputRowType);149 outputRowTypes);
143 }150 }
144151
145 // Operator interface152 // Operator interface
@@ -152,7 +159,14 @@
152 @Override159 @Override
153 public Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)160 public Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
154 {161 {
155 return new Execution(context, bindingsCursor);162 if (lookaheadQuantum <= 1) {
163 return new Execution(context, bindingsCursor);
164 }
165 else {
166 return new LookaheadExecution(context, bindingsCursor,
167 context.getStore(commonAncestor),
168 lookaheadQuantum);
169 }
156 }170 }
157171
158 @Override172 @Override
@@ -167,14 +181,15 @@
167 RowType inputRowType,181 RowType inputRowType,
168 RowType sourceRowType,182 RowType sourceRowType,
169 UserTableRowType ancestorRowType,183 UserTableRowType ancestorRowType,
170 UserTableRowType outputRowType,184 Collection<UserTableRowType> outputRowTypes,
171 API.InputPreservationOption flag,185 API.InputPreservationOption flag,
172 int inputBindingPosition)186 int inputBindingPosition,
187 int lookaheadQuantum)
173 {188 {
174 ArgumentValidation.notNull("group", group);189 ArgumentValidation.notNull("group", group);
175 ArgumentValidation.notNull("inputRowType", inputRowType);190 ArgumentValidation.notNull("inputRowType", inputRowType);
176 ArgumentValidation.notNull("sourceRowType", sourceRowType);191 ArgumentValidation.notNull("sourceRowType", sourceRowType);
177 ArgumentValidation.notNull("outputRowType", outputRowType);192 ArgumentValidation.notEmpty("outputRowTypes", outputRowTypes);
178 ArgumentValidation.notNull("flag", flag);193 ArgumentValidation.notNull("flag", flag);
179 ArgumentValidation.isTrue("sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT",194 ArgumentValidation.isTrue("sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT",
180 sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT);195 sourceRowType instanceof UserTableRowType || flag == API.InputPreservationOption.DISCARD_INPUT);
@@ -185,42 +200,75 @@
185 } else if (sourceRowType instanceof IndexRowType) {200 } else if (sourceRowType instanceof IndexRowType) {
186 inputTableType = ((IndexRowType) sourceRowType).tableType();201 inputTableType = ((IndexRowType) sourceRowType).tableType();
187 } else if (sourceRowType instanceof HKeyRowType) {202 } else if (sourceRowType instanceof HKeyRowType) {
188 Schema schema = outputRowType.schema();203 Schema schema = outputRowTypes.iterator().next().schema();
189 inputTableType = schema.userTableRowType(sourceRowType.hKey().userTable());204 inputTableType = schema.userTableRowType(sourceRowType.hKey().userTable());
190 }205 }
191 assert inputTableType != null : sourceRowType;206 assert inputTableType != null : sourceRowType;
192 UserTable inputTable = inputTableType.userTable();207 UserTable inputTable = inputTableType.userTable();
193 UserTable outputTable = outputRowType.userTable();208 ArgumentValidation.isSame("inputTable.getGroup()", inputTable.getGroup(),
194 ArgumentValidation.isSame("inputTable.getGroup()",209 "group", group);
195 inputTable.getGroup(),210 UserTable commonAncestor;
196 "outputTable.getGroup()",211 if (ancestorRowType == null) {
197 outputTable.getGroup());212 commonAncestor = inputTable;
213 } else {
214 commonAncestor = ancestorRowType.userTable();
215 ArgumentValidation.isTrue("ancestorRowType.ancestorOf(inputTableType)",
216 ancestorRowType.ancestorOf(inputTableType));
217 }
218 for (UserTableRowType outputRowType : outputRowTypes) {
219 UserTable outputTable = outputRowType.userTable();
220 ArgumentValidation.isSame("outputTable.getGroup()", outputTable.getGroup(),
221 "group", group);
222 if (ancestorRowType == null) {
223 commonAncestor = commonAncestor(commonAncestor, outputTable);
224 }
225 else {
226 ArgumentValidation.isTrue("ancestorRowType.ancestorOf(outputRowType)",
227 ancestorRowType.ancestorOf(outputRowType));
228 }
229 }
198 this.group = group;230 this.group = group;
199 this.inputRowType = inputRowType;231 this.inputRowType = inputRowType;
200 this.sourceRowType = sourceRowType;232 this.sourceRowType = sourceRowType;
201 this.outputRowType = outputRowType;233 this.outputRowTypes = new ArrayList<>(outputRowTypes);
234 Collections.sort(this.outputRowTypes,
235 new Comparator<UserTableRowType>()
236 {
237 @Override
238 public int compare(UserTableRowType x, UserTableRowType y)
239 {
240 return x.userTable().getDepth() - y.userTable().getDepth();
241 }
242 });
243 this.commonAncestor = commonAncestor;
202 this.keepInput = flag == API.InputPreservationOption.KEEP_INPUT;244 this.keepInput = flag == API.InputPreservationOption.KEEP_INPUT;
203 this.inputBindingPosition = inputBindingPosition;245 this.inputBindingPosition = inputBindingPosition;
204 if (ancestorRowType == null) {246 this.lookaheadQuantum = lookaheadQuantum;
205 this.commonAncestor = commonAncestor(inputTable, outputTable);247 // See whether there is a single branch beneath commonAncestor
206 } else {248 // with all output row types.
207 this.commonAncestor = ancestorRowType.userTable();249 UserTable outputTable = this.outputRowTypes.get(0).userTable();
208 ArgumentValidation.isTrue("ancestorRowType.ancestorOf(inputTableType)",250 boolean allOneBranch;
209 ancestorRowType.ancestorOf(inputTableType));251 if (outputTable == commonAncestor) {
210 ArgumentValidation.isTrue("ancestorRowType.ancestorOf(outputRowType)",252 allOneBranch = false;
211 ancestorRowType.ancestorOf(outputRowType));253 }
212 }254 else {
213 switch (outputTable.getDepth() - commonAncestor.getDepth()) {255 while (outputTable.parentTable() != commonAncestor) {
214 case 0:256 outputTable = outputTable.parentTable();
215 branchRootOrdinal = -1;257 }
216 break;258 UserTableRowType outputTableRowType = this.outputRowTypes.get(0).schema().userTableRowType(outputTable);
217 case 1:259 allOneBranch = true;
218 branchRootOrdinal = ordinal(outputTable);260 for (int i = 1; i < this.outputRowTypes.size(); i++) {
219 break;261 if (!outputTableRowType.ancestorOf(this.outputRowTypes.get(i))) {
220 default:262 allOneBranch = false;
221 branchRootOrdinal = -1;263 break;
222 ArgumentValidation.isTrue("false", false);264 }
223 break;265 }
266 }
267 if (allOneBranch) {
268 branchRootOrdinal = ordinal(outputTable);
269 }
270 else {
271 branchRootOrdinal = -1;
224 }272 }
225 // branchRootOrdinal = -1 means that outputTable is an ancestor of inputTable. In this case, inputPrecedesBranch273 // branchRootOrdinal = -1 means that outputTable is an ancestor of inputTable. In this case, inputPrecedesBranch
226 // is false. Otherwise, branchRoot's parent is the common ancestor. Find inputTable's ancestor that is also274 // is false. Otherwise, branchRoot's parent is the common ancestor. Find inputTable's ancestor that is also
@@ -268,11 +316,12 @@
268316
269 private final Group group;317 private final Group group;
270 private final RowType inputRowType, sourceRowType;318 private final RowType inputRowType, sourceRowType;
271 private final UserTableRowType outputRowType;319 private final List<UserTableRowType> outputRowTypes;
272 private final boolean keepInput;320 private final boolean keepInput;
273 // If keepInput is true, inputPrecedesBranch controls whether input row appears before the retrieved branch.321 // If keepInput is true, inputPrecedesBranch controls whether input row appears before the retrieved branch.
274 private final boolean inputPrecedesBranch;322 private final boolean inputPrecedesBranch;
275 private final int inputBindingPosition;323 private final int inputBindingPosition;
324 private final int lookaheadQuantum;
276 private final UserTable commonAncestor;325 private final UserTable commonAncestor;
277 private final int branchRootOrdinal;326 private final int branchRootOrdinal;
278327
@@ -281,10 +330,15 @@
281 {330 {
282 Attributes atts = new Attributes();331 Attributes atts = new Attributes();
283 atts.put(Label.BINDING_POSITION, PrimitiveExplainer.getInstance(inputBindingPosition));332 atts.put(Label.BINDING_POSITION, PrimitiveExplainer.getInstance(inputBindingPosition));
284 atts.put(Label.OUTPUT_TYPE, outputRowType.getExplainer(context));333 for (UserTableRowType outputRowType : outputRowTypes) {
334 atts.put(Label.OUTPUT_TYPE, outputRowType.getExplainer(context));
335 }
336 UserTableRowType outputRowType = outputRowTypes.get(0);
285 UserTableRowType ancestorRowType = outputRowType.schema().userTableRowType(commonAncestor);337 UserTableRowType ancestorRowType = outputRowType.schema().userTableRowType(commonAncestor);
286 if ((ancestorRowType != sourceRowType) && (ancestorRowType != outputRowType))338 if ((ancestorRowType != sourceRowType) && (ancestorRowType != outputRowType)) {
287 atts.put(Label.ANCESTOR_TYPE, ancestorRowType.getExplainer(context));339 atts.put(Label.ANCESTOR_TYPE, ancestorRowType.getExplainer(context));
340 }
341 atts.put(Label.PIPELINE, PrimitiveExplainer.getInstance(lookaheadQuantum));
288 return new LookUpOperatorExplainer(getName(), atts, sourceRowType, false, null, context);342 return new LookUpOperatorExplainer(getName(), atts, sourceRowType, false, null, context);
289 }343 }
290344
@@ -334,7 +388,9 @@
334 row = inputRow.get();388 row = inputRow.get();
335 inputRow.release();389 inputRow.release();
336 } else {390 } else {
337 row = cursor.next();391 do {
392 row = cursor.next();
393 } while ((row != null) && !outputRowTypes.contains(row.rowType()));
338 if (row == null) {394 if (row == null) {
339 if (keepInput && !inputPrecedesBranch) {395 if (keepInput && !inputPrecedesBranch) {
340 assert inputRow.isHolding();396 assert inputRow.isHolding();
@@ -395,7 +451,7 @@
395 {451 {
396 super(context, bindingsCursor);452 super(context, bindingsCursor);
397 this.cursor = adapter().newGroupCursor(group);453 this.cursor = adapter().newGroupCursor(group);
398 this.hKey = adapter().newHKey(outputRowType.hKey());454 this.hKey = adapter().newHKey(outputRowTypes.get(0).hKey());
399 }455 }
400456
401 // For use by this class457 // For use by this class
@@ -416,4 +472,161 @@
416 private ShareHolder<Row> inputRow = new ShareHolder<>();472 private ShareHolder<Row> inputRow = new ShareHolder<>();
417 private boolean idle = true;473 private boolean idle = true;
418 }474 }
475
476 private class BranchCursor implements BindingsAwareCursor
477 {
478 // BindingsAwareCursor interface
479
480 @Override
481 public void open() {
482 Row rowFromBindings = bindings.getRow(inputBindingPosition);
483 assert rowFromBindings.rowType() == inputRowType : rowFromBindings;
484 if (inputRowType != sourceRowType) {
485 rowFromBindings = rowFromBindings.subRow(sourceRowType);
486 }
487 computeLookupRowHKey(rowFromBindings);
488 cursor.rebind(hKey, true);
489 cursor.open();
490 inputRow.hold(rowFromBindings);
491 }
492
493 @Override
494 public Row next() {
495 Row row = null;
496 if (keepInput && inputPrecedesBranch && inputRow.isHolding()) {
497 row = inputRow.get();
498 inputRow.release();
499 } else {
500 do {
501 row = cursor.next();
502 } while ((row != null) && !outputRowTypes.contains(row.rowType()));
503 if (row == null) {
504 if (keepInput && !inputPrecedesBranch) {
505 assert inputRow.isHolding();
506 row = inputRow.get();
507 inputRow.release();
508 }
509 close();
510 }
511 }
512 return row;
513 }
514
515 @Override
516 public void jump(Row row, ColumnSelector columnSelector) {
517 cursor.jump(row, columnSelector);
518 }
519
520 @Override
521 public void close() {
522 inputRow.release();
523 cursor.close();
524 }
525
526 @Override
527 public void destroy() {
528 close();
529 cursor.destroy();
530 }
531
532 @Override
533 public boolean isIdle() {
534 return cursor.isIdle();
535 }
536
537 @Override
538 public boolean isActive() {
539 return cursor.isActive();
540 }
541
542 @Override
543 public boolean isDestroyed() {
544 return cursor.isDestroyed();
545 }
546
547 @Override
548 public void rebind(QueryBindings bindings) {
549 this.bindings = bindings;
550 }
551
552 // BranchCursor interface
553 public BranchCursor(StoreAdapter adapter) {
554 this.cursor = adapter.newGroupCursor(group);
555 this.hKey = adapter.newHKey(outputRowTypes.get(0).hKey());
556 }
557
558 // For use by this class
559
560 private void computeLookupRowHKey(Row row)
561 {
562 HKey ancestorHKey = row.ancestorHKey(commonAncestor);
563 ancestorHKey.copyTo(hKey);
564 if (branchRootOrdinal != -1) {
565 hKey.extendWithOrdinal(branchRootOrdinal);
566 }
567 }
568
569 // Object state
570
571 private final GroupCursor cursor;
572 private final HKey hKey;
573 private ShareHolder<Row> inputRow = new ShareHolder<>();
574 private QueryBindings bindings;
575 }
576
577 private class LookaheadExecution extends LookaheadLeafCursor<BranchCursor>
578 {
579 // Cursor interface
580
581 @Override
582 public void open() {
583 TAP_OPEN.in();
584 try {
585 super.open();
586 } finally {
587 TAP_OPEN.out();
588 }
589 }
590
591 @Override
592 public Row next() {
593 if (TAP_NEXT_ENABLED) {
594 TAP_NEXT.in();
595 }
596 try {
597 Row row = super.next();
598 if (LOG_EXECUTION) {
599 LOG.debug("BranchLookup_Nested: yield {}", row);
600 }
601 return row;
602 } finally {
603 if (TAP_NEXT_ENABLED) {
604 TAP_NEXT.out();
605 }
606 }
607 }
608
609 // LookaheadLeafCursor interface
610
611 @Override
612 protected BranchCursor newCursor(QueryContext context, StoreAdapter adapter) {
613 return new BranchCursor(adapter);
614 }
615
616 @Override
617 protected BranchCursor openACursor(QueryBindings bindings, boolean lookahead) {
618 BranchCursor cursor = super.openACursor(bindings, lookahead);
619 if (LOG_EXECUTION) {
620 LOG.debug("BranchLookup_Nested: open{} using {}", lookahead ? " lookahead" : "", cursor.inputRow.get());
621 }
622 return cursor;
623 }
624
625 // LookaheadExecution interface
626
627 LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor,
628 StoreAdapter adapter, int quantum) {
629 super(context, bindingsCursor, adapter, quantum);
630 }
631 }
419}632}
420633
=== modified file 'src/main/java/com/akiban/qp/operator/IndexScan_Default.java'
--- src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-25 00:26:26 +0000
+++ src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-25 00:26:27 +0000
@@ -170,7 +170,9 @@
170 return new Execution(context, bindingsCursor);170 return new Execution(context, bindingsCursor);
171 }171 }
172 else {172 else {
173 return new LookaheadExecution(context, bindingsCursor, lookaheadQuantum);173 return new LookaheadExecution(context, bindingsCursor,
174 context.getStore((UserTable)index.rootMostTable()),
175 lookaheadQuantum);
174 }176 }
175 }177 }
176178
@@ -383,17 +385,7 @@
383 private final RowCursor cursor;385 private final RowCursor cursor;
384 }386 }
385387
386 static final class BindingsAndCursor {388 private class LookaheadExecution extends LookaheadLeafCursor<BindingsAwareCursor>
387 QueryBindings bindings;
388 RowCursor cursor;
389
390 BindingsAndCursor(QueryBindings bindings, RowCursor cursor) {
391 this.bindings = bindings;
392 this.cursor = cursor;
393 }
394 }
395
396 private class LookaheadExecution extends OperatorCursor
397 {389 {
398 // Cursor interface390 // Cursor interface
399391
@@ -401,31 +393,7 @@
401 public void open() {393 public void open() {
402 TAP_OPEN.in();394 TAP_OPEN.in();
403 try {395 try {
404 CursorLifecycle.checkIdle(this);396 super.open();
405 if (currentCursor != null) {
406 currentCursor.open();
407 }
408 else if (pendingCursor != null) {
409 currentCursor = pendingCursor;
410 pendingCursor = null;
411 }
412 else {
413 // At the very beginning, the pipeline isn't started.
414 currentCursor = openACursor(currentBindings);
415 }
416 while (!cursorPool.isEmpty() && !bindingsExhausted) {
417 QueryBindings bindings = bindingsCursor.nextBindings();
418 if (bindings == null) {
419 bindingsExhausted = true;
420 break;
421 }
422 RowCursor cursor = null;
423 if (bindings.getDepth() == currentBindings.getDepth()) {
424 cursor = openACursor(bindings);
425 LOG.debug("IndexScan: lookahead {}", bindings);
426 }
427 pendingBindings.add(new BindingsAndCursor(bindings, cursor));
428 }
429 } finally {397 } finally {
430 TAP_OPEN.out();398 TAP_OPEN.out();
431 }399 }
@@ -437,11 +405,7 @@
437 TAP_NEXT.in();405 TAP_NEXT.in();
438 }406 }
439 try {407 try {
440 checkQueryCancelation();408 Row row = super.next();
441 Row row = currentCursor.next();
442 if (row == null) {
443 currentCursor.close();
444 }
445 if (LOG_EXECUTION) {409 if (LOG_EXECUTION) {
446 LOG.debug("IndexScan: yield {}", row);410 LOG.debug("IndexScan: yield {}", row);
447 }411 }
@@ -453,162 +417,26 @@
453 }417 }
454 }418 }
455419
456 @Override420 // LookaheadLeafCursor interface
457 public void jump(Row row, ColumnSelector columnSelector) {421
458 currentCursor.jump(row, columnSelector);422 @Override
459 }423 protected BindingsAwareCursor newCursor(QueryContext context, StoreAdapter adapter) {
460424 return (BindingsAwareCursor)adapter.newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues, true);
461 @Override425 }
462 public void close() {426
463 if (currentCursor != null) {427 @Override
464 currentCursor.close();428 protected BindingsAwareCursor openACursor(QueryBindings bindings, boolean lookahead) {
465 }429 if (LOG_EXECUTION) {
466 }430 LOG.debug("IndexScan: open{} for {}", lookahead ? " lookahead" : "", bindings);
467431 }
468 @Override432 return super.openACursor(bindings, lookahead);
469 public void destroy() {433 }
470 CursorLifecycle.checkIdleOrActive(this);434
471 if (currentCursor != null) {
472 currentCursor.destroy();
473 currentCursor = null;
474 }
475 if (pendingCursor != null) {
476 pendingCursor.destroy();
477 pendingCursor = null;
478 }
479 recyclePending();
480 while (true) {
481 RowCursor cursor = cursorPool.poll();
482 if (cursor == null) break;
483 cursor.destroy();
484 }
485 destroyed = true;
486 }
487
488 @Override
489 public boolean isIdle() {
490 return (currentCursor != null) ? currentCursor.isIdle() : !destroyed;
491 }
492
493 @Override
494 public boolean isActive() {
495 return ((currentCursor != null) && currentCursor.isActive());
496 }
497
498 @Override
499 public boolean isDestroyed() {
500 return destroyed;
501 }
502
503 @Override
504 public void openBindings() {
505 recyclePending();
506 bindingsCursor.openBindings();
507 bindingsExhausted = false;
508 currentCursor = pendingCursor = null;
509 }
510
511 @Override
512 public QueryBindings nextBindings() {
513 if (currentCursor != null) {
514 cursorPool.add(currentCursor);
515 currentCursor = null;
516 }
517 if (pendingCursor != null) {
518 pendingCursor.close(); // Abandoning lookahead.
519 cursorPool.add(pendingCursor);
520 pendingCursor = null;
521 }
522 BindingsAndCursor bandc = pendingBindings.poll();
523 if (bandc != null) {
524 currentBindings = bandc.bindings;
525 pendingCursor = bandc.cursor;
526 return currentBindings;
527 }
528 currentBindings = bindingsCursor.nextBindings();
529 if (currentBindings == null) {
530 bindingsExhausted = true;
531 }
532 return currentBindings;
533 }
534
535 @Override
536 public void closeBindings() {
537 bindingsCursor.closeBindings();
538 recyclePending();
539 }
540
541 @Override
542 public void cancelBindings(QueryBindings bindings) {
543 if ((currentBindings != null) && currentBindings.isAncestor(bindings)) {
544 if (currentCursor != null) {
545 currentCursor.close();
546 cursorPool.add(currentCursor);
547 currentCursor = null;
548 }
549 if (pendingCursor != null) {
550 pendingCursor.close();
551 cursorPool.add(pendingCursor);
552 pendingCursor = null;
553 }
554 currentBindings = null;
555 }
556 while (true) {
557 BindingsAndCursor bandc = pendingBindings.peek();
558 if (bandc == null) break;
559 if (!bandc.bindings.isAncestor(bindings)) break;
560 bandc = pendingBindings.remove();
561 if (bandc.cursor != null) {
562 bandc.cursor.close();
563 cursorPool.add(bandc.cursor);
564 }
565 }
566 bindingsCursor.cancelBindings(bindings);
567 }
568
569 // LookaheadExecution interface435 // LookaheadExecution interface
570436
571 LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor, 437 LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor,
572 int quantum) {438 StoreAdapter adapter, int quantum) {
573 super(context);439 super(context, bindingsCursor, adapter, quantum);
574 this.bindingsCursor = bindingsCursor;440 }
575 this.pendingBindings = new ArrayDeque<>(quantum+1);
576 this.cursorPool = new ArrayDeque<>(quantum);
577 UserTable table = (UserTable)index.rootMostTable();
578 StoreAdapter adapter = adapter(table);
579 for (int i = 0; i < quantum; i++) {
580 RowCursor cursor = adapter.newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues, true);
581 cursorPool.add(cursor);
582 }
583 }
584
585 // For use by this class
586
587 private void recyclePending() {
588 while (true) {
589 BindingsAndCursor bandc = pendingBindings.poll();
590 if (bandc == null) break;
591 if (bandc.cursor != null) {
592 bandc.cursor.close();
593 cursorPool.add(bandc.cursor);
594 }
595 }
596 }
597
598 private RowCursor openACursor(QueryBindings bindings) {
599 RowCursor cursor = cursorPool.remove();
600 ((BindingsAwareCursor)cursor).rebind(bindings);
601 cursor.open();
602 return cursor;
603 }
604
605 // Object state
606
607 private final QueryBindingsCursor bindingsCursor;
608 private final Queue<BindingsAndCursor> pendingBindings;
609 private final Queue<RowCursor> cursorPool;
610 private QueryBindings currentBindings;
611 private RowCursor pendingCursor, currentCursor;
612 private boolean bindingsExhausted, destroyed;
613 }441 }
614}442}
615443
=== added file 'src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java'
--- src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java 1970-01-01 00:00:00 +0000
+++ src/main/java/com/akiban/qp/operator/LookaheadLeafCursor.java 2013-07-25 00:26:27 +0000
@@ -0,0 +1,243 @@
1/**
2 * Copyright (C) 2009-2013 Akiban Technologies, Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18package com.akiban.qp.operator;
19
20import com.akiban.qp.row.Row;
21import com.akiban.server.api.dml.ColumnSelector;
22
23import java.util.ArrayDeque;
24import java.util.List;
25import java.util.Queue;
26
27/** An {@link OperatorCursor} that opens a single {@link BindingsAwareCursor}
28* for each {@link QueryBindings} with lookahead.
29*/
30public abstract class LookaheadLeafCursor<C extends BindingsAwareCursor> extends OperatorCursor
31{
32 // Cursor interface
33
34 @Override
35 public void open() {
36 CursorLifecycle.checkIdle(this);
37 if (currentCursor != null) {
38 currentCursor.open();
39 }
40 else if (pendingCursor != null) {
41 currentCursor = pendingCursor;
42 pendingCursor = null;
43 }
44 else {
45 // At the very beginning, the pipeline isn't started.
46 currentCursor = openACursor(currentBindings, false);
47 }
48 while (!cursorPool.isEmpty() && !bindingsExhausted) {
49 QueryBindings bindings = bindingsCursor.nextBindings();
50 if (bindings == null) {
51 bindingsExhausted = true;
52 break;
53 }
54 C cursor = null;
55 if (bindings.getDepth() == currentBindings.getDepth()) {
56 cursor = openACursor(bindings, true);
57 }
58 pendingBindings.add(new BindingsAndCursor<C>(bindings, cursor));
59 }
60 }
61
62 @Override
63 public Row next() {
64 checkQueryCancelation();
65 Row row = currentCursor.next();
66 if (row == null) {
67 currentCursor.close();
68 }
69 return row;
70 }
71
72 @Override
73 public void jump(Row row, ColumnSelector columnSelector) {
74 currentCursor.jump(row, columnSelector);
75 }
76
77 @Override
78 public void close() {
79 if (currentCursor != null) {
80 currentCursor.close();
81 }
82 }
83
84 @Override
85 public void destroy() {
86 CursorLifecycle.checkIdleOrActive(this);
87 if (currentCursor != null) {
88 currentCursor.destroy();
89 currentCursor = null;
90 }
91 if (pendingCursor != null) {
92 pendingCursor.destroy();
93 pendingCursor = null;
94 }
95 recyclePending();
96 while (true) {
97 C cursor = cursorPool.poll();
98 if (cursor == null) break;
99 cursor.destroy();
100 }
101 destroyed = true;
102 }
103
104 @Override
105 public boolean isIdle() {
106 return (currentCursor != null) ? currentCursor.isIdle() : !destroyed;
107 }
108
109 @Override
110 public boolean isActive() {
111 return ((currentCursor != null) && currentCursor.isActive());
112 }
113
114 @Override
115 public boolean isDestroyed() {
116 return destroyed;
117 }
118
119 @Override
120 public void openBindings() {
121 recyclePending();
122 bindingsCursor.openBindings();
123 bindingsExhausted = false;
124 currentCursor = pendingCursor = null;
125 }
126
127 @Override
128 public QueryBindings nextBindings() {
129 if (currentCursor != null) {
130 cursorPool.add(currentCursor);
131 currentCursor = null;
132 }
133 if (pendingCursor != null) {
134 pendingCursor.close(); // Abandoning lookahead.
135 cursorPool.add(pendingCursor);
136 pendingCursor = null;
137 }
138 BindingsAndCursor<C> bandc = pendingBindings.poll();
139 if (bandc != null) {
140 currentBindings = bandc.bindings;
141 pendingCursor = bandc.cursor;
142 return currentBindings;
143 }
144 currentBindings = bindingsCursor.nextBindings();
145 if (currentBindings == null) {
146 bindingsExhausted = true;
147 }
148 return currentBindings;
149 }
150
151 @Override
152 public void closeBindings() {
153 bindingsCursor.closeBindings();
154 recyclePending();
155 }
156
157 @Override
158 public void cancelBindings(QueryBindings bindings) {
159 if ((currentBindings != null) && currentBindings.isAncestor(bindings)) {
160 if (currentCursor != null) {
161 currentCursor.close();
162 cursorPool.add(currentCursor);
163 currentCursor = null;
164 }
165 if (pendingCursor != null) {
166 pendingCursor.close();
167 cursorPool.add(pendingCursor);
168 pendingCursor = null;
169 }
170 currentBindings = null;
171 }
172 while (true) {
173 BindingsAndCursor<C> bandc = pendingBindings.peek();
174 if (bandc == null) break;
175 if (!bandc.bindings.isAncestor(bindings)) break;
176 bandc = pendingBindings.remove();
177 if (bandc.cursor != null) {
178 bandc.cursor.close();
179 cursorPool.add(bandc.cursor);
180 }
181 }
182 bindingsCursor.cancelBindings(bindings);
183 }
184
185 // LookaheadLeafCursor interface
186
187 LookaheadLeafCursor(QueryContext context, QueryBindingsCursor bindingsCursor,
188 StoreAdapter adapter, int quantum) {
189 super(context);
190 this.bindingsCursor = bindingsCursor;
191 this.pendingBindings = new ArrayDeque<>(quantum+1);
192 this.cursorPool = new ArrayDeque<>(quantum);
193 for (int i = 0; i < quantum; i++) {
194 C cursor = newCursor(context, adapter);
195 cursorPool.add(cursor);
196 }
197 }
198
199 // Implemented by subclass
200
201 protected abstract C newCursor(QueryContext context, StoreAdapter adapter);
202
203 // Inner classes
204
205 protected static final class BindingsAndCursor<C extends BindingsAwareCursor> {
206 QueryBindings bindings;
207 C cursor;
208
209 BindingsAndCursor(QueryBindings bindings, C cursor) {
210 this.bindings = bindings;
211 this.cursor = cursor;
212 }
213 }
214
215 // For use by this class
216
217 protected void recyclePending() {
218 while (true) {
219 BindingsAndCursor<C> bandc = pendingBindings.poll();
220 if (bandc == null) break;
221 if (bandc.cursor != null) {
222 bandc.cursor.close();
223 cursorPool.add(bandc.cursor);
224 }
225 }
226 }
227
228 protected C openACursor(QueryBindings bindings, boolean lookahead) {
229 C cursor = cursorPool.remove();
230 cursor.rebind(bindings);
231 cursor.open();
232 return cursor;
233 }
234
235 // Object state
236
237 protected final QueryBindingsCursor bindingsCursor;
238 protected final Queue<BindingsAndCursor<C>> pendingBindings;
239 protected final Queue<C> cursorPool;
240 protected QueryBindings currentBindings;
241 protected C pendingCursor, currentCursor;
242 protected boolean bindingsExhausted, destroyed;
243}
0244
=== modified file 'src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java'
--- src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-25 00:26:26 +0000
+++ src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-25 00:26:27 +0000
@@ -1489,6 +1489,13 @@
1489 protected RowStream assembleBranchLookup(BranchLookup branchLookup) {1489 protected RowStream assembleBranchLookup(BranchLookup branchLookup) {
1490 RowStream stream;1490 RowStream stream;
1491 Group group = branchLookup.getSource().getGroup();1491 Group group = branchLookup.getSource().getGroup();
1492 List<UserTableRowType> outputRowTypes =
1493 new ArrayList<>(branchLookup.getTables().size());
1494 if (false) // TODO: Any way to check that this matched?
1495 outputRowTypes.add(tableRowType(branchLookup.getBranch()));
1496 for (TableSource table : branchLookup.getTables()) {
1497 outputRowTypes.add(tableRowType(table));
1498 }
1492 if (branchLookup.getInput() == null) {1499 if (branchLookup.getInput() == null) {
1493 // Simple version for Product_Nested.1500 // Simple version for Product_Nested.
1494 stream = new RowStream();1501 stream = new RowStream();
@@ -1498,9 +1505,10 @@
1498 boundRow.getRowType(),1505 boundRow.getRowType(),
1499 tableRowType(branchLookup.getSource()),1506 tableRowType(branchLookup.getSource()),
1500 tableRowType(branchLookup.getAncestor()),1507 tableRowType(branchLookup.getAncestor()),
1501 tableRowType(branchLookup.getBranch()), 1508 outputRowTypes,
1502 flag,1509 flag,
1503 currentBindingPosition());1510 currentBindingPosition(),
1511 rulesContext.getPipelineConfiguration().getGroupLookupLookaheadQuantum());
1504 1512
1505 }1513 }
1506 else if (branchLookup.getInput() instanceof GroupLoopScan) {1514 else if (branchLookup.getInput() instanceof GroupLoopScan) {
@@ -1513,9 +1521,10 @@
1513 boundRow.getRowType(),1521 boundRow.getRowType(),
1514 boundRow.getRowType(),1522 boundRow.getRowType(),
1515 tableRowType(branchLookup.getAncestor()),1523 tableRowType(branchLookup.getAncestor()),
1516 tableRowType(branchLookup.getBranch()), 1524 outputRowTypes,
1517 flag,1525 flag,
1518 rowIndex + loopBindingsOffset);1526 rowIndex + loopBindingsOffset,
1527 rulesContext.getPipelineConfiguration().getGroupLookupLookaheadQuantum());
1519 }1528 }
1520 else {1529 else {
1521 // Ordinary inline version.1530 // Ordinary inline version.
@@ -1527,13 +1536,6 @@
1527 inputRowType = tableRowType(branchLookup.getSource());1536 inputRowType = tableRowType(branchLookup.getSource());
1528 flag = API.InputPreservationOption.KEEP_INPUT;1537 flag = API.InputPreservationOption.KEEP_INPUT;
1529 }1538 }
1530 List<UserTableRowType> outputRowTypes =
1531 new ArrayList<>(branchLookup.getTables().size());
1532 if (false) // TODO: Any way to check that this matched?
1533 outputRowTypes.add(tableRowType(branchLookup.getBranch()));
1534 for (TableSource table : branchLookup.getTables()) {
1535 outputRowTypes.add(tableRowType(table));
1536 }
1537 stream.operator = API.groupLookup_Default(stream.operator,1539 stream.operator = API.groupLookup_Default(stream.operator,
1538 group,1540 group,
1539 inputRowType,1541 inputRowType,
15401542
=== modified file 'src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java'
--- src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-13 19:25:25 +0000
+++ src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-25 00:26:27 +0000
@@ -116,9 +116,9 @@
116 }116 }
117117
118 @Test(expected = IllegalArgumentException.class)118 @Test(expected = IllegalArgumentException.class)
119 public void testBLNOutputRowTypeNull()119 public void testBLNOutputRowTypesEmpty()
120 {120 {
121 branchLookup_Nested(rabc, aRowType, null, InputPreservationOption.KEEP_INPUT, 0);121 branchLookup_Nested(rabc, aRowType, aRowType, null, Collections.<UserTableRowType>emptyList(), InputPreservationOption.KEEP_INPUT, 0, 1);
122 }122 }
123123
124 @Test(expected = IllegalArgumentException.class)124 @Test(expected = IllegalArgumentException.class)
125125
=== modified file 'src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java'
--- src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java 2013-07-18 01:55:53 +0000
+++ src/test/java/com/akiban/server/test/it/qp/Product3WayIT.java 2013-07-25 00:26:27 +0000
@@ -26,6 +26,7 @@
26import org.junit.Test;26import org.junit.Test;
2727
28import java.util.Arrays;28import java.util.Arrays;
29import java.util.List;
29import java.util.Set;30import java.util.Set;
3031
31import static com.akiban.qp.operator.API.JoinType.INNER_JOIN;32import static com.akiban.qp.operator.API.JoinType.INNER_JOIN;
@@ -132,9 +133,10 @@
132 RA.rowType(),133 RA.rowType(),
133 rRowType,134 rRowType,
134 null,135 null,
135 bRowType,136 list(bRowType),
136 KEEP_INPUT,137 KEEP_INPUT,
137 0),138 0,
139 1),
138 rRowType,140 rRowType,
139 bRowType,141 bRowType,
140 INNER_JOIN);142 INNER_JOIN);
@@ -146,8 +148,9 @@
146 RAB.rowType(),148 RAB.rowType(),
147 rRowType,149 rRowType,
148 null,150 null,
149 cRowType,151 list(cRowType),
150 KEEP_INPUT,152 KEEP_INPUT,
153 1,
151 1),154 1),
152 rRowType,155 rRowType,
153 cRowType,156 cRowType,
@@ -201,9 +204,10 @@
201 RA.rowType(),204 RA.rowType(),
202 rRowType,205 rRowType,
203 null,206 null,
204 cRowType,207 list(cRowType),
205 KEEP_INPUT,208 KEEP_INPUT,
206 0),209 0,
210 1),
207 rRowType,211 rRowType,
208 cRowType,212 cRowType,
209 INNER_JOIN);213 INNER_JOIN);
@@ -215,8 +219,9 @@
215 RAC.rowType(),219 RAC.rowType(),
216 rRowType,220 rRowType,
217 null,221 null,
218 bRowType,222 list(bRowType),
219 KEEP_INPUT,223 KEEP_INPUT,
224 1,
220 1),225 1),
221 rRowType,226 rRowType,
222 bRowType,227 bRowType,
@@ -265,9 +270,10 @@
265 rRowType,270 rRowType,
266 rRowType,271 rRowType,
267 null,272 null,
268 aRowType,273 list(aRowType),
269 KEEP_INPUT,274 KEEP_INPUT,
270 0),275 0,
276 1),
271 rRowType,277 rRowType,
272 aRowType,278 aRowType,
273 INNER_JOIN);279 INNER_JOIN);
@@ -279,8 +285,9 @@
279 RA.rowType(),285 RA.rowType(),
280 rRowType,286 rRowType,
281 null,287 null,
282 bRowType,288 list(bRowType),
283 KEEP_INPUT,289 KEEP_INPUT,
290 1,
284 1),291 1),
285 rRowType,292 rRowType,
286 bRowType,293 bRowType,
@@ -293,9 +300,10 @@
293 RAB.rowType(),300 RAB.rowType(),
294 rRowType,301 rRowType,
295 null,302 null,
296 cRowType,303 list(cRowType),
297 KEEP_INPUT,304 KEEP_INPUT,
298 2),305 2,
306 1),
299 rRowType,307 rRowType,
300 cRowType,308 cRowType,
301 INNER_JOIN);309 INNER_JOIN);
@@ -337,6 +345,11 @@
337 return keepTypes;345 return keepTypes;
338 }346 }
339347
348 private List<UserTableRowType> list(UserTableRowType... rowTypes)
349 {
350 return Arrays.asList(rowTypes);
351 }
352
340 protected int r;353 protected int r;
341 protected int a;354 protected int a;
342 protected int c;355 protected int c;
343356
=== modified file 'src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java'
--- src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java 2013-07-17 21:53:18 +0000
+++ src/test/java/com/akiban/server/test/it/qp/Product_NestedIT.java 2013-07-25 00:26:27 +0000
@@ -29,6 +29,7 @@
29import org.junit.Test;29import org.junit.Test;
3030
31import java.util.Arrays;31import java.util.Arrays;
32import java.util.List;
32import java.util.Collections;33import java.util.Collections;
33import java.util.Set;34import java.util.Set;
3435
@@ -85,6 +86,10 @@
85 use(db);86 use(db);
86 }87 }
8788
89 protected int lookaheadQuantum() {
90 return 1;
91 }
92
88 // Test assumption about ordinals93 // Test assumption about ordinals
8994
90 @Test95 @Test
@@ -146,7 +151,7 @@
146 INNER_JOIN);151 INNER_JOIN);
147 Operator flattenCA =152 Operator flattenCA =
148 flatten_HKeyOrdered(153 flatten_HKeyOrdered(
149 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0),154 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()),
150 customerRowType,155 customerRowType,
151 addressRowType,156 addressRowType,
152 INNER_JOIN);157 INNER_JOIN);
@@ -184,7 +189,7 @@
184 INNER_JOIN);189 INNER_JOIN);
185 Operator flattenCA =190 Operator flattenCA =
186 flatten_HKeyOrdered(191 flatten_HKeyOrdered(
187 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0),192 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()),
188 customerRowType,193 customerRowType,
189 addressRowType,194 addressRowType,
190 INNER_JOIN);195 INNER_JOIN);
@@ -224,9 +229,10 @@
224 flattenCAOuter.rowType(),229 flattenCAOuter.rowType(),
225 customerRowType,230 customerRowType,
226 customerRowType,231 customerRowType,
227 addressRowType,232 list(addressRowType),
228 InputPreservationOption.KEEP_INPUT,233 InputPreservationOption.KEEP_INPUT,
229 0),234 0,
235 lookaheadQuantum()),
230 customerRowType,236 customerRowType,
231 addressRowType,237 addressRowType,
232 JoinType.LEFT_JOIN);238 JoinType.LEFT_JOIN);
@@ -282,7 +288,7 @@
282 INNER_JOIN);288 INNER_JOIN);
283 Operator flattenCA =289 Operator flattenCA =
284 flatten_HKeyOrdered(290 flatten_HKeyOrdered(
285 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, addressRowType, InputPreservationOption.KEEP_INPUT, 0),291 branchLookup_Nested(coi, flattenCO.rowType(), customerRowType, null, list(addressRowType), InputPreservationOption.KEEP_INPUT, 0, lookaheadQuantum()),
286 customerRowType,292 customerRowType,
287 addressRowType,293 addressRowType,
288 INNER_JOIN);294 INNER_JOIN);
@@ -305,6 +311,11 @@
305 row(coaRowType, 1L, "northbridge", 101L, 1L, "ori", 1001L, 1L, "111 1001 st"),311 row(coaRowType, 1L, "northbridge", 101L, 1L, "ori", 1001L, 1L, "111 1001 st"),
306 };312 };
307 }313 }
314
315 @Override
316 public boolean reopenTopLevel() {
317 return pipelineMap();
318 }
308 };319 };
309 testCursorLifecycle(plan, testCase);320 testCursorLifecycle(plan, testCase);
310 }321 }
@@ -315,4 +326,9 @@
315 keepTypes.removeAll(Schema.descendentTypes(type, keepTypes));326 keepTypes.removeAll(Schema.descendentTypes(type, keepTypes));
316 return keepTypes;327 return keepTypes;
317 }328 }
329
330 private List<UserTableRowType> list(UserTableRowType... rowTypes)
331 {
332 return Arrays.asList(rowTypes);
333 }
318}334}
319335
=== added file 'src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java'
--- src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java 1970-01-01 00:00:00 +0000
+++ src/test/java/com/akiban/server/test/it/qp/Product_NestedLookaheadIT.java 2013-07-25 00:26:27 +0000
@@ -0,0 +1,31 @@
1/**
2 * Copyright (C) 2009-2013 Akiban Technologies, Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18package com.akiban.server.test.it.qp;
19
20public class Product_NestedLookaheadIT extends Product_NestedIT
21{
22 @Override
23 protected boolean pipelineMap() {
24 return true;
25 }
26
27 @Override
28 protected int lookaheadQuantum() {
29 return 4;
30 }
31}
032
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-duplicate.expected 2013-07-25 00:26:27 +0000
@@ -12,4 +12,4 @@
12 Flatten_HKeyOrdered(customers - orders INNER items)12 Flatten_HKeyOrdered(customers - orders INNER items)
13 Flatten_HKeyOrdered(customers INNER orders)13 Flatten_HKeyOrdered(customers INNER orders)
14 Select_HKeyOrdered(i2.sku == '4567')14 Select_HKeyOrdered(i2.sku == '4567')
15 BranchLookup_Nested(customers -> orders)
16\ No newline at end of file15\ No newline at end of file
16 BranchLookup_Nested(customers -> orders, items)
17\ No newline at end of file17\ No newline at end of file
1818
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/cbo/multiindex-multi-ordered.expected 2013-07-25 00:26:27 +0000
@@ -12,4 +12,4 @@
12 Flatten_HKeyOrdered(customers - orders INNER items)12 Flatten_HKeyOrdered(customers - orders INNER items)
13 Flatten_HKeyOrdered(customers INNER orders)13 Flatten_HKeyOrdered(customers INNER orders)
14 Select_HKeyOrdered(i2.sku == '4567')14 Select_HKeyOrdered(i2.sku == '4567')
15 BranchLookup_Nested(customers -> orders)
16\ No newline at end of file15\ No newline at end of file
16 BranchLookup_Nested(customers -> orders, items)
17\ No newline at end of file17\ No newline at end of file
1818
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/coia-group-index/select-17bu.expected 2013-07-25 00:26:27 +0000
@@ -13,4 +13,4 @@
13 Filter_Default(customers - orders - items)13 Filter_Default(customers - orders - items)
14 Flatten_HKeyOrdered(customers - orders INNER items)14 Flatten_HKeyOrdered(customers - orders INNER items)
15 Flatten_HKeyOrdered(customers INNER orders)15 Flatten_HKeyOrdered(customers INNER orders)
16 BranchLookup_Nested(customers -> orders)
17\ No newline at end of file16\ No newline at end of file
17 BranchLookup_Nested(customers -> orders, items)
18\ No newline at end of file18\ No newline at end of file
1919
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2.expected 2013-07-25 00:26:27 +0000
@@ -9,4 +9,4 @@
9 Filter_Default(customers - orders - items)9 Filter_Default(customers - orders - items)
10 Flatten_HKeyOrdered(customers - orders INNER items)10 Flatten_HKeyOrdered(customers - orders INNER items)
11 Flatten_HKeyOrdered(customers INNER orders)11 Flatten_HKeyOrdered(customers INNER orders)
12 BranchLookup_Nested(customers -> orders)
13\ No newline at end of file12\ No newline at end of file
13 BranchLookup_Nested(customers -> orders, items)
14\ No newline at end of file14\ No newline at end of file
1515
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2n.expected 2013-07-25 00:26:27 +0000
@@ -9,4 +9,4 @@
9 Filter_Default(customers - orders - items)9 Filter_Default(customers - orders - items)
10 Flatten_HKeyOrdered(customers - orders INNER items)10 Flatten_HKeyOrdered(customers - orders INNER items)
11 Flatten_HKeyOrdered(customers INNER orders)11 Flatten_HKeyOrdered(customers INNER orders)
12 BranchLookup_Nested(customers -> orders)
13\ No newline at end of file12\ No newline at end of file
13 BranchLookup_Nested(customers -> orders, items)
14\ No newline at end of file14\ No newline at end of file
1515
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/coia-text-index/full-text-2v.expected 2013-07-25 00:26:27 +0000
@@ -9,4 +9,4 @@
9 Filter_Default(customers - orders - items)9 Filter_Default(customers - orders - items)
10 Flatten_HKeyOrdered(customers - orders INNER items)10 Flatten_HKeyOrdered(customers - orders INNER items)
11 Flatten_HKeyOrdered(customers INNER orders)11 Flatten_HKeyOrdered(customers INNER orders)
12 BranchLookup_Nested(customers -> orders)
13\ No newline at end of file12\ No newline at end of file
13 BranchLookup_Nested(customers -> orders, items)
14\ No newline at end of file14\ No newline at end of file
1515
=== modified file 'src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected'
--- src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected 2013-07-17 21:00:35 +0000
+++ src/test/resources/com/akiban/sql/optimizer/operator/coia/select-8.expected 2013-07-25 00:26:27 +0000
@@ -8,4 +8,4 @@
8 Filter_Default(customers - orders - items)8 Filter_Default(customers - orders - items)
9 Flatten_HKeyOrdered(customers - orders INNER items)9 Flatten_HKeyOrdered(customers - orders INNER items)
10 Flatten_HKeyOrdered(customers INNER orders)10 Flatten_HKeyOrdered(customers INNER orders)
11 BranchLookup_Nested(customers -> orders)
12\ No newline at end of file11\ No newline at end of file
12 BranchLookup_Nested(customers -> orders, items)
13\ No newline at end of file13\ No newline at end of file
1414
=== modified file 'src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected'
--- src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected 2013-07-25 00:26:26 +0000
+++ src/test/resources/com/akiban/sql/optimizer/rule/operator/full-text-2.expected 2013-07-25 00:26:27 +0000
@@ -9,4 +9,4 @@
9 Filter_Default(test.customers - test.orders - test.items)9 Filter_Default(test.customers - test.orders - test.items)
10 Flatten_HKeyOrdered(test.customers - test.orders INNER test.items)10 Flatten_HKeyOrdered(test.customers - test.orders INNER test.items)
11 Flatten_HKeyOrdered(test.customers INNER test.orders)11 Flatten_HKeyOrdered(test.customers INNER test.orders)
12 BranchLookup_Nested(test.customers -> test.orders)
13\ No newline at end of file12\ No newline at end of file
13 BranchLookup_Nested(test.customers -> test.orders, test.items)
14\ No newline at end of file14\ No newline at end of file

Subscribers

People subscribed via source and target branches