Merge lp:~mmcm/akiban-server/query-bindings-cursor into lp:~akiban-technologies/akiban-server/trunk

Proposed by Mike McMahon
Status: Merged
Approved by: Nathan Williams
Approved revision: 2716
Merged at revision: 2692
Proposed branch: lp:~mmcm/akiban-server/query-bindings-cursor
Merge into: lp:~akiban-technologies/akiban-server/trunk
Prerequisite: lp:~mmcm/akiban-server/query-bindings
Diff against target: 6940 lines (+1597/-1012)
136 files modified
src/main/java/com/akiban/qp/loadableplan/std/DumpGroupLoadablePlan.java (+2/-2)
src/main/java/com/akiban/qp/memoryadapter/MemoryAdapter.java (+3/-2)
src/main/java/com/akiban/qp/operator/API.java (+6/-2)
src/main/java/com/akiban/qp/operator/Aggregate_Partial.java (+22/-6)
src/main/java/com/akiban/qp/operator/AncestorLookup_Default.java (+5/-25)
src/main/java/com/akiban/qp/operator/AncestorLookup_Nested.java (+5/-5)
src/main/java/com/akiban/qp/operator/BindingsAwareCursor.java (+23/-0)
src/main/java/com/akiban/qp/operator/BranchLookup_Default.java (+10/-12)
src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java (+5/-5)
src/main/java/com/akiban/qp/operator/ChainedCursor.java (+20/-3)
src/main/java/com/akiban/qp/operator/Count_Default.java (+5/-13)
src/main/java/com/akiban/qp/operator/Count_TableStatus.java (+5/-5)
src/main/java/com/akiban/qp/operator/Cursor.java (+31/-0)
src/main/java/com/akiban/qp/operator/CursorBase.java (+36/-0)
src/main/java/com/akiban/qp/operator/Delete_Default.java (+6/-5)
src/main/java/com/akiban/qp/operator/Delete_Returning.java (+11/-22)
src/main/java/com/akiban/qp/operator/Distinct_Partial.java (+5/-7)
src/main/java/com/akiban/qp/operator/EmitBoundRow_Nested.java (+5/-28)
src/main/java/com/akiban/qp/operator/ExecutionBase.java (+1/-3)
src/main/java/com/akiban/qp/operator/Filter_Default.java (+5/-19)
src/main/java/com/akiban/qp/operator/Flatten_HKeyOrdered.java (+5/-13)
src/main/java/com/akiban/qp/operator/GroupCursor.java (+1/-1)
src/main/java/com/akiban/qp/operator/GroupScan_Default.java (+68/-18)
src/main/java/com/akiban/qp/operator/HKeyUnion_Ordered.java (+34/-7)
src/main/java/com/akiban/qp/operator/IfEmpty_Default.java (+5/-13)
src/main/java/com/akiban/qp/operator/IndexScan_Default.java (+15/-7)
src/main/java/com/akiban/qp/operator/Insert_Default.java (+6/-5)
src/main/java/com/akiban/qp/operator/Insert_Returning.java (+12/-23)
src/main/java/com/akiban/qp/operator/Intersect_Ordered.java (+34/-7)
src/main/java/com/akiban/qp/operator/LeafCursor.java (+45/-0)
src/main/java/com/akiban/qp/operator/Limit_Default.java (+4/-4)
src/main/java/com/akiban/qp/operator/Map_NestedLoops.java (+30/-9)
src/main/java/com/akiban/qp/operator/MultipleQueryBindingsCursor.java (+121/-0)
src/main/java/com/akiban/qp/operator/Operator.java (+1/-1)
src/main/java/com/akiban/qp/operator/OperatorCursor.java (+42/-0)
src/main/java/com/akiban/qp/operator/OperatorExecutionBase.java (+2/-2)
src/main/java/com/akiban/qp/operator/Product_NestedLoops.java (+31/-11)
src/main/java/com/akiban/qp/operator/Project_Default.java (+12/-17)
src/main/java/com/akiban/qp/operator/QueryBindingsCursor.java (+33/-0)
src/main/java/com/akiban/qp/operator/RowCursor.java (+1/-1)
src/main/java/com/akiban/qp/operator/RowOrientedCursorBase.java (+0/-76)
src/main/java/com/akiban/qp/operator/Select_BloomFilter.java (+30/-10)
src/main/java/com/akiban/qp/operator/Select_HKeyOrdered.java (+5/-13)
src/main/java/com/akiban/qp/operator/SingletonQueryBindingsCursor.java (+61/-0)
src/main/java/com/akiban/qp/operator/Sort_General.java (+6/-8)
src/main/java/com/akiban/qp/operator/Sort_InsertionLimited.java (+6/-8)
src/main/java/com/akiban/qp/operator/SorterToCursorAdapter.java (+5/-5)
src/main/java/com/akiban/qp/operator/StoreAdapter.java (+7/-8)
src/main/java/com/akiban/qp/operator/UnionAll_Default.java (+40/-14)
src/main/java/com/akiban/qp/operator/Union_Ordered.java (+34/-7)
src/main/java/com/akiban/qp/operator/Update_Default.java (+6/-5)
src/main/java/com/akiban/qp/operator/Update_Returning.java (+12/-23)
src/main/java/com/akiban/qp/operator/Using_BloomFilter.java (+8/-35)
src/main/java/com/akiban/qp/operator/ValuesScan_Default.java (+5/-5)
src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java (+1/-1)
src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java (+2/-3)
src/main/java/com/akiban/qp/persistitadapter/PersistitIndexCursor.java (+8/-5)
src/main/java/com/akiban/qp/persistitadapter/Sorter.java (+2/-2)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursor.java (+15/-11)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorMixedOrder.java (+2/-5)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_InBox.java (+12/-6)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_NearPoint.java (+16/-9)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectional.java (+4/-8)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectionalLexicographic.java (+2/-5)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/MemorySorter.java (+5/-5)
src/main/java/com/akiban/qp/persistitadapter/indexcursor/PersistitSorter.java (+8/-6)
src/main/java/com/akiban/qp/util/MultiCursor.java (+20/-6)
src/main/java/com/akiban/server/expression/subquery/ResultSetSubqueryExpression.java (+1/-1)
src/main/java/com/akiban/server/expression/subquery/SubqueryExpressionEvaluation.java (+2/-2)
src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+4/-4)
src/main/java/com/akiban/server/service/externaldata/JsonRowWriter.java (+11/-2)
src/main/java/com/akiban/server/service/restdml/DeleteProcessor.java (+3/-2)
src/main/java/com/akiban/server/service/restdml/ModelBuilder.java (+5/-5)
src/main/java/com/akiban/server/service/restdml/RestDMLServiceImpl.java (+2/-1)
src/main/java/com/akiban/server/service/restdml/SQLOutputCursor.java (+2/-2)
src/main/java/com/akiban/server/service/restdml/UpsertProcessor.java (+1/-1)
src/main/java/com/akiban/server/service/text/FullTextCursor.java (+2/-2)
src/main/java/com/akiban/server/service/text/FullTextIndexService.java (+3/-2)
src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java (+2/-3)
src/main/java/com/akiban/server/service/text/FullTextQueryBuilder.java (+30/-0)
src/main/java/com/akiban/server/service/text/FullTextQueryExpression.java (+1/-0)
src/main/java/com/akiban/server/service/text/IndexScan_FullText.java (+88/-5)
src/main/java/com/akiban/server/service/text/RowIndexer.java (+2/-2)
src/main/java/com/akiban/server/service/text/Searcher.java (+3/-3)
src/main/java/com/akiban/server/store/AbstractStore.java (+5/-3)
src/main/java/com/akiban/server/store/StoreGIMaintenance.java (+2/-2)
src/main/java/com/akiban/server/types3/texpressions/ResultSetSubqueryTExpression.java (+1/-1)
src/main/java/com/akiban/server/types3/texpressions/SubqueryTEvaluateble.java (+2/-2)
src/main/java/com/akiban/sql/embedded/ExecutableModifyOperatorStatement.java (+4/-3)
src/main/java/com/akiban/sql/embedded/ExecutableQueryOperatorStatement.java (+1/-1)
src/main/java/com/akiban/sql/embedded/ExecuteResults.java (+5/-5)
src/main/java/com/akiban/sql/embedded/JDBCResultSet.java (+6/-6)
src/main/java/com/akiban/sql/pg/PostgresModifyOperatorStatement.java (+1/-1)
src/main/java/com/akiban/sql/pg/PostgresOperatorStatement.java (+1/-1)
src/test/java/com/akiban/qp/operator/OperatorTestHelper.java (+4/-4)
src/test/java/com/akiban/qp/operator/TimeOperator.java (+5/-34)
src/test/java/com/akiban/server/test/costmodel/DistinctCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/FlattenCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/HKeyUnionCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/IntersectCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/MapCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/ProductCT.java (+3/-3)
src/test/java/com/akiban/server/test/costmodel/ProjectCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/SelectCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/Select_BloomFilterCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/SortCT.java (+2/-2)
src/test/java/com/akiban/server/test/costmodel/SortWithLimitCT.java (+1/-1)
src/test/java/com/akiban/server/test/costmodel/TreeScanCT.java (+3/-3)
src/test/java/com/akiban/server/test/it/ITBase.java (+20/-8)
src/test/java/com/akiban/server/test/it/qp/GroupIndexScanIT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/GroupScanIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/qp/IndexScanIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/qp/IndexScanJumpBoundedIT.java (+130/-130)
src/test/java/com/akiban/server/test/it/qp/IndexScanJumpUnboundedIT.java (+32/-32)
src/test/java/com/akiban/server/test/it/qp/MultiCursorIT.java (+11/-11)
src/test/java/com/akiban/server/test/it/qp/NWaySkipScanIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/qp/OperatorITBase.java (+25/-12)
src/test/java/com/akiban/server/test/it/qp/QueryTimeoutIT.java (+5/-5)
src/test/java/com/akiban/server/test/it/qp/SkipScanPerformanceIT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/SpatialLatLonGroupIndexScanIT.java (+3/-3)
src/test/java/com/akiban/server/test/it/qp/SpatialLatLonTableIndexScanIT.java (+7/-7)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexJumpUnboundedCompositeKeyIT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexScanJumpBoundedUnboundedWithNulls2IT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexScanJumpBoundedWithNullsIT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexScanJumpUnboundedIT.java (+32/-32)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexScanJumpUnboundedWithNullsIT.java (+2/-2)
src/test/java/com/akiban/server/test/it/qp/UniqueIndexUpdateIT.java (+5/-5)
src/test/java/com/akiban/server/test/it/sort/PersistitSorterOverflowIT.java (+4/-3)
src/test/java/com/akiban/server/test/it/sort/SorterITBase.java (+3/-2)
src/test/java/com/akiban/server/test/pt/AggregatePT.java (+41/-25)
src/test/java/com/akiban/server/test/pt/gi/GIUpdateProfilePT.java (+1/-1)
src/test/java/com/akiban/server/test/pt/qp/GroupScanProfilePT.java (+2/-2)
src/test/java/com/akiban/server/test/pt/qp/IndexScanPT.java (+2/-2)
src/test/java/com/akiban/server/test/pt/qp/QPProfilePTBase.java (+4/-4)
src/test/java/com/akiban/server/test/pt/qp/SimpleJoinPT.java (+2/-2)
src/test/java/com/akiban/server/test/pt/qp/SortPT.java (+2/-2)
To merge this branch: bzr merge lp:~mmcm/akiban-server/query-bindings-cursor
Reviewer Review Type Date Requested Status
Nathan Williams Approve
Review via email: mp+173848@code.launchpad.net

Description of the change

Add QueryBindingCursor, which is a stream of QueryBindings.

These methods are then added to Cursor, making it a combined stream of rows and bindings, with the additional contract that the row cursor lifecycle is within a a set of bindings, fixed at open() time.

Since there are still internal streams of rows that are not streams of bindings, such as index and sort cursors, formalize a RowCursor interface for just that.

At top level, when a plan is constructed, a QueryBindingsCursor is supplied for the whole query. In almost all cases, this is a singleton over a set of QueryBindings (holding any parameter passed to the query). This stream is passed to the Operator's cursor method to construct the combined stream cursors. An operator with an input just passes it along to its child's constructor. A leaf operator remembers the stream so that it can implement the new bindings methods using it.

An operator like Union or Intersection that has multiple children that run at the same time needs to multiplex the stream, for which a new helper class is added.

An operator like Map_NestedLoops or Select_BloomFilter that has a slow loop and faster inside loop passes the root stream to the outer loop and arranges for the inner loop to have a stream driven by the outer loop. At present, this means a singleton on the outer loop's bindings, because we are still opening the inner loop each time. That will change when pipelining it added in upcoming branches.

The top-level idea is to have all the operators written to obey the bindings stream protocol, maintaining their state based on it. But there is still only one set of bindings for the whole query, that gets passed along in these various ways. Realistically, that means that the tests find places that would get a NPE from failing to maintin it, but not actual isolation between bindings in the stream. That will have to come with some non-singleton cases.

This would have been a little easier if Types 2 were gone, but obviously I didn't do that here.

This is made somewhat harder by mostly gratuitous differnces in how the various operators are implemented. I made that a tiny bit better, by introducing some classes for the common cases of extends OperatorExecutionBase implements Cursor, but I didn't go crazy cleaning up.

This would have been a little easier without UpdatePlannable, whose run() isn't very cursor-like / prepare friendly, but I think I kept those working.

One of the messier things is the difference between open() and openTopLevel(). The latter means open the bindings stream, get the first (only) bindings, and then open the cursor. It's usually what you want. Except that RowCursor doesn't support it. And some tests on Cursor still want the more limited one when they are testing lifecycle within a bindings. I think I got everything calling the right method, but I am definitely open to suggestions on a different approach to that distinction.

As with the prereq branch, there is no urgency in getting this in, if we want to wait until the latency hiding that will actually make use of it all is working.

To post a comment you must log in.
2716. By Mike McMahon

Merge from trunk.

Revision history for this message
Nathan Williams (nwilliams) wrote :

Sounds, and looks, like previously discussed.

I don't have a suggestion for open vs openTopLevel at the moment and it doesn't look to objectionable from the diff. Perhaps something will come to us later.

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/loadableplan/std/DumpGroupLoadablePlan.java'
2--- src/main/java/com/akiban/qp/loadableplan/std/DumpGroupLoadablePlan.java 2013-07-05 21:35:32 +0000
3+++ src/main/java/com/akiban/qp/loadableplan/std/DumpGroupLoadablePlan.java 2013-07-10 21:47:26 +0000
4@@ -23,7 +23,7 @@
5 import com.akiban.qp.loadableplan.DirectObjectPlan;
6 import com.akiban.qp.loadableplan.LoadableDirectObjectPlan;
7 import com.akiban.qp.operator.BindingNotSetException;
8-import com.akiban.qp.operator.Cursor;
9+import com.akiban.qp.operator.RowCursor;
10 import com.akiban.qp.operator.QueryBindings;
11 import com.akiban.qp.operator.QueryContext;
12 import com.akiban.qp.row.Row;
13@@ -68,7 +68,7 @@
14 private final QueryContext context;
15 private final QueryBindings bindings;
16 private UserTable rootTable;
17- private Cursor cursor;
18+ private RowCursor cursor;
19 private Map<UserTable,Integer> tableSizes;
20 private StringBuilder buffer;
21 private GroupRowFormatter formatter;
22
23=== modified file 'src/main/java/com/akiban/qp/memoryadapter/MemoryAdapter.java'
24--- src/main/java/com/akiban/qp/memoryadapter/MemoryAdapter.java 2013-07-08 15:56:07 +0000
25+++ src/main/java/com/akiban/qp/memoryadapter/MemoryAdapter.java 2013-07-10 21:47:26 +0000
26@@ -28,6 +28,7 @@
27 import com.akiban.qp.operator.IndexScanSelector;
28 import com.akiban.qp.operator.QueryBindings;
29 import com.akiban.qp.operator.QueryContext;
30+import com.akiban.qp.operator.RowCursor;
31 import com.akiban.qp.operator.StoreAdapter;
32 import com.akiban.qp.operator.API.Ordering;
33 import com.akiban.qp.operator.API.SortOption;
34@@ -72,7 +73,7 @@
35 }
36
37 @Override
38- public Cursor newIndexCursor(QueryContext context, QueryBindings bindings, Index index,
39+ public RowCursor newIndexCursor(QueryContext context, Index index,
40 IndexKeyRange keyRange, Ordering ordering,
41 IndexScanSelector scanSelector, boolean usePValues) {
42
43@@ -93,7 +94,7 @@
44 }
45
46 @Override
47- public Sorter createSorter(QueryContext context, QueryBindings bindings, Cursor input, RowType rowType,
48+ public Sorter createSorter(QueryContext context, QueryBindings bindings, RowCursor input, RowType rowType,
49 Ordering ordering, SortOption sortOption, InOutTap loadTap) {
50 throw new UnsupportedOperationException();
51 }
52
53=== modified file 'src/main/java/com/akiban/qp/operator/API.java'
54--- src/main/java/com/akiban/qp/operator/API.java 2013-07-05 21:35:32 +0000
55+++ src/main/java/com/akiban/qp/operator/API.java 2013-07-10 21:47:26 +0000
56@@ -738,10 +738,14 @@
57
58 // Execution interface
59
60+ public static Cursor cursor(Operator root, QueryContext context, QueryBindingsCursor bindingsCursor)
61+ {
62+ return new ChainedCursor(context, root.cursor(context, bindingsCursor));
63+ }
64+
65 public static Cursor cursor(Operator root, QueryContext context, QueryBindings bindings)
66 {
67- // if all they need is the wrapped cursor, create it directly
68- return new ChainedCursor(context, bindings, root.cursor(context, bindings));
69+ return cursor(root, context, new SingletonQueryBindingsCursor(bindings));
70 }
71
72 // Options
73
74=== modified file 'src/main/java/com/akiban/qp/operator/Aggregate_Partial.java'
75--- src/main/java/com/akiban/qp/operator/Aggregate_Partial.java 2013-07-05 21:35:32 +0000
76+++ src/main/java/com/akiban/qp/operator/Aggregate_Partial.java 2013-07-10 21:47:26 +0000
77@@ -165,7 +165,7 @@
78 // Operator interface
79
80 @Override
81- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
82+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
83 final List<Aggregator> aggregators;
84 if (aggregatorFactories != null) {
85 aggregators = new ArrayList<>();
86@@ -182,7 +182,7 @@
87 aggregators = null;
88 }
89 return new AggregateCursor(
90- context, bindings,
91+ context, bindingsCursor,
92 aggregators
93 );
94 }
95@@ -369,7 +369,7 @@
96
97 // nested classes
98
99- private class AggregateCursor extends OperatorExecutionBase implements Cursor
100+ private class AggregateCursor extends OperatorCursor
101 {
102
103 // Cursor interface
104@@ -487,6 +487,22 @@
105 return cursorState == CursorState.DESTROYED;
106 }
107
108+
109+ @Override
110+ public void openBindings() {
111+ inputCursor.openBindings();
112+ }
113+
114+ @Override
115+ public QueryBindings nextBindings() {
116+ return inputCursor.nextBindings();
117+ }
118+
119+ @Override
120+ public void closeBindings() {
121+ inputCursor.closeBindings();
122+ }
123+
124 // for use in this class
125
126 private void aggregate(Row input) {
127@@ -641,10 +657,10 @@
128
129 // AggregateCursor interface
130
131- private AggregateCursor(QueryContext context, QueryBindings bindings,
132+ private AggregateCursor(QueryContext context, QueryBindingsCursor bindingsCursor,
133 List<Aggregator> aggregators) {
134- super(context, bindings);
135- this.inputCursor = inputOperator.cursor(context, bindings);
136+ super(context);
137+ this.inputCursor = inputOperator.cursor(context, bindingsCursor);
138 this.aggregators = aggregators;
139 if (aggregators != null) {
140 keyValues = new ArrayList<>();
141
142=== modified file 'src/main/java/com/akiban/qp/operator/AncestorLookup_Default.java'
143--- src/main/java/com/akiban/qp/operator/AncestorLookup_Default.java 2013-07-05 21:35:32 +0000
144+++ src/main/java/com/akiban/qp/operator/AncestorLookup_Default.java 2013-07-10 21:47:26 +0000
145@@ -131,9 +131,9 @@
146 }
147
148 @Override
149- protected Cursor cursor(QueryContext context, QueryBindings bindings)
150+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
151 {
152- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
153+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
154 }
155
156 @Override
157@@ -252,7 +252,7 @@
158
159 // Inner classes
160
161- private class Execution extends OperatorExecutionBase implements Cursor
162+ private class Execution extends ChainedCursor
163 {
164 // Cursor interface
165
166@@ -313,30 +313,11 @@
167 input.destroy();
168 }
169
170- @Override
171- public boolean isIdle()
172- {
173- return input.isIdle();
174- }
175-
176- @Override
177- public boolean isActive()
178- {
179- return input.isActive();
180- }
181-
182- @Override
183- public boolean isDestroyed()
184- {
185- return input.isDestroyed();
186- }
187-
188 // Execution interface
189
190- Execution(QueryContext context, QueryBindings bindings, Cursor input)
191+ Execution(QueryContext context, Cursor input)
192 {
193- super(context, bindings);
194- this.input = input;
195+ super(context, input);
196 // Why + 1: Because the input row (whose ancestors get discovered) also goes into pending.
197 this.pending = new PendingRows(ancestors.size() + 1);
198 this.ancestorCursor = adapter().newGroupCursor(group);
199@@ -391,7 +372,6 @@
200
201 // Object state
202
203- private final Cursor input;
204 private final ShareHolder<Row> inputRow = new ShareHolder<>();
205 private final GroupCursor ancestorCursor;
206 private final ShareHolder<Row> ancestorRow = new ShareHolder<>();
207
208=== modified file 'src/main/java/com/akiban/qp/operator/AncestorLookup_Nested.java'
209--- src/main/java/com/akiban/qp/operator/AncestorLookup_Nested.java 2013-07-05 21:35:32 +0000
210+++ src/main/java/com/akiban/qp/operator/AncestorLookup_Nested.java 2013-07-10 21:47:26 +0000
211@@ -129,9 +129,9 @@
212 }
213
214 @Override
215- protected Cursor cursor(QueryContext context, QueryBindings bindings)
216+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
217 {
218- return new Execution(context, bindings);
219+ return new Execution(context, bindingsCursor);
220 }
221
222 @Override
223@@ -235,7 +235,7 @@
224
225 // Inner classes
226
227- private class Execution extends OperatorExecutionBase implements Cursor
228+ private class Execution extends LeafCursor
229 {
230 // Cursor interface
231
232@@ -320,9 +320,9 @@
233
234 // Execution interface
235
236- Execution(QueryContext context, QueryBindings bindings)
237+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
238 {
239- super(context, bindings);
240+ super(context, bindingsCursor);
241 this.pending = new PendingRows(ancestors.size() + 1);
242 this.ancestorCursor = adapter().newGroupCursor(group);
243 }
244
245=== added file 'src/main/java/com/akiban/qp/operator/BindingsAwareCursor.java'
246--- src/main/java/com/akiban/qp/operator/BindingsAwareCursor.java 1970-01-01 00:00:00 +0000
247+++ src/main/java/com/akiban/qp/operator/BindingsAwareCursor.java 2013-07-10 21:47:26 +0000
248@@ -0,0 +1,23 @@
249+/**
250+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
251+ *
252+ * This program is free software: you can redistribute it and/or modify
253+ * it under the terms of the GNU Affero General Public License as published by
254+ * the Free Software Foundation, either version 3 of the License, or
255+ * (at your option) any later version.
256+ *
257+ * This program is distributed in the hope that it will be useful,
258+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
259+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
260+ * GNU Affero General Public License for more details.
261+ *
262+ * You should have received a copy of the GNU Affero General Public License
263+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
264+ */
265+
266+package com.akiban.qp.operator;
267+
268+public interface BindingsAwareCursor extends RowCursor
269+{
270+ public void rebind(QueryBindings bindings);
271+}
272
273=== modified file 'src/main/java/com/akiban/qp/operator/BranchLookup_Default.java'
274--- src/main/java/com/akiban/qp/operator/BranchLookup_Default.java 2013-07-05 21:35:32 +0000
275+++ src/main/java/com/akiban/qp/operator/BranchLookup_Default.java 2013-07-10 21:47:26 +0000
276@@ -162,9 +162,9 @@
277 }
278
279 @Override
280- public Cursor cursor(QueryContext context, QueryBindings bindings)
281+ public Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
282 {
283- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
284+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
285 }
286
287 @Override
288@@ -300,7 +300,7 @@
289 return new LookUpOperatorExplainer(getName(), atts, inputRowType, keepInput, inputOperator, context);
290 }
291
292- private class Execution extends OperatorExecutionBase implements Cursor
293+ private class Execution extends ChainedCursor
294 {
295 // Cursor interface
296
297@@ -310,7 +310,7 @@
298 TAP_OPEN.in();
299 try {
300 CursorLifecycle.checkIdle(this);
301- inputCursor.open();
302+ input.open();
303 advanceInput();
304 idle = false;
305 } finally {
306@@ -371,7 +371,7 @@
307 {
308 CursorLifecycle.checkIdleOrActive(this);
309 if (!idle) {
310- inputCursor.close();
311+ input.close();
312 inputRow.release();
313 lookupCursor.close();
314 lookupRow.release();
315@@ -383,7 +383,7 @@
316 public void destroy()
317 {
318 close();
319- inputCursor.destroy();
320+ input.destroy();
321 lookupCursor.destroy();
322 }
323
324@@ -402,15 +402,14 @@
325 @Override
326 public boolean isDestroyed()
327 {
328- return inputCursor.isDestroyed();
329+ return input.isDestroyed();
330 }
331
332 // Execution interface
333
334- Execution(QueryContext context, QueryBindings bindings, Cursor input)
335+ Execution(QueryContext context, Cursor input)
336 {
337- super(context, bindings);
338- this.inputCursor = input;
339+ super(context, input);
340 this.lookupCursor = adapter().newGroupCursor(group);
341 this.lookupRowHKey = adapter().newHKey(outputRowType.hKey());
342 }
343@@ -439,7 +438,7 @@
344 lookupState = LookupState.BEFORE;
345 lookupRow.release();
346 lookupCursor.close();
347- Row currentInputRow = inputCursor.next();
348+ Row currentInputRow = input.next();
349 if (currentInputRow != null) {
350 if (currentInputRow.rowType() == inputRowType) {
351 lookupRow.release();
352@@ -464,7 +463,6 @@
353
354 // Object state
355
356- private final Cursor inputCursor;
357 private final ShareHolder<Row> inputRow = new ShareHolder<>();
358 private final GroupCursor lookupCursor;
359 private final ShareHolder<Row> lookupRow = new ShareHolder<>();
360
361=== modified file 'src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java'
362--- src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-05 21:35:32 +0000
363+++ src/main/java/com/akiban/qp/operator/BranchLookup_Nested.java 2013-07-10 21:47:26 +0000
364@@ -148,9 +148,9 @@
365 }
366
367 @Override
368- public Cursor cursor(QueryContext context, QueryBindings bindings)
369+ public Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
370 {
371- return new Execution(context, bindings);
372+ return new Execution(context, bindingsCursor);
373 }
374
375 @Override
376@@ -285,7 +285,7 @@
377
378 // Inner classes
379
380- private class Execution extends OperatorExecutionBase implements Cursor
381+ private class Execution extends LeafCursor
382 {
383 // Cursor interface
384
385@@ -383,9 +383,9 @@
386
387 // Execution interface
388
389- Execution(QueryContext context, QueryBindings bindings)
390+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
391 {
392- super(context, bindings);
393+ super(context, bindingsCursor);
394 this.cursor = adapter().newGroupCursor(group);
395 this.hKey = adapter().newHKey(outputRowType.hKey());
396 }
397
398=== modified file 'src/main/java/com/akiban/qp/operator/ChainedCursor.java'
399--- src/main/java/com/akiban/qp/operator/ChainedCursor.java 2013-07-05 21:35:32 +0000
400+++ src/main/java/com/akiban/qp/operator/ChainedCursor.java 2013-07-10 21:47:26 +0000
401@@ -20,12 +20,13 @@
402 import com.akiban.qp.row.Row;
403 import com.akiban.server.api.dml.ColumnSelector;
404
405-public class ChainedCursor extends OperatorExecutionBase implements Cursor
406+public class ChainedCursor extends OperatorCursor
407 {
408 protected final Cursor input;
409+ protected QueryBindings bindings;
410
411- protected ChainedCursor(QueryContext context, QueryBindings bindings, Cursor input) {
412- super(context, bindings);
413+ protected ChainedCursor(QueryContext context, Cursor input) {
414+ super(context);
415 this.input = input;
416 }
417
418@@ -74,4 +75,20 @@
419 {
420 return input.isDestroyed();
421 }
422+
423+ @Override
424+ public void openBindings() {
425+ input.openBindings();
426+ }
427+
428+ @Override
429+ public QueryBindings nextBindings() {
430+ bindings = input.nextBindings();
431+ return bindings;
432+ }
433+
434+ @Override
435+ public void closeBindings() {
436+ input.closeBindings();
437+ }
438 }
439
440=== modified file 'src/main/java/com/akiban/qp/operator/Count_Default.java'
441--- src/main/java/com/akiban/qp/operator/Count_Default.java 2013-07-05 21:35:32 +0000
442+++ src/main/java/com/akiban/qp/operator/Count_Default.java 2013-07-10 21:47:26 +0000
443@@ -93,9 +93,9 @@
444 }
445
446 @Override
447- protected Cursor cursor(QueryContext context, QueryBindings bindings)
448+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
449 {
450- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
451+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
452 }
453
454 @Override
455@@ -151,7 +151,7 @@
456
457 // Inner classes
458
459- private class Execution extends OperatorExecutionBase implements Cursor
460+ private class Execution extends ChainedCursor
461 {
462 // Cursor interface
463
464@@ -233,23 +233,15 @@
465 return !closed;
466 }
467
468- @Override
469- public boolean isDestroyed()
470- {
471- return input.isDestroyed();
472- }
473-
474 // Execution interface
475
476- Execution(QueryContext context, QueryBindings bindings, Cursor input)
477+ Execution(QueryContext context, Cursor input)
478 {
479- super(context, bindings);
480- this.input = input;
481+ super(context, input);
482 }
483
484 // Object state
485
486- private final Cursor input;
487 private long count;
488 private boolean closed = true;
489 }
490
491=== modified file 'src/main/java/com/akiban/qp/operator/Count_TableStatus.java'
492--- src/main/java/com/akiban/qp/operator/Count_TableStatus.java 2013-07-05 21:35:32 +0000
493+++ src/main/java/com/akiban/qp/operator/Count_TableStatus.java 2013-07-10 21:47:26 +0000
494@@ -86,9 +86,9 @@
495 // Operator interface
496
497 @Override
498- protected Cursor cursor(QueryContext context, QueryBindings bindings)
499+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
500 {
501- return new Execution(context, bindings);
502+ return new Execution(context, bindingsCursor);
503 }
504
505 @Override
506@@ -137,7 +137,7 @@
507
508 // Inner classes
509
510- private class Execution extends OperatorExecutionBase implements Cursor
511+ private class Execution extends LeafCursor
512 {
513 // Cursor interface
514
515@@ -219,9 +219,9 @@
516
517 // Execution interface
518
519- Execution(QueryContext context, QueryBindings bindings)
520+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
521 {
522- super(context, bindings);
523+ super(context, bindingsCursor);
524 }
525
526 // Object state
527
528=== added file 'src/main/java/com/akiban/qp/operator/Cursor.java'
529--- src/main/java/com/akiban/qp/operator/Cursor.java 1970-01-01 00:00:00 +0000
530+++ src/main/java/com/akiban/qp/operator/Cursor.java 2013-07-10 21:47:26 +0000
531@@ -0,0 +1,31 @@
532+/**
533+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
534+ *
535+ * This program is free software: you can redistribute it and/or modify
536+ * it under the terms of the GNU Affero General Public License as published by
537+ * the Free Software Foundation, either version 3 of the License, or
538+ * (at your option) any later version.
539+ *
540+ * This program is distributed in the hope that it will be useful,
541+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
542+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
543+ * GNU Affero General Public License for more details.
544+ *
545+ * You should have received a copy of the GNU Affero General Public License
546+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
547+ */
548+
549+package com.akiban.qp.operator;
550+
551+public interface Cursor extends RowCursor, QueryBindingsCursor
552+{
553+ /** Open this cursor for top-level execution: opens the bindings
554+ * stream and then the cursor within the only bindings.
555+ */
556+ public QueryBindings openTopLevel();
557+
558+ /** Close top-level execution: check that there are no further
559+ * bindings and close cursor and bindings.
560+ */
561+ public void closeTopLevel();
562+}
563
564=== modified file 'src/main/java/com/akiban/qp/operator/CursorBase.java'
565--- src/main/java/com/akiban/qp/operator/CursorBase.java 2013-03-22 20:05:57 +0000
566+++ src/main/java/com/akiban/qp/operator/CursorBase.java 2013-07-10 21:47:26 +0000
567@@ -17,6 +17,42 @@
568
569 package com.akiban.qp.operator;
570
571+/*
572+
573+A Cursor is used to scan a sequence of rows resulting from the execution of an operator.
574+The same cursor may be used for multiple executions of the operator, possibly with different bindings.
575+
576+A Cursor is always in one of three states:
577+
578+- IDLE: The cursor is not currently involved in a scan. The cursor is in this state when one
579+ of the following is true:
580+ - open() has never been called.
581+ - The most recent method invocation was to next(), which returned null.
582+ - The most recent method invocation was to close().
583+
584+- ACTIVE: The cursor is currently involved in a scan. The cursor is in this state when one
585+ of the following is true:
586+ - The most recent method invocation was to open().
587+ - The most recent method invocation was to next(), which returned a non-null value.
588+
589+- DESTROYED: The cursor has been destroyed. Invocations of open, next, or close on such a cursor
590+ will raise an exception. The only way to get into this state is to call destroy().
591+
592+The Cursor lifecycle is as follows:
593+
594+ next/jump == null next/jump != null
595+ +-+ +-+
596+ | | | |
597+ | V open | V destroy
598+ --> IDLE ----------> ACTIVE ----------> DESTROYED
599+ | <---------- ^
600+ | next/jump = null, |
601+ | close |
602+ | |
603+ +--------------------------------------+
604+ destroy
605+ */
606+
607 public interface CursorBase<T>
608 {
609 /**
610
611=== modified file 'src/main/java/com/akiban/qp/operator/Delete_Default.java'
612--- src/main/java/com/akiban/qp/operator/Delete_Default.java 2013-07-05 21:35:32 +0000
613+++ src/main/java/com/akiban/qp/operator/Delete_Default.java 2013-07-10 21:47:26 +0000
614@@ -118,7 +118,8 @@
615
616 @Override
617 public UpdateResult run(QueryContext context, QueryBindings bindings) {
618- return new Execution(context, bindings, inputOperator.cursor(context, bindings)).run();
619+ QueryBindingsCursor bindingsCursor = new SingletonQueryBindingsCursor(bindings);
620+ return new Execution(context, inputOperator.cursor(context, bindingsCursor)).run();
621 }
622
623 @Override
624@@ -152,7 +153,7 @@
625 DELETE_TAP.in();
626 }
627 try {
628- input.open();
629+ input.openTopLevel();
630 Row oldRow;
631 while ((oldRow = input.next()) != null) {
632 checkQueryCancelation();
633@@ -165,7 +166,7 @@
634 }
635 } finally {
636 if (input != null) {
637- input.close();
638+ input.destroy();
639 }
640 if (TAP_NEXT_ENABLED) {
641 DELETE_TAP.out();
642@@ -174,9 +175,9 @@
643 return new StandardUpdateResult(seen, modified);
644 }
645
646- protected Execution(QueryContext queryContext, QueryBindings bindings, Cursor input)
647+ protected Execution(QueryContext queryContext, Cursor input)
648 {
649- super(queryContext, bindings);
650+ super(queryContext);
651 this.input = input;
652 }
653
654
655=== modified file 'src/main/java/com/akiban/qp/operator/Delete_Returning.java'
656--- src/main/java/com/akiban/qp/operator/Delete_Returning.java 2013-07-05 21:35:32 +0000
657+++ src/main/java/com/akiban/qp/operator/Delete_Returning.java 2013-07-10 21:47:26 +0000
658@@ -84,8 +84,8 @@
659
660
661 @Override
662- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
663- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
664+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
665+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
666 }
667
668 @Override
669@@ -125,7 +125,7 @@
670 private final boolean cascadeDelete;
671
672 // Inner classes
673- private class Execution extends OperatorExecutionBase implements Cursor
674+ private class Execution extends ChainedCursor
675 {
676
677 // Cursor interface
678@@ -183,42 +183,31 @@
679 @Override
680 public void destroy()
681 {
682- if (input != null) {
683- close();
684- input.destroy();
685- input = null;
686- }
687+ close();
688+ input.destroy();
689 }
690
691 @Override
692 public boolean isIdle()
693 {
694- return input != null && idle;
695+ return !input.isDestroyed() && idle;
696 }
697
698 @Override
699 public boolean isActive()
700 {
701- return input != null && !idle;
702- }
703-
704- @Override
705- public boolean isDestroyed()
706- {
707- return input == null;
708- }
709-
710+ return !input.isDestroyed() && !idle;
711+ }
712+
713 // Execution interface
714
715- Execution(QueryContext context, QueryBindings bindings, Cursor input)
716+ Execution(QueryContext context, Cursor input)
717 {
718- super(context, bindings);
719- this.input = input;
720+ super(context, input);
721 }
722
723 // Object state
724
725- private Cursor input; // input = null indicates destroyed.
726 private boolean idle = true;
727 }
728
729
730=== modified file 'src/main/java/com/akiban/qp/operator/Distinct_Partial.java'
731--- src/main/java/com/akiban/qp/operator/Distinct_Partial.java 2013-07-05 21:35:32 +0000
732+++ src/main/java/com/akiban/qp/operator/Distinct_Partial.java 2013-07-10 21:47:26 +0000
733@@ -102,9 +102,9 @@
734 }
735
736 @Override
737- protected Cursor cursor(QueryContext context, QueryBindings bindings)
738+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
739 {
740- return new Execution(context, bindings, inputOperator.cursor(context, bindings), usePValue);
741+ return new Execution(context, inputOperator.cursor(context, bindingsCursor), usePValue);
742 }
743
744 @Override
745@@ -158,7 +158,7 @@
746
747 // Inner classes
748
749- private class Execution extends OperatorExecutionBase implements Cursor
750+ private class Execution extends ChainedCursor
751 {
752 // Cursor interface
753
754@@ -240,10 +240,9 @@
755
756 // Execution interface
757
758- Execution(QueryContext context, QueryBindings bindings, Cursor input, boolean usePValue)
759+ Execution(QueryContext context, Cursor input, boolean usePValue)
760 {
761- super(context, bindings);
762- this.input = input;
763+ super(context, input);
764
765 nfields = distinctType.nFields();
766 if (!usePValue) {
767@@ -346,7 +345,6 @@
768
769 // Object state
770
771- private final Cursor input;
772 private final ShareHolder<Row> currentRow = new ShareHolder<>();
773 private final int nfields;
774 // currentValues contains copies of the first nvalid of currentRow's fields,
775
776=== modified file 'src/main/java/com/akiban/qp/operator/EmitBoundRow_Nested.java'
777--- src/main/java/com/akiban/qp/operator/EmitBoundRow_Nested.java 2013-07-05 21:35:32 +0000
778+++ src/main/java/com/akiban/qp/operator/EmitBoundRow_Nested.java 2013-07-10 21:47:26 +0000
779@@ -92,9 +92,9 @@
780 }
781
782 @Override
783- protected Cursor cursor(QueryContext context, QueryBindings bindings)
784+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
785 {
786- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
787+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
788 }
789
790 @Override
791@@ -163,7 +163,7 @@
792
793 // Inner classes
794
795- private class Execution extends OperatorExecutionBase implements Cursor
796+ private class Execution extends ChainedCursor
797 {
798 // Cursor interface
799
800@@ -236,34 +236,11 @@
801 input.destroy();
802 }
803
804- @Override
805- public boolean isIdle()
806- {
807- return input.isIdle();
808- }
809-
810- @Override
811- public boolean isActive()
812- {
813- return input.isActive();
814- }
815-
816- @Override
817- public boolean isDestroyed()
818- {
819- return input.isDestroyed();
820- }
821-
822 // Execution interface
823
824- Execution(QueryContext context, QueryBindings bindings, Cursor input)
825+ Execution(QueryContext context, Cursor input)
826 {
827- super(context, bindings);
828- this.input = input;
829+ super(context, input);
830 }
831-
832- // Object state
833-
834- private final Cursor input;
835 }
836 }
837
838=== modified file 'src/main/java/com/akiban/qp/operator/ExecutionBase.java'
839--- src/main/java/com/akiban/qp/operator/ExecutionBase.java 2013-07-05 21:35:32 +0000
840+++ src/main/java/com/akiban/qp/operator/ExecutionBase.java 2013-07-10 21:47:26 +0000
841@@ -36,14 +36,12 @@
842 context.checkQueryCancelation();
843 }
844
845- public ExecutionBase(QueryContext context, QueryBindings bindings)
846+ public ExecutionBase(QueryContext context)
847 {
848 this.context = context;
849- this.bindings = bindings;
850 }
851
852 protected QueryContext context;
853- protected QueryBindings bindings;
854
855 protected static final boolean LOG_EXECUTION = false;
856 protected static final boolean TAP_NEXT_ENABLED = false;
857
858=== modified file 'src/main/java/com/akiban/qp/operator/Filter_Default.java'
859--- src/main/java/com/akiban/qp/operator/Filter_Default.java 2013-07-05 21:35:32 +0000
860+++ src/main/java/com/akiban/qp/operator/Filter_Default.java 2013-07-10 21:47:26 +0000
861@@ -93,9 +93,9 @@
862 }
863
864 @Override
865- protected Cursor cursor(QueryContext context, QueryBindings bindings)
866+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
867 {
868- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
869+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
870 }
871
872 @Override
873@@ -132,7 +132,7 @@
874
875 // Inner classes
876
877- private class Execution extends OperatorExecutionBase implements Cursor
878+ private class Execution extends ChainedCursor
879 {
880 // Cursor interface
881
882@@ -191,12 +191,6 @@
883 }
884
885 @Override
886- public void destroy()
887- {
888- input.destroy();
889- }
890-
891- @Override
892 public boolean isIdle()
893 {
894 return closed;
895@@ -208,23 +202,15 @@
896 return !closed;
897 }
898
899- @Override
900- public boolean isDestroyed()
901- {
902- return input.isDestroyed();
903- }
904-
905 // Execution interface
906
907- Execution(QueryContext context, QueryBindings bindings, Cursor input)
908+ Execution(QueryContext context, Cursor input)
909 {
910- super(context, bindings);
911- this.input = input;
912+ super(context, input);
913 }
914
915 // Object state
916
917- private final Cursor input;
918 private boolean closed = true;
919 }
920 }
921
922=== modified file 'src/main/java/com/akiban/qp/operator/Flatten_HKeyOrdered.java'
923--- src/main/java/com/akiban/qp/operator/Flatten_HKeyOrdered.java 2013-07-05 21:35:32 +0000
924+++ src/main/java/com/akiban/qp/operator/Flatten_HKeyOrdered.java 2013-07-10 21:47:26 +0000
925@@ -179,9 +179,9 @@
926 // Operator interface
927
928 @Override
929- protected Cursor cursor(QueryContext context, QueryBindings bindings)
930+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
931 {
932- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
933+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
934 }
935
936 @Override
937@@ -292,7 +292,7 @@
938
939 // Inner classes
940
941- private class Execution extends OperatorExecutionBase implements Cursor
942+ private class Execution extends ChainedCursor
943 {
944 // Cursor interface
945
946@@ -402,18 +402,11 @@
947 return !idle;
948 }
949
950- @Override
951- public boolean isDestroyed()
952- {
953- return input.isDestroyed();
954- }
955-
956 // Execution interface
957
958- Execution(QueryContext context, QueryBindings bindings, Cursor input)
959+ Execution(QueryContext context, Cursor input)
960 {
961- super(context, bindings);
962- this.input = input;
963+ super(context, input);
964 this.leftJoinHKey = adapter().newHKey(childType.hKey());
965 }
966
967@@ -503,7 +496,6 @@
968
969 // Object state
970
971- private final Cursor input;
972 private final ShareHolder<Row> parent = new ShareHolder<>();
973 private final PendingRows pending = new PendingRows(MAX_PENDING);
974 private final HKey leftJoinHKey;
975
976=== modified file 'src/main/java/com/akiban/qp/operator/GroupCursor.java'
977--- src/main/java/com/akiban/qp/operator/GroupCursor.java 2013-03-22 20:05:57 +0000
978+++ src/main/java/com/akiban/qp/operator/GroupCursor.java 2013-07-10 21:47:26 +0000
979@@ -19,6 +19,6 @@
980
981 import com.akiban.qp.row.HKey;
982
983-public interface GroupCursor extends Cursor {
984+public interface GroupCursor extends RowCursor {
985 void rebind(HKey hKey, boolean deep);
986 }
987
988=== modified file 'src/main/java/com/akiban/qp/operator/GroupScan_Default.java'
989--- src/main/java/com/akiban/qp/operator/GroupScan_Default.java 2013-07-05 21:35:32 +0000
990+++ src/main/java/com/akiban/qp/operator/GroupScan_Default.java 2013-07-10 21:47:26 +0000
991@@ -22,6 +22,7 @@
992 import com.akiban.ais.model.UserTable;
993 import com.akiban.qp.row.HKey;
994 import com.akiban.qp.row.Row;
995+import com.akiban.server.api.dml.ColumnSelector;
996 import com.akiban.server.explain.*;
997 import com.akiban.util.ArgumentValidation;
998 import com.akiban.util.tap.InOutTap;
999@@ -88,9 +89,9 @@
1000 // Operator interface
1001
1002 @Override
1003- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1004+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1005 {
1006- return new Execution(context, bindings, cursorCreator);
1007+ return new Execution(context, bindingsCursor, cursorCreator);
1008 }
1009
1010 // GroupScan_Default interface
1011@@ -126,7 +127,7 @@
1012
1013 // Inner classes
1014
1015- private static class Execution extends OperatorExecutionBase implements Cursor
1016+ private static class Execution extends LeafCursor
1017 {
1018
1019 // Cursor interface
1020@@ -196,22 +197,30 @@
1021 return cursor.isDestroyed();
1022 }
1023
1024+ @Override
1025+ public QueryBindings nextBindings() {
1026+ QueryBindings bindings = super.nextBindings();
1027+ if (cursor instanceof BindingsAwareCursor)
1028+ ((BindingsAwareCursor)cursor).rebind(bindings);
1029+ return bindings;
1030+ }
1031+
1032 // Execution interface
1033
1034- Execution(QueryContext context, QueryBindings bindings, GroupCursorCreator cursorCreator)
1035+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor, GroupCursorCreator cursorCreator)
1036 {
1037- super(context, bindings);
1038- this.cursor = cursorCreator.cursor(context, bindings);
1039+ super(context, bindingsCursor);
1040+ this.cursor = cursorCreator.cursor(context);
1041 }
1042
1043 // Object state
1044
1045- private final Cursor cursor;
1046+ private final RowCursor cursor;
1047 }
1048
1049 static interface GroupCursorCreator
1050 {
1051- Cursor cursor(QueryContext context, QueryBindings bindings);
1052+ RowCursor cursor(QueryContext context);
1053
1054 Group group();
1055
1056@@ -254,7 +263,7 @@
1057 // GroupCursorCreator interface
1058
1059 @Override
1060- public Cursor cursor(QueryContext context, QueryBindings bindings)
1061+ public RowCursor cursor(QueryContext context)
1062 {
1063 return context.getStore(group().getRoot()).newGroupCursor(group());
1064 }
1065@@ -281,9 +290,9 @@
1066 // GroupCursorCreator interface
1067
1068 @Override
1069- public Cursor cursor(QueryContext context, QueryBindings bindings)
1070+ public RowCursor cursor(QueryContext context)
1071 {
1072- return new HKeyBoundCursor(context, bindings,
1073+ return new HKeyBoundCursor(context,
1074 context.getStore(group().getRoot()).newGroupCursor(group()),
1075 hKeyBindingPosition,
1076 deep,
1077@@ -329,7 +338,7 @@
1078 private final UserTable hKeyType;
1079 }
1080
1081- private static class HKeyBoundCursor extends ChainedCursor
1082+ private static class HKeyBoundCursor implements BindingsAwareCursor
1083 {
1084
1085 @Override
1086@@ -342,12 +351,12 @@
1087
1088 @Override
1089 public Row next() {
1090- // If we've ever seen a row, just defer to super
1091+ // If we've ever seen a row, just defer to input
1092 if (sawOne) {
1093- return super.next();
1094+ return input.next();
1095 }
1096- Row result = super.next();
1097- // If we saw a row, mark it as such and defer to super
1098+ Row result = input.next();
1099+ // If we saw a row, mark it as such and defer to input
1100 if (result != null) {
1101 sawOne = true;
1102 return result;
1103@@ -366,15 +375,54 @@
1104 return next();
1105 }
1106
1107+ @Override
1108+ public void jump(Row row, ColumnSelector columnSelector)
1109+ {
1110+ input.jump(row, columnSelector);
1111+ }
1112+
1113+ @Override
1114+ public void close() {
1115+ input.close();
1116+ }
1117+
1118+ @Override
1119+ public void destroy()
1120+ {
1121+ input.destroy();
1122+ }
1123+
1124+ @Override
1125+ public boolean isIdle()
1126+ {
1127+ return input.isIdle();
1128+ }
1129+
1130+ @Override
1131+ public boolean isActive()
1132+ {
1133+ return input.isActive();
1134+ }
1135+
1136+ @Override
1137+ public boolean isDestroyed()
1138+ {
1139+ return input.isDestroyed();
1140+ }
1141+
1142+ @Override
1143+ public void rebind(QueryBindings bindings) {
1144+ this.bindings = bindings;
1145+ }
1146+
1147 HKeyBoundCursor(QueryContext context,
1148- QueryBindings bindings,
1149 GroupCursor input,
1150 int hKeyBindingPosition,
1151 boolean deep,
1152 UserTable hKeyType,
1153 UserTable shortenUntil)
1154 {
1155- super(context, bindings, input);
1156+ this.context = context;
1157 this.input = input;
1158 this.hKeyBindingPosition = hKeyBindingPosition;
1159 this.deep = deep;
1160@@ -386,11 +434,13 @@
1161 return bindings.getHKey(hKeyBindingPosition);
1162 }
1163
1164+ private final QueryContext context;
1165 private final GroupCursor input;
1166 private final int hKeyBindingPosition;
1167 private final boolean deep;
1168 private UserTable atTable;
1169 private final UserTable stopSearchTable;
1170 private boolean sawOne = false;
1171+ private QueryBindings bindings;
1172 }
1173 }
1174
1175=== modified file 'src/main/java/com/akiban/qp/operator/HKeyUnion_Ordered.java'
1176--- src/main/java/com/akiban/qp/operator/HKeyUnion_Ordered.java 2013-07-05 21:35:32 +0000
1177+++ src/main/java/com/akiban/qp/operator/HKeyUnion_Ordered.java 2013-07-10 21:47:26 +0000
1178@@ -86,9 +86,9 @@
1179 // Operator interface
1180
1181 @Override
1182- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1183+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1184 {
1185- return new Execution(context, bindings);
1186+ return new Execution(context, bindingsCursor);
1187 }
1188
1189 @Override
1190@@ -194,7 +194,7 @@
1191
1192 // Inner classes
1193
1194- private class Execution extends OperatorExecutionBase implements Cursor
1195+ private class Execution extends OperatorCursor
1196 {
1197 // Cursor interface
1198
1199@@ -308,13 +308,39 @@
1200 return leftInput.isDestroyed();
1201 }
1202
1203+ @Override
1204+ public void openBindings() {
1205+ bindingsCursor.openBindings();
1206+ leftInput.openBindings();
1207+ rightInput.openBindings();
1208+ }
1209+
1210+ @Override
1211+ public QueryBindings nextBindings() {
1212+ QueryBindings bindings = bindingsCursor.nextBindings();
1213+ QueryBindings other = leftInput.nextBindings();
1214+ assert (bindings == other);
1215+ other = rightInput.nextBindings();
1216+ assert (bindings == other);
1217+ return bindings;
1218+ }
1219+
1220+ @Override
1221+ public void closeBindings() {
1222+ bindingsCursor.closeBindings();
1223+ leftInput.closeBindings();
1224+ rightInput.closeBindings();
1225+ }
1226+
1227 // Execution interface
1228
1229- Execution(QueryContext context, QueryBindings bindings)
1230+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1231 {
1232- super(context, bindings);
1233- leftInput = left.cursor(context, bindings);
1234- rightInput = right.cursor(context, bindings);
1235+ super(context);
1236+ MultipleQueryBindingsCursor multiple = new MultipleQueryBindingsCursor(bindingsCursor);
1237+ this.bindingsCursor = multiple;
1238+ this.leftInput = left.cursor(context, multiple.newCursor());
1239+ this.rightInput = right.cursor(context, multiple.newCursor());
1240 hKeyCache = new HKeyCache<>(context.getStore());
1241 }
1242
1243@@ -366,6 +392,7 @@
1244 // Rows from each input stream are bound to the QueryContext. However, QueryContext doesn't use
1245 // ShareHolders, so they are needed here.
1246
1247+ private final QueryBindingsCursor bindingsCursor;
1248 private final Cursor leftInput;
1249 private final Cursor rightInput;
1250 private final ShareHolder<Row> leftRow = new ShareHolder<>();
1251
1252=== modified file 'src/main/java/com/akiban/qp/operator/IfEmpty_Default.java'
1253--- src/main/java/com/akiban/qp/operator/IfEmpty_Default.java 2013-07-08 18:56:18 +0000
1254+++ src/main/java/com/akiban/qp/operator/IfEmpty_Default.java 2013-07-10 21:47:26 +0000
1255@@ -116,9 +116,9 @@
1256 // Operator interface
1257
1258 @Override
1259- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1260+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1261 {
1262- return new Execution(context, bindings);
1263+ return new Execution(context, bindingsCursor);
1264 }
1265
1266 @Override
1267@@ -213,7 +213,7 @@
1268 UNKNOWN, DONE, ECHO_INPUT
1269 }
1270
1271- private class Execution extends OperatorExecutionBase implements Cursor
1272+ private class Execution extends ChainedCursor
1273 {
1274 // Cursor interface
1275
1276@@ -310,18 +310,11 @@
1277 return !closed;
1278 }
1279
1280- @Override
1281- public boolean isDestroyed()
1282- {
1283- return input.isDestroyed();
1284- }
1285-
1286 // Execution interface
1287
1288- Execution(QueryContext context, QueryBindings bindings)
1289+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1290 {
1291- super(context, bindings);
1292- this.input = inputOperator.cursor(context, bindings);
1293+ super(context, inputOperator.cursor(context, bindingsCursor));
1294 if (pExpressions != null) {
1295 this.oEvaluations = null;
1296 this.pEvaluations = new ArrayList<>(pExpressions.size());
1297@@ -378,7 +371,6 @@
1298
1299 // Object state
1300
1301- private final Cursor input;
1302 private final List<ExpressionEvaluation> oEvaluations;
1303 private final List<TEvaluatableExpression> pEvaluations;
1304 private final ShareHolder<ValuesHolderRow> emptySubstitute = new ShareHolder<>();
1305
1306=== modified file 'src/main/java/com/akiban/qp/operator/IndexScan_Default.java'
1307--- src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-05 21:35:32 +0000
1308+++ src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-10 21:47:26 +0000
1309@@ -163,9 +163,9 @@
1310 // Operator interface
1311
1312 @Override
1313- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1314+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1315 {
1316- return new Execution(context, bindings);
1317+ return new Execution(context, bindingsCursor);
1318 }
1319
1320 // IndexScan_Default interface
1321@@ -277,7 +277,7 @@
1322
1323 // Inner classes
1324
1325- private class Execution extends OperatorExecutionBase implements Cursor
1326+ private class Execution extends LeafCursor
1327 {
1328 // Cursor interface
1329
1330@@ -351,17 +351,25 @@
1331 return cursor.isDestroyed();
1332 }
1333
1334+ @Override
1335+ public QueryBindings nextBindings() {
1336+ QueryBindings bindings = super.nextBindings();
1337+ if (cursor instanceof BindingsAwareCursor)
1338+ ((BindingsAwareCursor)cursor).rebind(bindings);
1339+ return bindings;
1340+ }
1341+
1342 // Execution interface
1343
1344- Execution(QueryContext context, QueryBindings bindings)
1345+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1346 {
1347- super(context, bindings);
1348+ super(context, bindingsCursor);
1349 UserTable table = (UserTable)index.rootMostTable();
1350- this.cursor = adapter(table).newIndexCursor(context, bindings, index, indexKeyRange, ordering, scanSelector, usePValues);
1351+ this.cursor = adapter(table).newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues);
1352 }
1353
1354 // Object state
1355
1356- private final Cursor cursor;
1357+ private final RowCursor cursor;
1358 }
1359 }
1360
1361=== modified file 'src/main/java/com/akiban/qp/operator/Insert_Default.java'
1362--- src/main/java/com/akiban/qp/operator/Insert_Default.java 2013-07-08 15:56:07 +0000
1363+++ src/main/java/com/akiban/qp/operator/Insert_Default.java 2013-07-10 21:47:26 +0000
1364@@ -86,7 +86,8 @@
1365
1366 @Override
1367 public UpdateResult run(QueryContext context, QueryBindings bindings) {
1368- return new Execution(context, bindings, inputOperator.cursor(context, bindings)).run();
1369+ QueryBindingsCursor bindingsCursor = new SingletonQueryBindingsCursor(bindings);
1370+ return new Execution(context, inputOperator.cursor(context, bindingsCursor)).run();
1371 }
1372
1373 @Override
1374@@ -139,7 +140,7 @@
1375 INSERT_TAP.in();
1376 }
1377 try {
1378- input.open();
1379+ input.openTopLevel();
1380 Row row;
1381 while ((row = input.next()) != null) {
1382 // LOG.warn("About to insert {}: {}", row.rowType().userTable(), row);
1383@@ -154,7 +155,7 @@
1384 }
1385 } finally {
1386 if (input != null) {
1387- input.close();
1388+ input.destroy();
1389 }
1390 if (TAP_NEXT_ENABLED) {
1391 INSERT_TAP.out();
1392@@ -163,9 +164,9 @@
1393 return new StandardUpdateResult(seen, modified);
1394 }
1395
1396- protected Execution(QueryContext queryContext, QueryBindings queryBindings, Cursor input)
1397+ protected Execution(QueryContext queryContext, Cursor input)
1398 {
1399- super(queryContext, queryBindings);
1400+ super(queryContext);
1401 this.input = input;
1402 }
1403
1404
1405=== modified file 'src/main/java/com/akiban/qp/operator/Insert_Returning.java'
1406--- src/main/java/com/akiban/qp/operator/Insert_Returning.java 2013-07-08 15:56:07 +0000
1407+++ src/main/java/com/akiban/qp/operator/Insert_Returning.java 2013-07-10 21:47:26 +0000
1408@@ -82,8 +82,8 @@
1409 public class Insert_Returning extends Operator {
1410
1411 @Override
1412- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
1413- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
1414+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
1415+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
1416 }
1417
1418 @Override
1419@@ -125,7 +125,7 @@
1420 private final boolean usePValues;
1421
1422 // Inner classes
1423- private class Execution extends OperatorExecutionBase implements Cursor
1424+ private class Execution extends ChainedCursor
1425 {
1426
1427 // Cursor interface
1428@@ -187,42 +187,31 @@
1429 @Override
1430 public void destroy()
1431 {
1432- if (input != null) {
1433- close();
1434- input.destroy();
1435- input = null;
1436- }
1437+ close();
1438+ input.destroy();
1439 }
1440
1441 @Override
1442 public boolean isIdle()
1443 {
1444- return input != null && idle;
1445+ return !input.isDestroyed() && idle;
1446 }
1447
1448 @Override
1449 public boolean isActive()
1450 {
1451- return input != null && !idle;
1452- }
1453-
1454- @Override
1455- public boolean isDestroyed()
1456- {
1457- return input == null;
1458- }
1459-
1460+ return !input.isDestroyed() && !idle;
1461+ }
1462+
1463 // Execution interface
1464
1465- Execution(QueryContext context, QueryBindings bindings, Cursor input)
1466+ Execution(QueryContext context, Cursor input)
1467 {
1468- super(context, bindings);
1469- this.input = input;
1470+ super(context, input);
1471 }
1472
1473 // Object state
1474-
1475- private Cursor input; // input = null indicates destroyed.
1476+
1477 private boolean idle = true;
1478 }
1479 }
1480
1481=== modified file 'src/main/java/com/akiban/qp/operator/Intersect_Ordered.java'
1482--- src/main/java/com/akiban/qp/operator/Intersect_Ordered.java 2013-07-05 21:35:32 +0000
1483+++ src/main/java/com/akiban/qp/operator/Intersect_Ordered.java 2013-07-10 21:47:26 +0000
1484@@ -118,9 +118,9 @@
1485 // Operator interface
1486
1487 @Override
1488- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1489+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1490 {
1491- return new Execution(context, bindings);
1492+ return new Execution(context, bindingsCursor);
1493 }
1494
1495 @Override
1496@@ -260,7 +260,7 @@
1497
1498 // Inner classes
1499
1500- private class Execution extends OperatorExecutionBase implements Cursor
1501+ private class Execution extends OperatorCursor
1502 {
1503 // Cursor interface
1504
1505@@ -407,13 +407,39 @@
1506 return leftInput.isDestroyed();
1507 }
1508
1509+ @Override
1510+ public void openBindings() {
1511+ bindingsCursor.openBindings();
1512+ leftInput.openBindings();
1513+ rightInput.openBindings();
1514+ }
1515+
1516+ @Override
1517+ public QueryBindings nextBindings() {
1518+ QueryBindings bindings = bindingsCursor.nextBindings();
1519+ QueryBindings other = leftInput.nextBindings();
1520+ assert (bindings == other);
1521+ other = rightInput.nextBindings();
1522+ assert (bindings == other);
1523+ return bindings;
1524+ }
1525+
1526+ @Override
1527+ public void closeBindings() {
1528+ bindingsCursor.closeBindings();
1529+ leftInput.closeBindings();
1530+ rightInput.closeBindings();
1531+ }
1532+
1533 // Execution interface
1534
1535- Execution(QueryContext context, QueryBindings bindings)
1536+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1537 {
1538- super(context, bindings);
1539- leftInput = left.cursor(context, bindings);
1540- rightInput = right.cursor(context, bindings);
1541+ super(context);
1542+ MultipleQueryBindingsCursor multiple = new MultipleQueryBindingsCursor(bindingsCursor);
1543+ this.bindingsCursor = multiple;
1544+ this.leftInput = left.cursor(context, multiple.newCursor());
1545+ this.rightInput = right.cursor(context, multiple.newCursor());
1546 }
1547
1548 // For use by this class
1549@@ -592,6 +618,7 @@
1550 // ShareHolders, so they are needed here.
1551
1552 private boolean closed = true;
1553+ private final QueryBindingsCursor bindingsCursor;
1554 private final Cursor leftInput;
1555 private final Cursor rightInput;
1556 private final ShareHolder<Row> leftRow = new ShareHolder<>();
1557
1558=== added file 'src/main/java/com/akiban/qp/operator/LeafCursor.java'
1559--- src/main/java/com/akiban/qp/operator/LeafCursor.java 1970-01-01 00:00:00 +0000
1560+++ src/main/java/com/akiban/qp/operator/LeafCursor.java 2013-07-10 21:47:26 +0000
1561@@ -0,0 +1,45 @@
1562+/**
1563+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
1564+ *
1565+ * This program is free software: you can redistribute it and/or modify
1566+ * it under the terms of the GNU Affero General Public License as published by
1567+ * the Free Software Foundation, either version 3 of the License, or
1568+ * (at your option) any later version.
1569+ *
1570+ * This program is distributed in the hope that it will be useful,
1571+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1572+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1573+ * GNU Affero General Public License for more details.
1574+ *
1575+ * You should have received a copy of the GNU Affero General Public License
1576+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1577+ */
1578+
1579+package com.akiban.qp.operator;
1580+
1581+public class LeafCursor extends OperatorCursor
1582+{
1583+ protected final QueryBindingsCursor bindingsCursor;
1584+ protected QueryBindings bindings;
1585+
1586+ protected LeafCursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
1587+ super(context);
1588+ this.bindingsCursor = bindingsCursor;
1589+ }
1590+
1591+ @Override
1592+ public void openBindings() {
1593+ bindingsCursor.openBindings();
1594+ }
1595+
1596+ @Override
1597+ public QueryBindings nextBindings() {
1598+ bindings = bindingsCursor.nextBindings();
1599+ return bindings;
1600+ }
1601+
1602+ @Override
1603+ public void closeBindings() {
1604+ bindingsCursor.closeBindings();
1605+ }
1606+}
1607
1608=== modified file 'src/main/java/com/akiban/qp/operator/Limit_Default.java'
1609--- src/main/java/com/akiban/qp/operator/Limit_Default.java 2013-07-05 21:35:32 +0000
1610+++ src/main/java/com/akiban/qp/operator/Limit_Default.java 2013-07-10 21:47:26 +0000
1611@@ -87,8 +87,8 @@
1612 // Operator interface
1613
1614 @Override
1615- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
1616- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
1617+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
1618+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
1619 }
1620
1621 // Plannable interface
1622@@ -326,8 +326,8 @@
1623 }
1624
1625 // Execution interface
1626- Execution(QueryContext context, QueryBindings bindings, Cursor input) {
1627- super(context, bindings, input);
1628+ Execution(QueryContext context, Cursor input) {
1629+ super(context, input);
1630 }
1631
1632 // object state
1633
1634=== modified file 'src/main/java/com/akiban/qp/operator/Map_NestedLoops.java'
1635--- src/main/java/com/akiban/qp/operator/Map_NestedLoops.java 2013-07-05 21:35:32 +0000
1636+++ src/main/java/com/akiban/qp/operator/Map_NestedLoops.java 2013-07-10 21:47:26 +0000
1637@@ -85,9 +85,9 @@
1638 // Operator interface
1639
1640 @Override
1641- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1642+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1643 {
1644- return new Execution(context, bindings);
1645+ return new Execution(context, bindingsCursor);
1646 }
1647
1648 @Override
1649@@ -150,7 +150,7 @@
1650
1651 // Inner classes
1652
1653- private class Execution extends OperatorExecutionBase implements Cursor
1654+ private class Execution extends OperatorCursor
1655 {
1656 // Cursor interface
1657
1658@@ -242,13 +242,31 @@
1659 return outerInput.isDestroyed();
1660 }
1661
1662+ @Override
1663+ public void openBindings() {
1664+ outerInput.openBindings();
1665+ }
1666+
1667+ @Override
1668+ public QueryBindings nextBindings() {
1669+ outerBindings = outerInput.nextBindings();
1670+ return outerBindings;
1671+ }
1672+
1673+ @Override
1674+ public void closeBindings() {
1675+ outerInput.closeBindings();
1676+ }
1677+
1678 // Execution interface
1679
1680- Execution(QueryContext context, QueryBindings bindings)
1681+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1682 {
1683- super(context, bindings);
1684- this.outerInput = outerInputOperator.cursor(context, bindings);
1685- this.innerInput = innerInputOperator.cursor(context, bindings);
1686+ super(context);
1687+ this.outerInput = outerInputOperator.cursor(context, bindingsCursor);
1688+ // For now, the inside sees whatever bindings the outside currently has.
1689+ this.innerBindingsCursor = new SingletonQueryBindingsCursor(null);
1690+ this.innerInput = innerInputOperator.cursor(context, innerBindingsCursor);
1691 }
1692
1693 // For use by this class
1694@@ -276,8 +294,9 @@
1695 private void startNewInnerLoop(Row row)
1696 {
1697 innerInput.close();
1698- bindings.setRow(inputBindingPosition, row);
1699- innerInput.open();
1700+ outerBindings.setRow(inputBindingPosition, row);
1701+ innerBindingsCursor.reset(outerBindings);
1702+ innerInput.openTopLevel();
1703 }
1704
1705 // Object state
1706@@ -286,5 +305,7 @@
1707 private final Cursor innerInput;
1708 private final ShareHolder<Row> outerRow = new ShareHolder<>();
1709 private boolean closed = true;
1710+ private QueryBindings outerBindings;
1711+ private final SingletonQueryBindingsCursor innerBindingsCursor;
1712 }
1713 }
1714
1715=== added file 'src/main/java/com/akiban/qp/operator/MultipleQueryBindingsCursor.java'
1716--- src/main/java/com/akiban/qp/operator/MultipleQueryBindingsCursor.java 1970-01-01 00:00:00 +0000
1717+++ src/main/java/com/akiban/qp/operator/MultipleQueryBindingsCursor.java 2013-07-10 21:47:26 +0000
1718@@ -0,0 +1,121 @@
1719+/**
1720+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
1721+ *
1722+ * This program is free software: you can redistribute it and/or modify
1723+ * it under the terms of the GNU Affero General Public License as published by
1724+ * the Free Software Foundation, either version 3 of the License, or
1725+ * (at your option) any later version.
1726+ *
1727+ * This program is distributed in the hope that it will be useful,
1728+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1729+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1730+ * GNU Affero General Public License for more details.
1731+ *
1732+ * You should have received a copy of the GNU Affero General Public License
1733+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1734+ */
1735+
1736+package com.akiban.qp.operator;
1737+
1738+import java.util.ArrayList;
1739+import java.util.List;
1740+
1741+/**
1742+ * A generator of {@link QueryBindingsCursor}s from a common source.
1743+ */
1744+public class MultipleQueryBindingsCursor implements QueryBindingsCursor
1745+{
1746+ private final QueryBindingsCursor input;
1747+ private final List<QueryBindings> buffer = new ArrayList<QueryBindings>();
1748+ private final List<SubCursor> cursors = new ArrayList<SubCursor>();
1749+ private boolean exhausted;
1750+ private int offset;
1751+
1752+ public MultipleQueryBindingsCursor(QueryBindingsCursor input) {
1753+ this.input = input;
1754+ newCursor();
1755+ }
1756+
1757+ @Override
1758+ public void openBindings() {
1759+ input.openBindings();
1760+ exhausted = false;
1761+ buffer.clear();
1762+ offset = 0;
1763+ cursors.get(0).openBindings();
1764+ for (int i = 1; i < cursors.size(); i++) {
1765+ cursors.get(i).closeBindings();
1766+ }
1767+ }
1768+
1769+ @Override
1770+ public QueryBindings nextBindings() {
1771+ return cursors.get(0).nextBindings();
1772+ }
1773+
1774+ @Override
1775+ public void closeBindings() {
1776+ cursors.get(0).closeBindings();
1777+ }
1778+
1779+ public QueryBindingsCursor newCursor() {
1780+ assert (offset == 0);
1781+ SubCursor cursor = new SubCursor();
1782+ cursors.add(cursor);
1783+ return cursor;
1784+ }
1785+
1786+ protected void shrink() {
1787+ int minIndex = cursors.get(0).index;
1788+ for (int i = 1; i < cursors.size(); i++) {
1789+ SubCursor cursor = cursors.get(i);
1790+ if (!cursor.open) continue;
1791+ if (minIndex > cursor.index) {
1792+ minIndex = cursor.index;
1793+ }
1794+ }
1795+ while (offset < minIndex) {
1796+ buffer.remove(0);
1797+ offset++;
1798+ }
1799+ }
1800+
1801+ class SubCursor implements QueryBindingsCursor {
1802+ boolean open;
1803+ int index;
1804+
1805+ @Override
1806+ public void openBindings() {
1807+ assert (offset == 0);
1808+ open = true;
1809+ index = 0;
1810+ }
1811+
1812+ @Override
1813+ public QueryBindings nextBindings() {
1814+ assert (open && (index >= offset));
1815+ while (index - offset >= buffer.size()) {
1816+ if (exhausted) {
1817+ return null;
1818+ }
1819+ else {
1820+ QueryBindings bindings = input.nextBindings();
1821+ if (bindings == null) {
1822+ exhausted = true;
1823+ return null;
1824+ }
1825+ buffer.add(bindings);
1826+ }
1827+ }
1828+ QueryBindings bindings = buffer.get(index - offset);
1829+ index++;
1830+ shrink();
1831+ return bindings;
1832+ }
1833+
1834+ @Override
1835+ public void closeBindings() {
1836+ open = false;
1837+ }
1838+ }
1839+}
1840
1841=== modified file 'src/main/java/com/akiban/qp/operator/Operator.java'
1842--- src/main/java/com/akiban/qp/operator/Operator.java 2013-07-05 21:35:32 +0000
1843+++ src/main/java/com/akiban/qp/operator/Operator.java 2013-07-10 21:47:26 +0000
1844@@ -69,7 +69,7 @@
1845 return Collections.emptyList();
1846 }
1847
1848- protected abstract Cursor cursor(QueryContext context, QueryBindings bindings);
1849+ protected abstract Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor);
1850
1851 @Override
1852 public String describePlan()
1853
1854=== added file 'src/main/java/com/akiban/qp/operator/OperatorCursor.java'
1855--- src/main/java/com/akiban/qp/operator/OperatorCursor.java 1970-01-01 00:00:00 +0000
1856+++ src/main/java/com/akiban/qp/operator/OperatorCursor.java 2013-07-10 21:47:26 +0000
1857@@ -0,0 +1,42 @@
1858+/**
1859+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
1860+ *
1861+ * This program is free software: you can redistribute it and/or modify
1862+ * it under the terms of the GNU Affero General Public License as published by
1863+ * the Free Software Foundation, either version 3 of the License, or
1864+ * (at your option) any later version.
1865+ *
1866+ * This program is distributed in the hope that it will be useful,
1867+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1868+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1869+ * GNU Affero General Public License for more details.
1870+ *
1871+ * You should have received a copy of the GNU Affero General Public License
1872+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1873+ */
1874+
1875+package com.akiban.qp.operator;
1876+
1877+public abstract class OperatorCursor extends OperatorExecutionBase implements Cursor
1878+{
1879+ protected OperatorCursor(QueryContext context) {
1880+ super(context);
1881+ }
1882+
1883+ @Override
1884+ public QueryBindings openTopLevel() {
1885+ openBindings();
1886+ QueryBindings bindings = nextBindings();
1887+ assert (bindings != null);
1888+ open();
1889+ return bindings;
1890+ }
1891+
1892+ @Override
1893+ public void closeTopLevel() {
1894+ close();
1895+ QueryBindings bindings = nextBindings();
1896+ assert (bindings == null);
1897+ closeBindings();
1898+ }
1899+}
1900
1901=== modified file 'src/main/java/com/akiban/qp/operator/OperatorExecutionBase.java'
1902--- src/main/java/com/akiban/qp/operator/OperatorExecutionBase.java 2013-07-05 21:35:32 +0000
1903+++ src/main/java/com/akiban/qp/operator/OperatorExecutionBase.java 2013-07-10 21:47:26 +0000
1904@@ -81,8 +81,8 @@
1905 }
1906 }
1907
1908- protected OperatorExecutionBase(QueryContext context, QueryBindings bindings)
1909+ protected OperatorExecutionBase(QueryContext context)
1910 {
1911- super(context, bindings);
1912+ super(context);
1913 }
1914 }
1915
1916=== modified file 'src/main/java/com/akiban/qp/operator/Product_NestedLoops.java'
1917--- src/main/java/com/akiban/qp/operator/Product_NestedLoops.java 2013-07-05 21:35:32 +0000
1918+++ src/main/java/com/akiban/qp/operator/Product_NestedLoops.java 2013-07-10 21:47:26 +0000
1919@@ -123,9 +123,9 @@
1920 // Operator interface
1921
1922 @Override
1923- protected Cursor cursor(QueryContext context, QueryBindings bindings)
1924+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
1925 {
1926- return new Execution(context, bindings);
1927+ return new Execution(context, bindingsCursor);
1928 }
1929
1930 @Override
1931@@ -198,7 +198,7 @@
1932
1933 // Inner classes
1934
1935- private class Execution extends OperatorExecutionBase implements Cursor
1936+ private class Execution extends OperatorCursor
1937 {
1938 // Cursor interface
1939
1940@@ -301,13 +301,29 @@
1941 return outerInput.isDestroyed();
1942 }
1943
1944+ @Override
1945+ public void openBindings() {
1946+ outerInput.openBindings();
1947+ }
1948+
1949+ @Override
1950+ public QueryBindings nextBindings() {
1951+ outerBindings = outerInput.nextBindings();
1952+ return outerBindings;
1953+ }
1954+
1955+ @Override
1956+ public void closeBindings() {
1957+ outerInput.closeBindings();
1958+ }
1959+
1960 // Execution interface
1961
1962- Execution(QueryContext context, QueryBindings bindings)
1963+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
1964 {
1965- super(context, bindings);
1966- this.outerInput = outerInputOperator.cursor(context, bindings);
1967- this.innerRows = new InnerRows(innerInputOperator.cursor(context, bindings));
1968+ super(context);
1969+ this.outerInput = outerInputOperator.cursor(context, bindingsCursor);
1970+ this.innerRows = new InnerRows(context, bindingsCursor);
1971 }
1972
1973 // For use by this class
1974@@ -345,14 +361,16 @@
1975 private final ShareHolder<Row> outerBranchRow = new ShareHolder<>();
1976 private final InnerRows innerRows;
1977 private boolean closed = true;
1978+ private QueryBindings outerBindings;
1979
1980 // Inner classes
1981
1982 private class InnerRows
1983 {
1984- public InnerRows(Cursor innerInput)
1985+ public InnerRows(QueryContext context, QueryBindingsCursor bindingsCursor)
1986 {
1987- this.innerInput = innerInput;
1988+ this.innerBindingsCursor = new SingletonQueryBindingsCursor(null);
1989+ this.innerInput = innerInputOperator.cursor(context, innerBindingsCursor);
1990 }
1991
1992 public Row next()
1993@@ -368,8 +386,9 @@
1994 public void newBranchRow(Row branchRow)
1995 {
1996 close();
1997- bindings.setRow(inputBindingPosition, branchRow);
1998- innerInput.open();
1999+ outerBindings.setRow(inputBindingPosition, branchRow);
2000+ innerBindingsCursor.reset(outerBindings);
2001+ innerInput.openTopLevel();
2002 rows.clear();
2003 Row row;
2004 while ((row = innerInput.next()) != null) {
2005@@ -392,6 +411,7 @@
2006 private final Cursor innerInput;
2007 private final RowList rows = new RowList();
2008 private final RowList.Scan scan = rows.scan();
2009+ private final SingletonQueryBindingsCursor innerBindingsCursor;
2010 }
2011 }
2012 }
2013
2014=== modified file 'src/main/java/com/akiban/qp/operator/Project_Default.java'
2015--- src/main/java/com/akiban/qp/operator/Project_Default.java 2013-07-05 21:35:32 +0000
2016+++ src/main/java/com/akiban/qp/operator/Project_Default.java 2013-07-10 21:47:26 +0000
2017@@ -88,9 +88,9 @@
2018 // Operator interface
2019
2020 @Override
2021- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2022+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2023 {
2024- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
2025+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
2026 }
2027
2028 @Override
2029@@ -204,7 +204,7 @@
2030
2031 // Inner classes
2032
2033- private class Execution extends OperatorExecutionBase implements Cursor
2034+ private class Execution extends ChainedCursor
2035 {
2036 // Cursor interface
2037
2038@@ -268,47 +268,42 @@
2039 @Override
2040 public void destroy()
2041 {
2042- if (input != null) {
2043- close();
2044- input.destroy();
2045- input = null;
2046- pEvalExpr = null;
2047- }
2048+ close();
2049+ input.destroy();
2050+ pEvalExpr = null;
2051 }
2052
2053 @Override
2054 public boolean isIdle()
2055 {
2056- return input != null && idle;
2057+ return !input.isDestroyed() && idle;
2058 }
2059
2060 @Override
2061 public boolean isActive()
2062 {
2063- return input != null && !idle;
2064+ return !input.isDestroyed() && !idle;
2065 }
2066
2067 @Override
2068 public boolean isDestroyed()
2069 {
2070- return input == null;
2071+ return input.isDestroyed();
2072 }
2073
2074 // Execution interface
2075
2076- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2077+ Execution(QueryContext context, Cursor input)
2078 {
2079- super(context, bindings);
2080- this.input = input;
2081+ super(context, input);
2082 // one list of evaluatables per execution
2083 if (pExpressions != null)
2084- pEvalExpr = ProjectedRow.createTEvaluatableExpressions(pExpressions);
2085+ pEvalExpr = ProjectedRow.createTEvaluatableExpressions(pExpressions);
2086 else
2087 pEvalExpr = null;
2088 }
2089
2090 // Object state
2091- private Cursor input; // input = null indicates destroyed.
2092 private boolean idle = true;
2093 private List<TEvaluatableExpression> pEvalExpr = null;
2094 }
2095
2096=== added file 'src/main/java/com/akiban/qp/operator/QueryBindingsCursor.java'
2097--- src/main/java/com/akiban/qp/operator/QueryBindingsCursor.java 1970-01-01 00:00:00 +0000
2098+++ src/main/java/com/akiban/qp/operator/QueryBindingsCursor.java 2013-07-10 21:47:26 +0000
2099@@ -0,0 +1,33 @@
2100+/**
2101+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
2102+ *
2103+ * This program is free software: you can redistribute it and/or modify
2104+ * it under the terms of the GNU Affero General Public License as published by
2105+ * the Free Software Foundation, either version 3 of the License, or
2106+ * (at your option) any later version.
2107+ *
2108+ * This program is distributed in the hope that it will be useful,
2109+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2110+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2111+ * GNU Affero General Public License for more details.
2112+ *
2113+ * You should have received a copy of the GNU Affero General Public License
2114+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2115+ */
2116+
2117+package com.akiban.qp.operator;
2118+
2119+/**
2120+ * A stream of {@link QueryBindings}.
2121+ */
2122+public interface QueryBindingsCursor
2123+{
2124+ /** Open stream of bindings. */
2125+ public void openBindings();
2126+
2127+ /** Get (and make current for <code>open</code>) the next set of bindings. */
2128+ public QueryBindings nextBindings();
2129+
2130+ /** Close stream of bindings. */
2131+ public void closeBindings();
2132+}
2133
2134=== renamed file 'src/main/java/com/akiban/qp/operator/Cursor.java' => 'src/main/java/com/akiban/qp/operator/RowCursor.java'
2135--- src/main/java/com/akiban/qp/operator/Cursor.java 2013-03-22 20:05:57 +0000
2136+++ src/main/java/com/akiban/qp/operator/RowCursor.java 2013-07-10 21:47:26 +0000
2137@@ -19,6 +19,6 @@
2138
2139 import com.akiban.qp.row.Row;
2140
2141-public interface Cursor extends RowOrientedCursorBase<Row>
2142+public interface RowCursor extends RowOrientedCursorBase<Row>
2143 {
2144 }
2145
2146=== modified file 'src/main/java/com/akiban/qp/operator/RowOrientedCursorBase.java'
2147--- src/main/java/com/akiban/qp/operator/RowOrientedCursorBase.java 2013-03-22 20:05:57 +0000
2148+++ src/main/java/com/akiban/qp/operator/RowOrientedCursorBase.java 2013-07-10 21:47:26 +0000
2149@@ -17,60 +17,12 @@
2150
2151 package com.akiban.qp.operator;
2152
2153-/*
2154-
2155-A Cursor is used to scan a sequence of rows resulting from the execution of an operator.
2156-The same cursor may be used for multiple executions of the operator, possibly with different bindings.
2157-
2158-A Cursor is always in one of three states:
2159-
2160-- IDLE: The cursor is not currently involved in a scan. The cursor is in this state when one
2161- of the following is true:
2162- - open() has never been called.
2163- - The most recent method invocation was to next(), which returned null.
2164- - The most recent method invocation was to close().
2165-
2166-- ACTIVE: The cursor is currently involved in a scan. The cursor is in this state when one
2167- of the following is true:
2168- - The most recent method invocation was to open().
2169- - The most recent method invocation was to next(), which returned a non-null value.
2170-
2171-- DESTROYED: The cursor has been destroyed. Invocations of open, next, or close on such a cursor
2172- will raise an exception. The only way to get into this state is to call destroy().
2173-
2174-The Cursor lifecycle is as follows:
2175-
2176- next/jump == null next/jump != null
2177- +-+ +-+
2178- | | | |
2179- | V open | V destroy
2180- --> IDLE ----------> ACTIVE ----------> DESTROYED
2181- | <---------- ^
2182- | next/jump = null, |
2183- | close |
2184- | |
2185- +--------------------------------------+
2186- destroy
2187- */
2188-
2189-
2190 import com.akiban.qp.expression.BoundExpressions;
2191 import com.akiban.server.api.dml.ColumnSelector;
2192
2193 public interface RowOrientedCursorBase<T extends BoundExpressions> extends CursorBase<T>
2194 {
2195 /**
2196- * Starts a cursor scan.
2197- */
2198- void open();
2199-
2200- /**
2201- * Advances to and returns the next row.
2202- * @return The next object, or <code>null</code> if at the end.
2203- */
2204- T next();
2205-
2206- /**
2207 * Advances to the first row, r, such that r.compareTo(row) >= 0. (Call next to get the row.)
2208 *
2209 * @param row
2210@@ -78,32 +30,4 @@
2211 * @return
2212 */
2213 void jump(T row, ColumnSelector columnSelector);
2214-
2215- /**
2216- * Terminates the current cursor scan.
2217- */
2218- void close();
2219-
2220- /**
2221- * Destroys the cursor. No further operations on the cursor are permitted.
2222- */
2223- void destroy();
2224-
2225- /**
2226- * Indicates whether the cursor is in the IDLE state.
2227- * @return true iff the cursor is IDLE.
2228- */
2229- boolean isIdle();
2230-
2231- /**
2232- * Indicates whether the cursor is in the ACTIVE state.
2233- * @return true iff the cursor is ACTIVE.
2234- */
2235- boolean isActive();
2236-
2237- /**
2238- * Indicates whether the cursor is in the DESTROYED state.
2239- * @return true iff the cursor is DESTROYED.
2240- */
2241- boolean isDestroyed();
2242 }
2243
2244=== modified file 'src/main/java/com/akiban/qp/operator/Select_BloomFilter.java'
2245--- src/main/java/com/akiban/qp/operator/Select_BloomFilter.java 2013-07-05 21:35:32 +0000
2246+++ src/main/java/com/akiban/qp/operator/Select_BloomFilter.java 2013-07-10 21:47:26 +0000
2247@@ -101,12 +101,12 @@
2248 }
2249
2250 @Override
2251- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2252+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2253 {
2254 if (tFields == null)
2255- return new Execution<>(context, bindings, fields, oldExpressionsAdapater);
2256+ return new Execution<>(context, bindingsCursor, fields, oldExpressionsAdapater);
2257 else
2258- return new Execution<>(context, bindings, tFields, newExpressionsAdapter);
2259+ return new Execution<>(context, bindingsCursor, tFields, newExpressionsAdapter);
2260 }
2261
2262 @Override
2263@@ -233,7 +233,7 @@
2264 }
2265 };
2266
2267- private class Execution<E> extends OperatorExecutionBase implements Cursor
2268+ private class Execution<E> extends OperatorCursor
2269 {
2270 // Cursor interface
2271
2272@@ -322,14 +322,31 @@
2273 return destroyed;
2274 }
2275
2276+ @Override
2277+ public void openBindings() {
2278+ inputCursor.openBindings();
2279+ }
2280+
2281+ @Override
2282+ public QueryBindings nextBindings() {
2283+ bindings = inputCursor.nextBindings();
2284+ return bindings;
2285+ }
2286+
2287+ @Override
2288+ public void closeBindings() {
2289+ inputCursor.closeBindings();
2290+ }
2291+
2292 // Execution interface
2293
2294- <EXPR> Execution(QueryContext context, QueryBindings bindings,
2295+ <EXPR> Execution(QueryContext context, QueryBindingsCursor bindingsCursor,
2296 List<? extends EXPR> expressions, ExpressionAdapter<EXPR,E> adapter)
2297 {
2298- super(context, bindings);
2299- this.inputCursor = input.cursor(context, bindings);
2300- this.onPositiveCursor = onPositive.cursor(context, bindings);
2301+ super(context);
2302+ this.inputCursor = input.cursor(context, bindingsCursor);
2303+ this.onPositiveBindingsCursor = new SingletonQueryBindingsCursor(null);
2304+ this.onPositiveCursor = onPositive.cursor(context, onPositiveBindingsCursor);
2305 this.adapter = adapter;
2306 for (EXPR field : expressions) {
2307 E eval = adapter.evaluate(field, context);
2308@@ -360,11 +377,12 @@
2309 TAP_CHECK.in();
2310 try {
2311 bindings.setRow(bindingPosition, row);
2312- onPositiveCursor.open();
2313+ onPositiveBindingsCursor.reset(bindings);
2314+ onPositiveCursor.openTopLevel();
2315 try {
2316 return onPositiveCursor.next() != null;
2317 } finally {
2318- onPositiveCursor.close();
2319+ onPositiveCursor.closeTopLevel();
2320 bindings.setRow(bindingPosition, null);
2321 }
2322 } finally {
2323@@ -376,6 +394,8 @@
2324
2325 private final Cursor inputCursor;
2326 private final Cursor onPositiveCursor;
2327+ private final SingletonQueryBindingsCursor onPositiveBindingsCursor;
2328+ private QueryBindings bindings;
2329 private BloomFilter filter;
2330 private final List<E> fieldEvals = new ArrayList<>();
2331 private final ExpressionAdapter<?, E> adapter;
2332
2333=== modified file 'src/main/java/com/akiban/qp/operator/Select_HKeyOrdered.java'
2334--- src/main/java/com/akiban/qp/operator/Select_HKeyOrdered.java 2013-07-08 18:56:18 +0000
2335+++ src/main/java/com/akiban/qp/operator/Select_HKeyOrdered.java 2013-07-10 21:47:26 +0000
2336@@ -102,9 +102,9 @@
2337 }
2338
2339 @Override
2340- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2341+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2342 {
2343- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
2344+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
2345 }
2346
2347 @Override
2348@@ -177,7 +177,7 @@
2349
2350 // Inner classes
2351
2352- private class Execution extends OperatorExecutionBase implements Cursor
2353+ private class Execution extends ChainedCursor
2354 {
2355 // Cursor interface
2356
2357@@ -298,18 +298,11 @@
2358 return !input.isDestroyed() && !idle;
2359 }
2360
2361- @Override
2362- public boolean isDestroyed()
2363- {
2364- return input.isDestroyed();
2365- }
2366-
2367 // Execution interface
2368
2369- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2370+ Execution(QueryContext context, Cursor input)
2371 {
2372- super(context, bindings);
2373- this.input = input;
2374+ super(context, input);
2375 if (predicate == null) {
2376 this.evaluation = null;
2377 this.pEvaluation = pPredicate.build();
2378@@ -322,7 +315,6 @@
2379
2380 // Object state
2381
2382- private final Cursor input;
2383 private final ShareHolder<Row> selectedRow = new ShareHolder<>(); // The last input row with type = predicateRowType.
2384 private final ExpressionEvaluation evaluation;
2385 private final TEvaluatableExpression pEvaluation;
2386
2387=== added file 'src/main/java/com/akiban/qp/operator/SingletonQueryBindingsCursor.java'
2388--- src/main/java/com/akiban/qp/operator/SingletonQueryBindingsCursor.java 1970-01-01 00:00:00 +0000
2389+++ src/main/java/com/akiban/qp/operator/SingletonQueryBindingsCursor.java 2013-07-10 21:47:26 +0000
2390@@ -0,0 +1,61 @@
2391+/**
2392+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
2393+ *
2394+ * This program is free software: you can redistribute it and/or modify
2395+ * it under the terms of the GNU Affero General Public License as published by
2396+ * the Free Software Foundation, either version 3 of the License, or
2397+ * (at your option) any later version.
2398+ *
2399+ * This program is distributed in the hope that it will be useful,
2400+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2401+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2402+ * GNU Affero General Public License for more details.
2403+ *
2404+ * You should have received a copy of the GNU Affero General Public License
2405+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2406+ */
2407+
2408+package com.akiban.qp.operator;
2409+
2410+/**
2411+ * A single {@link QueryBindings} stream.
2412+ */
2413+public class SingletonQueryBindingsCursor implements QueryBindingsCursor
2414+{
2415+ enum State { CLOSED, PENDING, EXHAUSTED };
2416+ private QueryBindings bindings;
2417+ private State state;
2418+
2419+ public SingletonQueryBindingsCursor(QueryBindings bindings) {
2420+ reset(bindings);
2421+ }
2422+
2423+ @Override
2424+ public void openBindings() {
2425+ state = State.PENDING;
2426+ }
2427+
2428+ @Override
2429+ public QueryBindings nextBindings() {
2430+ switch (state) {
2431+ case CLOSED:
2432+ throw new IllegalStateException("Bindings cursor not open");
2433+ case PENDING:
2434+ state = State.EXHAUSTED;
2435+ return bindings;
2436+ case EXHAUSTED:
2437+ default:
2438+ return null;
2439+ }
2440+ }
2441+
2442+ @Override
2443+ public void closeBindings() {
2444+ state = State.CLOSED;
2445+ }
2446+
2447+ public void reset(QueryBindings bindings) {
2448+ this.bindings = bindings;
2449+ this.state = State.CLOSED;
2450+ }
2451+}
2452
2453=== modified file 'src/main/java/com/akiban/qp/operator/Sort_General.java'
2454--- src/main/java/com/akiban/qp/operator/Sort_General.java 2013-07-05 21:35:32 +0000
2455+++ src/main/java/com/akiban/qp/operator/Sort_General.java 2013-07-10 21:47:26 +0000
2456@@ -92,9 +92,9 @@
2457 }
2458
2459 @Override
2460- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2461+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2462 {
2463- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
2464+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
2465 }
2466
2467 @Override
2468@@ -153,7 +153,7 @@
2469
2470 // Inner classes
2471
2472- private class Execution extends OperatorExecutionBase implements Cursor
2473+ private class Execution extends ChainedCursor
2474 {
2475 // Cursor interface
2476
2477@@ -243,16 +243,14 @@
2478
2479 // Execution interface
2480
2481- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2482+ Execution(QueryContext context, Cursor input)
2483 {
2484- super(context, bindings);
2485- this.input = input;
2486+ super(context, input);
2487 }
2488
2489 // Object state
2490
2491- private final Cursor input;
2492- private Cursor output;
2493+ private RowCursor output;
2494 private boolean destroyed = false;
2495 }
2496 }
2497
2498=== modified file 'src/main/java/com/akiban/qp/operator/Sort_InsertionLimited.java'
2499--- src/main/java/com/akiban/qp/operator/Sort_InsertionLimited.java 2013-07-08 18:56:18 +0000
2500+++ src/main/java/com/akiban/qp/operator/Sort_InsertionLimited.java 2013-07-10 21:47:26 +0000
2501@@ -104,9 +104,9 @@
2502 }
2503
2504 @Override
2505- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2506+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2507 {
2508- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
2509+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
2510 }
2511
2512 @Override
2513@@ -173,7 +173,7 @@
2514
2515 private enum State { CLOSED, FILLING, EMPTYING, DESTROYED }
2516
2517- private class Execution extends OperatorExecutionBase implements Cursor
2518+ private class Execution extends ChainedCursor
2519 {
2520 // Cursor interface
2521
2522@@ -326,7 +326,7 @@
2523 {
2524 return state == State.DESTROYED;
2525 }
2526-
2527+
2528 // private methods
2529
2530 private boolean usingPValues() {
2531@@ -335,10 +335,9 @@
2532
2533 // Execution interface
2534
2535- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2536+ Execution(QueryContext context, Cursor input)
2537 {
2538- super(context, bindings);
2539- this.input = input;
2540+ super(context, input);
2541 int nsort = ordering.sortColumns();
2542 tEvaluations = new ArrayList<>(nsort);
2543 for (int i = 0; i < nsort; ++i) {
2544@@ -349,7 +348,6 @@
2545
2546 // Object state
2547
2548- private final Cursor input;
2549 private final List<TEvaluatableExpression> tEvaluations;
2550 private State state = State.CLOSED;
2551 private SortedSet<Holder> sorted;
2552
2553=== modified file 'src/main/java/com/akiban/qp/operator/SorterToCursorAdapter.java'
2554--- src/main/java/com/akiban/qp/operator/SorterToCursorAdapter.java 2013-07-05 21:35:32 +0000
2555+++ src/main/java/com/akiban/qp/operator/SorterToCursorAdapter.java 2013-07-10 21:47:26 +0000
2556@@ -27,9 +27,9 @@
2557 * Cursors are reusable but Sorters are not.
2558 * This class creates a new Sorter each time a new cursor scan is started.
2559 */
2560-class SorterToCursorAdapter implements Cursor
2561+class SorterToCursorAdapter implements RowCursor
2562 {
2563- // Cursor interface
2564+ // RowCursor interface
2565
2566 @Override
2567 public void open()
2568@@ -99,7 +99,7 @@
2569 public SorterToCursorAdapter(StoreAdapter adapter,
2570 QueryContext context,
2571 QueryBindings bindings,
2572- Cursor input,
2573+ RowCursor input,
2574 RowType rowType,
2575 API.Ordering ordering,
2576 API.SortOption sortOption,
2577@@ -118,12 +118,12 @@
2578 private final StoreAdapter adapter;
2579 private final QueryContext context;
2580 private final QueryBindings bindings;
2581- private final Cursor input;
2582+ private final RowCursor input;
2583 private final RowType rowType;
2584 private final API.Ordering ordering;
2585 private final API.SortOption sortOption;
2586 private final InOutTap loadTap;
2587 private Sorter sorter;
2588- private Cursor cursor;
2589+ private RowCursor cursor;
2590 private boolean destroyed = false;
2591 }
2592
2593=== modified file 'src/main/java/com/akiban/qp/operator/StoreAdapter.java'
2594--- src/main/java/com/akiban/qp/operator/StoreAdapter.java 2013-07-08 15:56:07 +0000
2595+++ src/main/java/com/akiban/qp/operator/StoreAdapter.java 2013-07-10 21:47:26 +0000
2596@@ -52,13 +52,12 @@
2597 {
2598 public abstract GroupCursor newGroupCursor(Group group);
2599
2600- public abstract Cursor newIndexCursor(QueryContext context,
2601- QueryBindings bindings,
2602- Index index,
2603- IndexKeyRange keyRange,
2604- API.Ordering ordering,
2605- IndexScanSelector scanSelector,
2606- boolean usePValues);
2607+ public abstract RowCursor newIndexCursor(QueryContext context,
2608+ Index index,
2609+ IndexKeyRange keyRange,
2610+ API.Ordering ordering,
2611+ IndexScanSelector scanSelector,
2612+ boolean usePValues);
2613
2614 public abstract <HKEY extends com.akiban.qp.row.HKey> HKEY newHKey(HKey hKeyMetadata);
2615
2616@@ -75,7 +74,7 @@
2617
2618 public abstract Sorter createSorter(QueryContext context,
2619 QueryBindings bindings,
2620- Cursor input,
2621+ RowCursor input,
2622 RowType rowType,
2623 API.Ordering ordering,
2624 API.SortOption sortOption,
2625
2626=== modified file 'src/main/java/com/akiban/qp/operator/UnionAll_Default.java'
2627--- src/main/java/com/akiban/qp/operator/UnionAll_Default.java 2013-07-05 21:35:32 +0000
2628+++ src/main/java/com/akiban/qp/operator/UnionAll_Default.java 2013-07-10 21:47:26 +0000
2629@@ -101,8 +101,8 @@
2630 }
2631
2632 @Override
2633- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
2634- return new Execution(context, bindings);
2635+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
2636+ return new Execution(context, bindingsCursor);
2637 }
2638
2639 UnionAll_Default(Operator input1, RowType input1Type, Operator input2, RowType input2Type, boolean usePValues) {
2640@@ -205,7 +205,7 @@
2641 return new CompoundExplainer(Type.UNION, att);
2642 }
2643
2644- private class Execution extends OperatorExecutionBase implements Cursor {
2645+ private class Execution extends OperatorCursor {
2646
2647 @Override
2648 public void open() {
2649@@ -213,6 +213,8 @@
2650 try {
2651 CursorLifecycle.checkIdle(this);
2652 idle = false;
2653+ // TODO: Have a mode where all the cursors get opened
2654+ // so that they can start in parallel.
2655 } finally {
2656 TAP_OPEN.out();
2657 }
2658@@ -299,10 +301,41 @@
2659 return destroyed;
2660 }
2661
2662- private Execution(QueryContext context, QueryBindings bindings)
2663+ @Override
2664+ public void openBindings() {
2665+ bindingsCursor.openBindings();
2666+ for (int i = 0; i < cursors.length; i++) {
2667+ cursors[i].openBindings();
2668+ }
2669+ }
2670+
2671+ @Override
2672+ public QueryBindings nextBindings() {
2673+ QueryBindings bindings = bindingsCursor.nextBindings();
2674+ for (int i = 0; i < cursors.length; i++) {
2675+ QueryBindings other = cursors[i].nextBindings();
2676+ assert (bindings == other);
2677+ }
2678+ return bindings;
2679+ }
2680+
2681+ @Override
2682+ public void closeBindings() {
2683+ bindingsCursor.closeBindings();
2684+ for (int i = 0; i < cursors.length; i++) {
2685+ cursors[i].closeBindings();
2686+ }
2687+ }
2688+
2689+ private Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
2690 {
2691- super(context, bindings);
2692+ super(context);
2693+ MultipleQueryBindingsCursor multiple = new MultipleQueryBindingsCursor(bindingsCursor);
2694+ this.bindingsCursor = multiple;
2695 cursors = new Cursor[inputs.size()];
2696+ for (int i = 0; i < cursors.length; i++) {
2697+ cursors[i] = inputs.get(i).cursor(context, multiple.newCursor());
2698+ }
2699 }
2700
2701 /**
2702@@ -313,7 +346,7 @@
2703 */
2704 private Row nextCursorFirstRow() {
2705 while (++inputOperatorsIndex < inputs.size()) {
2706- Cursor nextCursor = cursor(inputOperatorsIndex);
2707+ Cursor nextCursor = cursors[inputOperatorsIndex];
2708 nextCursor.open();
2709 Row nextRow = nextCursor.next();
2710 if (nextRow == null) {
2711@@ -350,15 +383,8 @@
2712 return row;
2713 }
2714
2715- private Cursor cursor(int i)
2716- {
2717- if (cursors[i] == null) {
2718- cursors[i] = inputs.get(i).cursor(context, bindings);
2719- }
2720- return cursors[i];
2721- }
2722-
2723 private final ShareHolder<MasqueradingRow> rowHolder = new ShareHolder<>();
2724+ private final QueryBindingsCursor bindingsCursor;
2725 private int inputOperatorsIndex = -1; // right before the first operator
2726 private Cursor[] cursors;
2727 private Cursor currentCursor;
2728
2729=== modified file 'src/main/java/com/akiban/qp/operator/Union_Ordered.java'
2730--- src/main/java/com/akiban/qp/operator/Union_Ordered.java 2013-07-05 21:35:32 +0000
2731+++ src/main/java/com/akiban/qp/operator/Union_Ordered.java 2013-07-10 21:47:26 +0000
2732@@ -95,9 +95,9 @@
2733 // Operator interface
2734
2735 @Override
2736- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2737+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2738 {
2739- return new Execution(context, bindings);
2740+ return new Execution(context, bindingsCursor);
2741 }
2742
2743 @Override
2744@@ -194,7 +194,7 @@
2745
2746 // Inner classes
2747
2748- private class Execution extends OperatorExecutionBase implements Cursor
2749+ private class Execution extends OperatorCursor
2750 {
2751 // Cursor interface
2752
2753@@ -309,13 +309,39 @@
2754 return leftInput.isDestroyed();
2755 }
2756
2757+ @Override
2758+ public void openBindings() {
2759+ bindingsCursor.openBindings();
2760+ leftInput.openBindings();
2761+ rightInput.openBindings();
2762+ }
2763+
2764+ @Override
2765+ public QueryBindings nextBindings() {
2766+ QueryBindings bindings = bindingsCursor.nextBindings();
2767+ QueryBindings other = leftInput.nextBindings();
2768+ assert (bindings == other);
2769+ other = rightInput.nextBindings();
2770+ assert (bindings == other);
2771+ return bindings;
2772+ }
2773+
2774+ @Override
2775+ public void closeBindings() {
2776+ bindingsCursor.closeBindings();
2777+ leftInput.closeBindings();
2778+ rightInput.closeBindings();
2779+ }
2780+
2781 // Execution interface
2782
2783- Execution(QueryContext context, QueryBindings bindings)
2784+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
2785 {
2786- super(context, bindings);
2787- leftInput = left.cursor(context, bindings);
2788- rightInput = right.cursor(context, bindings);
2789+ super(context);
2790+ MultipleQueryBindingsCursor multiple = new MultipleQueryBindingsCursor(bindingsCursor);
2791+ this.bindingsCursor = multiple;
2792+ this.leftInput = left.cursor(context, multiple.newCursor());
2793+ this.rightInput = right.cursor(context, multiple.newCursor());
2794 }
2795
2796 // For use by this class
2797@@ -474,6 +500,7 @@
2798 // ShareHolders, so they are needed here.
2799
2800 private boolean closed = true;
2801+ private final QueryBindingsCursor bindingsCursor;
2802 private final Cursor leftInput;
2803 private final Cursor rightInput;
2804 private final ShareHolder<Row> leftRow = new ShareHolder<>();
2805
2806=== modified file 'src/main/java/com/akiban/qp/operator/Update_Default.java'
2807--- src/main/java/com/akiban/qp/operator/Update_Default.java 2013-07-08 18:56:18 +0000
2808+++ src/main/java/com/akiban/qp/operator/Update_Default.java 2013-07-10 21:47:26 +0000
2809@@ -110,7 +110,8 @@
2810
2811 @Override
2812 public UpdateResult run(QueryContext context, QueryBindings bindings) {
2813- return new Execution(context, bindings, inputOperator.cursor(context, bindings)).run();
2814+ QueryBindingsCursor bindingsCursor = new SingletonQueryBindingsCursor(bindings);
2815+ return new Execution(context, inputOperator.cursor(context, bindingsCursor)).run();
2816 }
2817
2818 // Plannable interface
2819@@ -167,7 +168,7 @@
2820 UPDATE_TAP.in();
2821 }
2822 try {
2823- input.open();
2824+ QueryBindings bindings = input.openTopLevel();
2825 Row oldRow;
2826 while ((oldRow = input.next()) != null) {
2827 checkQueryCancelation();
2828@@ -184,7 +185,7 @@
2829 }
2830 } finally {
2831 if (input != null) {
2832- input.close();
2833+ input.destroy();
2834 }
2835 if (TAP_NEXT_ENABLED) {
2836 UPDATE_TAP.out();
2837@@ -193,9 +194,9 @@
2838 return new StandardUpdateResult(seen, modified);
2839 }
2840
2841- public Execution(QueryContext queryContext, QueryBindings bindings, Cursor input)
2842+ public Execution(QueryContext queryContext, Cursor input)
2843 {
2844- super(queryContext, bindings);
2845+ super(queryContext);
2846 this.input = input;
2847 }
2848
2849
2850=== modified file 'src/main/java/com/akiban/qp/operator/Update_Returning.java'
2851--- src/main/java/com/akiban/qp/operator/Update_Returning.java 2013-07-08 18:56:18 +0000
2852+++ src/main/java/com/akiban/qp/operator/Update_Returning.java 2013-07-10 21:47:26 +0000
2853@@ -94,8 +94,8 @@
2854 }
2855
2856 @Override
2857- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
2858- return new Execution(context, bindings, inputOperator.cursor(context, bindings));
2859+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
2860+ return new Execution(context, inputOperator.cursor(context, bindingsCursor));
2861 }
2862
2863 public Update_Returning (Operator inputOperator, UpdateFunction updateFunction, boolean usePvals) {
2864@@ -120,7 +120,7 @@
2865 private static final Logger LOG = LoggerFactory.getLogger(Update_Returning.class);
2866
2867 // Inner classes
2868- private class Execution extends OperatorExecutionBase implements Cursor
2869+ private class Execution extends ChainedCursor
2870 {
2871
2872 // Cursor interface
2873@@ -181,42 +181,31 @@
2874 @Override
2875 public void destroy()
2876 {
2877- if (input != null) {
2878- close();
2879- input.destroy();
2880- input = null;
2881- }
2882+ close();
2883+ input.destroy();
2884 }
2885
2886 @Override
2887 public boolean isIdle()
2888 {
2889- return input != null && idle;
2890+ return !input.isDestroyed() && idle;
2891 }
2892
2893 @Override
2894 public boolean isActive()
2895 {
2896- return input != null && !idle;
2897- }
2898-
2899- @Override
2900- public boolean isDestroyed()
2901- {
2902- return input == null;
2903- }
2904-
2905+ return !input.isDestroyed() && !idle;
2906+ }
2907+
2908 // Execution interface
2909
2910- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2911+ Execution(QueryContext context, Cursor input)
2912 {
2913- super(context, bindings);
2914- this.input = input;
2915+ super(context, input);
2916 }
2917
2918 // Object state
2919-
2920- private Cursor input; // input = null indicates destroyed.
2921+
2922 private boolean idle = true;
2923 }
2924
2925
2926=== modified file 'src/main/java/com/akiban/qp/operator/Using_BloomFilter.java'
2927--- src/main/java/com/akiban/qp/operator/Using_BloomFilter.java 2013-07-05 21:35:32 +0000
2928+++ src/main/java/com/akiban/qp/operator/Using_BloomFilter.java 2013-07-10 21:47:26 +0000
2929@@ -95,9 +95,9 @@
2930 }
2931
2932 @Override
2933- protected Cursor cursor(QueryContext context, QueryBindings bindings)
2934+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
2935 {
2936- return new Execution(context, bindings, streamInput.cursor(context, bindings));
2937+ return new Execution(context, streamInput.cursor(context, bindingsCursor));
2938 }
2939
2940 @Override
2941@@ -174,7 +174,7 @@
2942
2943 // Inner classes
2944
2945- private class Execution extends OperatorExecutionBase implements Cursor
2946+ private class Execution extends ChainedCursor
2947 {
2948 // Cursor interface
2949
2950@@ -211,12 +211,6 @@
2951 }
2952
2953 @Override
2954- public void close()
2955- {
2956- input.close();
2957- }
2958-
2959- @Override
2960 public void destroy()
2961 {
2962 close();
2963@@ -224,30 +218,11 @@
2964 bindings.setBloomFilter(filterBindingPosition, null);
2965 }
2966
2967- @Override
2968- public boolean isIdle()
2969- {
2970- return input.isIdle();
2971- }
2972-
2973- @Override
2974- public boolean isActive()
2975- {
2976- return input.isActive();
2977- }
2978-
2979- @Override
2980- public boolean isDestroyed()
2981- {
2982- return input.isDestroyed();
2983- }
2984-
2985 // Execution interface
2986
2987- Execution(QueryContext context, QueryBindings bindings, Cursor input)
2988+ Execution(QueryContext context, Cursor input)
2989 {
2990- super(context, bindings);
2991- this.input = input;
2992+ super(context, input);
2993 }
2994
2995 // For use by this class
2996@@ -268,8 +243,9 @@
2997 {
2998 int fields = filterRowType.nFields();
2999 int rows = 0;
3000- Cursor loadCursor = filterInput.cursor(context, bindings);
3001- loadCursor.open();
3002+ QueryBindingsCursor bindingsCursor = new SingletonQueryBindingsCursor(bindings);
3003+ Cursor loadCursor = filterInput.cursor(context, bindingsCursor);
3004+ loadCursor.openTopLevel();
3005 Row row;
3006 while ((row = loadCursor.next()) != null) {
3007 int h = 0;
3008@@ -290,8 +266,5 @@
3009 return rows;
3010 }
3011
3012- // Object state
3013-
3014- private final Cursor input;
3015 }
3016 }
3017
3018=== modified file 'src/main/java/com/akiban/qp/operator/ValuesScan_Default.java'
3019--- src/main/java/com/akiban/qp/operator/ValuesScan_Default.java 2013-07-08 18:56:18 +0000
3020+++ src/main/java/com/akiban/qp/operator/ValuesScan_Default.java 2013-07-10 21:47:26 +0000
3021@@ -77,8 +77,8 @@
3022 }
3023
3024 @Override
3025- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
3026- return new Execution(context, bindings, rows);
3027+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
3028+ return new Execution(context, bindingsCursor, rows);
3029 }
3030
3031 @Override
3032@@ -117,14 +117,14 @@
3033 return new CompoundExplainer(Type.SCAN_OPERATOR, att);
3034 }
3035
3036- private static class Execution extends OperatorExecutionBase implements Cursor
3037+ private static class Execution extends LeafCursor
3038 {
3039 private final Collection<? extends BindableRow> rows;
3040 private Iterator<? extends BindableRow> iter;
3041 private boolean destroyed = false;
3042
3043- public Execution (QueryContext context, QueryBindings bindings, Collection<? extends BindableRow> rows) {
3044- super(context, bindings);
3045+ public Execution (QueryContext context, QueryBindingsCursor bindingsCursor, Collection<? extends BindableRow> rows) {
3046+ super(context, bindingsCursor);
3047 this.rows = rows;
3048 }
3049
3050
3051=== modified file 'src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java'
3052--- src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java 2013-07-08 16:06:08 +0000
3053+++ src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java 2013-07-10 21:47:26 +0000
3054@@ -70,7 +70,7 @@
3055 QueryContext context = new SimpleQueryContext(adapter);
3056 QueryBindings bindings = context.createBindings();
3057 cursor = cursor(operator, context, bindings);
3058- cursor.open();
3059+ cursor.openTopLevel();
3060 // closed was initialized to true, because hasMore is checked before open. (This is due to scan being
3061 // spread across possibly multiple requests.) Now set closed to false for the actual scanning of rows.
3062 closed = false;
3063
3064=== modified file 'src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java'
3065--- src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-07-10 17:01:24 +0000
3066+++ src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-07-10 21:47:26 +0000
3067@@ -71,11 +71,10 @@
3068 }
3069
3070 @Override
3071- public Cursor newIndexCursor(QueryContext context, QueryBindings bindings, Index index, IndexKeyRange keyRange, API.Ordering ordering,
3072+ public RowCursor newIndexCursor(QueryContext context, Index index, IndexKeyRange keyRange, API.Ordering ordering,
3073 IndexScanSelector selector, boolean usePValues)
3074 {
3075 return new PersistitIndexCursor(context,
3076- bindings,
3077 schema.indexRowType(index),
3078 keyRange,
3079 ordering,
3080@@ -86,7 +85,7 @@
3081 @Override
3082 public Sorter createSorter(QueryContext context,
3083 QueryBindings bindings,
3084- Cursor input,
3085+ RowCursor input,
3086 RowType rowType,
3087 API.Ordering ordering,
3088 API.SortOption sortOption,
3089
3090=== modified file 'src/main/java/com/akiban/qp/persistitadapter/PersistitIndexCursor.java'
3091--- src/main/java/com/akiban/qp/persistitadapter/PersistitIndexCursor.java 2013-07-05 21:35:32 +0000
3092+++ src/main/java/com/akiban/qp/persistitadapter/PersistitIndexCursor.java 2013-07-10 21:47:26 +0000
3093@@ -28,7 +28,7 @@
3094 import com.akiban.server.api.dml.ColumnSelector;
3095 import com.persistit.exception.PersistitException;
3096
3097-class PersistitIndexCursor implements Cursor
3098+class PersistitIndexCursor implements BindingsAwareCursor
3099 {
3100 // Cursor interface
3101
3102@@ -103,10 +103,15 @@
3103 return destroyed;
3104 }
3105
3106+ @Override
3107+ public void rebind(QueryBindings bindings)
3108+ {
3109+ indexCursor.rebind(bindings);
3110+ }
3111+
3112 // For use by this package
3113
3114 PersistitIndexCursor(QueryContext context,
3115- QueryBindings bindings,
3116 IndexRowType indexRowType,
3117 IndexKeyRange keyRange,
3118 API.Ordering ordering,
3119@@ -116,14 +121,13 @@
3120 this.keyRange = keyRange;
3121 this.ordering = ordering;
3122 this.context = context;
3123- this.bindings = bindings;
3124 this.indexRowType = indexRowType;
3125 this.isTableIndex = indexRowType.index().isTableIndex();
3126 this.usePValues = usePValues;
3127 this.selector = selector;
3128 this.idle = true;
3129 this.rowState = context.getStore().createIterationHelper(indexRowType);
3130- this.indexCursor = IndexCursor.create(context, bindings, keyRange, ordering, rowState, usePValues);
3131+ this.indexCursor = IndexCursor.create(context, keyRange, ordering, rowState, usePValues);
3132 }
3133
3134 // For use by this class
3135@@ -131,7 +135,6 @@
3136 // Object state
3137
3138 private final QueryContext context;
3139- private final QueryBindings bindings;
3140 private final IndexRowType indexRowType;
3141 private final IndexKeyRange keyRange;
3142 private final API.Ordering ordering;
3143
3144=== modified file 'src/main/java/com/akiban/qp/persistitadapter/Sorter.java'
3145--- src/main/java/com/akiban/qp/persistitadapter/Sorter.java 2013-06-06 14:38:02 +0000
3146+++ src/main/java/com/akiban/qp/persistitadapter/Sorter.java 2013-07-10 21:47:26 +0000
3147@@ -17,10 +17,10 @@
3148
3149 package com.akiban.qp.persistitadapter;
3150
3151-import com.akiban.qp.operator.Cursor;
3152+import com.akiban.qp.operator.RowCursor;
3153 import com.persistit.exception.PersistitException;
3154
3155 public interface Sorter {
3156- Cursor sort();
3157+ RowCursor sort();
3158 void close();
3159 }
3160
3161=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursor.java'
3162--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursor.java 2013-07-05 21:35:32 +0000
3163+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursor.java 2013-07-10 21:47:26 +0000
3164@@ -19,7 +19,7 @@
3165
3166 import com.akiban.qp.expression.IndexKeyRange;
3167 import com.akiban.qp.operator.API;
3168-import com.akiban.qp.operator.Cursor;
3169+import com.akiban.qp.operator.BindingsAwareCursor;
3170 import com.akiban.qp.operator.CursorLifecycle;
3171 import com.akiban.qp.operator.QueryBindings;
3172 import com.akiban.qp.operator.QueryContext;
3173@@ -32,7 +32,7 @@
3174 import com.persistit.Key.Direction;
3175 import com.persistit.exception.PersistitException;
3176
3177-public abstract class IndexCursor implements Cursor
3178+public abstract class IndexCursor implements BindingsAwareCursor
3179 {
3180 // Cursor interface
3181
3182@@ -89,6 +89,12 @@
3183 return destroyed;
3184 }
3185
3186+ @Override
3187+ public void rebind(QueryBindings bindings)
3188+ {
3189+ this.bindings = bindings;
3190+ }
3191+
3192 // For use by subclasses
3193
3194 protected boolean nextInternal(boolean deep)
3195@@ -119,7 +125,6 @@
3196 // IndexCursor interface
3197
3198 public static IndexCursor create(QueryContext context,
3199- QueryBindings bindings,
3200 IndexKeyRange keyRange,
3201 API.Ordering ordering,
3202 IterationHelper iterationHelper,
3203@@ -132,21 +137,20 @@
3204 return
3205 keyRange != null && keyRange.spatial()
3206 ? keyRange.hi() == null
3207- ? IndexCursorSpatial_NearPoint.create(context, bindings, iterationHelper, keyRange)
3208- : IndexCursorSpatial_InBox.create(context, bindings, iterationHelper, keyRange)
3209+ ? IndexCursorSpatial_NearPoint.create(context, iterationHelper, keyRange)
3210+ : IndexCursorSpatial_InBox.create(context, iterationHelper, keyRange)
3211 : ordering.allAscending() || ordering.allDescending()
3212 ? (keyRange != null && keyRange.lexicographic()
3213- ? IndexCursorUnidirectionalLexicographic.create(context, bindings, iterationHelper, keyRange, ordering, adapter)
3214- : IndexCursorUnidirectional.create(context, bindings, iterationHelper, keyRange, ordering, adapter))
3215- : IndexCursorMixedOrder.create(context, bindings, iterationHelper, keyRange, ordering, adapter);
3216+ ? IndexCursorUnidirectionalLexicographic.create(context, iterationHelper, keyRange, ordering, adapter)
3217+ : IndexCursorUnidirectional.create(context, iterationHelper, keyRange, ordering, adapter))
3218+ : IndexCursorMixedOrder.create(context, iterationHelper, keyRange, ordering, adapter);
3219 }
3220
3221 // For use by subclasses
3222
3223- protected IndexCursor(QueryContext context, QueryBindings bindings, IterationHelper iterationHelper)
3224+ protected IndexCursor(QueryContext context, IterationHelper iterationHelper)
3225 {
3226 this.context = context;
3227- this.bindings = bindings;
3228 this.adapter = context.getStore();
3229 this.iterationHelper = iterationHelper;
3230 }
3231@@ -159,9 +163,9 @@
3232 // Object state
3233
3234 protected final QueryContext context;
3235- protected final QueryBindings bindings;
3236 protected final StoreAdapter adapter;
3237 protected final IterationHelper iterationHelper;
3238+ protected QueryBindings bindings;
3239 private boolean idle = true;
3240 private boolean destroyed = false;
3241
3242
3243=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorMixedOrder.java'
3244--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorMixedOrder.java 2013-07-08 18:56:18 +0000
3245+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorMixedOrder.java 2013-07-10 21:47:26 +0000
3246@@ -24,7 +24,6 @@
3247 import com.akiban.qp.expression.IndexBound;
3248 import com.akiban.qp.expression.IndexKeyRange;
3249 import com.akiban.qp.operator.API;
3250-import com.akiban.qp.operator.QueryBindings;
3251 import com.akiban.qp.operator.QueryContext;
3252 import com.akiban.qp.persistitadapter.indexrow.PersistitIndexRow;
3253 import com.akiban.qp.persistitadapter.indexrow.PersistitIndexRowBuffer;
3254@@ -181,13 +180,12 @@
3255 // IndexCursorMixedOrder interface
3256
3257 public static <S, E> IndexCursorMixedOrder<S, E> create(QueryContext context,
3258- QueryBindings bindings,
3259 IterationHelper iterationHelper,
3260 IndexKeyRange keyRange,
3261 API.Ordering ordering,
3262 SortKeyAdapter<S, E> sortKeyAdapter)
3263 {
3264- return new IndexCursorMixedOrder<>(context, bindings, iterationHelper, keyRange, ordering, sortKeyAdapter);
3265+ return new IndexCursorMixedOrder<>(context, iterationHelper, keyRange, ordering, sortKeyAdapter);
3266 }
3267
3268 public void initializeScanStates()
3269@@ -277,13 +275,12 @@
3270 // For use by subclasses
3271
3272 protected IndexCursorMixedOrder(QueryContext context,
3273- QueryBindings bindings,
3274 IterationHelper iterationHelper,
3275 IndexKeyRange keyRange,
3276 API.Ordering ordering,
3277 SortKeyAdapter<S, E> sortKeyAdapter)
3278 {
3279- super(context, bindings, iterationHelper);
3280+ super(context, iterationHelper);
3281 this.keyRange = keyRange;
3282 this.ordering = ordering;
3283 this.ascending = new boolean[ordering.sortColumns()];
3284
3285=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_InBox.java'
3286--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_InBox.java 2013-07-08 18:56:18 +0000
3287+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_InBox.java 2013-07-10 21:47:26 +0000
3288@@ -82,21 +82,27 @@
3289 multiCursor.destroy();
3290 }
3291
3292+ @Override
3293+ public void rebind(QueryBindings bindings)
3294+ {
3295+ super.rebind(bindings);
3296+ multiCursor.rebind(bindings);
3297+ }
3298+
3299 // IndexCursorSpatial_InBox interface
3300
3301 public static IndexCursorSpatial_InBox create(QueryContext context,
3302- QueryBindings bindings,
3303 IterationHelper iterationHelper,
3304 IndexKeyRange keyRange)
3305 {
3306- return new IndexCursorSpatial_InBox(context, bindings, iterationHelper, keyRange);
3307+ return new IndexCursorSpatial_InBox(context, iterationHelper, keyRange);
3308 }
3309
3310 // For use by this class
3311
3312- private IndexCursorSpatial_InBox(QueryContext context, QueryBindings bindings, IterationHelper iterationHelper, IndexKeyRange keyRange)
3313+ private IndexCursorSpatial_InBox(QueryContext context, IterationHelper iterationHelper, IndexKeyRange keyRange)
3314 {
3315- super(context, bindings, iterationHelper);
3316+ super(context, iterationHelper);
3317 assert keyRange.spatial();
3318 this.multiCursor = new MultiCursor();
3319 this.iterationHelper = iterationHelper;
3320@@ -116,7 +122,7 @@
3321 IterationHelper rowState = adapter.createIterationHelper(keyRange.indexRowType());
3322 if (Types3Switch.ON) {
3323 IndexCursorUnidirectional<PValueSource> zIntervalCursor =
3324- new IndexCursorUnidirectional<>(context, bindings,
3325+ new IndexCursorUnidirectional<>(context,
3326 rowState,
3327 zKeyRange,
3328 zOrdering,
3329@@ -125,7 +131,7 @@
3330 }
3331 else {
3332 IndexCursorUnidirectional<ValueSource> zIntervalCursor =
3333- new IndexCursorUnidirectional<>(context, bindings,
3334+ new IndexCursorUnidirectional<>(context,
3335 rowState,
3336 zKeyRange,
3337 zOrdering,
3338
3339=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_NearPoint.java'
3340--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_NearPoint.java 2013-07-08 18:56:18 +0000
3341+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorSpatial_NearPoint.java 2013-07-10 21:47:26 +0000
3342@@ -22,7 +22,7 @@
3343 import com.akiban.qp.expression.IndexBound;
3344 import com.akiban.qp.expression.IndexKeyRange;
3345 import com.akiban.qp.operator.API;
3346-import com.akiban.qp.operator.Cursor;
3347+import com.akiban.qp.operator.BindingsAwareCursor;
3348 import com.akiban.qp.operator.QueryBindings;
3349 import com.akiban.qp.operator.QueryContext;
3350 import com.akiban.qp.row.Row;
3351@@ -110,21 +110,28 @@
3352 }
3353 }
3354
3355+ @Override
3356+ public void rebind(QueryBindings bindings)
3357+ {
3358+ super.rebind(bindings);
3359+ geCursor.rebind(bindings);
3360+ ltCursor.rebind(bindings);
3361+ }
3362+
3363 // IndexCursorSpatial_InBox interface
3364
3365 public static IndexCursorSpatial_NearPoint create(QueryContext context,
3366- QueryBindings bindings,
3367 IterationHelper iterationHelper,
3368 IndexKeyRange keyRange)
3369 {
3370- return new IndexCursorSpatial_NearPoint(context, bindings, iterationHelper, keyRange);
3371+ return new IndexCursorSpatial_NearPoint(context, iterationHelper, keyRange);
3372 }
3373
3374 // For use by this class
3375
3376- private IndexCursorSpatial_NearPoint(QueryContext context, QueryBindings bindings, IterationHelper iterationHelper, IndexKeyRange keyRange)
3377+ private IndexCursorSpatial_NearPoint(QueryContext context, IterationHelper iterationHelper, IndexKeyRange keyRange)
3378 {
3379- super(context, bindings, iterationHelper);
3380+ super(context, iterationHelper);
3381 assert keyRange.spatial();
3382 this.iterationHelper = iterationHelper;
3383 IndexRowType physicalIndexRowType = keyRange.indexRowType().physicalRowType();
3384@@ -183,12 +190,12 @@
3385 upOrdering.append((TPreparedExpression)null, true);
3386 downOrdering.append((TPreparedExpression)null, false);
3387 }
3388- geCursor = new IndexCursorUnidirectional<>(context, bindings,
3389+ geCursor = new IndexCursorUnidirectional<>(context,
3390 geRowState,
3391 geKeyRange,
3392 upOrdering,
3393 PValueSortKeyAdapter.INSTANCE);
3394- ltCursor = new IndexCursorUnidirectional<>(context, bindings,
3395+ ltCursor = new IndexCursorUnidirectional<>(context,
3396 ltRowState,
3397 ltKeyRange,
3398 downOrdering,
3399@@ -222,11 +229,11 @@
3400 private final int zPosition;
3401 private final IterationHelper iterationHelper;
3402 private long zStart;
3403- private Cursor geCursor;
3404+ private BindingsAwareCursor geCursor;
3405 private Row geRow;
3406 private long geDistance;
3407 private boolean geNeedToAdvance;
3408- private Cursor ltCursor;
3409+ private BindingsAwareCursor ltCursor;
3410 private Row ltRow;
3411 private long ltDistance;
3412 private boolean ltNeedToAdvance;
3413
3414=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectional.java'
3415--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectional.java 2013-07-08 18:56:18 +0000
3416+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectional.java 2013-07-10 21:47:26 +0000
3417@@ -25,7 +25,6 @@
3418 import com.akiban.qp.expression.IndexBound;
3419 import com.akiban.qp.expression.IndexKeyRange;
3420 import com.akiban.qp.operator.API;
3421-import com.akiban.qp.operator.QueryBindings;
3422 import com.akiban.qp.operator.QueryContext;
3423 import com.akiban.qp.persistitadapter.SpatialHelper;
3424 import com.akiban.qp.persistitadapter.indexrow.PersistitIndexRow;
3425@@ -140,7 +139,6 @@
3426 // IndexCursorUnidirectional interface
3427
3428 public static <S> IndexCursorUnidirectional<S> create(QueryContext context,
3429- QueryBindings bindings,
3430 IterationHelper iterationHelper,
3431 IndexKeyRange keyRange,
3432 API.Ordering ordering,
3433@@ -148,20 +146,19 @@
3434 {
3435 return
3436 keyRange == null // occurs if we're doing a sort (PersistitSorter)
3437- ? new IndexCursorUnidirectional<>(context, bindings, iterationHelper, ordering, sortKeyAdapter)
3438- : new IndexCursorUnidirectional<>(context, bindings, iterationHelper, keyRange, ordering, sortKeyAdapter);
3439+ ? new IndexCursorUnidirectional<>(context, iterationHelper, ordering, sortKeyAdapter)
3440+ : new IndexCursorUnidirectional<>(context, iterationHelper, keyRange, ordering, sortKeyAdapter);
3441 }
3442
3443 // For use by this subclasses
3444
3445 protected IndexCursorUnidirectional(QueryContext context,
3446- QueryBindings bindings,
3447 IterationHelper iterationHelper,
3448 IndexKeyRange keyRange,
3449 API.Ordering ordering,
3450 SortKeyAdapter<S, ?> sortKeyAdapter)
3451 {
3452- super(context, bindings, iterationHelper);
3453+ super(context, iterationHelper);
3454 // end state never changes. start state can change on a jump, so it is set in initializeCursor.
3455 this.endBoundColumns = keyRange.boundColumns();
3456 this.endKey = endBoundColumns == 0 ? null : adapter.takeIndexRow(keyRange.indexRowType());
3457@@ -483,12 +480,11 @@
3458 }
3459
3460 private IndexCursorUnidirectional(QueryContext context,
3461- QueryBindings bindings,
3462 IterationHelper iterationHelper,
3463 API.Ordering ordering,
3464 SortKeyAdapter<S, ?> sortKeyAdapter)
3465 {
3466- super(context, bindings, iterationHelper);
3467+ super(context, iterationHelper);
3468 this.keyRange = null;
3469 this.ordering = ordering;
3470 if (ordering.allAscending()) {
3471
3472=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectionalLexicographic.java'
3473--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectionalLexicographic.java 2013-07-08 18:56:18 +0000
3474+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/IndexCursorUnidirectionalLexicographic.java 2013-07-10 21:47:26 +0000
3475@@ -20,7 +20,6 @@
3476 import com.akiban.qp.expression.BoundExpressions;
3477 import com.akiban.qp.expression.IndexKeyRange;
3478 import com.akiban.qp.operator.API;
3479-import com.akiban.qp.operator.QueryBindings;
3480 import com.akiban.qp.operator.QueryContext;
3481 import com.persistit.Key;
3482
3483@@ -31,25 +30,23 @@
3484 // IndexCursorUnidirectional interface
3485
3486 public static <S> IndexCursorUnidirectionalLexicographic<S> create(QueryContext context,
3487- QueryBindings bindings,
3488 IterationHelper iterationHelper,
3489 IndexKeyRange keyRange,
3490 API.Ordering ordering,
3491 SortKeyAdapter<S, ?> sortKeyAdapter)
3492 {
3493- return new IndexCursorUnidirectionalLexicographic<>(context, bindings, iterationHelper, keyRange, ordering, sortKeyAdapter);
3494+ return new IndexCursorUnidirectionalLexicographic<>(context, iterationHelper, keyRange, ordering, sortKeyAdapter);
3495 }
3496
3497 // For use by this class
3498
3499 private IndexCursorUnidirectionalLexicographic(QueryContext context,
3500- QueryBindings bindings,
3501 IterationHelper iterationHelper,
3502 IndexKeyRange keyRange,
3503 API.Ordering ordering,
3504 SortKeyAdapter<S, ?> sortKeyAdapter)
3505 {
3506- super(context, bindings, iterationHelper, keyRange, ordering, sortKeyAdapter);
3507+ super(context, iterationHelper, keyRange, ordering, sortKeyAdapter);
3508 }
3509
3510 @Override
3511
3512=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/MemorySorter.java'
3513--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/MemorySorter.java 2013-07-08 18:16:50 +0000
3514+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/MemorySorter.java 2013-07-10 21:47:26 +0000
3515@@ -18,7 +18,7 @@
3516 package com.akiban.qp.persistitadapter.indexcursor;
3517
3518 import com.akiban.qp.operator.API;
3519-import com.akiban.qp.operator.Cursor;
3520+import com.akiban.qp.operator.RowCursor;
3521 import com.akiban.qp.operator.CursorLifecycle;
3522 import com.akiban.qp.operator.QueryBindings;
3523 import com.akiban.qp.operator.QueryContext;
3524@@ -75,7 +75,7 @@
3525
3526 private final QueryContext context;
3527 private final QueryBindings bindings;
3528- private final Cursor input;
3529+ private final RowCursor input;
3530 private final API.Ordering ordering;
3531 private final Key key;
3532 private final InOutTap loadTap;
3533@@ -83,7 +83,7 @@
3534
3535 public MemorySorter(QueryContext context,
3536 QueryBindings bindings,
3537- Cursor input,
3538+ RowCursor input,
3539 RowType rowType,
3540 API.Ordering ordering,
3541 API.SortOption sortOption,
3542@@ -114,7 +114,7 @@
3543 }
3544
3545 @Override
3546- public Cursor sort() {
3547+ public RowCursor sort() {
3548 loadMap();
3549 return new CollectionCursor(navigableMap.values());
3550 }
3551@@ -181,7 +181,7 @@
3552 return states;
3553 }
3554
3555- private static final class CollectionCursor implements Cursor {
3556+ private static final class CollectionCursor implements RowCursor {
3557 private final Collection<Row> collection;
3558 private boolean isIdle = true;
3559 private boolean isDestroyed = false;
3560
3561=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexcursor/PersistitSorter.java'
3562--- src/main/java/com/akiban/qp/persistitadapter/indexcursor/PersistitSorter.java 2013-07-08 18:16:50 +0000
3563+++ src/main/java/com/akiban/qp/persistitadapter/indexcursor/PersistitSorter.java 2013-07-10 21:47:26 +0000
3564@@ -18,7 +18,7 @@
3565 package com.akiban.qp.persistitadapter.indexcursor;
3566
3567 import com.akiban.qp.operator.API;
3568-import com.akiban.qp.operator.Cursor;
3569+import com.akiban.qp.operator.RowCursor;
3570 import com.akiban.qp.operator.QueryBindings;
3571 import com.akiban.qp.operator.QueryContext;
3572 import com.akiban.qp.persistitadapter.PersistitAdapter;
3573@@ -67,7 +67,7 @@
3574 {
3575 public PersistitSorter(QueryContext context,
3576 QueryBindings bindings,
3577- Cursor input,
3578+ RowCursor input,
3579 RowType rowType,
3580 API.Ordering ordering,
3581 API.SortOption sortOption,
3582@@ -95,7 +95,7 @@
3583 }
3584
3585 @Override
3586- public Cursor sort()
3587+ public RowCursor sort()
3588 {
3589 loadTree();
3590 return cursor();
3591@@ -144,10 +144,12 @@
3592 }
3593 }
3594
3595- private Cursor cursor()
3596+ private RowCursor cursor()
3597 {
3598 exchange.clear();
3599- return IndexCursor.create(context, bindings, null, ordering, iterationHelper, usePValues);
3600+ IndexCursor indexCursor = IndexCursor.create(context, null, ordering, iterationHelper, usePValues);
3601+ indexCursor.rebind(bindings);
3602+ return indexCursor;
3603 }
3604
3605 private void createKey(Row row)
3606@@ -188,7 +190,7 @@
3607 // Object state
3608
3609 final PersistitAdapter adapter;
3610- final Cursor input;
3611+ final RowCursor input;
3612 final RowType rowType;
3613 final API.Ordering ordering;
3614 final QueryContext context;
3615
3616=== modified file 'src/main/java/com/akiban/qp/util/MultiCursor.java'
3617--- src/main/java/com/akiban/qp/util/MultiCursor.java 2013-03-22 20:05:57 +0000
3618+++ src/main/java/com/akiban/qp/util/MultiCursor.java 2013-07-10 21:47:26 +0000
3619@@ -17,7 +17,9 @@
3620
3621 package com.akiban.qp.util;
3622
3623-import com.akiban.qp.operator.Cursor;
3624+import com.akiban.qp.operator.BindingsAwareCursor;
3625+import com.akiban.qp.operator.QueryBindings;
3626+import com.akiban.qp.operator.RowCursor;
3627 import com.akiban.qp.row.Row;
3628 import com.akiban.server.api.dml.ColumnSelector;
3629
3630@@ -25,7 +27,7 @@
3631 import java.util.Iterator;
3632 import java.util.List;
3633
3634-public class MultiCursor implements Cursor
3635+public class MultiCursor implements BindingsAwareCursor
3636 {
3637 // Cursor interface
3638
3639@@ -33,6 +35,8 @@
3640 public void open()
3641 {
3642 sealed = false;
3643+ // TODO: Have a mode where all the cursors get opened so that
3644+ // they can start in parallel.
3645 cursorIterator = cursors.iterator();
3646 startNextCursor();
3647 }
3648@@ -93,9 +97,19 @@
3649 return cursorIterator == null;
3650 }
3651
3652+ @Override
3653+ public void rebind(QueryBindings bindings)
3654+ {
3655+ for (RowCursor cursor : cursors) {
3656+ if (cursor instanceof BindingsAwareCursor) {
3657+ ((BindingsAwareCursor)cursor).rebind(bindings);
3658+ }
3659+ }
3660+ }
3661+
3662 // MultiCursor interface
3663
3664- public void addCursor(Cursor cursor)
3665+ public void addCursor(RowCursor cursor)
3666 {
3667 if (sealed) {
3668 throw new IllegalStateException();
3669@@ -120,9 +134,9 @@
3670
3671 // Object state
3672
3673- private final List<Cursor> cursors = new ArrayList<>();
3674+ private final List<RowCursor> cursors = new ArrayList<>();
3675 private boolean sealed = false;
3676- private Iterator<Cursor> cursorIterator;
3677- private Cursor current;
3678+ private Iterator<RowCursor> cursorIterator;
3679+ private RowCursor current;
3680
3681 }
3682
3683=== modified file 'src/main/java/com/akiban/server/expression/subquery/ResultSetSubqueryExpression.java'
3684--- src/main/java/com/akiban/server/expression/subquery/ResultSetSubqueryExpression.java 2013-07-05 21:35:32 +0000
3685+++ src/main/java/com/akiban/server/expression/subquery/ResultSetSubqueryExpression.java 2013-07-10 21:47:26 +0000
3686@@ -83,7 +83,7 @@
3687 public ValueSource eval() {
3688 bindings.setRow(bindingPosition, outerRow);
3689 Cursor cursor = API.cursor(subquery, context, bindings);
3690- cursor.open();
3691+ cursor.openTopLevel();
3692 return new ValueHolder(AkType.RESULT_SET, cursor);
3693 }
3694
3695
3696=== modified file 'src/main/java/com/akiban/server/expression/subquery/SubqueryExpressionEvaluation.java'
3697--- src/main/java/com/akiban/server/expression/subquery/SubqueryExpressionEvaluation.java 2013-07-08 19:23:25 +0000
3698+++ src/main/java/com/akiban/server/expression/subquery/SubqueryExpressionEvaluation.java 2013-07-10 21:47:26 +0000
3699@@ -56,12 +56,12 @@
3700 if (cursor == null) {
3701 cursor = API.cursor(subquery, context, bindings);
3702 }
3703- cursor.open();
3704+ cursor.openTopLevel();
3705 try {
3706 return doEval();
3707 }
3708 finally {
3709- cursor.close();
3710+ cursor.closeTopLevel();
3711 }
3712 }
3713
3714
3715=== modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java'
3716--- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-07-10 18:04:32 +0000
3717+++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-07-10 21:47:26 +0000
3718@@ -310,14 +310,14 @@
3719 );
3720 com.akiban.qp.operator.Cursor cursor = API.cursor(plan, queryContext, queryBindings);
3721
3722- cursor.open();
3723+ cursor.openTopLevel();
3724 try {
3725 Row oldRow;
3726 while((oldRow = cursor.next()) != null) {
3727 checker.checkConstraints(oldRow, Types3Switch.ON);
3728 }
3729 } finally {
3730- cursor.close();
3731+ cursor.closeTopLevel();
3732 }
3733 }
3734 schemaManager().alterTableDefinitions(session, changedTables);
3735@@ -487,7 +487,7 @@
3736 for(UserTable root : roots) {
3737 Operator plan = groupScan_Default(root.getGroup());
3738 com.akiban.qp.operator.Cursor cursor = API.cursor(plan, queryContext, queryBindings);
3739- cursor.open();
3740+ cursor.openTopLevel();
3741 try {
3742 Row oldRow;
3743 while((oldRow = cursor.next()) != null) {
3744@@ -512,7 +512,7 @@
3745 adapter.writeRow(newRow, indexes, usePValues);
3746 }
3747 } finally {
3748- cursor.close();
3749+ cursor.closeTopLevel();
3750 }
3751 }
3752
3753
3754=== modified file 'src/main/java/com/akiban/server/service/externaldata/JsonRowWriter.java'
3755--- src/main/java/com/akiban/server/service/externaldata/JsonRowWriter.java 2013-03-25 23:55:33 +0000
3756+++ src/main/java/com/akiban/server/service/externaldata/JsonRowWriter.java 2013-07-10 21:47:26 +0000
3757@@ -20,6 +20,7 @@
3758 import com.akiban.ais.model.Column;
3759 import com.akiban.ais.model.IndexColumn;
3760 import com.akiban.qp.operator.Cursor;
3761+import com.akiban.qp.operator.RowCursor;
3762 import com.akiban.qp.row.Row;
3763 import com.akiban.server.types3.pvalue.PValueSource;
3764 import com.akiban.util.AkibanAppender;
3765@@ -42,7 +43,16 @@
3766 }
3767
3768 public boolean writeRows(Cursor cursor, AkibanAppender appender, String prefix, WriteRow rowWriter) {
3769- cursor.open();
3770+ try {
3771+ cursor.openTopLevel();
3772+ return writeRowsFromOpenCursor(cursor, appender, prefix, rowWriter);
3773+ }
3774+ finally {
3775+ cursor.closeTopLevel();
3776+ }
3777+ }
3778+
3779+ public boolean writeRowsFromOpenCursor(RowCursor cursor, AkibanAppender appender, String prefix, WriteRow rowWriter) {
3780 tracker.reset();
3781 final int minDepth = tracker.getMinDepth();
3782 final int maxDepth = tracker.getMaxDepth();
3783@@ -81,7 +91,6 @@
3784 appender.append('{');
3785 rowWriter.write(row, appender);
3786 }
3787- cursor.close();
3788 if (depth < minDepth)
3789 return false; // Cursor was empty = not found.
3790 do {
3791
3792=== modified file 'src/main/java/com/akiban/server/service/restdml/DeleteProcessor.java'
3793--- src/main/java/com/akiban/server/service/restdml/DeleteProcessor.java 2013-07-05 21:35:32 +0000
3794+++ src/main/java/com/akiban/server/service/restdml/DeleteProcessor.java 2013-07-10 21:47:26 +0000
3795@@ -28,6 +28,7 @@
3796 import com.akiban.qp.operator.API;
3797 import com.akiban.qp.operator.Cursor;
3798 import com.akiban.qp.operator.Operator;
3799+import com.akiban.qp.operator.QueryBindings;
3800 import com.akiban.qp.row.Row;
3801 import com.akiban.server.service.session.Session;
3802 import com.akiban.server.store.Store;
3803@@ -76,14 +77,14 @@
3804 context.queryBindings.setPValue(i, pvalue);
3805 }
3806
3807- cursor.open();
3808+ cursor.openTopLevel();
3809 Row row;
3810 while ((row = cursor.next()) != null) {
3811 // Do Nothing - the act of reading the cursor
3812 // does the delete row processing.
3813 // TODO: Check that we got 1 row through.
3814 }
3815- cursor.close();
3816+ cursor.closeTopLevel();
3817 }
3818 } finally {
3819 if (cursor != null)
3820
3821=== modified file 'src/main/java/com/akiban/server/service/restdml/ModelBuilder.java'
3822--- src/main/java/com/akiban/server/service/restdml/ModelBuilder.java 2013-07-08 16:06:08 +0000
3823+++ src/main/java/com/akiban/server/service/restdml/ModelBuilder.java 2013-07-10 21:47:26 +0000
3824@@ -204,7 +204,7 @@
3825 int convertedRows = 0;
3826 try(CloseableTransaction txn = txnService.beginCloseableTransaction(session)) {
3827 Cursor cursor = groupScanCursor(session, tempName);
3828- cursor.open();
3829+ cursor.openTopLevel();
3830 try {
3831 while((row = cursor.next()) != null) {
3832 node = (ObjectNode)JsonUtils.readTree(row.pvalue(1).getString());
3833@@ -213,7 +213,7 @@
3834 restDMLService.insertNoTxn(session, null, tableName, node);
3835 ++convertedRows;
3836 }
3837- cursor.close();
3838+ cursor.closeTopLevel();
3839 } finally {
3840 cursor.destroy();
3841 }
3842@@ -311,7 +311,7 @@
3843 QueryContext queryContext = new SimpleQueryContext(adapter);
3844 QueryBindings queryBindings = queryContext.createBindings();
3845 Cursor cursor = API.cursor(plan, queryContext, queryBindings);
3846- cursor.open();
3847+ cursor.openTopLevel();
3848 try {
3849 return cursor.next();
3850 } finally {
3851@@ -334,7 +334,7 @@
3852
3853 private boolean scanCursor(PrintWriter writer, Cursor cursor, boolean first) throws IOException {
3854 Row row;
3855- cursor.open();
3856+ cursor.openTopLevel();
3857 try {
3858 while((row = cursor.next()) != null) {
3859 if(!first) {
3860@@ -348,7 +348,7 @@
3861 writer.write(node.toString());
3862 }
3863 } finally {
3864- cursor.close();
3865+ cursor.closeTopLevel();
3866 }
3867 return first;
3868 }
3869
3870=== modified file 'src/main/java/com/akiban/server/service/restdml/RestDMLServiceImpl.java'
3871--- src/main/java/com/akiban/server/service/restdml/RestDMLServiceImpl.java 2013-07-10 16:12:59 +0000
3872+++ src/main/java/com/akiban/server/service/restdml/RestDMLServiceImpl.java 2013-07-10 21:47:26 +0000
3873@@ -614,9 +614,10 @@
3874 private static void collectResults(JDBCResultSet resultSet, AkibanAppender appender) throws SQLException {
3875 SQLOutputCursor cursor = new SQLOutputCursor(resultSet);
3876 JsonRowWriter jsonRowWriter = new JsonRowWriter(cursor);
3877- if(jsonRowWriter.writeRows(cursor, appender, "\n", cursor)) {
3878+ if(jsonRowWriter.writeRowsFromOpenCursor(cursor, appender, "\n", cursor)) {
3879 appender.append('\n');
3880 }
3881+ cursor.close();
3882 }
3883
3884 private JDBCConnection jdbcConnection(HttpServletRequest request) throws SQLException {
3885
3886=== modified file 'src/main/java/com/akiban/server/service/restdml/SQLOutputCursor.java'
3887--- src/main/java/com/akiban/server/service/restdml/SQLOutputCursor.java 2013-03-22 20:05:57 +0000
3888+++ src/main/java/com/akiban/server/service/restdml/SQLOutputCursor.java 2013-07-10 21:47:26 +0000
3889@@ -17,7 +17,7 @@
3890
3891 package com.akiban.server.service.restdml;
3892
3893-import com.akiban.qp.operator.Cursor;
3894+import com.akiban.qp.operator.RowCursor;
3895 import com.akiban.qp.row.DelegateRow;
3896 import com.akiban.qp.row.Row;
3897 import com.akiban.server.api.dml.ColumnSelector;
3898@@ -32,7 +32,7 @@
3899 import java.util.ArrayDeque;
3900 import java.util.Deque;
3901
3902-public class SQLOutputCursor extends GenericRowTracker implements Cursor, JsonRowWriter.WriteRow {
3903+public class SQLOutputCursor extends GenericRowTracker implements RowCursor, JsonRowWriter.WriteRow {
3904 private final Deque<ResultSetHolder> holderStack = new ArrayDeque<>();
3905 private ResultSetHolder currentHolder;
3906
3907
3908=== modified file 'src/main/java/com/akiban/server/service/restdml/UpsertProcessor.java'
3909--- src/main/java/com/akiban/server/service/restdml/UpsertProcessor.java 2013-07-05 21:35:32 +0000
3910+++ src/main/java/com/akiban/server/service/restdml/UpsertProcessor.java 2013-07-10 21:47:26 +0000
3911@@ -155,7 +155,7 @@
3912 i++;
3913 }
3914 cursor = API.cursor(plan, context.queryContext, context.queryBindings);
3915- cursor.open();
3916+ cursor.openTopLevel();
3917 return cursor.next();
3918 } finally {
3919 if (cursor != null) {
3920
3921=== modified file 'src/main/java/com/akiban/server/service/text/FullTextCursor.java'
3922--- src/main/java/com/akiban/server/service/text/FullTextCursor.java 2013-04-25 17:04:25 +0000
3923+++ src/main/java/com/akiban/server/service/text/FullTextCursor.java 2013-07-10 21:47:26 +0000
3924@@ -17,7 +17,7 @@
3925
3926 package com.akiban.server.service.text;
3927
3928-import com.akiban.qp.operator.Cursor;
3929+import com.akiban.qp.operator.RowCursor;
3930 import com.akiban.qp.operator.CursorLifecycle;
3931 import com.akiban.qp.operator.QueryContext;
3932 import com.akiban.qp.persistitadapter.PersistitHKey;
3933@@ -45,7 +45,7 @@
3934
3935 import java.io.IOException;
3936
3937-public class FullTextCursor implements Cursor
3938+public class FullTextCursor implements RowCursor
3939 {
3940 private final QueryContext context;
3941 private final HKeyRowType rowType;
3942
3943=== modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexService.java'
3944--- src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-07-10 16:12:59 +0000
3945+++ src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-07-10 21:47:26 +0000
3946@@ -18,7 +18,7 @@
3947 package com.akiban.server.service.text;
3948
3949 import com.akiban.ais.model.IndexName;
3950-import com.akiban.qp.operator.Cursor;
3951+import com.akiban.qp.operator.RowCursor;
3952 import com.akiban.qp.operator.QueryContext;
3953 import com.akiban.server.service.BackgroundWork;
3954
3955@@ -32,5 +32,6 @@
3956 */
3957 public List<? extends BackgroundWork> getBackgroundWorks();
3958
3959- public Cursor searchIndex(QueryContext context, IndexName name, Query query, int limit);
3960+ public RowCursor searchIndex(QueryContext context, IndexName name,
3961+ Query query, int limit);
3962 }
3963
3964=== modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java'
3965--- src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-07-10 18:04:32 +0000
3966+++ src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-07-10 21:47:26 +0000
3967@@ -31,6 +31,7 @@
3968 import com.akiban.qp.operator.Operator;
3969 import com.akiban.qp.operator.QueryBindings;
3970 import com.akiban.qp.operator.QueryContext;
3971+import com.akiban.qp.operator.RowCursor;
3972 import com.akiban.qp.operator.SimpleQueryContext;
3973 import com.akiban.qp.operator.StoreAdapter;
3974 import com.akiban.qp.persistitadapter.PersistitAdapter;
3975@@ -177,7 +178,7 @@
3976 }
3977
3978 @Override
3979- public Cursor searchIndex(QueryContext context, IndexName name, Query query, int limit) {
3980+ public RowCursor searchIndex(QueryContext context, IndexName name, Query query, int limit) {
3981 FullTextIndexInfo index = getIndex(context.getSession(), name, null);
3982 try {
3983 return index.getSearcher().search(context, index.getHKeyRowType(),
3984@@ -266,7 +267,6 @@
3985 }
3986 finally {
3987 if(cursor != null) {
3988- cursor.close();
3989 cursor.destroy();
3990 }
3991 if(!success) {
3992@@ -308,7 +308,6 @@
3993 finally
3994 {
3995 if(cursor != null) {
3996- cursor.close();
3997 cursor.destroy();
3998 }
3999 if(!success) {
4000
4001=== modified file 'src/main/java/com/akiban/server/service/text/FullTextQueryBuilder.java'
4002--- src/main/java/com/akiban/server/service/text/FullTextQueryBuilder.java 2013-07-08 18:56:18 +0000
4003+++ src/main/java/com/akiban/server/service/text/FullTextQueryBuilder.java 2013-07-10 21:47:26 +0000
4004@@ -104,6 +104,11 @@
4005 }
4006
4007 @Override
4008+ public boolean needsBindings() {
4009+ return false;
4010+ }
4011+
4012+ @Override
4013 public Query getQuery(QueryContext context, QueryBindings bindings) {
4014 return query;
4015 }
4016@@ -138,6 +143,11 @@
4017 }
4018 return new FullTextQueryExpression() {
4019 @Override
4020+ public boolean needsBindings() {
4021+ return false;
4022+ }
4023+
4024+ @Override
4025 public Query getQuery(QueryContext context, QueryBindings bindings) {
4026 return infos.parseQuery(context, indexName, fieldName, query);
4027 }
4028@@ -161,6 +171,11 @@
4029 final String fieldName = (defaultField == null) ? null : defaultField.getColumn().getName();
4030 return new FullTextQueryExpression() {
4031 @Override
4032+ public boolean needsBindings() {
4033+ return true;
4034+ }
4035+
4036+ @Override
4037 public Query getQuery(QueryContext context, QueryBindings bindings) {
4038 TEvaluatableExpression qeval = qexpr.build();
4039 qeval.with(context);
4040@@ -197,6 +212,11 @@
4041 final String fieldName = checkFieldForMatch(field);
4042 return new FullTextQueryExpression() {
4043 @Override
4044+ public boolean needsBindings() {
4045+ return true;
4046+ }
4047+
4048+ @Override
4049 public Query getQuery(QueryContext context, QueryBindings bindings) {
4050 TEvaluatableExpression qeval = qexpr.build();
4051 qeval.with(context);
4052@@ -246,6 +266,16 @@
4053 FullTextQueryExpression result =
4054 new FullTextQueryExpression() {
4055 @Override
4056+ public boolean needsBindings() {
4057+ for (FullTextQueryExpression query : queries) {
4058+ if (query.needsBindings()) {
4059+ return true;
4060+ }
4061+ }
4062+ return false;
4063+ }
4064+
4065+ @Override
4066 public Query getQuery(QueryContext context, QueryBindings bindings) {
4067 BooleanQuery query = new BooleanQuery();
4068 for (int i = 0; i < queries.size(); i++) {
4069
4070=== modified file 'src/main/java/com/akiban/server/service/text/FullTextQueryExpression.java'
4071--- src/main/java/com/akiban/server/service/text/FullTextQueryExpression.java 2013-07-08 18:56:18 +0000
4072+++ src/main/java/com/akiban/server/service/text/FullTextQueryExpression.java 2013-07-10 21:47:26 +0000
4073@@ -27,5 +27,6 @@
4074 * parsed from a string, or built up from expressions.
4075 */
4076 public interface FullTextQueryExpression extends Explainable {
4077+ public boolean needsBindings();
4078 public Query getQuery(QueryContext context, QueryBindings bindings);
4079 }
4080
4081=== modified file 'src/main/java/com/akiban/server/service/text/IndexScan_FullText.java'
4082--- src/main/java/com/akiban/server/service/text/IndexScan_FullText.java 2013-07-08 18:56:18 +0000
4083+++ src/main/java/com/akiban/server/service/text/IndexScan_FullText.java 2013-07-10 21:47:26 +0000
4084@@ -19,10 +19,14 @@
4085
4086 import com.akiban.ais.model.IndexName;
4087 import com.akiban.qp.operator.Cursor;
4088+import com.akiban.qp.operator.LeafCursor;
4089 import com.akiban.qp.operator.Operator;
4090-import com.akiban.qp.operator.QueryBindings;
4091+import com.akiban.qp.operator.QueryBindingsCursor;
4092 import com.akiban.qp.operator.QueryContext;
4093+import com.akiban.qp.operator.RowCursor;
4094+import com.akiban.qp.row.Row;
4095 import com.akiban.qp.rowtype.RowType;
4096+import com.akiban.server.api.dml.ColumnSelector;
4097 import com.akiban.server.explain.*;
4098
4099 import org.apache.lucene.search.Query;
4100@@ -53,12 +57,91 @@
4101 }
4102
4103 @Override
4104- protected Cursor cursor(QueryContext context, QueryBindings bindings) {
4105- Query query = queryExpression.getQuery(context, bindings);
4106- FullTextIndexService service = context.getServiceManager().getServiceByClass(FullTextIndexService.class);
4107- return service.searchIndex(context, index, query, limit);
4108+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
4109+ return new Execution(context, bindingsCursor);
4110 }
4111
4112+ protected class Execution extends LeafCursor {
4113+ private final FullTextIndexService service;
4114+ private RowCursor cursor;
4115+ private boolean destroyed;
4116+
4117+ public Execution(QueryContext context, QueryBindingsCursor bindingsCursor) {
4118+ super(context, bindingsCursor);
4119+ service = context.getServiceManager().getServiceByClass(FullTextIndexService.class);
4120+ if (!queryExpression.needsBindings()) {
4121+ // Can reuse cursor if it doesn't need bindings at open() time.
4122+ Query query = queryExpression.getQuery(context, null);
4123+ cursor = service.searchIndex(context, index, query, limit);
4124+ }
4125+ }
4126+
4127+ @Override
4128+ public void open()
4129+ {
4130+ if (queryExpression.needsBindings()) {
4131+ Query query = queryExpression.getQuery(context, bindings);
4132+ cursor = service.searchIndex(context, index, query, limit);
4133+ }
4134+ cursor.open();
4135+ }
4136+
4137+ @Override
4138+ public Row next()
4139+ {
4140+ checkQueryCancelation();
4141+ return cursor.next();
4142+ }
4143+
4144+ @Override
4145+ public void jump(Row row, ColumnSelector columnSelector)
4146+ {
4147+ cursor.jump(row, columnSelector);
4148+ }
4149+
4150+ @Override
4151+ public void close()
4152+ {
4153+ if (cursor != null) {
4154+ if (queryExpression.needsBindings()) {
4155+ cursor.destroy();
4156+ cursor = null;
4157+ }
4158+ else {
4159+ cursor.close();
4160+ }
4161+ }
4162+ }
4163+
4164+ @Override
4165+ public void destroy()
4166+ {
4167+ if (cursor != null) {
4168+ cursor.destroy();
4169+ cursor = null;
4170+ }
4171+ destroyed = true;
4172+ }
4173+
4174+ @Override
4175+ public boolean isIdle()
4176+ {
4177+ return (cursor == null) ? !destroyed : cursor.isIdle();
4178+ }
4179+
4180+ @Override
4181+ public boolean isActive()
4182+ {
4183+ return (cursor != null) && cursor.isActive();
4184+ }
4185+
4186+ @Override
4187+ public boolean isDestroyed()
4188+ {
4189+ return destroyed;
4190+ }
4191+ }
4192+
4193 @Override
4194 public CompoundExplainer getExplainer(ExplainContext context)
4195 {
4196
4197=== modified file 'src/main/java/com/akiban/server/service/text/RowIndexer.java'
4198--- src/main/java/com/akiban/server/service/text/RowIndexer.java 2013-07-02 19:16:02 +0000
4199+++ src/main/java/com/akiban/server/service/text/RowIndexer.java 2013-07-10 21:47:26 +0000
4200@@ -124,13 +124,13 @@
4201
4202 public long indexRows(Cursor cursor) throws IOException {
4203 documentCount = 0;
4204- cursor.open();
4205+ cursor.openTopLevel();
4206 Row row;
4207 do {
4208 row = cursor.next();
4209 indexRow(row);
4210 } while (row != null);
4211- cursor.close();
4212+ cursor.closeTopLevel();
4213 return documentCount;
4214 }
4215
4216
4217=== modified file 'src/main/java/com/akiban/server/service/text/Searcher.java'
4218--- src/main/java/com/akiban/server/service/text/Searcher.java 2013-03-22 20:05:57 +0000
4219+++ src/main/java/com/akiban/server/service/text/Searcher.java 2013-07-10 21:47:26 +0000
4220@@ -17,7 +17,7 @@
4221
4222 package com.akiban.server.service.text;
4223
4224-import com.akiban.qp.operator.Cursor;
4225+import com.akiban.qp.operator.RowCursor;
4226 import com.akiban.qp.operator.QueryContext;
4227 import com.akiban.qp.rowtype.HKeyRowType;
4228
4229@@ -45,8 +45,8 @@
4230 this.searcherManager = new SearcherManager(index.open(), new SearcherFactory());
4231 }
4232
4233- public Cursor search(QueryContext context, HKeyRowType rowType,
4234- Query query, int limit)
4235+ public RowCursor search(QueryContext context, HKeyRowType rowType,
4236+ Query query, int limit)
4237 throws IOException {
4238 searcherManager.maybeRefresh(); // TODO: Move to better place.
4239 if (limit <= 0) limit = DEFAULT_LIMIT;
4240
4241=== modified file 'src/main/java/com/akiban/server/store/AbstractStore.java'
4242--- src/main/java/com/akiban/server/store/AbstractStore.java 2013-07-10 18:04:32 +0000
4243+++ src/main/java/com/akiban/server/store/AbstractStore.java 2013-07-10 21:47:26 +0000
4244@@ -35,6 +35,7 @@
4245 import com.akiban.qp.operator.GroupCursor;
4246 import com.akiban.qp.operator.Operator;
4247 import com.akiban.qp.operator.QueryBindings;
4248+import com.akiban.qp.operator.QueryBindingsCursor;
4249 import com.akiban.qp.operator.QueryContext;
4250 import com.akiban.qp.operator.SimpleQueryContext;
4251 import com.akiban.qp.operator.StoreAdapter;
4252@@ -1217,7 +1218,7 @@
4253 }
4254 try {
4255 Row row;
4256- cursor.open();
4257+ cursor.openTopLevel();
4258 while((row = cursor.next()) != null) {
4259 UserTable table = row.rowType().userTable();
4260 RowData data = adapter.rowData(table.rowDef(), row, new PValueRowDataCreator());
4261@@ -1229,7 +1230,7 @@
4262 StoreGIHandler.forTable(this, adapter, uTable),
4263 StoreGIHandler.Action.CASCADE);
4264 }
4265- cursor.close();
4266+ cursor.closeTopLevel();
4267 } finally {
4268 cursor.destroy();
4269 }
4270@@ -1308,7 +1309,7 @@
4271 StoreGIHandler handler,
4272 StoreGIHandler.Action action) {
4273 Cursor cursor = API.cursor(rootOperator, context, bindings);
4274- cursor.open();
4275+ cursor.openTopLevel();
4276 try {
4277 Row row;
4278 while((row = cursor.next()) != null) {
4279@@ -1316,6 +1317,7 @@
4280 handler.handleRow(groupIndex, row, action);
4281 }
4282 }
4283+ cursor.closeTopLevel();
4284 } finally {
4285 cursor.destroy();
4286 }
4287
4288=== modified file 'src/main/java/com/akiban/server/store/StoreGIMaintenance.java'
4289--- src/main/java/com/akiban/server/store/StoreGIMaintenance.java 2013-07-08 16:06:08 +0000
4290+++ src/main/java/com/akiban/server/store/StoreGIMaintenance.java 2013-07-10 21:47:26 +0000
4291@@ -87,7 +87,7 @@
4292 cursor = API.cursor(planOperator, context, bindings);
4293 RUN_TAP.in();
4294 runTapEntered = true;
4295- cursor.open();
4296+ cursor.openTopLevel();
4297 Row row;
4298 while ((row = cursor.next()) != null) {
4299 boolean actioned = false;
4300@@ -160,7 +160,7 @@
4301 Cursor siblingsCounter = API.cursor(siblingsLookup, context, bindings);
4302 SIBLING_ALL_TAP.in();
4303 try {
4304- siblingsCounter.open();
4305+ siblingsCounter.openTopLevel();
4306 int siblings = 0;
4307 while (siblingsCounter.next() != null) {
4308 SIBLING_ROW_TAP.hit();
4309
4310=== modified file 'src/main/java/com/akiban/server/types3/texpressions/ResultSetSubqueryTExpression.java'
4311--- src/main/java/com/akiban/server/types3/texpressions/ResultSetSubqueryTExpression.java 2013-07-05 21:35:32 +0000
4312+++ src/main/java/com/akiban/server/types3/texpressions/ResultSetSubqueryTExpression.java 2013-07-10 21:47:26 +0000
4313@@ -42,7 +42,7 @@
4314 public void evaluate() {
4315 bindings.setRow(bindingPosition, outerRow);
4316 Cursor cursor = API.cursor(subquery, context, bindings);
4317- cursor.open();
4318+ cursor.openTopLevel();
4319 pvalue.putObject(cursor);
4320 }
4321
4322
4323=== modified file 'src/main/java/com/akiban/server/types3/texpressions/SubqueryTEvaluateble.java'
4324--- src/main/java/com/akiban/server/types3/texpressions/SubqueryTEvaluateble.java 2013-07-08 18:56:18 +0000
4325+++ src/main/java/com/akiban/server/types3/texpressions/SubqueryTEvaluateble.java 2013-07-10 21:47:26 +0000
4326@@ -43,12 +43,12 @@
4327 if (cursor == null) {
4328 cursor = API.cursor(subquery, context, bindings);
4329 }
4330- cursor.open();
4331+ cursor.openTopLevel();
4332 try {
4333 doEval(pvalue);
4334 }
4335 finally {
4336- cursor.close();
4337+ cursor.closeTopLevel();
4338 }
4339 }
4340
4341
4342=== modified file 'src/main/java/com/akiban/sql/embedded/ExecutableModifyOperatorStatement.java'
4343--- src/main/java/com/akiban/sql/embedded/ExecutableModifyOperatorStatement.java 2013-07-05 21:35:32 +0000
4344+++ src/main/java/com/akiban/sql/embedded/ExecutableModifyOperatorStatement.java 2013-07-10 21:47:26 +0000
4345@@ -22,6 +22,7 @@
4346 import com.akiban.qp.operator.CursorLifecycle;
4347 import com.akiban.qp.operator.Operator;
4348 import com.akiban.qp.operator.QueryBindings;
4349+import com.akiban.qp.operator.RowCursor;
4350 import com.akiban.qp.row.ImmutableRow;
4351 import com.akiban.qp.row.ProjectedRow;
4352 import com.akiban.qp.row.Row;
4353@@ -54,7 +55,7 @@
4354 @Override
4355 public ExecuteResults execute(EmbeddedQueryContext context, QueryBindings bindings) {
4356 int updateCount = 0;
4357- SpoolCursor returningRows = null;
4358+ SpoolCursor returningRows = null;
4359 if (resultSetMetaData != null)
4360 // If there are results, we need to read them all now to get the update
4361 // count right and have this all happen even if the caller
4362@@ -65,7 +66,7 @@
4363 RuntimeException runtimeException = null;
4364 try {
4365 cursor = API.cursor(resultOperator, context, bindings);
4366- cursor.open();
4367+ cursor.openTopLevel();
4368 Row row;
4369 while ((row = cursor.next()) != null) {
4370 updateCount++;
4371@@ -116,7 +117,7 @@
4372 return AISGenerationMode.NOT_ALLOWED;
4373 }
4374
4375- static class SpoolCursor implements Cursor {
4376+ static class SpoolCursor implements RowCursor {
4377 private List<ShareHolder<Row>> rows = new ArrayList<>();
4378 private Iterator<ShareHolder<Row>> iterator;
4379 private enum State { CLOSED, FILLING, EMPTYING, DESTROYED }
4380
4381=== modified file 'src/main/java/com/akiban/sql/embedded/ExecutableQueryOperatorStatement.java'
4382--- src/main/java/com/akiban/sql/embedded/ExecutableQueryOperatorStatement.java 2013-07-05 21:35:32 +0000
4383+++ src/main/java/com/akiban/sql/embedded/ExecutableQueryOperatorStatement.java 2013-07-10 21:47:26 +0000
4384@@ -40,7 +40,7 @@
4385 Cursor cursor = null;
4386 try {
4387 cursor = API.cursor(resultOperator, context, bindings);
4388- cursor.open();
4389+ cursor.openTopLevel();
4390 ExecuteResults result = new ExecuteResults(cursor);
4391 cursor = null;
4392 return result;
4393
4394=== modified file 'src/main/java/com/akiban/sql/embedded/ExecuteResults.java'
4395--- src/main/java/com/akiban/sql/embedded/ExecuteResults.java 2013-03-22 20:05:57 +0000
4396+++ src/main/java/com/akiban/sql/embedded/ExecuteResults.java 2013-07-10 21:47:26 +0000
4397@@ -17,7 +17,7 @@
4398
4399 package com.akiban.sql.embedded;
4400
4401-import com.akiban.qp.operator.Cursor;
4402+import com.akiban.qp.operator.RowCursor;
4403
4404 import java.sql.ResultSet;
4405 import java.util.Queue;
4406@@ -25,7 +25,7 @@
4407 class ExecuteResults
4408 {
4409 private int updateCount;
4410- private Cursor cursor;
4411+ private RowCursor cursor;
4412 private Queue<ResultSet> additionalResultSets;
4413
4414 /** No results. */
4415@@ -36,7 +36,7 @@
4416 /** Ordinary select result.
4417 * Transaction remains open while it is visited.
4418 */
4419- public ExecuteResults(Cursor cursor) {
4420+ public ExecuteResults(RowCursor cursor) {
4421 this.updateCount = -1;
4422 this.cursor = cursor;
4423 }
4424@@ -44,7 +44,7 @@
4425 /** Update result, possibly with returned keys.
4426 * These keys are already copied in order to get update count correct.
4427 */
4428- public ExecuteResults(int updateCount, Cursor generatedKeys) {
4429+ public ExecuteResults(int updateCount, RowCursor generatedKeys) {
4430 this.updateCount = updateCount;
4431 this.cursor = generatedKeys;
4432 }
4433@@ -59,7 +59,7 @@
4434 return updateCount;
4435 }
4436
4437- public Cursor getCursor() {
4438+ public RowCursor getCursor() {
4439 return cursor;
4440 }
4441
4442
4443=== modified file 'src/main/java/com/akiban/sql/embedded/JDBCResultSet.java'
4444--- src/main/java/com/akiban/sql/embedded/JDBCResultSet.java 2013-04-24 19:15:51 +0000
4445+++ src/main/java/com/akiban/sql/embedded/JDBCResultSet.java 2013-07-10 21:47:26 +0000
4446@@ -29,7 +29,7 @@
4447 import com.akiban.direct.AbstractDirectObject;
4448 import com.akiban.direct.Direct;
4449 import com.akiban.direct.DirectResultSet;
4450-import com.akiban.qp.operator.Cursor;
4451+import com.akiban.qp.operator.RowCursor;
4452 import com.akiban.qp.row.Row;
4453 import com.akiban.server.types.AkType;
4454 import com.akiban.server.types.ValueSource;
4455@@ -42,14 +42,14 @@
4456 {
4457 protected final JDBCStatement statement;
4458 protected final JDBCResultSetMetaData metaData;
4459- protected Cursor cursor;
4460+ protected RowCursor cursor;
4461 protected Row row;
4462 private final EmbeddedQueryContext context;
4463 private final Values values;
4464 private JDBCWarning warnings;
4465
4466 protected JDBCResultSet(JDBCStatement statement, JDBCResultSetMetaData metaData,
4467- Cursor cursor) {
4468+ RowCursor cursor) {
4469 this.statement = statement;
4470 this.metaData = metaData;
4471 this.cursor = cursor;
4472@@ -100,7 +100,7 @@
4473 protected ResultSet toResultSet(int index, Object cursor) {
4474 if (cursor == null)
4475 return null;
4476- JDBCResultSet resultSet = new JDBCResultSet(statement, metaData.getNestedResultSet(index + 1), (Cursor)cursor);
4477+ JDBCResultSet resultSet = new JDBCResultSet(statement, metaData.getNestedResultSet(index + 1), (RowCursor)cursor);
4478 statement.secondaryResultSet(resultSet);
4479 return resultSet;
4480 }
4481@@ -137,7 +137,7 @@
4482
4483 @Override
4484 public <T> T unwrap(Class<T> iface) throws SQLException {
4485- if (iface == Cursor.class)
4486+ if (iface == RowCursor.class)
4487 return (T)cursor;
4488 if (iface == Row.class)
4489 return (T)row;
4490@@ -146,7 +146,7 @@
4491
4492 @Override
4493 public boolean isWrapperFor(Class<?> iface) throws SQLException {
4494- if (iface == Cursor.class)
4495+ if (iface == RowCursor.class)
4496 return true;
4497 if (iface == Row.class)
4498 return true;
4499
4500=== modified file 'src/main/java/com/akiban/sql/pg/PostgresModifyOperatorStatement.java'
4501--- src/main/java/com/akiban/sql/pg/PostgresModifyOperatorStatement.java 2013-07-06 17:46:02 +0000
4502+++ src/main/java/com/akiban/sql/pg/PostgresModifyOperatorStatement.java 2013-07-10 21:47:26 +0000
4503@@ -127,7 +127,7 @@
4504 @Override
4505 public Cursor openCursor(PostgresQueryContext context, QueryBindings bindings) {
4506 Cursor cursor = API.cursor(resultOperator, context, bindings);
4507- cursor.open();
4508+ cursor.openTopLevel();
4509 return cursor;
4510 }
4511
4512
4513=== modified file 'src/main/java/com/akiban/sql/pg/PostgresOperatorStatement.java'
4514--- src/main/java/com/akiban/sql/pg/PostgresOperatorStatement.java 2013-07-06 17:46:02 +0000
4515+++ src/main/java/com/akiban/sql/pg/PostgresOperatorStatement.java 2013-07-10 21:47:26 +0000
4516@@ -84,7 +84,7 @@
4517 @Override
4518 public Cursor openCursor(PostgresQueryContext context, QueryBindings bindings) {
4519 Cursor cursor = API.cursor(resultOperator, context, bindings);
4520- cursor.open();
4521+ cursor.openTopLevel();
4522 return cursor;
4523 }
4524
4525
4526=== modified file 'src/test/java/com/akiban/qp/operator/OperatorTestHelper.java'
4527--- src/test/java/com/akiban/qp/operator/OperatorTestHelper.java 2013-07-08 18:16:50 +0000
4528+++ src/test/java/com/akiban/qp/operator/OperatorTestHelper.java 2013-07-10 21:47:26 +0000
4529@@ -133,13 +133,14 @@
4530 public static Cursor open(Operator plan) {
4531 QueryContext queryContext = new SimpleQueryContext(ADAPTER);
4532 QueryBindings queryBindings = queryContext.createBindings();
4533- Cursor result = plan.cursor(queryContext, queryBindings);
4534+ QueryBindingsCursor queryBindingsCursor = new SingletonQueryBindingsCursor(queryBindings);
4535+ Cursor result = plan.cursor(queryContext, queryBindingsCursor);
4536 reopen(result);
4537 return result;
4538 }
4539
4540 public static void reopen(Cursor cursor) {
4541- cursor.open();
4542+ cursor.openTopLevel();
4543 }
4544
4545 public static List<Row> execute(Operator plan) {
4546@@ -188,7 +189,6 @@
4547
4548 @Override
4549 public Cursor newIndexCursor(QueryContext context,
4550- QueryBindings bindings,
4551 Index index,
4552 IndexKeyRange keyRange,
4553 API.Ordering ordering,
4554@@ -230,7 +230,7 @@
4555 @Override
4556 public Sorter createSorter(QueryContext context,
4557 QueryBindings bindings,
4558- Cursor input,
4559+ RowCursor input,
4560 RowType rowType,
4561 API.Ordering ordering,
4562 API.SortOption sortOption,
4563
4564=== modified file 'src/test/java/com/akiban/qp/operator/TimeOperator.java'
4565--- src/test/java/com/akiban/qp/operator/TimeOperator.java 2013-07-08 18:16:50 +0000
4566+++ src/test/java/com/akiban/qp/operator/TimeOperator.java 2013-07-10 21:47:26 +0000
4567@@ -41,9 +41,9 @@
4568 // Operator interface
4569
4570 @Override
4571- protected Cursor cursor(QueryContext context, QueryBindings bindings)
4572+ protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
4573 {
4574- return new Execution(context, bindings);
4575+ return new Execution(context, bindingsCursor);
4576 }
4577
4578 @Override
4579@@ -90,7 +90,7 @@
4580
4581 // Inner classes
4582
4583- private class Execution extends OperatorExecutionBase implements Cursor
4584+ private class Execution extends ChainedCursor
4585 {
4586 // Cursor interface
4587
4588@@ -122,40 +122,11 @@
4589 elapsedNsec += stop - start;
4590 }
4591
4592- @Override
4593- public void destroy()
4594- {
4595- input.destroy();
4596- }
4597-
4598- @Override
4599- public boolean isIdle()
4600- {
4601- return input.isIdle();
4602- }
4603-
4604- @Override
4605- public boolean isActive()
4606- {
4607- return input.isActive();
4608- }
4609-
4610- @Override
4611- public boolean isDestroyed()
4612- {
4613- return input.isDestroyed();
4614- }
4615-
4616 // Execution interface
4617
4618- Execution(QueryContext context, QueryBindings bindings)
4619+ Execution(QueryContext context, QueryBindingsCursor bindingsCursor)
4620 {
4621- super(context, bindings);
4622- this.input = inputOperator.cursor(context, bindings);
4623+ super(context, inputOperator.cursor(context, bindingsCursor));
4624 }
4625-
4626- // Object state
4627-
4628- private final Cursor input;
4629 }
4630 }
4631
4632=== modified file 'src/test/java/com/akiban/server/test/costmodel/DistinctCT.java'
4633--- src/test/java/com/akiban/server/test/costmodel/DistinctCT.java 2013-07-08 18:16:50 +0000
4634+++ src/test/java/com/akiban/server/test/costmodel/DistinctCT.java 2013-07-10 21:47:26 +0000
4635@@ -122,7 +122,7 @@
4636 long start = System.nanoTime();
4637 for (int r = 0; r < runs; r++) {
4638 Cursor cursor = cursor(distinct, queryContext, queryBindings);
4639- cursor.open();
4640+ cursor.openTopLevel();
4641 while (cursor.next() != null);
4642 }
4643 long stop = System.nanoTime();
4644
4645=== modified file 'src/test/java/com/akiban/server/test/costmodel/FlattenCT.java'
4646--- src/test/java/com/akiban/server/test/costmodel/FlattenCT.java 2013-07-08 18:16:50 +0000
4647+++ src/test/java/com/akiban/server/test/costmodel/FlattenCT.java 2013-07-10 21:47:26 +0000
4648@@ -107,7 +107,7 @@
4649 long start = System.nanoTime();
4650 for (int r = 0; r < runs; r++) {
4651 Cursor cursor = cursor(plan, queryContext, queryBindings);
4652- cursor.open();
4653+ cursor.openTopLevel();
4654 while (cursor.next() != null);
4655 }
4656 long stop = System.nanoTime();
4657
4658=== modified file 'src/test/java/com/akiban/server/test/costmodel/HKeyUnionCT.java'
4659--- src/test/java/com/akiban/server/test/costmodel/HKeyUnionCT.java 2013-07-08 18:16:50 +0000
4660+++ src/test/java/com/akiban/server/test/costmodel/HKeyUnionCT.java 2013-07-10 21:47:26 +0000
4661@@ -124,7 +124,7 @@
4662 long start = System.nanoTime();
4663 for (int r = 0; r < runs; r++) {
4664 Cursor cursor = cursor(union, queryContext, queryBindings);
4665- cursor.open();
4666+ cursor.openTopLevel();
4667 while (cursor.next() != null);
4668 }
4669 long stop = System.nanoTime();
4670
4671=== modified file 'src/test/java/com/akiban/server/test/costmodel/IntersectCT.java'
4672--- src/test/java/com/akiban/server/test/costmodel/IntersectCT.java 2013-07-08 18:16:50 +0000
4673+++ src/test/java/com/akiban/server/test/costmodel/IntersectCT.java 2013-07-10 21:47:26 +0000
4674@@ -126,7 +126,7 @@
4675 long start = System.nanoTime();
4676 for (int r = 0; r < runs; r++) {
4677 Cursor cursor = cursor(intersect, queryContext, queryBindings);
4678- cursor.open();
4679+ cursor.openTopLevel();
4680 while (cursor.next() != null);
4681 }
4682 long stop = System.nanoTime();
4683
4684=== modified file 'src/test/java/com/akiban/server/test/costmodel/MapCT.java'
4685--- src/test/java/com/akiban/server/test/costmodel/MapCT.java 2013-07-08 18:16:50 +0000
4686+++ src/test/java/com/akiban/server/test/costmodel/MapCT.java 2013-07-10 21:47:26 +0000
4687@@ -87,7 +87,7 @@
4688 long start = System.nanoTime();
4689 for (int r = 0; r < runs; r++) {
4690 Cursor cursor = cursor(plan, queryContext, queryBindings);
4691- cursor.open();
4692+ cursor.openTopLevel();
4693 while (cursor.next() != null);
4694 }
4695 long stop = System.nanoTime();
4696
4697=== modified file 'src/test/java/com/akiban/server/test/costmodel/ProductCT.java'
4698--- src/test/java/com/akiban/server/test/costmodel/ProductCT.java 2013-07-08 18:16:50 +0000
4699+++ src/test/java/com/akiban/server/test/costmodel/ProductCT.java 2013-07-10 21:47:26 +0000
4700@@ -143,7 +143,7 @@
4701 long start = System.nanoTime();
4702 for (int r = 0; r < runs; r++) {
4703 Cursor cursor = cursor(plan, queryContext, queryBindings);
4704- cursor.open();
4705+ cursor.openTopLevel();
4706 while (cursor.next() != null);
4707 }
4708 long stop = System.nanoTime();
4709@@ -201,7 +201,7 @@
4710 long start = System.nanoTime();
4711 for (int r = 0; r < runs; r++) {
4712 Cursor cursor = cursor(plan, queryContext, queryBindings);
4713- cursor.open();
4714+ cursor.openTopLevel();
4715 while (cursor.next() != null);
4716 }
4717 long stop = System.nanoTime();
4718@@ -217,7 +217,7 @@
4719 private void dump(Operator plan)
4720 {
4721 Cursor cursor = cursor(plan, queryContext, queryBindings);
4722- cursor.open();
4723+ cursor.openTopLevel();
4724 Row row;
4725 while ((row = cursor.next()) != null) {
4726 System.out.println(row);
4727
4728=== modified file 'src/test/java/com/akiban/server/test/costmodel/ProjectCT.java'
4729--- src/test/java/com/akiban/server/test/costmodel/ProjectCT.java 2013-07-08 18:16:50 +0000
4730+++ src/test/java/com/akiban/server/test/costmodel/ProjectCT.java 2013-07-10 21:47:26 +0000
4731@@ -72,7 +72,7 @@
4732 long start = System.nanoTime();
4733 for (int r = 0; r < runs; r++) {
4734 Cursor cursor = cursor(project, queryContext, queryBindings);
4735- cursor.open();
4736+ cursor.openTopLevel();
4737 while (cursor.next() != null);
4738 }
4739 long stop = System.nanoTime();
4740
4741=== modified file 'src/test/java/com/akiban/server/test/costmodel/SelectCT.java'
4742--- src/test/java/com/akiban/server/test/costmodel/SelectCT.java 2013-07-08 18:16:50 +0000
4743+++ src/test/java/com/akiban/server/test/costmodel/SelectCT.java 2013-07-10 21:47:26 +0000
4744@@ -70,7 +70,7 @@
4745 long start = System.nanoTime();
4746 for (int r = 0; r < runs; r++) {
4747 Cursor cursor = cursor(select, queryContext, queryBindings);
4748- cursor.open();
4749+ cursor.openTopLevel();
4750 while (cursor.next() != null);
4751 }
4752 long stop = System.nanoTime();
4753
4754=== modified file 'src/test/java/com/akiban/server/test/costmodel/Select_BloomFilterCT.java'
4755--- src/test/java/com/akiban/server/test/costmodel/Select_BloomFilterCT.java 2013-07-08 18:16:50 +0000
4756+++ src/test/java/com/akiban/server/test/costmodel/Select_BloomFilterCT.java 2013-07-10 21:47:26 +0000
4757@@ -97,7 +97,7 @@
4758 long start = System.nanoTime();
4759 for (int r = 0; r < runs; r++) {
4760 Cursor cursor = cursor(plan, queryContext, queryBindings);
4761- cursor.open();
4762+ cursor.openTopLevel();
4763 Row row;
4764 while ((row = cursor.next()) != null) {
4765 // System.out.println(row);
4766
4767=== modified file 'src/test/java/com/akiban/server/test/costmodel/SortCT.java'
4768--- src/test/java/com/akiban/server/test/costmodel/SortCT.java 2013-07-08 18:16:50 +0000
4769+++ src/test/java/com/akiban/server/test/costmodel/SortCT.java 2013-07-10 21:47:26 +0000
4770@@ -161,7 +161,7 @@
4771 start = System.nanoTime();
4772 for (int r = 0; r < runs; r++) {
4773 Cursor cursor = cursor(setup, queryContext, queryBindings);
4774- cursor.open();
4775+ cursor.openTopLevel();
4776 while (cursor.next() != null);
4777 }
4778 stop = System.nanoTime();
4779@@ -170,7 +170,7 @@
4780 start = System.nanoTime();
4781 for (int r = 0; r < runs; r++) {
4782 Cursor cursor = cursor(sort, queryContext, queryBindings);
4783- cursor.open();
4784+ cursor.openTopLevel();
4785 while (cursor.next() != null);
4786 }
4787 stop = System.nanoTime();
4788
4789=== modified file 'src/test/java/com/akiban/server/test/costmodel/SortWithLimitCT.java'
4790--- src/test/java/com/akiban/server/test/costmodel/SortWithLimitCT.java 2013-07-08 18:16:50 +0000
4791+++ src/test/java/com/akiban/server/test/costmodel/SortWithLimitCT.java 2013-07-10 21:47:26 +0000
4792@@ -107,7 +107,7 @@
4793 long start = System.nanoTime();
4794 for (int r = 0; r < runs; r++) {
4795 Cursor cursor = cursor(sort, queryContext, queryBindings);
4796- cursor.open();
4797+ cursor.openTopLevel();
4798 while (cursor.next() != null);
4799 }
4800 long stop = System.nanoTime();
4801
4802=== modified file 'src/test/java/com/akiban/server/test/costmodel/TreeScanCT.java'
4803--- src/test/java/com/akiban/server/test/costmodel/TreeScanCT.java 2013-07-08 18:16:50 +0000
4804+++ src/test/java/com/akiban/server/test/costmodel/TreeScanCT.java 2013-07-10 21:47:26 +0000
4805@@ -135,7 +135,7 @@
4806 long start = System.nanoTime();
4807 for (int r = 0; r < runs; r++) {
4808 Cursor cursor = cursor(plan, queryContext, queryBindings);
4809- cursor.open();
4810+ cursor.openTopLevel();
4811 for (int s = 0; s < sequentialAccessesPerRandom; s++) {
4812 Row row = cursor.next();
4813 assert row != null;
4814@@ -170,10 +170,10 @@
4815 } else {
4816 valueHolder.putString((String) key);
4817 }
4818- cursor.open();
4819+ cursor.openTopLevel();
4820 Row row = cursor.next();
4821 assert row != null;
4822- cursor.close();
4823+ cursor.closeTopLevel();
4824 }
4825 }
4826 long endTime = System.nanoTime();
4827
4828=== modified file 'src/test/java/com/akiban/server/test/it/ITBase.java'
4829--- src/test/java/com/akiban/server/test/it/ITBase.java 2013-03-22 20:05:57 +0000
4830+++ src/test/java/com/akiban/server/test/it/ITBase.java 2013-07-10 21:47:26 +0000
4831@@ -21,6 +21,7 @@
4832 import com.akiban.ais.model.TableIndex;
4833 import com.akiban.ais.model.UserTable;
4834 import com.akiban.qp.operator.Cursor;
4835+import com.akiban.qp.operator.RowCursor;
4836 import com.akiban.qp.row.Row;
4837 import com.akiban.qp.row.RowBase;
4838 import com.akiban.qp.rowtype.IndexRowType;
4839@@ -51,16 +52,24 @@
4840 super(suffix);
4841 }
4842
4843- protected void compareRows(RowBase[] expected, Cursor cursor)
4844- {
4845- compareRows(expected, cursor, null);
4846- }
4847-
4848- protected void compareRows(RowBase[] expected, Cursor cursor, AkCollator ... collators)
4849+ protected void compareRows(RowBase[] expected, RowCursor cursor)
4850+ {
4851+ compareRows(expected, cursor, (cursor instanceof Cursor), null);
4852+ }
4853+
4854+ protected void compareRows(RowBase[] expected, RowCursor cursor, AkCollator ... collators)
4855+ {
4856+ compareRows(expected, cursor, (cursor instanceof Cursor), collators);
4857+ }
4858+
4859+ protected void compareRows(RowBase[] expected, RowCursor cursor, boolean topLevel, AkCollator ... collators)
4860 {
4861 List<ShareHolder<Row>> actualRows = new ArrayList<>(); // So that result is viewable in debugger
4862 try {
4863- cursor.open();
4864+ if (topLevel)
4865+ ((Cursor)cursor).openTopLevel();
4866+ else
4867+ cursor.open();
4868 RowBase actualRow;
4869 while ((actualRow = cursor.next()) != null) {
4870 int count = actualRows.size();
4871@@ -80,7 +89,10 @@
4872 actualRows.add(new ShareHolder<>((Row) actualRow));
4873 }
4874 } finally {
4875- cursor.close();
4876+ if (topLevel)
4877+ ((Cursor)cursor).closeTopLevel();
4878+ else
4879+ cursor.close();
4880 }
4881 assertEquals(expected.length, actualRows.size());
4882 }
4883
4884=== modified file 'src/test/java/com/akiban/server/test/it/qp/GroupIndexScanIT.java'
4885--- src/test/java/com/akiban/server/test/it/qp/GroupIndexScanIT.java 2013-07-08 18:16:50 +0000
4886+++ src/test/java/com/akiban/server/test/it/qp/GroupIndexScanIT.java 2013-07-10 21:47:26 +0000
4887@@ -133,7 +133,7 @@
4888 private List<List<?>> planToList(Operator plan) {
4889 List<List<?>> actualResults = new ArrayList<>();
4890 Cursor cursor = API.cursor(plan, queryContext, queryBindings);
4891- cursor.open();
4892+ cursor.openTopLevel();
4893 try {
4894 ToObjectValueTarget target = new ToObjectValueTarget();
4895 for (Row row = cursor.next(); row != null; row = cursor.next()) {
4896@@ -157,7 +157,7 @@
4897 actualResults.add(Arrays.asList(rowArray));
4898 }
4899 } finally {
4900- cursor.close();
4901+ cursor.closeTopLevel();
4902 }
4903 return actualResults;
4904 }
4905
4906=== modified file 'src/test/java/com/akiban/server/test/it/qp/GroupScanIT.java'
4907--- src/test/java/com/akiban/server/test/it/qp/GroupScanIT.java 2013-07-08 18:16:50 +0000
4908+++ src/test/java/com/akiban/server/test/it/qp/GroupScanIT.java 2013-07-10 21:47:26 +0000
4909@@ -140,7 +140,7 @@
4910 use(db);
4911 Operator groupScan = groupScan_Default(coi);
4912 Cursor cursor = cursor(groupScan, queryContext, queryBindings);
4913- cursor.open();
4914+ cursor.openTopLevel();
4915 Row row = cursor.next();
4916 assertSame(customerRowType, row.rowType());
4917 row = cursor.next();
4918
4919=== modified file 'src/test/java/com/akiban/server/test/it/qp/IndexScanIT.java'
4920--- src/test/java/com/akiban/server/test/it/qp/IndexScanIT.java 2013-07-08 18:16:50 +0000
4921+++ src/test/java/com/akiban/server/test/it/qp/IndexScanIT.java 2013-07-10 21:47:26 +0000
4922@@ -550,7 +550,7 @@
4923 {
4924 Operator indexScan = indexScan_Default(itemOidIidIndexRowType, false, null);
4925 Cursor cursor = cursor(indexScan, queryContext, queryBindings);
4926- cursor.open();
4927+ cursor.openTopLevel();
4928 Row row = cursor.next();
4929 if (usingPValues()) {
4930 // Get and checking each field should work
4931
4932=== modified file 'src/test/java/com/akiban/server/test/it/qp/IndexScanJumpBoundedIT.java'
4933--- src/test/java/com/akiban/server/test/it/qp/IndexScanJumpBoundedIT.java 2013-07-08 20:48:05 +0000
4934+++ src/test/java/com/akiban/server/test/it/qp/IndexScanJumpBoundedIT.java 2013-07-10 21:47:26 +0000
4935@@ -88,34 +88,34 @@
4936 {
4937 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, true, 13, true), ordering);
4938 Cursor cursor = cursor(plan, queryContext, queryBindings);
4939- cursor.open();
4940+ cursor.openTopLevel();
4941 testJump(cursor, idOrdering, 0);
4942 testJump(cursor, idOrdering, -1);
4943- cursor.close();
4944+ cursor.closeTopLevel();
4945 }
4946 {
4947 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, true, 13, false), ordering);
4948 Cursor cursor = cursor(plan, queryContext, queryBindings);
4949- cursor.open();
4950+ cursor.openTopLevel();
4951 testJump(cursor, first4(idOrdering), 0);
4952 testJump(cursor, first4(idOrdering), -1);
4953- cursor.close();
4954+ cursor.closeTopLevel();
4955 }
4956 {
4957 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, false, 13, true), ordering);
4958 Cursor cursor = cursor(plan, queryContext, queryBindings);
4959- cursor.open();
4960+ cursor.openTopLevel();
4961 testJump(cursor, last4(idOrdering), 0);
4962 testJump(cursor, last4(idOrdering), -1);
4963- cursor.close();
4964+ cursor.closeTopLevel();
4965 }
4966 {
4967 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, false, 13, false), ordering);
4968 Cursor cursor = cursor(plan, queryContext, queryBindings);
4969- cursor.open();
4970+ cursor.openTopLevel();
4971 testJump(cursor, middle2(idOrdering), 0);
4972 testJump(cursor, middle2(idOrdering), -1);
4973- cursor.close();
4974+ cursor.closeTopLevel();
4975 }
4976 }
4977
4978@@ -127,34 +127,34 @@
4979 {
4980 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, true, 13, true), ordering);
4981 Cursor cursor = cursor(plan, queryContext, queryBindings);
4982- cursor.open();
4983+ cursor.openTopLevel();
4984 testJump(cursor, idOrdering, 0);
4985 testJump(cursor, idOrdering, 1);
4986- cursor.close();
4987+ cursor.closeTopLevel();
4988 }
4989 {
4990 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, true, 13, false), ordering);
4991 Cursor cursor = cursor(plan, queryContext, queryBindings);
4992- cursor.open();
4993+ cursor.openTopLevel();
4994 testJump(cursor, first4(idOrdering), 0);
4995 testJump(cursor, first4(idOrdering), 1);
4996- cursor.close();
4997+ cursor.closeTopLevel();
4998 }
4999 {
5000 Operator plan = indexScan_Default(idxRowType, bounded(1, 11, false, 13, true), ordering);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches