github.com/dolthub/go-mysql-server@v0.18.0/sql/rowexec/join_iters.go (about)

     1  // Copyright 2020-2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package rowexec
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"reflect"
    22  
    23  	"go.opentelemetry.io/otel/attribute"
    24  	"go.opentelemetry.io/otel/trace"
    25  
    26  	"github.com/dolthub/go-mysql-server/sql"
    27  	"github.com/dolthub/go-mysql-server/sql/expression"
    28  	"github.com/dolthub/go-mysql-server/sql/plan"
    29  	"github.com/dolthub/go-mysql-server/sql/transform"
    30  )
    31  
    32  func newJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) {
    33  	var leftName, rightName string
    34  	if leftTable, ok := j.Left().(sql.Nameable); ok {
    35  		leftName = leftTable.Name()
    36  	} else {
    37  		leftName = reflect.TypeOf(j.Left()).String()
    38  	}
    39  
    40  	if rightTable, ok := j.Right().(sql.Nameable); ok {
    41  		rightName = rightTable.Name()
    42  	} else {
    43  		rightName = reflect.TypeOf(j.Right()).String()
    44  	}
    45  
    46  	span, ctx := ctx.Span("plan.joinIter", trace.WithAttributes(
    47  		attribute.String("left", leftName),
    48  		attribute.String("right", rightName),
    49  	))
    50  
    51  	l, err := b.Build(ctx, j.Left(), row)
    52  	if err != nil {
    53  		span.End()
    54  		return nil, err
    55  	}
    56  	return sql.NewSpanIter(span, &joinIter{
    57  		parentRow:         row,
    58  		primary:           l,
    59  		secondaryProvider: j.Right(),
    60  		cond:              j.Filter,
    61  		joinType:          j.Op,
    62  		rowSize:           len(row) + len(j.Left().Schema()) + len(j.Right().Schema()),
    63  		scopeLen:          j.ScopeLen,
    64  		b:                 b,
    65  	}), nil
    66  }
    67  
    68  // joinIter is an iterator that iterates over every row in the primary table and performs an index lookup in
    69  // the secondary table for each value
    70  type joinIter struct {
    71  	parentRow         sql.Row
    72  	primary           sql.RowIter
    73  	primaryRow        sql.Row
    74  	secondaryProvider sql.Node
    75  	secondary         sql.RowIter
    76  	cond              sql.Expression
    77  	joinType          plan.JoinType
    78  
    79  	foundMatch bool
    80  	rowSize    int
    81  	scopeLen   int
    82  	b          sql.NodeExecBuilder
    83  }
    84  
    85  func (i *joinIter) loadPrimary(ctx *sql.Context) error {
    86  	if i.primaryRow == nil {
    87  		r, err := i.primary.Next(ctx)
    88  		if err != nil {
    89  			return err
    90  		}
    91  
    92  		i.primaryRow = i.parentRow.Append(r)
    93  		i.foundMatch = false
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  func (i *joinIter) loadSecondary(ctx *sql.Context) (sql.Row, error) {
   100  	if i.secondary == nil {
   101  		rowIter, err := i.b.Build(ctx, i.secondaryProvider, i.primaryRow)
   102  
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		if plan.IsEmptyIter(rowIter) {
   107  			return nil, plan.ErrEmptyCachedResult
   108  		}
   109  		i.secondary = rowIter
   110  	}
   111  
   112  	secondaryRow, err := i.secondary.Next(ctx)
   113  	if err != nil {
   114  		if err == io.EOF {
   115  			err = i.secondary.Close(ctx)
   116  			i.secondary = nil
   117  			if err != nil {
   118  				return nil, err
   119  			}
   120  			i.primaryRow = nil
   121  			return nil, io.EOF
   122  		}
   123  		return nil, err
   124  	}
   125  
   126  	return secondaryRow, nil
   127  }
   128  
   129  func (i *joinIter) Next(ctx *sql.Context) (sql.Row, error) {
   130  	for {
   131  		if err := i.loadPrimary(ctx); err != nil {
   132  			return nil, err
   133  		}
   134  
   135  		primary := i.primaryRow
   136  		secondary, err := i.loadSecondary(ctx)
   137  		if err != nil {
   138  			if errors.Is(err, io.EOF) {
   139  				if !i.foundMatch && i.joinType.IsLeftOuter() {
   140  					i.primaryRow = nil
   141  					row := i.buildRow(primary, nil)
   142  					return i.removeParentRow(row), nil
   143  				}
   144  				continue
   145  			} else if errors.Is(err, plan.ErrEmptyCachedResult) {
   146  				if !i.foundMatch && i.joinType.IsLeftOuter() {
   147  					i.primaryRow = nil
   148  					row := i.buildRow(primary, nil)
   149  					return i.removeParentRow(row), nil
   150  				}
   151  
   152  				return nil, io.EOF
   153  			}
   154  			return nil, err
   155  		}
   156  
   157  		row := i.buildRow(primary, secondary)
   158  		res, err := sql.EvaluateCondition(ctx, i.cond, row)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  
   163  		if res == nil && i.joinType.IsExcludeNulls() {
   164  			err = i.secondary.Close(ctx)
   165  			i.secondary = nil
   166  			if err != nil {
   167  				return nil, err
   168  			}
   169  			i.primaryRow = nil
   170  			continue
   171  		}
   172  
   173  		if !sql.IsTrue(res) {
   174  			continue
   175  		}
   176  
   177  		i.foundMatch = true
   178  		return i.removeParentRow(row), nil
   179  	}
   180  }
   181  
   182  func (i *joinIter) removeParentRow(r sql.Row) sql.Row {
   183  	copy(r[i.scopeLen:], r[len(i.parentRow):])
   184  	r = r[:len(r)-len(i.parentRow)+i.scopeLen]
   185  	return r
   186  }
   187  
   188  // buildRow builds the result set row using the rows from the primary and secondary tables
   189  func (i *joinIter) buildRow(primary, secondary sql.Row) sql.Row {
   190  	row := make(sql.Row, i.rowSize)
   191  
   192  	copy(row, primary)
   193  	copy(row[len(primary):], secondary)
   194  
   195  	return row
   196  }
   197  
   198  func (i *joinIter) Close(ctx *sql.Context) (err error) {
   199  	if i.primary != nil {
   200  		if err = i.primary.Close(ctx); err != nil {
   201  			if i.secondary != nil {
   202  				_ = i.secondary.Close(ctx)
   203  			}
   204  			return err
   205  		}
   206  	}
   207  
   208  	if i.secondary != nil {
   209  		err = i.secondary.Close(ctx)
   210  		i.secondary = nil
   211  	}
   212  
   213  	return err
   214  }
   215  
   216  func newExistsIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) {
   217  	leftIter, err := b.Build(ctx, j.Left(), row)
   218  
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return &existsIter{
   223  		parentRow:         row,
   224  		typ:               j.Op,
   225  		primary:           leftIter,
   226  		secondaryProvider: j.Right(),
   227  		cond:              j.Filter,
   228  		scopeLen:          j.ScopeLen,
   229  		rowSize:           len(row) + len(j.Left().Schema()) + len(j.Right().Schema()),
   230  		nullRej:           !(j.Filter != nil && plan.IsNullRejecting(j.Filter)),
   231  		b:                 b,
   232  	}, nil
   233  }
   234  
   235  type existsIter struct {
   236  	typ               plan.JoinType
   237  	primary           sql.RowIter
   238  	secondaryProvider sql.Node
   239  	cond              sql.Expression
   240  
   241  	primaryRow sql.Row
   242  
   243  	parentRow         sql.Row
   244  	scopeLen          int
   245  	rowSize           int
   246  	nullRej           bool
   247  	rightIterNonEmpty bool
   248  	b                 sql.NodeExecBuilder
   249  }
   250  
   251  type existsState uint8
   252  
   253  const (
   254  	esIncLeft existsState = iota
   255  	esIncRight
   256  	esRightIterEOF
   257  	esCompare
   258  	esRejectNull
   259  	esRet
   260  )
   261  
   262  func (i *existsIter) Next(ctx *sql.Context) (sql.Row, error) {
   263  	var row sql.Row
   264  	var right sql.Row
   265  	var left sql.Row
   266  	var rIter sql.RowIter
   267  	var err error
   268  
   269  	// the common sequence is: LOAD_LEFT -> LOAD_RIGHT -> COMPARE -> RET
   270  	// notable exceptions are represented as goto jumps:
   271  	//  - non-null rejecting filters jump to COMPARE with a nil right row
   272  	//    when the secondaryProvider is empty
   273  	//  - antiJoin succeeds to RET when LOAD_RIGHT EOF's
   274  	//  - semiJoin fails when LOAD_RIGHT EOF's, falling back to LOAD_LEFT
   275  	//  - antiJoin fails when COMPARE returns true, falling back to LOAD_LEFT
   276  	nextState := esIncLeft
   277  	for {
   278  		switch nextState {
   279  		case esIncLeft:
   280  			r, err := i.primary.Next(ctx)
   281  			if err != nil {
   282  				return nil, err
   283  			}
   284  			left = i.parentRow.Append(r)
   285  			rIter, err = i.b.Build(ctx, i.secondaryProvider, left)
   286  
   287  			if err != nil {
   288  				return nil, err
   289  			}
   290  			if plan.IsEmptyIter(rIter) {
   291  				if i.nullRej || i.typ.IsAnti() {
   292  					return nil, io.EOF
   293  				}
   294  				nextState = esCompare
   295  			} else {
   296  				nextState = esIncRight
   297  			}
   298  		case esIncRight:
   299  			right, err = rIter.Next(ctx)
   300  			if err != nil {
   301  				iterErr := rIter.Close(ctx)
   302  				if iterErr != nil {
   303  					return nil, fmt.Errorf("%w; error on close: %s", err, iterErr)
   304  				}
   305  				if errors.Is(err, io.EOF) {
   306  					nextState = esRightIterEOF
   307  				} else {
   308  					return nil, err
   309  				}
   310  			} else {
   311  				i.rightIterNonEmpty = true
   312  				nextState = esCompare
   313  			}
   314  		case esRightIterEOF:
   315  			if i.typ.IsSemi() {
   316  				// reset iter, no match
   317  				nextState = esIncLeft
   318  			} else if !i.rightIterNonEmpty && !isTrueLit(i.cond) {
   319  				// ANTI_JOIN with empty RHS is subject to special cases,
   320  				// the first two are a valid match.
   321  				//   1) If we matched no rows but rows were returned
   322  				//   2) No match and no rows returned, EXISTS check
   323  				//   3) No match and no rows returned, IN check
   324  				return nil, io.EOF
   325  			} else {
   326  				nextState = esRet
   327  			}
   328  		case esCompare:
   329  			row = i.buildRow(left, right)
   330  			res, err := sql.EvaluateCondition(ctx, i.cond, row)
   331  			if err != nil {
   332  				return nil, err
   333  			}
   334  
   335  			if res == nil && i.typ.IsExcludeNulls() {
   336  				nextState = esRejectNull
   337  				continue
   338  			}
   339  
   340  			if !sql.IsTrue(res) {
   341  				nextState = esIncRight
   342  			} else {
   343  				err = rIter.Close(ctx)
   344  				if err != nil {
   345  					return nil, err
   346  				}
   347  				if i.typ.IsAnti() {
   348  					// reset iter, found match -> no return row
   349  					nextState = esIncLeft
   350  				} else {
   351  					nextState = esRet
   352  				}
   353  			}
   354  		case esRejectNull:
   355  			if i.typ.IsAnti() {
   356  				nextState = esIncLeft
   357  			} else {
   358  				nextState = esIncRight
   359  			}
   360  		case esRet:
   361  			return i.removeParentRow(left), nil
   362  		default:
   363  			return nil, fmt.Errorf("invalid exists join state")
   364  		}
   365  	}
   366  }
   367  
   368  func isTrueLit(e sql.Expression) bool {
   369  	if lit, ok := e.(*expression.Literal); ok {
   370  		return lit.Value() == true
   371  	}
   372  	return false
   373  }
   374  
   375  func (i *existsIter) removeParentRow(r sql.Row) sql.Row {
   376  	copy(r[i.scopeLen:], r[len(i.parentRow):])
   377  	r = r[:len(r)-len(i.parentRow)+i.scopeLen]
   378  	return r
   379  }
   380  
   381  // buildRow builds the result set row using the rows from the primary and secondary tables
   382  func (i *existsIter) buildRow(primary, secondary sql.Row) sql.Row {
   383  	row := make(sql.Row, i.rowSize)
   384  
   385  	copy(row, primary)
   386  	copy(row[len(primary):], secondary)
   387  
   388  	return row
   389  }
   390  
   391  func (i *existsIter) Close(ctx *sql.Context) (err error) {
   392  	if i.primary != nil {
   393  		if err = i.primary.Close(ctx); err != nil {
   394  			return err
   395  		}
   396  	}
   397  	return err
   398  }
   399  
   400  func newFullJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) {
   401  	leftIter, err := b.Build(ctx, j.Left(), row)
   402  
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	return &fullJoinIter{
   407  		parentRow: row,
   408  		l:         leftIter,
   409  		rp:        j.Right(),
   410  		cond:      j.Filter,
   411  		scopeLen:  j.ScopeLen,
   412  		rowSize:   len(row) + len(j.Left().Schema()) + len(j.Right().Schema()),
   413  		seenLeft:  make(map[uint64]struct{}),
   414  		seenRight: make(map[uint64]struct{}),
   415  		b:         b,
   416  	}, nil
   417  }
   418  
   419  // fullJoinIter implements full join as a union of left and right join:
   420  // FJ(A,B) => U(LJ(A,B), RJ(A,B)). The current algorithm will have a
   421  // runtime and memory complexity O(m+n).
   422  type fullJoinIter struct {
   423  	l    sql.RowIter
   424  	rp   sql.Node
   425  	b    sql.NodeExecBuilder
   426  	r    sql.RowIter
   427  	cond sql.Expression
   428  
   429  	parentRow sql.Row
   430  	leftRow   sql.Row
   431  	scopeLen  int
   432  	rowSize   int
   433  
   434  	leftDone  bool
   435  	seenLeft  map[uint64]struct{}
   436  	seenRight map[uint64]struct{}
   437  }
   438  
   439  func (i *fullJoinIter) Next(ctx *sql.Context) (sql.Row, error) {
   440  	for {
   441  		if i.leftDone {
   442  			break
   443  		}
   444  		if i.leftRow == nil {
   445  			r, err := i.l.Next(ctx)
   446  			if errors.Is(err, io.EOF) {
   447  				i.leftDone = true
   448  				i.l = nil
   449  				i.r = nil
   450  			}
   451  			if err != nil {
   452  				return nil, err
   453  			}
   454  
   455  			i.leftRow = r
   456  		}
   457  
   458  		if i.r == nil {
   459  			iter, err := i.b.Build(ctx, i.rp, i.leftRow)
   460  			if err != nil {
   461  				return nil, err
   462  			}
   463  			i.r = iter
   464  		}
   465  
   466  		rightRow, err := i.r.Next(ctx)
   467  		if err == io.EOF {
   468  			key, err := sql.HashOf(i.leftRow)
   469  			if err != nil {
   470  				return nil, err
   471  			}
   472  			if _, ok := i.seenLeft[key]; !ok {
   473  				// (left, null) only if we haven't matched left
   474  				ret := i.buildRow(i.leftRow, nil)
   475  				i.r = nil
   476  				i.leftRow = nil
   477  				return i.removeParentRow(ret), nil
   478  			}
   479  			i.r = nil
   480  			i.leftRow = nil
   481  		}
   482  
   483  		row := i.buildRow(i.leftRow, rightRow)
   484  		matches, err := sql.EvaluateCondition(ctx, i.cond, row)
   485  		if err != nil {
   486  			return nil, err
   487  		}
   488  		if !sql.IsTrue(matches) {
   489  			continue
   490  		}
   491  		rkey, err := sql.HashOf(rightRow)
   492  		if err != nil {
   493  			return nil, err
   494  		}
   495  		i.seenRight[rkey] = struct{}{}
   496  		lKey, err := sql.HashOf(i.leftRow)
   497  		if err != nil {
   498  			return nil, err
   499  		}
   500  		i.seenLeft[lKey] = struct{}{}
   501  		return i.removeParentRow(row), nil
   502  	}
   503  
   504  	for {
   505  		if i.r == nil {
   506  			iter, err := i.b.Build(ctx, i.rp, i.leftRow)
   507  			if err != nil {
   508  				return nil, err
   509  			}
   510  
   511  			i.r = iter
   512  		}
   513  
   514  		rightRow, err := i.r.Next(ctx)
   515  		if errors.Is(err, io.EOF) {
   516  			err := i.r.Close(ctx)
   517  			if err != nil {
   518  				return nil, err
   519  			}
   520  			return nil, io.EOF
   521  		}
   522  
   523  		key, err := sql.HashOf(rightRow)
   524  		if err != nil {
   525  			return nil, err
   526  		}
   527  		if _, ok := i.seenRight[key]; ok {
   528  			continue
   529  		}
   530  		// (null, right) only if we haven't matched right
   531  		ret := i.buildRow(nil, rightRow)
   532  		return i.removeParentRow(ret), nil
   533  	}
   534  }
   535  
   536  func (i *fullJoinIter) removeParentRow(r sql.Row) sql.Row {
   537  	copy(r[i.scopeLen:], r[len(i.parentRow):])
   538  	r = r[:len(r)-len(i.parentRow)+i.scopeLen]
   539  	return r
   540  }
   541  
   542  // buildRow builds the result set row using the rows from the primary and secondary tables
   543  func (i *fullJoinIter) buildRow(primary, secondary sql.Row) sql.Row {
   544  	row := make(sql.Row, i.rowSize)
   545  
   546  	copy(row, primary)
   547  	copy(row[len(primary):], secondary)
   548  
   549  	return row
   550  }
   551  
   552  func (i *fullJoinIter) Close(ctx *sql.Context) (err error) {
   553  	if i.l != nil {
   554  		err = i.l.Close(ctx)
   555  	}
   556  
   557  	if i.r != nil {
   558  		if err == nil {
   559  			err = i.r.Close(ctx)
   560  		} else {
   561  			i.r.Close(ctx)
   562  		}
   563  	}
   564  
   565  	return err
   566  }
   567  
   568  func newCrossJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) {
   569  	var left, right string
   570  	if leftTable, ok := j.Left().(sql.Nameable); ok {
   571  		left = leftTable.Name()
   572  	} else {
   573  		left = reflect.TypeOf(j.Left()).String()
   574  	}
   575  
   576  	if rightTable, ok := j.Right().(sql.Nameable); ok {
   577  		right = rightTable.Name()
   578  	} else {
   579  		right = reflect.TypeOf(j.Right()).String()
   580  	}
   581  
   582  	span, ctx := ctx.Span("plan.CrossJoin", trace.WithAttributes(
   583  		attribute.String("left", left),
   584  		attribute.String("right", right),
   585  	))
   586  
   587  	l, err := b.Build(ctx, j.Left(), row)
   588  	if err != nil {
   589  		span.End()
   590  		return nil, err
   591  	}
   592  
   593  	return sql.NewSpanIter(span, &crossJoinIterator{
   594  		b:         b,
   595  		parentRow: row,
   596  		l:         l,
   597  		rp:        j.Right(),
   598  		rowSize:   len(row) + len(j.Left().Schema()) + len(j.Right().Schema()),
   599  		scopeLen:  j.ScopeLen,
   600  	}), nil
   601  }
   602  
   603  type crossJoinIterator struct {
   604  	l  sql.RowIter
   605  	r  sql.RowIter
   606  	rp sql.Node
   607  	b  sql.NodeExecBuilder
   608  
   609  	parentRow sql.Row
   610  
   611  	rowSize  int
   612  	scopeLen int
   613  
   614  	leftRow sql.Row
   615  }
   616  
   617  func (i *crossJoinIterator) Next(ctx *sql.Context) (sql.Row, error) {
   618  	for {
   619  		if i.leftRow == nil {
   620  			r, err := i.l.Next(ctx)
   621  			if err != nil {
   622  				return nil, err
   623  			}
   624  
   625  			i.leftRow = i.parentRow.Append(r)
   626  		}
   627  
   628  		if i.r == nil {
   629  			iter, err := i.b.Build(ctx, i.rp, i.leftRow)
   630  			if err != nil {
   631  				return nil, err
   632  			}
   633  
   634  			i.r = iter
   635  		}
   636  
   637  		rightRow, err := i.r.Next(ctx)
   638  		if err == io.EOF {
   639  			i.r = nil
   640  			i.leftRow = nil
   641  			continue
   642  		}
   643  
   644  		if err != nil {
   645  			return nil, err
   646  		}
   647  
   648  		var row sql.Row
   649  		row = append(row, i.leftRow...)
   650  		row = append(row, rightRow...)
   651  
   652  		return i.removeParentRow(row), nil
   653  	}
   654  }
   655  
   656  func (i *crossJoinIterator) removeParentRow(r sql.Row) sql.Row {
   657  	copy(r[i.scopeLen:], r[len(i.parentRow):])
   658  	r = r[:len(r)-len(i.parentRow)+i.scopeLen]
   659  	return r
   660  }
   661  
   662  func (i *crossJoinIterator) Close(ctx *sql.Context) (err error) {
   663  	if i.l != nil {
   664  		err = i.l.Close(ctx)
   665  	}
   666  
   667  	if i.r != nil {
   668  		if err == nil {
   669  			err = i.r.Close(ctx)
   670  		} else {
   671  			i.r.Close(ctx)
   672  		}
   673  	}
   674  
   675  	return err
   676  }
   677  
   678  // lateralJoinIter is an iterator that performs a lateral join.
   679  // A LateralJoin is a join where the right side is a subquery that can reference the left side, like through a filter.
   680  // MySQL Docs: https://dev.mysql.com/doc/refman/8.0/en/lateral-derived-tables.html
   681  // Example:
   682  // select * from t;
   683  // +---+
   684  // | i |
   685  // +---+
   686  // | 1 |
   687  // | 2 |
   688  // | 3 |
   689  // +---+
   690  // select * from t1;
   691  // +---+
   692  // | i |
   693  // +---+
   694  // | 1 |
   695  // | 4 |
   696  // | 5 |
   697  // +---+
   698  // select * from t, lateral (select * from t1 where t.i = t1.j) tt;
   699  // +---+---+
   700  // | i | j |
   701  // +---+---+
   702  // | 1 | 1 |
   703  // +---+---+
   704  // cond is passed to the filter iter to be evaluated.
   705  type lateralJoinIterator struct {
   706  	pRow  sql.Row
   707  	lRow  sql.Row
   708  	rRow  sql.Row
   709  	lIter sql.RowIter
   710  	rIter sql.RowIter
   711  	rNode sql.Node
   712  	cond  sql.Expression
   713  	jType plan.JoinType
   714  
   715  	rowSize  int
   716  	scopeLen int
   717  
   718  	foundMatch bool
   719  
   720  	b sql.NodeExecBuilder
   721  }
   722  
   723  func newLateralJoinIter(ctx *sql.Context, b sql.NodeExecBuilder, j *plan.JoinNode, row sql.Row) (sql.RowIter, error) {
   724  	var left, right string
   725  	if leftTable, ok := j.Left().(sql.Nameable); ok {
   726  		left = leftTable.Name()
   727  	} else {
   728  		left = reflect.TypeOf(j.Left()).String()
   729  	}
   730  	if rightTable, ok := j.Right().(sql.Nameable); ok {
   731  		right = rightTable.Name()
   732  	} else {
   733  		right = reflect.TypeOf(j.Right()).String()
   734  	}
   735  
   736  	span, ctx := ctx.Span("plan.LateralJoin", trace.WithAttributes(
   737  		attribute.String("left", left),
   738  		attribute.String("right", right),
   739  	))
   740  
   741  	l, err := b.Build(ctx, j.Left(), row)
   742  	if err != nil {
   743  		span.End()
   744  		return nil, err
   745  	}
   746  
   747  	return sql.NewSpanIter(span, &lateralJoinIterator{
   748  		pRow:     row,
   749  		lIter:    l,
   750  		rNode:    j.Right(),
   751  		cond:     j.Filter,
   752  		jType:    j.Op,
   753  		rowSize:  len(row) + len(j.Left().Schema()) + len(j.Right().Schema()),
   754  		scopeLen: j.ScopeLen,
   755  		b:        b,
   756  	}), nil
   757  }
   758  
   759  func (i *lateralJoinIterator) loadLeft(ctx *sql.Context) error {
   760  	if i.lRow == nil {
   761  		lRow, err := i.lIter.Next(ctx)
   762  		if err != nil {
   763  			return err
   764  		}
   765  		i.lRow = lRow
   766  		i.foundMatch = false
   767  	}
   768  	return nil
   769  }
   770  
   771  func (i *lateralJoinIterator) buildRight(ctx *sql.Context) error {
   772  	if i.rIter == nil {
   773  		prepended, _, err := transform.Node(i.rNode, plan.PrependRowInPlan(i.lRow, true))
   774  		if err != nil {
   775  			return err
   776  		}
   777  		iter, err := i.b.Build(ctx, prepended, i.lRow)
   778  		if err != nil {
   779  			return err
   780  		}
   781  		i.rIter = iter
   782  	}
   783  	return nil
   784  }
   785  
   786  func (i *lateralJoinIterator) loadRight(ctx *sql.Context) error {
   787  	if i.rRow == nil {
   788  		rRow, err := i.rIter.Next(ctx)
   789  		if err != nil {
   790  			return err
   791  		}
   792  		i.rRow = rRow[len(i.lRow):]
   793  	}
   794  	return nil
   795  }
   796  
   797  func (i *lateralJoinIterator) buildRow(lRow, rRow sql.Row) sql.Row {
   798  	row := make(sql.Row, i.rowSize)
   799  	copy(row, lRow)
   800  	copy(row[len(lRow):], rRow)
   801  	return row
   802  }
   803  
   804  func (i *lateralJoinIterator) removeParentRow(r sql.Row) sql.Row {
   805  	copy(r[i.scopeLen:], r[len(i.pRow):])
   806  	r = r[:len(r)-len(i.pRow)+i.scopeLen]
   807  	return r
   808  }
   809  
   810  func (i *lateralJoinIterator) reset(ctx *sql.Context) (err error) {
   811  	if i.rIter != nil {
   812  		err = i.rIter.Close(ctx)
   813  		i.rIter = nil
   814  	}
   815  	i.lRow = nil
   816  	i.rRow = nil
   817  	return
   818  }
   819  
   820  func (i *lateralJoinIterator) Next(ctx *sql.Context) (sql.Row, error) {
   821  	for {
   822  		if err := i.loadLeft(ctx); err != nil {
   823  			return nil, err
   824  		}
   825  		if err := i.buildRight(ctx); err != nil {
   826  			return nil, err
   827  		}
   828  		if err := i.loadRight(ctx); err != nil {
   829  			if errors.Is(err, io.EOF) {
   830  				if !i.foundMatch && i.jType == plan.JoinTypeLateralLeft {
   831  					res := i.buildRow(i.lRow, nil)
   832  					if rerr := i.reset(ctx); rerr != nil {
   833  						return nil, rerr
   834  					}
   835  					return i.removeParentRow(res), nil
   836  				}
   837  				if rerr := i.reset(ctx); rerr != nil {
   838  					return nil, rerr
   839  				}
   840  				continue
   841  			}
   842  			return nil, err
   843  		}
   844  
   845  		row := i.buildRow(i.lRow, i.rRow)
   846  		i.rRow = nil
   847  		if i.cond != nil {
   848  			if res, err := sql.EvaluateCondition(ctx, i.cond, row); err != nil {
   849  				return nil, err
   850  			} else if !sql.IsTrue(res) {
   851  				continue
   852  			}
   853  		}
   854  
   855  		i.foundMatch = true
   856  		return i.removeParentRow(row), nil
   857  	}
   858  }
   859  
   860  func (i *lateralJoinIterator) Close(ctx *sql.Context) error {
   861  	var lerr, rerr error
   862  	if i.lIter != nil {
   863  		lerr = i.lIter.Close(ctx)
   864  	}
   865  	if i.rIter != nil {
   866  		rerr = i.rIter.Close(ctx)
   867  	}
   868  	if lerr != nil {
   869  		return lerr
   870  	}
   871  	if rerr != nil {
   872  		return rerr
   873  	}
   874  	return nil
   875  }