Skip to content

Commit 12c2025

Browse files
committed
New RowIterExpression interface, subbing it into the expr tree
1 parent 94e279c commit 12c2025

File tree

4 files changed

+144
-6
lines changed

4 files changed

+144
-6
lines changed

sql/core.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ type Expression interface {
4545
WithChildren(children ...Expression) (Expression, error)
4646
}
4747

48+
type RowIterExpression interface {
49+
Expression
50+
// EvalRowIter evaluates the expression, which must be a RowIter
51+
EvalRowIter(ctx *Context, r Row) (RowIter, error)
52+
}
53+
4854
// ExpressionWithNodes is an expression that contains nodes as children.
4955
type ExpressionWithNodes interface {
5056
Expression

sql/plan/project.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,6 @@ func (p *Project) WithCanDefer(canDefer bool) *Project {
219219
func (p *Project) WithIncludesNestedIters(includesNestedIters bool) *Project {
220220
np := *p
221221
np.IncludesNestedIters = includesNestedIters
222+
np.CanDefer = false
222223
return &np
223224
}

sql/rowexec/rel.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,10 @@ func (b *BaseBuilder) buildProject(ctx *sql.Context, n *plan.Project, row sql.Ro
312312
}
313313

314314
return sql.NewSpanIter(span, &ProjectIter{
315-
projs: n.Projections,
316-
canDefer: n.CanDefer,
317-
childIter: i,
315+
projs: n.Projections,
316+
canDefer: n.CanDefer,
317+
hasNestedIters: n.IncludesNestedIters,
318+
childIter: i,
318319
}), nil
319320
}
320321

sql/rowexec/rel_iters.go

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/dolthub/go-mysql-server/sql/hash"
2626
"github.com/dolthub/go-mysql-server/sql/iters"
2727
"github.com/dolthub/go-mysql-server/sql/plan"
28+
"github.com/dolthub/go-mysql-server/sql/transform"
2829
"github.com/dolthub/go-mysql-server/sql/types"
2930
)
3031

@@ -126,16 +127,31 @@ func (i *offsetIter) Close(ctx *sql.Context) error {
126127
var _ sql.RowIter = &iters.JsonTableRowIter{}
127128

128129
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
132143
}
133144

134145
func (i *ProjectIter) Next(ctx *sql.Context) (sql.Row, error) {
135146
childRow, err := i.childIter.Next(ctx)
136147
if err != nil {
137148
return nil, err
138149
}
150+
151+
if i.hasNestedIters {
152+
return i.ProjectRowWithNestedIters(ctx, i.projs, childRow)
153+
}
154+
139155
return ProjectRow(ctx, i.projs, childRow)
140156
}
141157

@@ -155,6 +171,120 @@ func (i *ProjectIter) GetChildIter() sql.RowIter {
155171
return i.childIter
156172
}
157173

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+
158288
// ProjectRow evaluates a set of projections.
159289
func ProjectRow(
160290
ctx *sql.Context,

0 commit comments

Comments
 (0)