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