diff --git a/sql/rowexec/dml_iters.go b/sql/rowexec/dml_iters.go index 583c7c2dcf..4e298c1dc5 100644 --- a/sql/rowexec/dml_iters.go +++ b/sql/rowexec/dml_iters.go @@ -754,7 +754,8 @@ func (u *updateSourceIter) Next(ctx *sql.Context) (sql.Row, error) { newRow = newRow[len(newRow)-expectedSchemaLen:] } - return oldRow.Append(newRow), nil + row := append(oldRow, newRow...) + return row, nil } func (u *updateSourceIter) Close(ctx *sql.Context) error { diff --git a/sql/rowexec/insert.go b/sql/rowexec/insert.go index 28b1c2cec9..70238f4ce5 100644 --- a/sql/rowexec/insert.go +++ b/sql/rowexec/insert.go @@ -233,13 +233,11 @@ func (i *insertIter) handleOnDuplicateKeyUpdate(ctx *sql.Context, oldRow, newRow if !ok { return nil, err } - val = convertDataAndWarn(ctx, i.schema, newRow, idx, err) } else { return nil, err } } - updateAcc = val.(sql.Row) } // project LHS only diff --git a/sql/rowexec/join_iters.go b/sql/rowexec/join_iters.go index a39c5f0ff3..30d7de4100 100644 --- a/sql/rowexec/join_iters.go +++ b/sql/rowexec/join_iters.go @@ -30,6 +30,26 @@ import ( "github.com/dolthub/go-mysql-server/sql/transform" ) +// joinIter is an iterator that iterates over every row in the primary table and performs an index lookup in +// the secondary table for each value +type joinIter struct { + b sql.NodeExecBuilder + joinType plan.JoinType + cond sql.Expression + + primary sql.RowIter + primaryRow sql.Row + loadPrimaryRow bool + + secondaryProvider sql.Node + secondary sql.RowIter + + foundMatch bool + rowSize int + scopeLen int + parentLen int +} + func newJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) { var leftName, rightName string if leftTable, ok := j.Left().(sql.Nameable); ok { @@ -54,53 +74,45 @@ func newJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row span.End() return nil, err } + + parentLen := len(row) + + primaryRow := make(sql.Row, parentLen+len(j.Left().Schema())) + copy(primaryRow, row) + return sql.NewSpanIter(span, &joinIter{ - parentRow: row, - primary: l, - secondaryProvider: j.Right(), - cond: j.Filter, - joinType: j.Op, - rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), - scopeLen: j.ScopeLen, - b: b, - }), nil -} + b: b, + joinType: j.Op, + cond: j.Filter, -// joinIter is an iterator that iterates over every row in the primary table and performs an index lookup in -// the secondary table for each value -type joinIter struct { - parentRow sql.Row - primary sql.RowIter - primaryRow sql.Row - secondaryProvider sql.Node - secondary sql.RowIter - cond sql.Expression - joinType plan.JoinType + primary: l, + primaryRow: primaryRow, + loadPrimaryRow: true, - foundMatch bool - rowSize int - scopeLen int - b sql.NodeExecBuilder + secondaryProvider: j.Right(), + + rowSize: parentLen + len(j.Left().Schema()) + len(j.Right().Schema()), + scopeLen: j.ScopeLen, + parentLen: parentLen, + }), nil } func (i *joinIter) loadPrimary(ctx *sql.Context) error { - if i.primaryRow == nil { + if i.loadPrimaryRow { r, err := i.primary.Next(ctx) if err != nil { return err } - - i.primaryRow = i.parentRow.Append(r) + copy(i.primaryRow[i.parentLen:], r) i.foundMatch = false + i.loadPrimaryRow = false } - return nil } func (i *joinIter) loadSecondary(ctx *sql.Context) (sql.Row, error) { if i.secondary == nil { rowIter, err := i.b.Build(ctx, i.secondaryProvider, i.primaryRow) - if err != nil { return nil, err } @@ -118,7 +130,7 @@ func (i *joinIter) loadSecondary(ctx *sql.Context) (sql.Row, error) { if err != nil { return nil, err } - i.primaryRow = nil + i.loadPrimaryRow = true return nil, io.EOF } return nil, err @@ -138,18 +150,18 @@ func (i *joinIter) Next(ctx *sql.Context) (sql.Row, error) { if err != nil { if errors.Is(err, io.EOF) { if !i.foundMatch && i.joinType.IsLeftOuter() { - i.primaryRow = nil + i.loadPrimaryRow = true row := i.buildRow(primary, nil) return i.removeParentRow(row), nil } continue - } else if errors.Is(err, plan.ErrEmptyCachedResult) { + } + if errors.Is(err, plan.ErrEmptyCachedResult) { if !i.foundMatch && i.joinType.IsLeftOuter() { - i.primaryRow = nil + i.loadPrimaryRow = true row := i.buildRow(primary, nil) return i.removeParentRow(row), nil } - return nil, io.EOF } return nil, err @@ -167,7 +179,7 @@ func (i *joinIter) Next(ctx *sql.Context) (sql.Row, error) { if err != nil { return nil, err } - i.primaryRow = nil + i.loadPrimaryRow = true continue } @@ -181,18 +193,16 @@ func (i *joinIter) Next(ctx *sql.Context) (sql.Row, error) { } func (i *joinIter) removeParentRow(r sql.Row) sql.Row { - copy(r[i.scopeLen:], r[len(i.parentRow):]) - r = r[:len(r)-len(i.parentRow)+i.scopeLen] + copy(r[i.scopeLen:], r[i.parentLen:]) + r = r[:len(r)-i.parentLen+i.scopeLen] return r } // buildRow builds the result set row using the rows from the primary and secondary tables func (i *joinIter) buildRow(primary, secondary sql.Row) sql.Row { row := make(sql.Row, i.rowSize) - copy(row, primary) copy(row[len(primary):], secondary) - return row } @@ -216,37 +226,51 @@ func (i *joinIter) Close(ctx *sql.Context) (err error) { func newExistsIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) { leftIter, err := b.Build(ctx, j.Left(), row) - if err != nil { return nil, err } + + parentLen := len(row) + + rowSize := parentLen + len(j.Left().Schema()) + len(j.Right().Schema()) + fullRow := make(sql.Row, rowSize) + copy(fullRow, row) + + primaryRow := make(sql.Row, parentLen+len(j.Left().Schema())) + copy(primaryRow, row) + return &existsIter{ - parentRow: row, + b: b, typ: j.Op, primary: leftIter, + primaryRow: primaryRow, + fullRow: fullRow, + parentLen: parentLen, secondaryProvider: j.Right(), cond: j.Filter, scopeLen: j.ScopeLen, - rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), + rowSize: rowSize, nullRej: !(j.Filter != nil && plan.IsNullRejecting(j.Filter)), - b: b, }, nil } type existsIter struct { - typ plan.JoinType - primary sql.RowIter - secondaryProvider sql.Node - cond sql.Expression + b sql.NodeExecBuilder + typ plan.JoinType + cond sql.Expression + primary sql.RowIter primaryRow sql.Row + fullRow sql.Row + + secondaryProvider sql.Node + + parentLen int + scopeLen int + rowSize int - parentRow sql.Row - scopeLen int - rowSize int nullRej bool rightIterNonEmpty bool - b sql.NodeExecBuilder } type existsState uint8 @@ -261,9 +285,7 @@ const ( ) func (i *existsIter) Next(ctx *sql.Context) (sql.Row, error) { - var row sql.Row var right sql.Row - var left sql.Row var rIter sql.RowIter var err error @@ -282,8 +304,8 @@ func (i *existsIter) Next(ctx *sql.Context) (sql.Row, error) { if err != nil { return nil, err } - left = i.parentRow.Append(r) - rIter, err = i.b.Build(ctx, i.secondaryProvider, left) + copy(i.primaryRow[i.parentLen:], r) + rIter, err = i.b.Build(ctx, i.secondaryProvider, i.primaryRow) if err != nil { return nil, err } @@ -319,8 +341,9 @@ func (i *existsIter) Next(ctx *sql.Context) (sql.Row, error) { nextState = esRet } case esCompare: - row = i.buildRow(left, right) - res, err := sql.EvaluateCondition(ctx, i.cond, row) + copy(i.fullRow[i.parentLen:], i.primaryRow[i.parentLen:]) + copy(i.fullRow[len(i.primaryRow):], right) + res, err := sql.EvaluateCondition(ctx, i.cond, i.fullRow) if err != nil { return nil, err } @@ -351,7 +374,7 @@ func (i *existsIter) Next(ctx *sql.Context) (sql.Row, error) { nextState = esIncRight } case esRet: - return i.removeParentRow(left), nil + return i.removeParentRow(i.primaryRow.Copy()), nil default: return nil, fmt.Errorf("invalid exists join state") } @@ -366,18 +389,16 @@ func isTrueLit(e sql.Expression) bool { } func (i *existsIter) removeParentRow(r sql.Row) sql.Row { - copy(r[i.scopeLen:], r[len(i.parentRow):]) - r = r[:len(r)-len(i.parentRow)+i.scopeLen] + copy(r[i.scopeLen:], r[i.parentLen:]) + r = r[:len(r)-i.parentLen+i.scopeLen] return r } // buildRow builds the result set row using the rows from the primary and secondary tables func (i *existsIter) buildRow(primary, secondary sql.Row) sql.Row { row := make(sql.Row, i.rowSize) - copy(row, primary) copy(row[len(primary):], secondary) - return row } @@ -392,7 +413,6 @@ func (i *existsIter) Close(ctx *sql.Context) (err error) { func newFullJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) { leftIter, err := b.Build(ctx, j.Left(), row) - if err != nil { return nil, err } @@ -526,7 +546,8 @@ func (i *fullJoinIter) Next(ctx *sql.Context) (sql.Row, error) { continue } // (null, right) only if we haven't matched right - ret := i.buildRow(make(sql.Row, i.leftLen), rightRow) + ret := make(sql.Row, i.rowSize) + copy(ret[i.leftLen:], rightRow) return i.removeParentRow(ret), nil } } @@ -540,10 +561,8 @@ func (i *fullJoinIter) removeParentRow(r sql.Row) sql.Row { // buildRow builds the result set row using the rows from the primary and secondary tables func (i *fullJoinIter) buildRow(primary, secondary sql.Row) sql.Row { row := make(sql.Row, i.rowSize) - copy(row, primary) copy(row[len(primary):], secondary) - return row } @@ -563,6 +582,19 @@ func (i *fullJoinIter) Close(ctx *sql.Context) (err error) { return err } +type crossJoinIterator struct { + l sql.RowIter + r sql.RowIter + rp sql.Node + b sql.NodeExecBuilder + + primaryRow sql.Row + + rowSize int + scopeLen int + parentLen int +} + func newCrossJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) { var left, right string if leftTable, ok := j.Left().(sql.Nameable); ok { @@ -588,54 +620,43 @@ func newCrossJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, return nil, err } - return sql.NewSpanIter(span, &crossJoinIterator{ - b: b, - parentRow: row, - l: l, - rp: j.Right(), - rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), - scopeLen: j.ScopeLen, - }), nil -} + parentLen := len(row) -type crossJoinIterator struct { - l sql.RowIter - r sql.RowIter - rp sql.Node - b sql.NodeExecBuilder + primaryRow := make(sql.Row, parentLen+len(j.Left().Schema())) + copy(primaryRow, row) - parentRow sql.Row + return sql.NewSpanIter(span, &crossJoinIterator{ + b: b, + l: l, + rp: j.Right(), - rowSize int - scopeLen int + primaryRow: primaryRow, - leftRow sql.Row + rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), + scopeLen: j.ScopeLen, + parentLen: parentLen, + }), nil } func (i *crossJoinIterator) Next(ctx *sql.Context) (sql.Row, error) { for { - if i.leftRow == nil { + if i.r == nil { r, err := i.l.Next(ctx) if err != nil { return nil, err } + copy(i.primaryRow[i.parentLen:], r) - i.leftRow = i.parentRow.Append(r) - } - - if i.r == nil { - iter, err := i.b.Build(ctx, i.rp, i.leftRow) + iter, err := i.b.Build(ctx, i.rp, i.primaryRow) if err != nil { return nil, err } - i.r = iter } rightRow, err := i.r.Next(ctx) if err == io.EOF { i.r = nil - i.leftRow = nil continue } @@ -643,17 +664,16 @@ func (i *crossJoinIterator) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } - var row sql.Row - row = append(row, i.leftRow...) - row = append(row, rightRow...) - + row := make(sql.Row, i.rowSize) + copy(row, i.primaryRow) + copy(row[len(i.primaryRow):], rightRow) return i.removeParentRow(row), nil } } func (i *crossJoinIterator) removeParentRow(r sql.Row) sql.Row { - copy(r[i.scopeLen:], r[len(i.parentRow):]) - r = r[:len(r)-len(i.parentRow)+i.scopeLen] + copy(r[i.scopeLen:], r[i.parentLen:]) + r = r[:len(r)-i.parentLen+i.scopeLen] return r } @@ -661,7 +681,6 @@ func (i *crossJoinIterator) Close(ctx *sql.Context) (err error) { if i.l != nil { err = i.l.Close(ctx) } - if i.r != nil { if err == nil { err = i.r.Close(ctx) @@ -669,7 +688,6 @@ func (i *crossJoinIterator) Close(ctx *sql.Context) (err error) { i.r.Close(ctx) } } - return err } diff --git a/sql/rowexec/range_heap_iter.go b/sql/rowexec/range_heap_iter.go index 4ddbd7e3e2..12182bbfcf 100644 --- a/sql/rowexec/range_heap_iter.go +++ b/sql/rowexec/range_heap_iter.go @@ -13,6 +13,31 @@ import ( "github.com/dolthub/go-mysql-server/sql/plan" ) +// joinIter is an iterator that iterates over every row in the primary table and performs an index lookup in +// the secondary table for each value +type rangeHeapJoinIter struct { + ctx *sql.Context + err error + b sql.NodeExecBuilder + joinType plan.JoinType + cond sql.Expression + + primary sql.RowIter + primaryRow sql.Row + loadPrimaryRow bool + + secondary sql.RowIter + foundMatch bool + rowSize int + scopeLen int + parentLen int + + rangeHeapPlan *plan.RangeHeap + childRowIter sql.RowIter + pendingRow sql.Row + activeRanges []sql.Row +} + func newRangeHeapJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) { var leftName, rightName string if leftTable, ok := j.Left().(sql.Nameable); ok { @@ -43,53 +68,39 @@ func newRangeHeapJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinN return nil, errors.New("right side of join must be a range heap") } - return sql.NewSpanIter(span, &rangeHeapJoinIter{ - parentRow: row, - primary: l, - cond: j.Filter, - joinType: j.Op, - rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), - scopeLen: j.ScopeLen, - b: b, - rangeHeapPlan: rhp, - ctx: ctx, - }), nil -} + parentLen := len(row) -// joinIter is an iterator that iterates over every row in the primary table and performs an index lookup in -// the secondary table for each value -type rangeHeapJoinIter struct { - parentRow sql.Row - primary sql.RowIter - primaryRow sql.Row - secondary sql.RowIter - cond sql.Expression - joinType plan.JoinType + primaryRow := make(sql.Row, parentLen+len(j.Left().Schema())) + copy(primaryRow, row) - foundMatch bool - rowSize int - scopeLen int - b sql.NodeExecBuilder + return sql.NewSpanIter(span, &rangeHeapJoinIter{ + ctx: ctx, + b: b, + joinType: j.Op, + cond: j.Filter, - rangeHeapPlan *plan.RangeHeap - childRowIter sql.RowIter - pendingRow sql.Row + primary: l, + primaryRow: primaryRow, + loadPrimaryRow: true, - activeRanges []sql.Row - err error + rowSize: len(row) + len(j.Left().Schema()) + len(j.Right().Schema()), + scopeLen: j.ScopeLen, + parentLen: parentLen, - ctx *sql.Context + rangeHeapPlan: rhp, + }), nil } func (iter *rangeHeapJoinIter) loadPrimary(ctx *sql.Context) error { - if iter.primaryRow == nil { + if iter.loadPrimaryRow { r, err := iter.primary.Next(ctx) if err != nil { return err } - iter.primaryRow = iter.parentRow.Append(r) + copy(iter.primaryRow[iter.parentLen:], r) iter.foundMatch = false + iter.loadPrimaryRow = false err = iter.initializeHeap(ctx, iter.b, iter.primaryRow) if err != nil { @@ -103,7 +114,6 @@ func (iter *rangeHeapJoinIter) loadPrimary(ctx *sql.Context) error { func (iter *rangeHeapJoinIter) loadSecondary(ctx *sql.Context) (sql.Row, error) { if iter.secondary == nil { rowIter, err := iter.getActiveRanges(ctx, iter.b, iter.primaryRow) - if err != nil { return nil, err } @@ -121,7 +131,7 @@ func (iter *rangeHeapJoinIter) loadSecondary(ctx *sql.Context) (sql.Row, error) if err != nil { return nil, err } - iter.primaryRow = nil + iter.loadPrimaryRow = true return nil, io.EOF } return nil, err @@ -141,14 +151,14 @@ func (iter *rangeHeapJoinIter) Next(ctx *sql.Context) (sql.Row, error) { if err != nil { if errors.Is(err, io.EOF) { if !iter.foundMatch && iter.joinType.IsLeftOuter() { - iter.primaryRow = nil + iter.loadPrimaryRow = true row := iter.buildRow(primary, nil) return iter.removeParentRow(row), nil } continue } else if errors.Is(err, plan.ErrEmptyCachedResult) { if !iter.foundMatch && iter.joinType.IsLeftOuter() { - iter.primaryRow = nil + iter.loadPrimaryRow = true row := iter.buildRow(primary, nil) return iter.removeParentRow(row), nil } @@ -171,7 +181,7 @@ func (iter *rangeHeapJoinIter) Next(ctx *sql.Context) (sql.Row, error) { if err != nil { return nil, err } - iter.primaryRow = nil + iter.loadPrimaryRow = true continue } @@ -185,18 +195,16 @@ func (iter *rangeHeapJoinIter) Next(ctx *sql.Context) (sql.Row, error) { } func (iter *rangeHeapJoinIter) removeParentRow(r sql.Row) sql.Row { - copy(r[iter.scopeLen:], r[len(iter.parentRow):]) - r = r[:len(r)-len(iter.parentRow)+iter.scopeLen] + copy(r[iter.scopeLen:], r[iter.parentLen:]) + r = r[:len(r)-iter.parentLen+iter.scopeLen] return r } // buildRow builds the result set row using the rows from the primary and secondary tables func (iter *rangeHeapJoinIter) buildRow(primary, secondary sql.Row) sql.Row { row := make(sql.Row, iter.rowSize) - copy(row, primary) copy(row[len(primary):], secondary) - return row } @@ -306,7 +314,7 @@ func compareNullsFirst(ctx *sql.Context, comparisonType sql.Type, a, b interface return comparisonType.Compare(ctx, a, b) } -func (iter rangeHeapJoinIter) Len() int { return len(iter.activeRanges) } +func (iter *rangeHeapJoinIter) Len() int { return len(iter.activeRanges) } func (iter *rangeHeapJoinIter) Less(i, j int) bool { lhs := iter.activeRanges[i][iter.rangeHeapPlan.MaxColumnIndex] diff --git a/sql/rowexec/rel.go b/sql/rowexec/rel.go index 42942213f9..d5ea5107e0 100644 --- a/sql/rowexec/rel.go +++ b/sql/rowexec/rel.go @@ -103,7 +103,7 @@ func (b *BaseBuilder) buildValues(ctx *sql.Context, n *plan.Values, row sql.Row) } } - rows[i] = sql.NewRow(vals...) + rows[i] = vals } return sql.RowsToRowIter(rows...), nil diff --git a/sql/rows.go b/sql/rows.go index faf3a738bf..bd89fd7cd4 100644 --- a/sql/rows.go +++ b/sql/rows.go @@ -29,7 +29,7 @@ type Row []interface{} // NewRow creates a row from the given values. func NewRow(values ...interface{}) Row { - row := make([]interface{}, len(values)) + row := make(Row, len(values)) copy(row, values) return row }