github.com/dolthub/go-mysql-server@v0.18.0/enginetest/engine_only_test.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 enginetest_test
    16  
    17  import (
    18  	"context"
    19  	sql2 "database/sql"
    20  	"fmt"
    21  	"io"
    22  	"net"
    23  	"runtime"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/dolthub/vitess/go/sqltypes"
    29  	"github.com/pmezard/go-difflib/difflib"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  	"go.opentelemetry.io/otel/trace"
    33  	"gopkg.in/src-d/go-errors.v1"
    34  
    35  	sqle "github.com/dolthub/go-mysql-server"
    36  	"github.com/dolthub/go-mysql-server/enginetest"
    37  	"github.com/dolthub/go-mysql-server/enginetest/queries"
    38  	"github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup"
    39  	"github.com/dolthub/go-mysql-server/memory"
    40  	"github.com/dolthub/go-mysql-server/server"
    41  	"github.com/dolthub/go-mysql-server/sql"
    42  	"github.com/dolthub/go-mysql-server/sql/analyzer"
    43  	"github.com/dolthub/go-mysql-server/sql/expression"
    44  	"github.com/dolthub/go-mysql-server/sql/expression/function"
    45  	"github.com/dolthub/go-mysql-server/sql/plan"
    46  	"github.com/dolthub/go-mysql-server/sql/planbuilder"
    47  	"github.com/dolthub/go-mysql-server/sql/rowexec"
    48  	"github.com/dolthub/go-mysql-server/sql/types"
    49  )
    50  
    51  // This file is for tests of the engine that we are very sure do not rely on a particular database implementation. They
    52  // use the default in-memory implementation harness, but in principle they do not rely on it being correct (beyond
    53  // the ability to create databases and tables without panicking) and don't test the implementation itself. Despite this,
    54  // most test methods dispatch to exported Test functions in the enginetest package, so that integrators can run those
    55  // tests against their own implementations if they choose.
    56  //
    57  // Tests that rely on a correct implementation of the in-memory database (memory package) should go in
    58  // memory_engine_test.go
    59  
    60  func TestSessionSelectLimit(t *testing.T) {
    61  	enginetest.TestSessionSelectLimit(t, enginetest.NewDefaultMemoryHarness())
    62  }
    63  
    64  func TestVariables(t *testing.T) {
    65  	enginetest.TestVariables(t, enginetest.NewDefaultMemoryHarness())
    66  }
    67  
    68  func TestVariableErrors(t *testing.T) {
    69  	enginetest.TestVariableErrors(t, enginetest.NewDefaultMemoryHarness())
    70  }
    71  
    72  func TestWarnings(t *testing.T) {
    73  	harness := enginetest.NewDefaultMemoryHarness()
    74  	if harness.IsUsingServer() {
    75  		t.Skip("tracking issue: https://github.com/dolthub/dolt/issues/6921 and the one mentioned inside this issue as well")
    76  	}
    77  	t.Run("sequential", func(t *testing.T) {
    78  		enginetest.TestWarnings(t, harness)
    79  	})
    80  
    81  	harness = enginetest.NewMemoryHarness("parallel", 2, testNumPartitions, false, nil)
    82  	t.Run("parallel", func(t *testing.T) {
    83  		enginetest.TestWarnings(t, harness)
    84  	})
    85  }
    86  
    87  func TestClearWarnings(t *testing.T) {
    88  	harness := enginetest.NewDefaultMemoryHarness()
    89  	if harness.IsUsingServer() {
    90  		// TODO: needs more investigation on this test
    91  		t.Skip("tracking issue: https://github.com/dolthub/dolt/issues/6921 and the one mentioned inside this issue as well")
    92  	}
    93  	enginetest.TestClearWarnings(t, harness)
    94  }
    95  
    96  func TestUse(t *testing.T) {
    97  	enginetest.TestUse(t, enginetest.NewDefaultMemoryHarness())
    98  }
    99  
   100  func TestNoDatabaseSelected(t *testing.T) {
   101  	enginetest.TestNoDatabaseSelected(t, enginetest.NewDefaultMemoryHarness())
   102  }
   103  
   104  func TestTracing(t *testing.T) {
   105  	harness := enginetest.NewDefaultMemoryHarness()
   106  	if harness.IsUsingServer() {
   107  		t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context")
   108  	}
   109  	enginetest.TestTracing(t, harness)
   110  }
   111  
   112  func TestCurrentTimestamp(t *testing.T) {
   113  	enginetest.TestCurrentTimestamp(t, enginetest.NewDefaultMemoryHarness())
   114  }
   115  
   116  // TODO: it's not currently possible to test this via harness, because the underlying table implementations are added to
   117  // the database, rather than the wrapper tables. We need a better way of inspecting lock state to test this properly.
   118  // Also, currently locks are entirely implementation dependent, so there isn't much to test except that lock and unlock
   119  // are being called.
   120  func TestLocks(t *testing.T) {
   121  	require := require.New(t)
   122  
   123  	harness := enginetest.NewDefaultMemoryHarness()
   124  	db := harness.NewDatabases("db")[0].(*memory.HistoryDatabase)
   125  	t1 := newLockableTable(memory.NewTable(db.BaseDatabase, "t1", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection()))
   126  	t2 := newLockableTable(memory.NewTable(db.BaseDatabase, "t2", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection()))
   127  	t3 := memory.NewTable(db.BaseDatabase, "t3", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection())
   128  	db.AddTable("t1", t1)
   129  	db.AddTable("t2", t2)
   130  	db.AddTable("t3", t3)
   131  
   132  	analyzer := analyzer.NewDefault(harness.Provider())
   133  	engine := sqle.New(analyzer, new(sqle.Config))
   134  
   135  	ctx := enginetest.NewContext(harness)
   136  	ctx.SetCurrentDatabase("db")
   137  	_, iter, err := engine.Query(ctx, "LOCK TABLES t1 READ, t2 WRITE, t3 READ")
   138  	require.NoError(err)
   139  
   140  	_, err = sql.RowIterToRows(ctx, iter)
   141  	require.NoError(err)
   142  
   143  	ctx = enginetest.NewContext(harness)
   144  	ctx.SetCurrentDatabase("db")
   145  	_, iter, err = engine.Query(ctx, "UNLOCK TABLES")
   146  	require.NoError(err)
   147  
   148  	_, err = sql.RowIterToRows(ctx, iter)
   149  	require.NoError(err)
   150  
   151  	require.Equal(1, t1.readLocks)
   152  	require.Equal(0, t1.writeLocks)
   153  	require.Equal(1, t1.unlocks)
   154  	require.Equal(0, t2.readLocks)
   155  	require.Equal(1, t2.writeLocks)
   156  	require.Equal(1, t2.unlocks)
   157  }
   158  
   159  type mockSpan struct {
   160  	trace.Span
   161  	finished bool
   162  }
   163  
   164  func (m *mockSpan) End(options ...trace.SpanEndOption) {
   165  	m.finished = true
   166  	m.Span.End(options...)
   167  }
   168  
   169  func newMockSpan(ctx context.Context) (context.Context, *mockSpan) {
   170  	ctx, span := trace.NewNoopTracerProvider().Tracer("").Start(ctx, "")
   171  	return ctx, &mockSpan{span, false}
   172  }
   173  
   174  func TestRootSpanFinish(t *testing.T) {
   175  	harness := enginetest.NewDefaultMemoryHarness()
   176  	if harness.IsUsingServer() {
   177  		t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context")
   178  	}
   179  	e, err := harness.NewEngine(t)
   180  	if err != nil {
   181  		panic(err)
   182  	}
   183  	sqlCtx := harness.NewContext()
   184  	ctx, fakeSpan := newMockSpan(sqlCtx)
   185  	sql.WithRootSpan(fakeSpan)(sqlCtx)
   186  	sqlCtx = sqlCtx.WithContext(ctx)
   187  
   188  	_, iter, err := e.Query(sqlCtx, "SELECT 1")
   189  	require.NoError(t, err)
   190  
   191  	_, err = sql.RowIterToRows(sqlCtx, iter)
   192  	require.NoError(t, err)
   193  
   194  	require.True(t, fakeSpan.finished)
   195  }
   196  
   197  type lockableTable struct {
   198  	sql.Table
   199  	readLocks  int
   200  	writeLocks int
   201  	unlocks    int
   202  }
   203  
   204  func (l *lockableTable) IgnoreSessionData() bool {
   205  	return true
   206  }
   207  
   208  func (l *lockableTable) UnderlyingTable() *memory.Table {
   209  	return l.Table.(*memory.Table)
   210  }
   211  
   212  func newLockableTable(t sql.Table) *lockableTable {
   213  	return &lockableTable{Table: t}
   214  }
   215  
   216  var _ sql.Lockable = (*lockableTable)(nil)
   217  
   218  func (l *lockableTable) Lock(ctx *sql.Context, write bool) error {
   219  	if write {
   220  		l.writeLocks++
   221  	} else {
   222  		l.readLocks++
   223  	}
   224  	return nil
   225  }
   226  
   227  func (l *lockableTable) Unlock(ctx *sql.Context, id uint32) error {
   228  	l.unlocks++
   229  	return nil
   230  }
   231  
   232  type analyzerTestCase struct {
   233  	name          string
   234  	query         string
   235  	planGenerator func(*testing.T, *sql.Context, enginetest.QueryEngine) sql.Node
   236  	err           *errors.Kind
   237  }
   238  
   239  func TestShowProcessList(t *testing.T) {
   240  	require := require.New(t)
   241  
   242  	addr1 := "127.0.0.1:34567"
   243  	addr2 := "127.0.0.1:34568"
   244  	username := "foo"
   245  
   246  	p := sqle.NewProcessList()
   247  	p.AddConnection(1, addr1)
   248  	p.AddConnection(2, addr2)
   249  	sess := sql.NewBaseSessionWithClientServer("0.0.0.0:3306", sql.Client{Address: addr1, User: username}, 1)
   250  	p.ConnectionReady(sess)
   251  	ctx := sql.NewContext(context.Background(), sql.WithPid(1), sql.WithSession(sess), sql.WithProcessList(p))
   252  
   253  	ctx, err := p.BeginQuery(ctx, "SELECT foo")
   254  	require.NoError(err)
   255  
   256  	p.AddTableProgress(ctx.Pid(), "a", 5)
   257  	p.AddTableProgress(ctx.Pid(), "b", 6)
   258  
   259  	sess = sql.NewBaseSessionWithClientServer("0.0.0.0:3306", sql.Client{Address: addr2, User: username}, 2)
   260  	p.ConnectionReady(sess)
   261  	ctx = sql.NewContext(context.Background(), sql.WithPid(2), sql.WithSession(sess), sql.WithProcessList(p))
   262  	ctx, err = p.BeginQuery(ctx, "SELECT bar")
   263  	require.NoError(err)
   264  
   265  	p.AddTableProgress(ctx.Pid(), "foo", 2)
   266  
   267  	p.UpdateTableProgress(1, "a", 3)
   268  	p.UpdateTableProgress(1, "a", 1)
   269  	p.UpdatePartitionProgress(1, "a", "a-1", 7)
   270  	p.UpdatePartitionProgress(1, "a", "a-2", 9)
   271  	p.UpdateTableProgress(1, "b", 2)
   272  	p.UpdateTableProgress(2, "foo", 1)
   273  
   274  	n := plan.NewShowProcessList()
   275  
   276  	iter, err := rowexec.DefaultBuilder.Build(ctx, n, nil)
   277  	require.NoError(err)
   278  	rows, err := sql.RowIterToRows(ctx, iter)
   279  	require.NoError(err)
   280  
   281  	expected := []sql.Row{
   282  		{int64(1), username, addr1, nil, "Query", int64(0),
   283  			`
   284  a (4/5 partitions)
   285   ├─ a-1 (7/? rows)
   286   └─ a-2 (9/? rows)
   287  
   288  b (2/6 partitions)
   289  `, "SELECT foo"},
   290  		{int64(2), username, addr2, nil, "Query", int64(0), "\nfoo (1/2 partitions)\n", "SELECT bar"},
   291  	}
   292  
   293  	require.ElementsMatch(expected, rows)
   294  }
   295  
   296  // TODO: this was an analyzer test, but we don't have a mock process list for it to use, so it has to be here
   297  func TestTrackProcess(t *testing.T) {
   298  	require := require.New(t)
   299  	db := memory.NewDatabase("db")
   300  	provider := memory.NewDBProvider(db)
   301  	a := analyzer.NewDefault(provider)
   302  	sess := memory.NewSession(sql.NewBaseSession(), provider)
   303  
   304  	node := plan.NewInnerJoin(
   305  		plan.NewResolvedTable(&nonIndexableTable{memory.NewPartitionedTable(db.BaseDatabase, "foo", sql.PrimaryKeySchema{}, nil, 2)}, nil, nil),
   306  		plan.NewResolvedTable(memory.NewPartitionedTable(db.BaseDatabase, "bar", sql.PrimaryKeySchema{}, nil, 4), nil, nil),
   307  		expression.NewLiteral(int64(1), types.Int64),
   308  	)
   309  
   310  	pl := sqle.NewProcessList()
   311  
   312  	ctx := sql.NewContext(context.Background(), sql.WithPid(1), sql.WithProcessList(pl), sql.WithSession(sess))
   313  	pl.AddConnection(ctx.Session.ID(), "localhost")
   314  	pl.ConnectionReady(ctx.Session)
   315  	ctx, err := ctx.ProcessList.BeginQuery(ctx, "SELECT foo")
   316  	require.NoError(err)
   317  
   318  	rule := getRuleFrom(analyzer.OnceAfterAll, analyzer.TrackProcessId)
   319  	result, _, err := rule.Apply(ctx, a, node, nil, analyzer.DefaultRuleSelector)
   320  	require.NoError(err)
   321  
   322  	processes := ctx.ProcessList.Processes()
   323  	require.Len(processes, 1)
   324  	require.Equal("SELECT foo", processes[0].Query)
   325  	require.Equal(
   326  		map[string]sql.TableProgress{
   327  			"foo": sql.TableProgress{
   328  				Progress:           sql.Progress{Name: "foo", Done: 0, Total: 2},
   329  				PartitionsProgress: map[string]sql.PartitionProgress{}},
   330  			"bar": sql.TableProgress{
   331  				Progress:           sql.Progress{Name: "bar", Done: 0, Total: 4},
   332  				PartitionsProgress: map[string]sql.PartitionProgress{}},
   333  		},
   334  		processes[0].Progress)
   335  
   336  	proc, ok := result.(*plan.QueryProcess)
   337  	require.True(ok)
   338  
   339  	join, ok := proc.Child().(*plan.JoinNode)
   340  	require.True(ok)
   341  	require.Equal(join.JoinType(), plan.JoinTypeInner)
   342  
   343  	lhs, ok := join.Left().(*plan.ResolvedTable)
   344  	require.True(ok)
   345  	_, ok = lhs.Table.(*plan.ProcessTable)
   346  	require.True(ok)
   347  
   348  	rhs, ok := join.Right().(*plan.ResolvedTable)
   349  	require.True(ok)
   350  	_, ok = rhs.Table.(*plan.ProcessTable)
   351  	require.True(ok)
   352  
   353  	iter, err := rowexec.DefaultBuilder.Build(ctx, proc, nil)
   354  	require.NoError(err)
   355  	_, err = sql.RowIterToRows(ctx, iter)
   356  	require.NoError(err)
   357  
   358  	procs := ctx.ProcessList.Processes()
   359  	require.Len(procs, 1)
   360  	require.Equal(procs[0].Command, sql.ProcessCommandSleep)
   361  	require.Error(ctx.Err())
   362  }
   363  
   364  func TestConcurrentProcessList(t *testing.T) {
   365  	enginetest.TestConcurrentProcessList(t, enginetest.NewDefaultMemoryHarness())
   366  }
   367  
   368  func getRuleFrom(rules []analyzer.Rule, id analyzer.RuleId) *analyzer.Rule {
   369  	for _, rule := range rules {
   370  		if rule.Id == id {
   371  			return &rule
   372  		}
   373  	}
   374  
   375  	return nil
   376  }
   377  
   378  // wrapper around sql.Table to make it not indexable
   379  type nonIndexableTable struct {
   380  	*memory.Table
   381  }
   382  
   383  var _ memory.MemTable = (*nonIndexableTable)(nil)
   384  
   385  func (t *nonIndexableTable) IgnoreSessionData() bool {
   386  	return true
   387  }
   388  
   389  func TestLockTables(t *testing.T) {
   390  	require := require.New(t)
   391  	db := memory.NewDatabase("db")
   392  
   393  	t1 := newLockableTable(memory.NewTable(db.BaseDatabase, "foo", sql.PrimaryKeySchema{}, nil))
   394  	t2 := newLockableTable(memory.NewTable(db.BaseDatabase, "bar", sql.PrimaryKeySchema{}, nil))
   395  	node := plan.NewLockTables([]*plan.TableLock{
   396  		{plan.NewResolvedTable(t1, nil, nil), true},
   397  		{plan.NewResolvedTable(t2, nil, nil), false},
   398  	})
   399  	node.Catalog = analyzer.NewCatalog(sql.NewDatabaseProvider())
   400  
   401  	_, err := rowexec.DefaultBuilder.Build(sql.NewEmptyContext(), node, nil)
   402  
   403  	require.NoError(err)
   404  
   405  	require.Equal(1, t1.writeLocks)
   406  	require.Equal(0, t1.readLocks)
   407  	require.Equal(1, t2.readLocks)
   408  	require.Equal(0, t2.writeLocks)
   409  }
   410  
   411  func TestUnlockTables(t *testing.T) {
   412  	require := require.New(t)
   413  	db := memory.NewDatabase("db")
   414  
   415  	t1 := newLockableTable(memory.NewTable(db.BaseDatabase, "foo", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection()))
   416  	t2 := newLockableTable(memory.NewTable(db.BaseDatabase, "bar", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection()))
   417  	t3 := newLockableTable(memory.NewTable(db.BaseDatabase, "baz", sql.PrimaryKeySchema{}, db.GetForeignKeyCollection()))
   418  	db.AddTable("foo", t1)
   419  	db.AddTable("bar", t2)
   420  	db.AddTable("baz", t3)
   421  
   422  	catalog := analyzer.NewCatalog(sql.NewDatabaseProvider(db))
   423  
   424  	ctx := sql.NewContext(context.Background())
   425  	ctx.SetCurrentDatabase("db")
   426  	catalog.LockTable(ctx, "foo")
   427  	catalog.LockTable(ctx, "bar")
   428  
   429  	node := plan.NewUnlockTables()
   430  	node.Catalog = catalog
   431  
   432  	_, err := node.RowIter(ctx, nil)
   433  	require.NoError(err)
   434  
   435  	require.Equal(1, t1.unlocks)
   436  	require.Equal(1, t2.unlocks)
   437  	require.Equal(0, t3.unlocks)
   438  }
   439  
   440  var _ sql.PartitionCounter = (*nonIndexableTable)(nil)
   441  
   442  func (t *nonIndexableTable) PartitionCount(ctx *sql.Context) (int64, error) {
   443  	return t.Table.PartitionCount(ctx)
   444  }
   445  
   446  var analyzerTestCases = []analyzerTestCase{
   447  	{
   448  		name:  "show tables as of",
   449  		query: "SHOW TABLES AS OF 'abc123'",
   450  		planGenerator: func(t *testing.T, ctx *sql.Context, engine enginetest.QueryEngine) sql.Node {
   451  			db, err := engine.EngineAnalyzer().Catalog.Database(ctx, "mydb")
   452  			require.NoError(t, err)
   453  			return plan.NewShowTables(db, false, expression.NewLiteral("abc123", types.LongText))
   454  		},
   455  	},
   456  	{
   457  		name:  "show tables as of, from",
   458  		query: "SHOW TABLES FROM foo AS OF 'abc123'",
   459  		planGenerator: func(t *testing.T, ctx *sql.Context, engine enginetest.QueryEngine) sql.Node {
   460  			db, err := engine.EngineAnalyzer().Catalog.Database(ctx, "foo")
   461  			require.NoError(t, err)
   462  			return plan.NewShowTables(db, false, expression.NewLiteral("abc123", types.LongText))
   463  		},
   464  	},
   465  	{
   466  		name:  "show tables as of, function call",
   467  		query: "SHOW TABLES FROM foo AS OF GREATEST('abc123', 'cde456')",
   468  		planGenerator: func(t *testing.T, ctx *sql.Context, engine enginetest.QueryEngine) sql.Node {
   469  			db, err := engine.EngineAnalyzer().Catalog.Database(ctx, "foo")
   470  			require.NoError(t, err)
   471  			greatest, err := function.NewGreatest(
   472  				expression.NewLiteral("abc123", types.LongText),
   473  				expression.NewLiteral("cde456", types.LongText),
   474  			)
   475  			require.NoError(t, err)
   476  			return plan.NewShowTables(db, false, greatest)
   477  		},
   478  	},
   479  	{
   480  		name:  "show tables as of, timestamp",
   481  		query: "SHOW TABLES FROM foo AS OF TIMESTAMP('20200101:120000Z')",
   482  		planGenerator: func(t *testing.T, ctx *sql.Context, engine enginetest.QueryEngine) sql.Node {
   483  			db, err := engine.EngineAnalyzer().Catalog.Database(ctx, "foo")
   484  			require.NoError(t, err)
   485  			timestamp, err := function.NewTimestamp(
   486  				expression.NewLiteral("20200101:120000Z", types.LongText),
   487  			)
   488  			require.NoError(t, err)
   489  			return plan.NewShowTables(db, false, timestamp)
   490  		},
   491  	},
   492  	{
   493  		name:  "show tables as of, naked literal",
   494  		query: "SHOW TABLES AS OF abc123",
   495  		planGenerator: func(t *testing.T, ctx *sql.Context, engine enginetest.QueryEngine) sql.Node {
   496  			db, err := engine.EngineAnalyzer().Catalog.Database(ctx, "mydb")
   497  			require.NoError(t, err)
   498  			return plan.NewShowTables(db, false, expression.NewLiteral("abc123", types.LongText))
   499  		},
   500  	},
   501  }
   502  
   503  // Grab bag tests for testing analysis of various nodes that are difficult to verify through other means
   504  func TestAnalyzer_Exp(t *testing.T) {
   505  	harness := enginetest.NewDefaultMemoryHarness()
   506  	harness.Setup(setup.MydbData, setup.FooData)
   507  	for _, tt := range analyzerTestCases {
   508  		t.Run(tt.name, func(t *testing.T) {
   509  			e, err := harness.NewEngine(t)
   510  			require.NoError(t, err)
   511  
   512  			ctx := enginetest.NewContext(harness)
   513  			b := planbuilder.New(ctx, e.EngineAnalyzer().Catalog)
   514  			parsed, _, _, err := b.Parse(tt.query, false)
   515  			require.NoError(t, err)
   516  
   517  			analyzed, err := e.EngineAnalyzer().Analyze(ctx, parsed, nil)
   518  			analyzed = analyzer.StripPassthroughNodes(analyzed)
   519  			if tt.err != nil {
   520  				require.Error(t, err)
   521  				assert.True(t, tt.err.Is(err))
   522  			} else {
   523  				assertNodesEqualWithDiff(t, tt.planGenerator(t, ctx, e), analyzed)
   524  			}
   525  		})
   526  	}
   527  }
   528  
   529  func assertNodesEqualWithDiff(t *testing.T, expected, actual sql.Node) {
   530  	if x, ok := actual.(*plan.QueryProcess); ok {
   531  		actual = x.Child()
   532  	}
   533  
   534  	if !assert.Equal(t, expected, actual) {
   535  		expectedStr := sql.DebugString(expected)
   536  		actualStr := sql.DebugString(actual)
   537  		diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
   538  			A:        difflib.SplitLines(expectedStr),
   539  			B:        difflib.SplitLines(actualStr),
   540  			FromFile: "expected",
   541  			FromDate: "",
   542  			ToFile:   "actual",
   543  			ToDate:   "",
   544  			Context:  1,
   545  		})
   546  		require.NoError(t, err)
   547  
   548  		if len(diff) > 0 {
   549  			fmt.Println(diff)
   550  		}
   551  	}
   552  }
   553  
   554  func TestRecursiveViewDefinition(t *testing.T) {
   555  	enginetest.TestRecursiveViewDefinition(t, enginetest.NewDefaultMemoryHarness())
   556  }
   557  
   558  func TestShowCharset(t *testing.T) {
   559  	iterForAllImplemented := func(t *testing.T) []sql.Row {
   560  		var rows []sql.Row
   561  		iter := sql.NewCharacterSetsIterator()
   562  		for charset, ok := iter.Next(); ok; charset, ok = iter.Next() {
   563  			if charset.Encoder != nil {
   564  				rows = append(rows, sql.Row{
   565  					charset.Name,
   566  					charset.Description,
   567  					charset.DefaultCollation.String(),
   568  					uint64(charset.MaxLength),
   569  				})
   570  			}
   571  		}
   572  		return rows
   573  	}
   574  
   575  	tests := []struct {
   576  		Query  string
   577  		RowGen func(t *testing.T) []sql.Row
   578  	}{
   579  		{
   580  			Query:  "SHOW CHARACTER SET;",
   581  			RowGen: iterForAllImplemented,
   582  		},
   583  		{
   584  			Query:  "SHOW CHARSET;",
   585  			RowGen: iterForAllImplemented,
   586  		},
   587  		{
   588  			Query: "SHOW CHARSET LIKE 'utf8%'",
   589  			RowGen: func(t *testing.T) []sql.Row {
   590  				var rows []sql.Row
   591  				iter := sql.NewCharacterSetsIterator()
   592  				for charset, ok := iter.Next(); ok; charset, ok = iter.Next() {
   593  					if charset.Encoder != nil && strings.HasPrefix(charset.Name, "utf8") {
   594  						rows = append(rows, sql.Row{
   595  							charset.Name,
   596  							charset.Description,
   597  							charset.DefaultCollation.String(),
   598  							uint64(charset.MaxLength),
   599  						})
   600  					}
   601  				}
   602  				return rows
   603  			},
   604  		},
   605  		{
   606  			Query: "SHOW CHARSET WHERE Charset='binary'",
   607  			RowGen: func(t *testing.T) []sql.Row {
   608  				var rows []sql.Row
   609  				iter := sql.NewCharacterSetsIterator()
   610  				for charset, ok := iter.Next(); ok; charset, ok = iter.Next() {
   611  					if charset.Encoder != nil && charset.Name == "binary" {
   612  						rows = append(rows, sql.Row{
   613  							charset.Name,
   614  							charset.Description,
   615  							charset.DefaultCollation.String(),
   616  							uint64(charset.MaxLength),
   617  						})
   618  					}
   619  				}
   620  				return rows
   621  			},
   622  		},
   623  		{
   624  			Query: `SHOW CHARSET WHERE Charset = 'foo'`,
   625  			RowGen: func(t *testing.T) []sql.Row {
   626  				var rows []sql.Row
   627  				iter := sql.NewCharacterSetsIterator()
   628  				for charset, ok := iter.Next(); ok; charset, ok = iter.Next() {
   629  					if charset.Encoder != nil && charset.Name == "foo" {
   630  						rows = append(rows, sql.Row{
   631  							charset.Name,
   632  							charset.Description,
   633  							charset.DefaultCollation.String(),
   634  							uint64(charset.MaxLength),
   635  						})
   636  					}
   637  				}
   638  				return rows
   639  			},
   640  		},
   641  	}
   642  
   643  	harness := enginetest.NewMemoryHarness("", 1, 1, false, nil)
   644  	for _, test := range tests {
   645  		enginetest.TestQuery(t, harness, test.Query, test.RowGen(t), nil, nil)
   646  	}
   647  }
   648  
   649  func TestEngineJoinOps(t *testing.T) {
   650  	enginetest.TestJoinOps(t, enginetest.NewDefaultMemoryHarness(), enginetest.EngineOnlyJoinOpTests)
   651  }
   652  
   653  func TestTableFunctions(t *testing.T) {
   654  	harness := enginetest.NewDefaultMemoryHarness()
   655  	harness.Setup(setup.MydbData)
   656  
   657  	databaseProvider := harness.NewDatabaseProvider()
   658  	testDatabaseProvider := enginetest.NewTestProvider(
   659  		&databaseProvider,
   660  		SimpleTableFunction{},
   661  		memory.IntSequenceTable{},
   662  		memory.PointLookupTable{},
   663  		memory.TableFunc{},
   664  		memory.ExponentialDistTable{},
   665  		memory.NormalDistTable{})
   666  
   667  	engine := enginetest.NewEngineWithProvider(t, harness, testDatabaseProvider)
   668  	harness = harness.WithProvider(engine.Analyzer.Catalog.DbProvider)
   669  
   670  	engine.EngineAnalyzer().ExecBuilder = rowexec.DefaultBuilder
   671  
   672  	engine, err := enginetest.RunSetupScripts(harness.NewContext(), engine, setup.MydbData, true)
   673  	require.NoError(t, err)
   674  	_ = harness.NewSession()
   675  
   676  	for _, test := range queries.TableFunctionScriptTests {
   677  		enginetest.TestScriptWithEngine(t, engine, harness, test)
   678  	}
   679  }
   680  
   681  func TestExternalProcedures(t *testing.T) {
   682  	harness := enginetest.NewDefaultMemoryHarness()
   683  	harness.Setup(setup.MydbData)
   684  	for _, script := range queries.ExternalProcedureTests {
   685  		func() {
   686  			e, err := harness.NewEngine(t)
   687  			require.NoError(t, err)
   688  			defer func() {
   689  				_ = e.Close()
   690  			}()
   691  			enginetest.TestScriptWithEngine(t, e, harness, script)
   692  		}()
   693  	}
   694  }
   695  
   696  func TestCallAsOf(t *testing.T) {
   697  	harness := enginetest.NewDefaultMemoryHarness()
   698  	enginetest.CreateVersionedTestData(t, harness)
   699  	for _, script := range queries.CallAsofScripts {
   700  		func() {
   701  			e, err := harness.NewEngine(t)
   702  			require.NoError(t, err)
   703  			defer func() {
   704  				_ = e.Close()
   705  			}()
   706  			enginetest.TestScriptWithEngine(t, e, harness, script)
   707  		}()
   708  	}
   709  }
   710  
   711  func TestTriggerViewWarning(t *testing.T) {
   712  	// Old versions of Dolt could create view triggers.
   713  	// Check that users in this state can still write to
   714  	// regular table.
   715  	harness := enginetest.NewDefaultMemoryHarness()
   716  	harness.Setup(setup.MydbData, setup.MytableData)
   717  	e, err := harness.NewEngine(t)
   718  	assert.NoError(t, err)
   719  
   720  	prov := e.EngineAnalyzer().Catalog.DbProvider.(*memory.DbProvider)
   721  	db, err := prov.Database(nil, "mydb")
   722  	assert.NoError(t, err)
   723  
   724  	baseDb := db.(*memory.HistoryDatabase).BaseDatabase
   725  	err = baseDb.CreateTrigger(nil, sql.TriggerDefinition{
   726  		Name:            "view_trig",
   727  		CreateStatement: "CREATE TRIGGER view_trig BEFORE INSERT ON myview FOR EACH ROW SET i=i+2",
   728  	})
   729  	assert.NoError(t, err)
   730  
   731  	ctx := harness.NewContext()
   732  	enginetest.CreateNewConnectionForServerEngine(ctx, e)
   733  
   734  	enginetest.TestQueryWithContext(t, ctx, e, harness, "insert into mytable values (4, 'fourth row')", []sql.Row{{types.NewOkResult(1)}}, nil, nil)
   735  	enginetest.TestQueryWithContext(t, ctx, e, harness, "SHOW WARNINGS", []sql.Row{{"Warning", 0, "trigger on view is not supported; 'DROP TRIGGER  view_trig' to fix"}}, nil, nil)
   736  	enginetest.AssertErrWithCtx(t, e, harness, ctx, "insert into myview values (5, 'fifth row')", nil, "expected insert destination to be resolved or unresolved table")
   737  }
   738  
   739  func TestCollationCoercion(t *testing.T) {
   740  	harness := enginetest.NewDefaultMemoryHarness()
   741  	if harness.IsUsingServer() {
   742  		t.Skip("TODO: need further investigation")
   743  	}
   744  	harness.Setup(setup.MydbData)
   745  	engine, err := harness.NewEngine(t)
   746  	require.NoError(t, err)
   747  	defer engine.Close()
   748  
   749  	ctx := harness.NewContext()
   750  	ctx.SetCurrentDatabase("mydb")
   751  
   752  	for _, statement := range queries.CollationCoercionSetup {
   753  		enginetest.RunQueryWithContext(t, engine, harness, ctx, statement)
   754  	}
   755  
   756  	for _, test := range queries.CollationCoercionTests {
   757  		coercibilityQuery := fmt.Sprintf(`SELECT COERCIBILITY(%s) FROM temp_tbl LIMIT 1;`, test.Parameters)
   758  		collationQuery := fmt.Sprintf(`SELECT COLLATION(%s) FROM temp_tbl LIMIT 1;`, test.Parameters)
   759  		for i, query := range []string{coercibilityQuery, collationQuery} {
   760  			t.Run(query, func(t *testing.T) {
   761  				_, iter, err := engine.Query(ctx, query)
   762  				if test.Error {
   763  					if err == nil {
   764  						_, err := sql.RowIterToRows(ctx, iter)
   765  						require.Error(t, err)
   766  					} else {
   767  						require.Error(t, err)
   768  					}
   769  				} else {
   770  					require.NoError(t, err)
   771  					rows, err := sql.RowIterToRows(ctx, iter)
   772  					require.NoError(t, err)
   773  					require.Equal(t, 1, len(rows))
   774  					require.Equal(t, 1, len(rows[0]))
   775  					if i == 0 {
   776  						num, _, err := types.Int64.Convert(rows[0][0])
   777  						require.NoError(t, err)
   778  						require.Equal(t, test.Coercibility, num.(int64))
   779  					} else {
   780  						str, _, err := types.LongText.Convert(rows[0][0])
   781  						require.NoError(t, err)
   782  						require.Equal(t, test.Collation.Name(), str.(string))
   783  					}
   784  				}
   785  			})
   786  		}
   787  	}
   788  }
   789  
   790  func TestRegex(t *testing.T) {
   791  	harness := enginetest.NewDefaultMemoryHarness()
   792  	harness.Setup(setup.SimpleSetup...)
   793  	engine, err := harness.NewEngine(t)
   794  	require.NoError(t, err)
   795  	defer engine.Close()
   796  
   797  	ctx := enginetest.NewContext(harness)
   798  	for _, tt := range queries.RegexTests {
   799  		t.Run(tt.Query, func(t *testing.T) {
   800  			if harness.SkipQueryTest(tt.Query) {
   801  				t.Skipf("Skipping query plan for %s", tt.Query)
   802  			}
   803  			if tt.ExpectedErr == nil {
   804  				enginetest.TestQueryWithContext(t, ctx, engine, harness, tt.Query, tt.Expected, nil, nil)
   805  			} else {
   806  				newCtx := ctx.WithQuery(tt.Query)
   807  				_, iter, err := engine.Query(newCtx, tt.Query)
   808  				if err == nil {
   809  					_, err = sql.RowIterToRows(newCtx, iter)
   810  					require.Error(t, err)
   811  				}
   812  			}
   813  		})
   814  	}
   815  	// We force garbage collection twice as we have two levels of finalizers on our regex objects, and we want to make
   816  	// sure that neither of them panic.
   817  	runtime.GC()
   818  	runtime.GC()
   819  }
   820  
   821  var _ sql.TableFunction = (*SimpleTableFunction)(nil)
   822  var _ sql.CollationCoercible = (*SimpleTableFunction)(nil)
   823  var _ sql.ExecSourceRel = (*SimpleTableFunction)(nil)
   824  
   825  // SimpleTableFunction an extremely simple implementation of TableFunction for testing.
   826  // When evaluated, returns a single row: {"foo", 123}
   827  type SimpleTableFunction struct {
   828  	returnedResults bool
   829  	id              sql.TableId
   830  	cols            sql.ColSet
   831  }
   832  
   833  func (s SimpleTableFunction) WithId(id sql.TableId) plan.TableIdNode {
   834  	s.id = id
   835  	return s
   836  }
   837  
   838  func (s SimpleTableFunction) Id() sql.TableId {
   839  	return s.id
   840  }
   841  
   842  func (s SimpleTableFunction) WithColumns(set sql.ColSet) plan.TableIdNode {
   843  	s.cols = set
   844  	return s
   845  }
   846  
   847  func (s SimpleTableFunction) Columns() sql.ColSet {
   848  	return s.cols
   849  }
   850  
   851  func (s SimpleTableFunction) NewInstance(_ *sql.Context, _ sql.Database, _ []sql.Expression) (sql.Node, error) {
   852  	return SimpleTableFunction{}, nil
   853  }
   854  
   855  func (s SimpleTableFunction) RowIter(ctx *sql.Context, r sql.Row) (sql.RowIter, error) {
   856  	if s.returnedResults == true {
   857  		return nil, io.EOF
   858  	}
   859  	s.returnedResults = true
   860  	return &SimpleTableFunctionRowIter{}, nil
   861  }
   862  
   863  func (s SimpleTableFunction) IsReadOnly() bool {
   864  	return true
   865  }
   866  
   867  func (s SimpleTableFunction) Resolved() bool {
   868  	return true
   869  }
   870  
   871  func (s SimpleTableFunction) String() string {
   872  	return "SimpleTableFunction"
   873  }
   874  
   875  func (s SimpleTableFunction) Schema() sql.Schema {
   876  	schema := []*sql.Column{
   877  		&sql.Column{
   878  			Name: "one",
   879  			Type: types.TinyText,
   880  		},
   881  		&sql.Column{
   882  			Name: "two",
   883  			Type: types.Int64,
   884  		},
   885  	}
   886  
   887  	return schema
   888  }
   889  
   890  func (s SimpleTableFunction) Children() []sql.Node {
   891  	return []sql.Node{}
   892  }
   893  
   894  func (s SimpleTableFunction) WithChildren(_ ...sql.Node) (sql.Node, error) {
   895  	return s, nil
   896  }
   897  
   898  func (s SimpleTableFunction) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool {
   899  	return true
   900  }
   901  
   902  // CollationCoercibility implements the interface sql.CollationCoercible.
   903  func (SimpleTableFunction) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   904  	return sql.Collation_binary, 7
   905  }
   906  
   907  func (s SimpleTableFunction) Expressions() []sql.Expression {
   908  	return []sql.Expression{}
   909  }
   910  
   911  func (s SimpleTableFunction) WithExpressions(e ...sql.Expression) (sql.Node, error) {
   912  	return s, nil
   913  }
   914  
   915  func (s SimpleTableFunction) Database() sql.Database {
   916  	return nil
   917  }
   918  
   919  func (s SimpleTableFunction) WithDatabase(_ sql.Database) (sql.Node, error) {
   920  	return s, nil
   921  }
   922  
   923  func (s SimpleTableFunction) Name() string {
   924  	return "simple_table_function"
   925  }
   926  
   927  func (s SimpleTableFunction) Description() string {
   928  	return "SimpleTableFunction"
   929  }
   930  
   931  var _ sql.RowIter = (*SimpleTableFunctionRowIter)(nil)
   932  
   933  type SimpleTableFunctionRowIter struct {
   934  	returnedResults bool
   935  }
   936  
   937  func (itr *SimpleTableFunctionRowIter) Next(_ *sql.Context) (sql.Row, error) {
   938  	if itr.returnedResults {
   939  		return nil, io.EOF
   940  	}
   941  
   942  	itr.returnedResults = true
   943  	return sql.Row{"foo", 123}, nil
   944  }
   945  
   946  func (itr *SimpleTableFunctionRowIter) Close(_ *sql.Context) error {
   947  	return nil
   948  }
   949  
   950  func TestTimestampBindingsCanBeConverted(t *testing.T) {
   951  	db, close := newDatabase()
   952  	defer close()
   953  
   954  	_, err := db.Exec("CREATE TABLE mytable (t TIMESTAMP)")
   955  	require.NoError(t, err)
   956  
   957  	// All we are doing in this test is ensuring that writing a timestamp to the
   958  	// database does not throw an error.
   959  	_, err = db.Exec("INSERT INTO mytable (t) VALUES (?)", time.Now())
   960  	require.NoError(t, err)
   961  }
   962  
   963  func TestTimestampBindingsCanBeCompared(t *testing.T) {
   964  	db, close := newDatabase()
   965  	defer close()
   966  
   967  	_, err := db.Exec("CREATE TABLE mytable (t TIMESTAMP)")
   968  	require.NoError(t, err)
   969  
   970  	// We'll insert both of these timestamps and then try and filter them.
   971  	t0 := time.Date(2022, 01, 01, 0, 0, 0, 0, time.UTC)
   972  	t1 := t0.Add(1 * time.Minute)
   973  
   974  	_, err = db.Exec("INSERT INTO mytable (t) VALUES (?)", t0)
   975  	require.NoError(t, err)
   976  	_, err = db.Exec("INSERT INTO mytable (t) VALUES (?)", t1)
   977  	require.NoError(t, err)
   978  
   979  	var count int
   980  	err = db.QueryRow("SELECT COUNT(1) FROM mytable WHERE t > ?", t0).Scan(&count)
   981  	require.NoError(t, err)
   982  	require.Equal(t, 1, count)
   983  }
   984  
   985  // TestAlterTableWithBadSchema is a backwards compatibility test that
   986  // ensures tables made with old versions of the engine can be altered.
   987  func TestAlterTableWithBadSchema(t *testing.T) {
   988  	harness := enginetest.NewDefaultMemoryHarness()
   989  	pro := harness.Provider()
   990  	harness.NewDatabases("mydb")
   991  	ctx := harness.NewContext()
   992  	sqlDb, err := pro.Database(ctx, "mydb")
   993  	require.NoError(t, err)
   994  	db := sqlDb.(*memory.HistoryDatabase)
   995  
   996  	sch := sql.NewPrimaryKeySchema(sql.Schema{
   997  		{Name: "a", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 16383), Source: "mytable"},
   998  		{Name: "b", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 16383), Source: "mytable"},
   999  		{Name: "c", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 16383), Source: "mytable"},
  1000  	})
  1001  
  1002  	harness.NewTableAsOf(db, "mytable", sch, nil)
  1003  
  1004  	engine, err := harness.NewEngine(t)
  1005  	require.NoError(t, err)
  1006  
  1007  	tests := []struct {
  1008  		name string
  1009  		q    string
  1010  		err  bool
  1011  	}{
  1012  		{
  1013  			name: "noop modify triggers validation",
  1014  			q:    "alter table mytable rename column a to d",
  1015  			err:  true,
  1016  		},
  1017  		{
  1018  			name: "partial update with invalid final schema fails",
  1019  			q:    "alter table mytable modify column a varchar(100), modify column b varchar(100)",
  1020  			err:  true,
  1021  		},
  1022  		{
  1023  			name: "update with valid final schema succeeds",
  1024  			q:    "alter table mytable modify column a varchar(100), modify column b varchar(100), modify column c varchar(100)",
  1025  			err:  false,
  1026  		},
  1027  		{
  1028  			name: "mixed update add with invalid final schema fails",
  1029  			q:    "alter table mytable modify column a varchar(100), modify column b varchar(100), modify column c varchar(100), add column d varchar(max)",
  1030  			err:  true,
  1031  		},
  1032  	}
  1033  	for _, tt := range tests {
  1034  		t.Run(tt.name, func(t *testing.T) {
  1035  			ctx := harness.NewContext()
  1036  			_, iter, err := engine.Query(ctx, tt.q)
  1037  			// errors should be analyze time, not execution time
  1038  			if tt.err {
  1039  				require.Error(t, err)
  1040  			} else {
  1041  				require.NoError(t, err)
  1042  				_, err = sql.RowIterToRows(ctx, iter)
  1043  				require.NoError(t, err)
  1044  			}
  1045  		})
  1046  	}
  1047  }
  1048  
  1049  func newDatabase() (*sql2.DB, func()) {
  1050  	// Grab an empty port so that tests do not fail if a specific port is already in use
  1051  	listener, err := net.Listen("tcp", ":0")
  1052  	if err != nil {
  1053  		panic(err)
  1054  	}
  1055  	port := listener.Addr().(*net.TCPAddr).Port
  1056  	if err = listener.Close(); err != nil {
  1057  		panic(err)
  1058  	}
  1059  
  1060  	harness := enginetest.NewDefaultMemoryHarness()
  1061  	pro := harness.Provider()
  1062  	harness.NewDatabases("mydb")
  1063  
  1064  	engine := sqle.New(analyzer.NewDefault(pro), &sqle.Config{
  1065  		IncludeRootAccount: true,
  1066  	})
  1067  	cfg := server.Config{
  1068  		Protocol: "tcp",
  1069  		Address:  fmt.Sprintf("localhost:%d", port),
  1070  	}
  1071  	srv, err := server.NewServer(cfg, engine, harness.SessionBuilder(), nil)
  1072  	if err != nil {
  1073  		panic(err)
  1074  	}
  1075  	go srv.Start()
  1076  
  1077  	db, err := sql2.Open("mysql", fmt.Sprintf("root:@tcp(localhost:%d)/mydb", port))
  1078  	if err != nil {
  1079  		panic(err)
  1080  	}
  1081  	return db, func() { srv.Close() }
  1082  }