github.com/dolthub/go-mysql-server@v0.18.0/enginetest/evaluation.go (about)

     1  // Copyright 2022 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 enginetest
    16  
    17  import (
    18  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/dolthub/vitess/go/sqltypes"
    25  	querypb "github.com/dolthub/vitess/go/vt/proto/query"
    26  	"github.com/dolthub/vitess/go/vt/sqlparser"
    27  	"github.com/shopspring/decimal"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  	"gopkg.in/src-d/go-errors.v1"
    31  
    32  	sqle "github.com/dolthub/go-mysql-server"
    33  	"github.com/dolthub/go-mysql-server/enginetest/queries"
    34  	"github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup"
    35  	"github.com/dolthub/go-mysql-server/sql"
    36  	"github.com/dolthub/go-mysql-server/sql/expression"
    37  	"github.com/dolthub/go-mysql-server/sql/plan"
    38  	"github.com/dolthub/go-mysql-server/sql/planbuilder"
    39  	"github.com/dolthub/go-mysql-server/sql/transform"
    40  	"github.com/dolthub/go-mysql-server/sql/types"
    41  )
    42  
    43  // RunQueryWithContext runs the query given and asserts that it doesn't result in an error.
    44  // If |ctx| is nil, this function creates new context using `NewContext()` method on given harness.
    45  func RunQueryWithContext(t *testing.T, e QueryEngine, harness Harness, ctx *sql.Context, query string) {
    46  	if ctx == nil {
    47  		ctx = NewContext(harness)
    48  	}
    49  	ctx = ctx.WithQuery(query)
    50  	_, iter, err := e.Query(ctx, query)
    51  	require.NoError(t, err, "error running query %s: %v", query, err)
    52  	_, err = sql.RowIterToRows(ctx, iter)
    53  	require.NoError(t, err)
    54  	validateEngine(t, ctx, harness, e)
    55  }
    56  
    57  // TestScript runs the test script given, making any assertions given
    58  func TestScript(t *testing.T, harness Harness, script queries.ScriptTest) {
    59  	e := mustNewEngine(t, harness)
    60  	defer e.Close()
    61  	TestScriptWithEngine(t, e, harness, script)
    62  }
    63  
    64  func IsServerEngine(e QueryEngine) bool {
    65  	_, ok := e.(*ServerQueryEngine)
    66  	return ok
    67  }
    68  
    69  // CreateNewConnectionForServerEngine creates a new connection in the server engine.
    70  // If there was an existing one, it gets closed before the new gets created.
    71  // This function should be called when needing to use new session for the server.
    72  func CreateNewConnectionForServerEngine(ctx *sql.Context, e QueryEngine) error {
    73  	if IsServerEngine(e) {
    74  		return e.(*ServerQueryEngine).NewConnection(ctx)
    75  	}
    76  	return nil
    77  }
    78  
    79  // TestScriptWithEngine runs the test script given with the engine provided.
    80  func TestScriptWithEngine(t *testing.T, e QueryEngine, harness Harness, script queries.ScriptTest) {
    81  	ctx := NewContext(harness)
    82  	err := CreateNewConnectionForServerEngine(ctx, e)
    83  	require.NoError(t, err, nil)
    84  
    85  	t.Run(script.Name, func(t *testing.T) {
    86  		for _, statement := range script.SetUpScript {
    87  			if sh, ok := harness.(SkippingHarness); ok {
    88  				if sh.SkipQueryTest(statement) {
    89  					t.Skip()
    90  				}
    91  			}
    92  			ctx = ctx.WithQuery(statement)
    93  			RunQueryWithContext(t, e, harness, ctx, statement)
    94  		}
    95  
    96  		assertions := script.Assertions
    97  		if len(assertions) == 0 {
    98  			assertions = []queries.ScriptTestAssertion{
    99  				{
   100  					Query:           script.Query,
   101  					Expected:        script.Expected,
   102  					ExpectedErr:     script.ExpectedErr,
   103  					ExpectedIndexes: script.ExpectedIndexes,
   104  				},
   105  			}
   106  		}
   107  
   108  		for _, assertion := range assertions {
   109  			t.Run(assertion.Query, func(t *testing.T) {
   110  				if assertion.NewSession {
   111  					th, ok := harness.(TransactionHarness)
   112  					require.True(t, ok, "ScriptTestAssertion requested a NewSession, "+
   113  						"but harness doesn't implement TransactionHarness")
   114  					ctx = th.NewSession()
   115  				}
   116  
   117  				if sh, ok := harness.(SkippingHarness); ok && sh.SkipQueryTest(assertion.Query) {
   118  					t.Skip()
   119  				}
   120  				if assertion.Skip {
   121  					t.Skip()
   122  				}
   123  
   124  				if assertion.ExpectedErr != nil {
   125  					AssertErr(t, e, harness, assertion.Query, assertion.ExpectedErr)
   126  				} else if assertion.ExpectedErrStr != "" {
   127  					AssertErrWithCtx(t, e, harness, ctx, assertion.Query, nil, assertion.ExpectedErrStr)
   128  				} else if assertion.ExpectedWarning != 0 {
   129  					AssertWarningAndTestQuery(t, e, nil, harness, assertion.Query,
   130  						assertion.Expected, nil, assertion.ExpectedWarning, assertion.ExpectedWarningsCount,
   131  						assertion.ExpectedWarningMessageSubstring, assertion.SkipResultsCheck)
   132  				} else if assertion.SkipResultsCheck {
   133  					RunQueryWithContext(t, e, harness, nil, assertion.Query)
   134  				} else if assertion.CheckIndexedAccess {
   135  					TestQueryWithIndexCheck(t, ctx, e, harness, assertion.Query, assertion.Expected, assertion.ExpectedColumns, assertion.Bindings)
   136  				} else {
   137  					var expected = assertion.Expected
   138  					if IsServerEngine(e) && assertion.SkipResultCheckOnServerEngine {
   139  						// TODO: remove this check in the future
   140  						expected = nil
   141  					}
   142  					TestQueryWithContext(t, ctx, e, harness, assertion.Query, expected, assertion.ExpectedColumns, assertion.Bindings)
   143  				}
   144  				if assertion.ExpectedIndexes != nil && !IsServerEngine(e) {
   145  					evalIndexTest(t, harness, e, assertion.Query, assertion.ExpectedIndexes, assertion.Skip)
   146  				}
   147  				if assertion.JoinTypes != nil && !IsServerEngine(e) {
   148  					evalJoinTypeTest(t, harness, e, assertion.Query, assertion.JoinTypes, assertion.Skip)
   149  				}
   150  			})
   151  		}
   152  	})
   153  }
   154  
   155  // TestScriptPrepared substitutes literals for bindvars, runs the test script given,
   156  // and makes any assertions given
   157  func TestScriptPrepared(t *testing.T, harness Harness, script queries.ScriptTest) bool {
   158  	return t.Run(script.Name, func(t *testing.T) {
   159  		if script.SkipPrepared {
   160  			t.Skip()
   161  		}
   162  
   163  		e := mustNewEngine(t, harness)
   164  		defer e.Close()
   165  		TestScriptWithEnginePrepared(t, e, harness, script)
   166  	})
   167  }
   168  
   169  // TestScriptWithEnginePrepared runs the test script with bindvars substituted for literals
   170  // using the engine provided.
   171  func TestScriptWithEnginePrepared(t *testing.T, e QueryEngine, harness Harness, script queries.ScriptTest) {
   172  	ctx := NewContext(harness)
   173  	err := CreateNewConnectionForServerEngine(ctx, e)
   174  	require.NoError(t, err, nil)
   175  
   176  	for _, statement := range script.SetUpScript {
   177  		if sh, ok := harness.(SkippingHarness); ok {
   178  			if sh.SkipQueryTest(statement) {
   179  				t.Skip()
   180  			}
   181  		}
   182  		ctx = NewContext(harness).WithQuery(statement)
   183  		RunQueryWithContext(t, e, harness, ctx, statement)
   184  		validateEngine(t, ctx, harness, e)
   185  	}
   186  
   187  	assertions := script.Assertions
   188  	if len(assertions) == 0 {
   189  		assertions = []queries.ScriptTestAssertion{
   190  			{
   191  				Query:           script.Query,
   192  				Expected:        script.Expected,
   193  				ExpectedErr:     script.ExpectedErr,
   194  				ExpectedIndexes: script.ExpectedIndexes,
   195  			},
   196  		}
   197  	}
   198  
   199  	for _, assertion := range assertions {
   200  		t.Run(assertion.Query, func(t *testing.T) {
   201  
   202  			if sh, ok := harness.(SkippingHarness); ok {
   203  				if sh.SkipQueryTest(assertion.Query) {
   204  					t.Skip()
   205  				}
   206  			}
   207  			if assertion.Skip {
   208  				t.Skip()
   209  			}
   210  
   211  			if assertion.NewSession {
   212  				th, ok := harness.(TransactionHarness)
   213  				require.True(t, ok, "ScriptTestAssertion requested a NewSession, "+
   214  					"but harness doesn't implement TransactionHarness")
   215  				ctx = th.NewSession()
   216  			}
   217  			if assertion.ExpectedErr != nil {
   218  				AssertErrPreparedWithCtx(t, e, harness, ctx, assertion.Query, assertion.ExpectedErr)
   219  			} else if assertion.ExpectedErrStr != "" {
   220  				AssertErrPreparedWithCtx(t, e, harness, ctx, assertion.Query, nil, assertion.ExpectedErrStr)
   221  			} else if assertion.ExpectedWarning != 0 {
   222  				AssertWarningAndTestQuery(t, e, nil, harness, assertion.Query,
   223  					assertion.Expected, nil, assertion.ExpectedWarning, assertion.ExpectedWarningsCount,
   224  					assertion.ExpectedWarningMessageSubstring, assertion.SkipResultsCheck)
   225  			} else if assertion.SkipResultsCheck {
   226  				ctx = NewContext(harness).WithQuery(assertion.Query)
   227  				_, _, err := runQueryPreparedWithCtx(t, ctx, e, assertion.Query, assertion.Bindings, false)
   228  				require.NoError(t, err)
   229  			} else {
   230  				ctx = NewContext(harness).WithQuery(assertion.Query)
   231  				TestPreparedQueryWithContext(t, ctx, e, harness, assertion.Query, assertion.Expected, nil, assertion.Bindings, assertion.CheckIndexedAccess)
   232  			}
   233  			if assertion.ExpectedIndexes != nil {
   234  				evalIndexTest(t, harness, e, assertion.Query, assertion.ExpectedIndexes, assertion.Skip)
   235  			}
   236  		})
   237  	}
   238  }
   239  
   240  // TestTransactionScript runs the test script given, making any assertions given
   241  func TestTransactionScript(t *testing.T, harness Harness, script queries.TransactionTest) bool {
   242  	// todo(max): these use dolt_commit, need harness reset to reset back to original commit
   243  	return t.Run(script.Name, func(t *testing.T) {
   244  		harness.Setup(setup.MydbData)
   245  		e := mustNewEngine(t, harness)
   246  		defer e.Close()
   247  		TestTransactionScriptWithEngine(t, e, harness, script)
   248  	})
   249  }
   250  
   251  // TestTransactionScriptWithEngine runs the transaction test script given with the engine provided.
   252  func TestTransactionScriptWithEngine(t *testing.T, e QueryEngine, harness Harness, script queries.TransactionTest) {
   253  	setupSession := NewSession(harness)
   254  	for _, statement := range script.SetUpScript {
   255  		RunQueryWithContext(t, e, harness, setupSession, statement)
   256  	}
   257  
   258  	clientSessions := make(map[string]*sql.Context)
   259  	assertions := script.Assertions
   260  
   261  	for _, assertion := range assertions {
   262  		client := getClient(assertion.Query)
   263  
   264  		clientSession, ok := clientSessions[client]
   265  		if !ok {
   266  			clientSession = NewSession(harness)
   267  			clientSessions[client] = clientSession
   268  		}
   269  
   270  		t.Run(assertion.Query, func(t *testing.T) {
   271  			if assertion.ExpectedErr != nil {
   272  				AssertErrWithCtx(t, e, harness, clientSession, assertion.Query, assertion.ExpectedErr)
   273  			} else if assertion.ExpectedErrStr != "" {
   274  				AssertErrWithCtx(t, e, harness, clientSession, assertion.Query, nil, assertion.ExpectedErrStr)
   275  			} else if assertion.ExpectedWarning != 0 {
   276  				AssertWarningAndTestQuery(t, e, nil, harness, assertion.Query, assertion.Expected,
   277  					nil, assertion.ExpectedWarning, assertion.ExpectedWarningsCount,
   278  					assertion.ExpectedWarningMessageSubstring, false)
   279  			} else if assertion.SkipResultsCheck {
   280  				RunQueryWithContext(t, e, harness, clientSession, assertion.Query)
   281  			} else {
   282  				TestQueryWithContext(t, clientSession, e, harness, assertion.Query, assertion.Expected, nil, nil)
   283  			}
   284  		})
   285  	}
   286  }
   287  
   288  // TestQuery runs a query on the engine given and asserts that results are as expected.
   289  // TODO: this should take en engine
   290  func TestQuery(t *testing.T, harness Harness, q string, expected []sql.Row, expectedCols []*sql.Column, bindings map[string]*querypb.BindVariable) {
   291  	t.Run(q, func(t *testing.T) {
   292  		if sh, ok := harness.(SkippingHarness); ok {
   293  			if sh.SkipQueryTest(q) {
   294  				t.Skipf("Skipping query %s", q)
   295  			}
   296  		}
   297  
   298  		e := mustNewEngine(t, harness)
   299  		defer e.Close()
   300  		ctx := NewContext(harness)
   301  		TestQueryWithContext(t, ctx, e, harness, q, expected, expectedCols, bindings)
   302  	})
   303  }
   304  
   305  // TestQuery runs a query on the engine given and asserts that results are as expected.
   306  func TestQuery2(t *testing.T, harness Harness, e QueryEngine, q string, expected []sql.Row, expectedCols []*sql.Column, bindings map[string]*querypb.BindVariable) {
   307  	t.Run(q, func(t *testing.T) {
   308  		if sh, ok := harness.(SkippingHarness); ok {
   309  			if sh.SkipQueryTest(q) {
   310  				t.Skipf("Skipping query %s", q)
   311  			}
   312  		}
   313  
   314  		ctx := NewContext(harness)
   315  		TestQueryWithContext(t, ctx, e, harness, q, expected, expectedCols, bindings)
   316  	})
   317  }
   318  
   319  // TODO: collapse into TestQuery
   320  func TestQueryWithEngine(t *testing.T, harness Harness, e QueryEngine, tt queries.QueryTest) {
   321  	t.Run(tt.Query, func(t *testing.T) {
   322  		if sh, ok := harness.(SkippingHarness); ok {
   323  			if sh.SkipQueryTest(tt.Query) {
   324  				t.Skipf("Skipping query %s", tt.Query)
   325  			}
   326  		}
   327  
   328  		ctx := NewContext(harness)
   329  		TestQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, tt.Bindings)
   330  	})
   331  }
   332  
   333  func TestQueryWithContext(t *testing.T, ctx *sql.Context, e QueryEngine, harness Harness, q string, expected []sql.Row, expectedCols []*sql.Column, bindings map[string]*querypb.BindVariable) {
   334  	ctx = ctx.WithQuery(q)
   335  	require := require.New(t)
   336  	if len(bindings) > 0 {
   337  		_, err := e.PrepareQuery(ctx, q)
   338  		require.NoError(err)
   339  	}
   340  
   341  	sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindings)
   342  	require.NoError(err, "Unexpected error for query %s: %s", q, err)
   343  
   344  	rows, err := sql.RowIterToRows(ctx, iter)
   345  	require.NoError(err, "Unexpected error for query %s: %s", q, err)
   346  
   347  	if expected != nil {
   348  		checkResults(t, expected, expectedCols, sch, rows, q, e)
   349  	}
   350  
   351  	require.Equal(
   352  		0, ctx.Memory.NumCaches())
   353  	validateEngine(t, ctx, harness, e)
   354  }
   355  
   356  func GetFilterIndex(n sql.Node) sql.IndexLookup {
   357  	var lookup sql.IndexLookup
   358  	transform.InspectUp(n, func(n sql.Node) bool {
   359  		switch n := n.(type) {
   360  		case *plan.IndexedTableAccess:
   361  			lookup = plan.GetIndexLookup(n)
   362  			return true
   363  		default:
   364  			return false
   365  		}
   366  	})
   367  	return lookup
   368  }
   369  
   370  func TestQueryWithIndexCheck(t *testing.T, ctx *sql.Context, e QueryEngine, harness Harness, q string, expected []sql.Row, expectedCols []*sql.Column, bindings map[string]*querypb.BindVariable) {
   371  	ctx = ctx.WithQuery(q)
   372  	require := require.New(t)
   373  	if len(bindings) > 0 {
   374  		_, err := e.PrepareQuery(ctx, q)
   375  		require.NoError(err)
   376  	}
   377  
   378  	if !IsServerEngine(e) {
   379  		node, err := e.AnalyzeQuery(ctx, q)
   380  		require.NoError(err, "Unexpected error for query %s: %s", q, err)
   381  		require.True(CheckIndexedAccess(node), "expected plan to have index, but found: %s", sql.DebugString(node))
   382  	}
   383  
   384  	sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindings)
   385  	require.NoError(err, "Unexpected error for query %s: %s", q, err)
   386  
   387  	rows, err := sql.RowIterToRows(ctx, iter)
   388  	require.NoError(err, "Unexpected error for query %s: %s", q, err)
   389  
   390  	if expected != nil {
   391  		checkResults(t, expected, expectedCols, sch, rows, q, e)
   392  	}
   393  
   394  	require.Equal(
   395  		0, ctx.Memory.NumCaches())
   396  	validateEngine(t, ctx, harness, e)
   397  }
   398  
   399  func CheckIndexedAccess(n sql.Node) bool {
   400  	var hasIndex bool
   401  	transform.Inspect(n, func(n sql.Node) bool {
   402  		if n == nil {
   403  			return false
   404  		}
   405  		if _, ok := n.(*plan.IndexedTableAccess); ok {
   406  			hasIndex = true
   407  		}
   408  		return true
   409  	})
   410  	return hasIndex
   411  }
   412  
   413  // TestPreparedQuery runs a prepared query on the engine given and asserts that results are as expected.
   414  func TestPreparedQuery(t *testing.T, harness Harness, q string, expected []sql.Row, expectedCols []*sql.Column) {
   415  	t.Run(q, func(t *testing.T) {
   416  		if sh, ok := harness.(SkippingHarness); ok {
   417  			if sh.SkipQueryTest(q) {
   418  				t.Skipf("Skipping query %s", q)
   419  			}
   420  		}
   421  		e := mustNewEngine(t, harness)
   422  		defer e.Close()
   423  		ctx := NewContext(harness)
   424  		TestPreparedQueryWithContext(t, ctx, e, harness, q, expected, expectedCols, nil, false)
   425  	})
   426  }
   427  
   428  func TestPreparedQueryWithEngine(t *testing.T, harness Harness, e QueryEngine, tt queries.QueryTest) {
   429  	t.Run(tt.Query, func(t *testing.T) {
   430  		if sh, ok := harness.(SkippingHarness); ok {
   431  			if sh.SkipQueryTest(tt.Query) {
   432  				t.Skipf("Skipping query %s", tt.Query)
   433  			}
   434  		}
   435  		ctx := NewContext(harness)
   436  		TestPreparedQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil, false)
   437  	})
   438  }
   439  
   440  func TestPreparedQueryWithContext(t *testing.T, ctx *sql.Context, e QueryEngine, h Harness, q string, expected []sql.Row, expectedCols []*sql.Column, bindVars map[string]*querypb.BindVariable, checkIndexedAccess bool) {
   441  	require := require.New(t)
   442  	rows, sch, err := runQueryPreparedWithCtx(t, ctx, e, q, bindVars, false)
   443  	if err != nil {
   444  		print(q)
   445  	}
   446  	require.NoError(err, "Unexpected error for query %s", q)
   447  
   448  	if expected != nil {
   449  		// TODO fix expected cols for prepared?
   450  		checkResults(t, expected, nil, sch, rows, q, e)
   451  	}
   452  
   453  	require.Equal(0, ctx.Memory.NumCaches())
   454  	validateEngine(t, ctx, h, e)
   455  }
   456  
   457  func injectBindVarsAndPrepare(
   458  	t *testing.T,
   459  	ctx *sql.Context,
   460  	e QueryEngine,
   461  	q string,
   462  ) (string, map[string]*querypb.BindVariable, error) {
   463  	sqlMode := sql.LoadSqlMode(ctx)
   464  	parsed, err := sqlparser.ParseWithOptions(q, sqlMode.ParserOptions())
   465  	if err != nil {
   466  		// cannot prepare empty statement, can query
   467  		if err.Error() == "empty statement" {
   468  			return q, nil, nil
   469  		}
   470  		return q, nil, sql.ErrSyntaxError.New(err)
   471  	}
   472  
   473  	switch p := parsed.(type) {
   474  	case *sqlparser.Load, *sqlparser.Prepare, *sqlparser.Execute:
   475  		// LOAD DATA query cannot be used as PREPARED STATEMENT
   476  		return q, nil, nil
   477  	case *sqlparser.Set:
   478  		// SET system variable query cannot be used as PREPARED STATEMENT
   479  		for _, setVar := range p.Exprs {
   480  			if setVar.Scope != sqlparser.SetScope_User {
   481  				return q, nil, nil
   482  			}
   483  		}
   484  	}
   485  
   486  	resPlan, err := planbuilder.ParseWithOptions(ctx, e.EngineAnalyzer().Catalog, q, sqlMode.ParserOptions())
   487  	if err != nil {
   488  		return q, nil, err
   489  	}
   490  
   491  	b := planbuilder.New(ctx, sql.MapCatalog{})
   492  	_, isInsert := resPlan.(*plan.InsertInto)
   493  	bindVars := make(map[string]*querypb.BindVariable)
   494  	var bindCnt int
   495  	var foundBindVar bool
   496  	var skipTypeConv bool
   497  	err = sqlparser.Walk(func(n sqlparser.SQLNode) (kontinue bool, err error) {
   498  		switch n := n.(type) {
   499  		case *sqlparser.SQLVal:
   500  			if n == nil {
   501  				return false, nil
   502  			}
   503  			switch n.Type {
   504  			case sqlparser.HexNum, sqlparser.HexVal:
   505  				return false, nil
   506  			}
   507  			expr := b.ConvertVal(n)
   508  			var val interface{}
   509  			if l, ok := expr.(*expression.Literal); ok {
   510  				val, _, err = expr.Type().Promote().Convert(l.Value())
   511  				if err != nil {
   512  					skipTypeConv = true
   513  					return false, nil
   514  				}
   515  			} else {
   516  				// If the |expr| is not Literal, then |val| is nil
   517  				skipTypeConv = true
   518  				return false, nil
   519  			}
   520  
   521  			bindVar, err := sqltypes.BuildBindVariable(val)
   522  			if err != nil {
   523  				skipTypeConv = true
   524  				return false, nil
   525  			}
   526  			varName := fmt.Sprintf("v%d", bindCnt+1)
   527  			bindVars[varName] = bindVar
   528  			n.Type = sqlparser.ValArg
   529  			n.Val = []byte(fmt.Sprintf(":v%d", bindCnt+1))
   530  			bindCnt++
   531  		case *sqlparser.Insert:
   532  			isInsert = true
   533  		default:
   534  		}
   535  		return true, nil
   536  	}, parsed)
   537  	if err != nil {
   538  		return "", nil, err
   539  	}
   540  	if skipTypeConv {
   541  		return q, nil, nil
   542  	}
   543  
   544  	buf := sqlparser.NewTrackedBuffer(nil)
   545  	parsed.Format(buf)
   546  	e.EnginePreparedDataCache().CacheStmt(ctx.Session.ID(), buf.String(), parsed)
   547  
   548  	_, isDatabaser := resPlan.(sql.Databaser)
   549  
   550  	// *ast.MultiAlterDDL parses arbitrary nodes in a *plan.Block
   551  	if bl, ok := resPlan.(*plan.Block); ok {
   552  		for _, n := range bl.Children() {
   553  			if _, ok := n.(*plan.InsertInto); ok {
   554  				isInsert = true
   555  			} else if _, ok := n.(sql.Databaser); ok {
   556  				isDatabaser = true
   557  			}
   558  
   559  		}
   560  	}
   561  	if isDatabaser && !isInsert {
   562  		return q, nil, nil
   563  	}
   564  
   565  	if foundBindVar {
   566  		t.Skip()
   567  	}
   568  
   569  	return buf.String(), bindVars, nil
   570  }
   571  
   572  func runQueryPreparedWithCtx(t *testing.T, ctx *sql.Context, e QueryEngine, q string, bindVars map[string]*querypb.BindVariable, checkIndexedAccess bool) ([]sql.Row, sql.Schema, error) {
   573  	// If bindvars were not provided, try to inject some
   574  	if bindVars == nil || len(bindVars) == 0 {
   575  		var err error
   576  		q, bindVars, err = injectBindVarsAndPrepare(t, ctx, e, q)
   577  		if err != nil {
   578  			return nil, nil, err
   579  		}
   580  	}
   581  
   582  	if checkIndexedAccess {
   583  		n, err := e.AnalyzeQuery(ctx, q)
   584  		require.NoError(t, err)
   585  		require.True(t, CheckIndexedAccess(n), "expected plan to have index, but found: %s", sql.DebugString(n))
   586  	}
   587  
   588  	sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindVars)
   589  	if err != nil {
   590  		return nil, nil, err
   591  	}
   592  
   593  	rows, err := sql.RowIterToRows(ctx, iter)
   594  	return rows, sch, err
   595  }
   596  
   597  // CustomValueValidator is an interface for custom validation of values in the result set
   598  type CustomValueValidator interface {
   599  	Validate(interface{}) (bool, error)
   600  }
   601  
   602  // toSQL converts the given expected value into appropriate type of given column.
   603  // |isZeroTime| is true if the query is any `SHOW` statement, except for `SHOW EVENTS`.
   604  // This is set earlier in `checkResult()` method.
   605  func toSQL(c *sql.Column, expected any, isZeroTime bool) (any, error) {
   606  	_, isTime := expected.(time.Time)
   607  	_, isStr := expected.(string)
   608  	// cases where we don't want the result value to be converted
   609  	if expected == nil || types.IsDecimal(c.Type) || types.IsEnum(c.Type) || types.IsSet(c.Type) ||
   610  		c.Type.Type() == sqltypes.Year || (isTime && isZeroTime) || (isStr && types.IsTextOnly(c.Type)) {
   611  		return expected, nil
   612  	} else {
   613  		val, _, err := c.Type.Convert(expected)
   614  		return val, err
   615  	}
   616  }
   617  
   618  func checkResults(
   619  	t *testing.T,
   620  	expected []sql.Row,
   621  	expectedCols []*sql.Column,
   622  	sch sql.Schema,
   623  	rows []sql.Row,
   624  	q string,
   625  	e QueryEngine,
   626  ) {
   627  	widenedRows := WidenRows(sch, rows)
   628  	widenedExpected := WidenRows(sch, expected)
   629  
   630  	upperQuery := strings.ToUpper(q)
   631  	orderBy := strings.Contains(upperQuery, "ORDER BY ")
   632  
   633  	isServerEngine := IsServerEngine(e)
   634  	isNilOrEmptySchema := sch == nil || len(sch) == 0
   635  	// We replace all times for SHOW statements with the Unix epoch except for SHOW EVENTS
   636  	setZeroTime := strings.HasPrefix(upperQuery, "SHOW ") && !strings.Contains(upperQuery, "EVENTS")
   637  
   638  	for _, widenedRow := range widenedRows {
   639  		for i, val := range widenedRow {
   640  			switch v := val.(type) {
   641  			case time.Time:
   642  				if setZeroTime {
   643  					widenedRow[i] = time.Unix(0, 0).UTC()
   644  				}
   645  			case uint64:
   646  				// index value of enum, in uint16, and bit value of set, in uint64, are cast/widened to uint64.
   647  				if !isServerEngine && !isNilOrEmptySchema {
   648  					// index value for enum and bit value for set types returned
   649  					// from enginetests need conversion to its string type value.
   650  					if types.IsEnum(sch[i].Type) {
   651  						el, exists := sch[i].Type.(sql.EnumType).At(int(v))
   652  						if !exists {
   653  							t.Errorf("Enum type element does not exist at index: %v", v)
   654  						}
   655  						widenedRow[i] = el
   656  					} else if types.IsSet(sch[i].Type) {
   657  						el, err := sch[i].Type.(sql.SetType).BitsToString(v)
   658  						require.NoError(t, err)
   659  						widenedRow[i] = el
   660  					}
   661  				}
   662  			}
   663  		}
   664  	}
   665  
   666  	// if the sch is nil or empty, over the wire result is no row whereas single empty row is expected.
   667  	// This happens for SET and SELECT INTO statements.
   668  	if isServerEngine && isNilOrEmptySchema && len(widenedRows) == 0 && len(widenedExpected) == 1 && len(widenedExpected[0]) == 0 {
   669  		widenedExpected = widenedRows
   670  	}
   671  
   672  	// The expected results that need  conversion before checking against actual results.
   673  	for i, row := range widenedExpected {
   674  		for j, field := range row {
   675  			// Special case for custom values
   676  			if cvv, isCustom := field.(CustomValueValidator); isCustom {
   677  				if i >= len(widenedRows) {
   678  					continue
   679  				}
   680  				actual := widenedRows[i][j] // shouldn't panic, but fine if it does
   681  				ok, err := cvv.Validate(actual)
   682  				if err != nil {
   683  					t.Error(err.Error())
   684  				}
   685  				if !ok {
   686  					t.Errorf("Custom value validation, got %v", actual)
   687  				}
   688  				widenedExpected[i][j] = actual // ensure it passes equality check later
   689  			}
   690  
   691  			if !isServerEngine || isNilOrEmptySchema {
   692  				continue
   693  			}
   694  
   695  			// The result received from go sql driver does not have 'Info'
   696  			// data returned, so we set it to 'nil' for server engine tests only.
   697  			if okRes, ok := widenedExpected[i][j].(types.OkResult); ok {
   698  				okResult := types.OkResult{
   699  					RowsAffected: okRes.RowsAffected,
   700  					InsertID:     okRes.InsertID,
   701  					Info:         nil,
   702  				}
   703  				widenedExpected[i][j] = okResult
   704  			} else {
   705  				// this attempts to do what `rowToSQL()` method in `handler.go` on expected row
   706  				// because over the wire values gets converted to SQL values depending on the column types.
   707  				convertedExpected, err := toSQL(sch[j], widenedExpected[i][j], setZeroTime)
   708  				require.NoError(t, err)
   709  				widenedExpected[i][j] = convertedExpected
   710  			}
   711  		}
   712  	}
   713  
   714  	// .Equal gives better error messages than .ElementsMatch, so use it when possible
   715  	if orderBy || len(expected) <= 1 {
   716  		require.Equal(t, widenedExpected, widenedRows, "Unexpected result for query %s", q)
   717  	} else {
   718  		require.ElementsMatch(t, widenedExpected, widenedRows, "Unexpected result for query %s", q)
   719  	}
   720  
   721  	// If the expected schema was given, test it as well
   722  	if expectedCols != nil && !isServerEngine {
   723  		assert.Equal(t, simplifyResultSchema(expectedCols), simplifyResultSchema(sch))
   724  	}
   725  }
   726  
   727  type resultSchemaCol struct {
   728  	Name string
   729  	Type querypb.Type
   730  }
   731  
   732  func simplifyResultSchema(s sql.Schema) []resultSchemaCol {
   733  	fields := make([]resultSchemaCol, len(s))
   734  	for i, c := range s {
   735  		fields[i] = resultSchemaCol{
   736  			Name: c.Name,
   737  			Type: c.Type.Type(),
   738  		}
   739  	}
   740  	return fields
   741  }
   742  
   743  // WidenRows returns a slice of rows with all values widened to their widest type.
   744  // For a variety of reasons, the widths of various primitive types can vary when passed through different SQL queries
   745  // (and different database implementations). We may eventually decide that this undefined behavior is a problem, but
   746  // for now it's mostly just an issue when comparing results in tests. To get around this, we widen every type to its
   747  // widest value in actual and expected results.
   748  func WidenRows(sch sql.Schema, rows []sql.Row) []sql.Row {
   749  	widened := make([]sql.Row, len(rows))
   750  	for i, row := range rows {
   751  		widened[i] = WidenRow(sch, row)
   752  	}
   753  	return widened
   754  }
   755  
   756  // WidenRow returns a row with all values widened to their widest type
   757  func WidenRow(sch sql.Schema, row sql.Row) sql.Row {
   758  	widened := make(sql.Row, len(row))
   759  	for i, v := range row {
   760  
   761  		var vw interface{}
   762  		if i < len(sch) && types.IsJSON(sch[i].Type) {
   763  			widened[i] = widenJSONValues(v)
   764  			continue
   765  		}
   766  
   767  		switch x := v.(type) {
   768  		case int:
   769  			vw = int64(x)
   770  		case int8:
   771  			vw = int64(x)
   772  		case int16:
   773  			vw = int64(x)
   774  		case int32:
   775  			vw = int64(x)
   776  		case uint:
   777  			vw = uint64(x)
   778  		case uint8:
   779  			vw = uint64(x)
   780  		case uint16:
   781  			vw = uint64(x)
   782  		case uint32:
   783  			vw = uint64(x)
   784  		case float32:
   785  			// casting it to float64 causes approximation, which doesn't work for server engine results.
   786  			vw, _ = strconv.ParseFloat(fmt.Sprintf("%v", v), 64)
   787  		case decimal.Decimal:
   788  			// The exact expected decimal type value cannot be defined in enginetests,
   789  			// so convert the result to string format, which is the value we get on sql shell.
   790  			vw = x.StringFixed(x.Exponent() * -1)
   791  		default:
   792  			vw = v
   793  		}
   794  		widened[i] = vw
   795  	}
   796  	return widened
   797  }
   798  
   799  func widenJSONValues(val interface{}) sql.JSONWrapper {
   800  	if val == nil {
   801  		return nil
   802  	}
   803  
   804  	js, ok := val.(sql.JSONWrapper)
   805  	if !ok {
   806  		str, ok := val.(string)
   807  		if !ok {
   808  			panic(fmt.Sprintf("%v is not json", val))
   809  		}
   810  		js = types.MustJSON(str)
   811  	}
   812  
   813  	doc := js.ToInterface()
   814  
   815  	if _, ok := js.(sql.Statistic); ok {
   816  		// avoid comparing time values in statistics
   817  		delete(doc.(map[string]interface{})["statistic"].(map[string]interface{}), "created_at")
   818  	}
   819  
   820  	doc = widenJSON(doc)
   821  	return types.JSONDocument{Val: doc}
   822  }
   823  
   824  func widenJSON(val interface{}) interface{} {
   825  	switch x := val.(type) {
   826  	case int:
   827  		return float64(x)
   828  	case int8:
   829  		return float64(x)
   830  	case int16:
   831  		return float64(x)
   832  	case int32:
   833  		return float64(x)
   834  	case int64:
   835  		return float64(x)
   836  	case uint:
   837  		return float64(x)
   838  	case uint8:
   839  		return float64(x)
   840  	case uint16:
   841  		return float64(x)
   842  	case uint32:
   843  		return float64(x)
   844  	case uint64:
   845  		return float64(x)
   846  	case float32:
   847  		return float64(x)
   848  	case []interface{}:
   849  		return widenJSONArray(x)
   850  	case map[string]interface{}:
   851  		return widenJSONObject(x)
   852  	default:
   853  		return x
   854  	}
   855  }
   856  
   857  func widenJSONObject(narrow map[string]interface{}) (wide map[string]interface{}) {
   858  	wide = make(map[string]interface{}, len(narrow))
   859  	for k, v := range narrow {
   860  		wide[k] = widenJSON(v)
   861  	}
   862  	return
   863  }
   864  
   865  func widenJSONArray(narrow []interface{}) (wide []interface{}) {
   866  	wide = make([]interface{}, len(narrow))
   867  	for i, v := range narrow {
   868  		wide[i] = widenJSON(v)
   869  	}
   870  	return
   871  }
   872  
   873  // AssertErr asserts that the given query returns an error during its execution, optionally specifying a type of error.
   874  func AssertErr(t *testing.T, e QueryEngine, harness Harness, query string, expectedErrKind *errors.Kind, errStrs ...string) {
   875  	AssertErrWithCtx(t, e, harness, NewContext(harness), query, expectedErrKind, errStrs...)
   876  }
   877  
   878  // AssertErrWithBindings asserts that the given query returns an error during its execution, optionally specifying a
   879  // type of error.
   880  func AssertErrWithBindings(t *testing.T, e QueryEngine, harness Harness, query string, bindings map[string]*querypb.BindVariable, expectedErrKind *errors.Kind, errStrs ...string) {
   881  	ctx := NewContext(harness)
   882  	_, iter, err := e.QueryWithBindings(ctx, query, nil, bindings)
   883  	if err == nil {
   884  		_, err = sql.RowIterToRows(ctx, iter)
   885  	}
   886  	require.Error(t, err)
   887  	if expectedErrKind != nil {
   888  		if !IsServerEngine(e) {
   889  			require.True(t, expectedErrKind.Is(err), "Expected error of type %s but got %s", expectedErrKind, err)
   890  		}
   891  	} else if len(errStrs) >= 1 {
   892  		require.Equal(t, errStrs[0], err.Error())
   893  	}
   894  	validateEngine(t, ctx, harness, e)
   895  }
   896  
   897  // AssertErrWithCtx is the same as AssertErr, but uses the context given instead of creating one from a harness
   898  func AssertErrWithCtx(t *testing.T, e QueryEngine, harness Harness, ctx *sql.Context, query string, expectedErrKind *errors.Kind, errStrs ...string) {
   899  	ctx = ctx.WithQuery(query)
   900  	_, iter, err := e.Query(ctx, query)
   901  	if err == nil {
   902  		_, err = sql.RowIterToRows(ctx, iter)
   903  	}
   904  	require.Error(t, err)
   905  	if expectedErrKind != nil {
   906  		err = sql.UnwrapError(err)
   907  		if !IsServerEngine(e) {
   908  			require.True(t, expectedErrKind.Is(err), "Expected error of type %s but got %s", expectedErrKind, err)
   909  		}
   910  	}
   911  	// If there are multiple error strings then we only match against the first
   912  	if len(errStrs) >= 1 {
   913  		require.Equal(t, errStrs[0], err.Error())
   914  	}
   915  	validateEngine(t, ctx, harness, e)
   916  }
   917  
   918  // AssertErrPrepared asserts that the given query returns an error during its execution, optionally specifying a type of error.
   919  func AssertErrPrepared(t *testing.T, e QueryEngine, harness Harness, query string, expectedErrKind *errors.Kind, errStrs ...string) {
   920  	AssertErrPreparedWithCtx(t, e, harness, NewContext(harness), query, expectedErrKind, errStrs...)
   921  }
   922  
   923  // AssertErrPreparedWithCtx is the same as AssertErr, but uses the context given instead of creating one from a harness
   924  func AssertErrPreparedWithCtx(t *testing.T, e QueryEngine, harness Harness, ctx *sql.Context, query string, expectedErrKind *errors.Kind, errStrs ...string) {
   925  	ctx = ctx.WithQuery(query)
   926  	_, _, err := runQueryPreparedWithCtx(t, ctx, e, query, nil, false)
   927  	require.Error(t, err)
   928  	if expectedErrKind != nil {
   929  		err = sql.UnwrapError(err)
   930  		if !IsServerEngine(e) {
   931  			require.True(t, expectedErrKind.Is(err), "Expected error of type %s but got %s", expectedErrKind, err)
   932  		}
   933  	}
   934  	// If there are multiple error strings then we only match against the first
   935  	if len(errStrs) >= 1 {
   936  		require.Equal(t, errStrs[0], err.Error())
   937  	}
   938  	validateEngine(t, ctx, harness, e)
   939  }
   940  
   941  // AssertWarningAndTestQuery tests the query and asserts an expected warning code. If |ctx| is provided, it will be
   942  // used. Otherwise the harness will be used to create a fresh context.
   943  func AssertWarningAndTestQuery(
   944  	t *testing.T,
   945  	e QueryEngine,
   946  	ctx *sql.Context,
   947  	harness Harness,
   948  	query string,
   949  	expected []sql.Row,
   950  	expectedCols []*sql.Column,
   951  	expectedCode int,
   952  	expectedWarningsCount int,
   953  	expectedWarningMessageSubstring string,
   954  	skipResultsCheck bool,
   955  ) {
   956  	require := require.New(t)
   957  	if ctx == nil {
   958  		ctx = NewContext(harness)
   959  	}
   960  	ctx.ClearWarnings()
   961  	ctx = ctx.WithQuery(query)
   962  
   963  	sch, iter, err := e.Query(ctx, query)
   964  	require.NoError(err, "Unexpected error for query %s", query)
   965  
   966  	rows, err := sql.RowIterToRows(ctx, iter)
   967  	require.NoError(err, "Unexpected error for query %s", query)
   968  
   969  	if !IsServerEngine(e) {
   970  		// check warnings depend on context, which ServerEngine does not depend on
   971  		if expectedWarningsCount > 0 {
   972  			assert.Equal(t, expectedWarningsCount, len(ctx.Warnings()))
   973  		}
   974  
   975  		if expectedCode > 0 {
   976  			for _, warning := range ctx.Warnings() {
   977  				assert.Equal(t, expectedCode, warning.Code, "Unexpected warning code")
   978  			}
   979  		}
   980  
   981  		if len(expectedWarningMessageSubstring) > 0 {
   982  			for _, warning := range ctx.Warnings() {
   983  				assert.Contains(t, warning.Message, expectedWarningMessageSubstring, "Unexpected warning message")
   984  			}
   985  		}
   986  	}
   987  
   988  	if !skipResultsCheck {
   989  		checkResults(t, expected, expectedCols, sch, rows, query, e)
   990  	}
   991  	validateEngine(t, ctx, harness, e)
   992  }
   993  
   994  func assertSchemasEqualWithDefaults(t *testing.T, expected, actual sql.Schema) bool {
   995  	if len(expected) != len(actual) {
   996  		return assert.Equal(t, expected, actual)
   997  	}
   998  
   999  	ec, ac := make(sql.Schema, len(expected)), make(sql.Schema, len(actual))
  1000  	for i := range expected {
  1001  		ecc := *expected[i]
  1002  		acc := *actual[i]
  1003  
  1004  		ecc.Default = nil
  1005  		acc.Default = nil
  1006  
  1007  		ac[i] = &acc
  1008  		ec[i] = &ecc
  1009  
  1010  		// For the default, compare just the string representations. This makes it possible for integrators who don't reify
  1011  		// default value expressions at schema load time (best practice) to run these tests. We also trim off any parens
  1012  		// for the same reason.
  1013  		eds, ads := "NULL", "NULL"
  1014  		if expected[i].Default != nil {
  1015  			eds = strings.Trim(expected[i].Default.String(), "()")
  1016  		}
  1017  		if actual[i].Default != nil {
  1018  			ads = strings.Trim(actual[i].Default.String(), "()")
  1019  		}
  1020  
  1021  		assert.Equal(t, eds, ads, "column default values differ")
  1022  	}
  1023  
  1024  	return assert.Equal(t, ec, ac)
  1025  }
  1026  
  1027  func ExtractQueryNode(node sql.Node) sql.Node {
  1028  	switch node := node.(type) {
  1029  	case *plan.QueryProcess:
  1030  		return ExtractQueryNode(node.Child())
  1031  	case *plan.Releaser:
  1032  		return ExtractQueryNode(node.Child)
  1033  	default:
  1034  		return node
  1035  	}
  1036  }
  1037  
  1038  // RunWriteQueryTest runs the specified |tt| WriteQueryTest using the specified harness.
  1039  func RunWriteQueryTest(t *testing.T, harness Harness, tt queries.WriteQueryTest) {
  1040  	e := mustNewEngine(t, harness)
  1041  	defer e.Close()
  1042  	RunWriteQueryTestWithEngine(t, harness, e, tt)
  1043  }
  1044  
  1045  // RunWriteQueryTestWithEngine runs the specified |tt| WriteQueryTest, using the specified harness and engine. Callers
  1046  // are still responsible for closing the engine.
  1047  func RunWriteQueryTestWithEngine(t *testing.T, harness Harness, e QueryEngine, tt queries.WriteQueryTest) {
  1048  	t.Run(tt.WriteQuery, func(t *testing.T) {
  1049  		if sh, ok := harness.(SkippingHarness); ok {
  1050  			if sh.SkipQueryTest(tt.WriteQuery) {
  1051  				t.Logf("Skipping query %s", tt.WriteQuery)
  1052  				return
  1053  			}
  1054  			if sh.SkipQueryTest(tt.SelectQuery) {
  1055  				t.Logf("Skipping query %s", tt.SelectQuery)
  1056  				return
  1057  			}
  1058  		}
  1059  		ctx := NewContext(harness)
  1060  		TestQueryWithContext(t, ctx, e, harness, tt.WriteQuery, tt.ExpectedWriteResult, nil, nil)
  1061  		expectedSelect := tt.ExpectedSelect
  1062  		if IsServerEngine(e) && tt.SkipServerEngine {
  1063  			expectedSelect = nil
  1064  		}
  1065  		TestQueryWithContext(t, ctx, e, harness, tt.SelectQuery, expectedSelect, nil, nil)
  1066  	})
  1067  }
  1068  
  1069  func runWriteQueryTestPrepared(t *testing.T, harness Harness, tt queries.WriteQueryTest) {
  1070  	t.Run(tt.WriteQuery, func(t *testing.T) {
  1071  		if sh, ok := harness.(SkippingHarness); ok {
  1072  			if sh.SkipQueryTest(tt.WriteQuery) {
  1073  				t.Logf("Skipping query %s", tt.WriteQuery)
  1074  				return
  1075  			}
  1076  			if sh.SkipQueryTest(tt.SelectQuery) {
  1077  				t.Logf("Skipping query %s", tt.SelectQuery)
  1078  				return
  1079  			}
  1080  		}
  1081  		e := mustNewEngine(t, harness)
  1082  		defer e.Close()
  1083  		ctx := NewContext(harness)
  1084  		TestPreparedQueryWithContext(t, ctx, e, harness, tt.WriteQuery, tt.ExpectedWriteResult, nil, tt.Bindings, false)
  1085  		TestPreparedQueryWithContext(t, ctx, e, harness, tt.SelectQuery, tt.ExpectedSelect, nil, tt.Bindings, false)
  1086  	})
  1087  }
  1088  
  1089  func runGenericErrorTest(t *testing.T, h Harness, tt queries.GenericErrorQueryTest) {
  1090  	t.Run(tt.Name, func(t *testing.T) {
  1091  		if sh, ok := h.(SkippingHarness); ok {
  1092  			if sh.SkipQueryTest(tt.Query) {
  1093  				t.Skipf("skipping query %s", tt.Query)
  1094  			}
  1095  		}
  1096  		e := mustNewEngine(t, h)
  1097  		defer e.Close()
  1098  		AssertErr(t, e, h, tt.Query, nil)
  1099  	})
  1100  }
  1101  
  1102  func runQueryErrorTest(t *testing.T, h Harness, tt queries.QueryErrorTest) {
  1103  	t.Run(tt.Query, func(t *testing.T) {
  1104  		if sh, ok := h.(SkippingHarness); ok {
  1105  			if sh.SkipQueryTest(tt.Query) {
  1106  				t.Skipf("skipping query %s", tt.Query)
  1107  			}
  1108  		}
  1109  		e := mustNewEngine(t, h)
  1110  		defer e.Close()
  1111  		if tt.ExpectedErrStr == "" {
  1112  			AssertErr(t, e, h, tt.Query, tt.ExpectedErr)
  1113  		} else {
  1114  			AssertErr(t, e, h, tt.Query, tt.ExpectedErr, tt.ExpectedErrStr)
  1115  		}
  1116  
  1117  	})
  1118  }
  1119  
  1120  func validateEngine(t *testing.T, ctx *sql.Context, harness Harness, e QueryEngine) {
  1121  	if harness == nil {
  1122  		assert.NotNil(t, harness)
  1123  	}
  1124  	require.NotNil(t, harness)
  1125  	if vh, ok := harness.(ValidatingHarness); ok {
  1126  		if sqlEng, ok := e.(*sqle.Engine); ok {
  1127  			assert.NoError(t, vh.ValidateEngine(ctx, sqlEng))
  1128  		}
  1129  	}
  1130  }