@@ -25,6 +25,7 @@ import (
25
25
"github.com/dolthub/go-mysql-server/sql/hash"
26
26
"github.com/dolthub/go-mysql-server/sql/iters"
27
27
"github.com/dolthub/go-mysql-server/sql/plan"
28
+ "github.com/dolthub/go-mysql-server/sql/transform"
28
29
"github.com/dolthub/go-mysql-server/sql/types"
29
30
)
30
31
@@ -126,16 +127,31 @@ func (i *offsetIter) Close(ctx *sql.Context) error {
126
127
var _ sql.RowIter = & iters.JsonTableRowIter {}
127
128
128
129
type ProjectIter struct {
129
- projs []sql.Expression
130
- canDefer bool
131
- childIter sql.RowIter
130
+ projs []sql.Expression
131
+ canDefer bool
132
+ hasNestedIters bool
133
+ nestedState * nestedIterState
134
+ childIter sql.RowIter
135
+ }
136
+
137
+ type nestedIterState struct {
138
+ normalFields []sql.Expression
139
+ nestedIters []sql.RowIter
140
+ nestedIterIdxes []int
141
+ sourceRow sql.Row
142
+ iterEvaluators []* RowIterEvaluator
132
143
}
133
144
134
145
func (i * ProjectIter ) Next (ctx * sql.Context ) (sql.Row , error ) {
135
146
childRow , err := i .childIter .Next (ctx )
136
147
if err != nil {
137
148
return nil , err
138
149
}
150
+
151
+ if i .hasNestedIters {
152
+ return i .ProjectRowWithNestedIters (ctx , i .projs , childRow )
153
+ }
154
+
139
155
return ProjectRow (ctx , i .projs , childRow )
140
156
}
141
157
@@ -155,6 +171,120 @@ func (i *ProjectIter) GetChildIter() sql.RowIter {
155
171
return i .childIter
156
172
}
157
173
174
+ // ProjectRowWithNestedIters evaluates a set of projections, allowing for nested iterators in the expressions.
175
+ func (i * ProjectIter ) ProjectRowWithNestedIters (
176
+ ctx * sql.Context ,
177
+ projections []sql.Expression ,
178
+ row sql.Row ,
179
+ ) (sql.Row , error ) {
180
+
181
+ // For the set of iterators, we return one row each element in the longest of the iterators provided.
182
+ // Other iterator values will be NULL after they are depleted. All non-iterator fields for the row are returned
183
+ // identically for each row in the result set.
184
+ if i .nestedState != nil {
185
+
186
+ }
187
+
188
+ nestedState := & nestedIterState {
189
+ sourceRow : row ,
190
+ }
191
+
192
+ // We need a new set of projections, with any iterator-returning expressions replaced by new expressions that will
193
+ // return the result of the iteration on each call to Eval. We also need to keep a list of all such iterators, so
194
+ // that we can tell when they have all finished their iterations.
195
+ var rowIterEvaluators []* RowIterEvaluator
196
+ newProjs := make ([]sql.Expression , len (projections ))
197
+ for i , proj := range projections {
198
+ p , _ , err := transform .Expr (proj , func (e sql.Expression ) (sql.Expression , transform.TreeIdentity , error ) {
199
+ if rie , ok := e .(sql.RowIterExpression ); ok {
200
+ ri , err := rie .EvalRowIter (ctx , row )
201
+ if err != nil {
202
+ return nil , false , err
203
+ }
204
+
205
+ evaluator := & RowIterEvaluator {
206
+ iter : ri ,
207
+ }
208
+ rowIterEvaluators = append (rowIterEvaluators , evaluator )
209
+ return evaluator , transform .NewTree , nil
210
+ }
211
+ })
212
+ if err != nil {
213
+ return nil , err
214
+ }
215
+
216
+ newProjs [i ] = p
217
+ }
218
+
219
+ vals , err := ProjectRow (ctx , projections , row )
220
+ if err != nil {
221
+ return nil , err
222
+ }
223
+
224
+ nestedState .normalFields = make ([]sql.Expression , len (vals ))
225
+ for i , val := range vals {
226
+ if iter , ok := val .(sql.RowIter ); ok {
227
+ nestedState .nestedIters = append (nestedState .nestedIters , iter )
228
+ nestedState .nestedIterIdxes = append (nestedState .nestedIterIdxes , i )
229
+ } else {
230
+ nestedState .normalFields [i ] = projections [i ]
231
+ }
232
+ }
233
+
234
+ i .nestedState = nestedState
235
+ return i .ProjectRowWithNestedIters (ctx , projections , row )
236
+ }
237
+
238
+ type RowIterEvaluator struct {
239
+ iter sql.RowIter
240
+ finished bool
241
+ }
242
+
243
+ func (r RowIterEvaluator ) Resolved () bool {
244
+ return true
245
+ }
246
+
247
+ func (r RowIterEvaluator ) String () string {
248
+ return "RowIterEvaluator"
249
+ }
250
+
251
+ func (r RowIterEvaluator ) Type () sql.Type {
252
+ return nil
253
+ }
254
+
255
+ func (r RowIterEvaluator ) IsNullable () bool {
256
+ return false
257
+ }
258
+
259
+ func (r * RowIterEvaluator ) Eval (ctx * sql.Context , row sql.Row ) (interface {}, error ) {
260
+ if r .finished {
261
+ return nil , nil
262
+ }
263
+
264
+ nextRow , err := r .iter .Next (ctx )
265
+ if err != nil {
266
+ if errors .Is (err , io .EOF ) {
267
+ r .finished = true
268
+ return nil , nil
269
+ }
270
+ return nil , err
271
+ }
272
+
273
+ return nextRow , nil
274
+ }
275
+
276
+ func (r RowIterEvaluator ) Children () []sql.Expression {
277
+ // TODO implement me
278
+ panic ("implement me" )
279
+ }
280
+
281
+ func (r RowIterEvaluator ) WithChildren (children ... sql.Expression ) (sql.Expression , error ) {
282
+ // TODO implement me
283
+ panic ("implement me" )
284
+ }
285
+
286
+ var _ sql.Expression = (* RowIterEvaluator )(nil )
287
+
158
288
// ProjectRow evaluates a set of projections.
159
289
func ProjectRow (
160
290
ctx * sql.Context ,
0 commit comments