From 857710f1edbb9bc4498b0d632a41e7ea92490d81 Mon Sep 17 00:00:00 2001 From: jennifersp <44716627+jennifersp@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:24:16 -0700 Subject: [PATCH 01/11] [no-release-notes] rewrite engine tests that depend on context to use test scripts instead (#2119) --- enginetest/enginetests.go | 1565 ++------------------- enginetest/evaluation.go | 18 +- enginetest/memory_engine_test.go | 4 - enginetest/memory_harness.go | 5 +- enginetest/queries/alter_table_queries.go | 755 ++++++++++ enginetest/queries/check_scripts.go | 578 ++++++++ enginetest/queries/foreign_key_queries.go | 149 ++ enginetest/queries/queries.go | 4 +- enginetest/queries/script_queries.go | 460 +++--- enginetest/server_engine.go | 1 + sql/expression/arithmetic.go | 8 + sql/planbuilder/ddl.go | 3 - 12 files changed, 1895 insertions(+), 1655 deletions(-) diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index be538dc7df..8da3a4f2a4 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -24,7 +24,6 @@ import ( "testing" "time" - "github.com/dolthub/vitess/go/mysql" "github.com/dolthub/vitess/go/sqltypes" "github.com/dolthub/vitess/go/vt/proto/query" _ "github.com/go-sql-driver/mysql" @@ -1403,7 +1402,7 @@ func TestJsonScriptsPrepared(t *testing.T, harness Harness) { } func TestCreateCheckConstraintsScriptsPrepared(t *testing.T, harness Harness) { - harness.Setup(setup.MydbData) + harness.Setup(setup.MydbData, setup.Check_constraintData) for _, script := range queries.CreateCheckConstraintsScripts { TestScriptPrepared(t, harness, script) } @@ -2456,620 +2455,151 @@ func TestDropTable(t *testing.T, harness Harness) { } func TestRenameTable(t *testing.T, harness Harness) { - require := require.New(t) harness.Setup(setup.MydbData, setup.MytableData, setup.OthertableData, setup.NiltableData, setup.EmptytableData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(err) - - _, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - - TestQueryWithContext(t, ctx, e, harness, "RENAME TABLE mytable TO newTableName", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.False(ok) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "newTableName") - require.NoError(err) - require.True(ok) - - TestQueryWithContext(t, ctx, e, harness, "RENAME TABLE othertable to othertable2, newTableName to mytable", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "othertable") - require.NoError(err) - require.False(ok) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "othertable2") - require.NoError(err) - require.True(ok) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "newTableName") - require.NoError(err) - require.False(ok) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable RENAME newTableName", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.False(ok) - _, ok, err = db.GetTableInsensitive(NewContext(harness), "newTableName") - require.NoError(err) - require.True(ok) - - _, _, err = e.Query(NewContext(harness), "ALTER TABLE not_exist RENAME foo") - require.Error(err) - require.True(sql.ErrTableNotFound.Is(err)) - - _, _, err = e.Query(NewContext(harness), "ALTER TABLE emptytable RENAME niltable") - require.Error(err) - require.True(sql.ErrTableAlreadyExists.Is(err)) + for _, tt := range queries.RenameTableScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) t.Skip("broken") TestQueryWithContext(t, ctx, e, harness, "RENAME TABLE mydb.emptytable TO mydb.emptytable2", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "emptytable") - require.NoError(err) - require.False(ok) - - _, ok, err = db.GetTableInsensitive(NewContext(harness), "emptytable2") - require.NoError(err) - require.True(ok) - - _, _, err = e.Query(NewContext(harness), "RENAME TABLE mydb.emptytable2 TO emptytable3") - require.Error(err) - require.True(sql.ErrNoDatabaseSelected.Is(err)) + AssertErrWithCtx(t, e, harness, ctx, "SELECT COUNT(*) FROM mydb.emptytable", sql.ErrTableNotFound) + TestQueryWithContext(t, ctx, e, harness, "SELECT COUNT(*) FROM mydb.emptytable2", []sql.Row{{types.NewOkResult(0)}}, nil, nil) + AssertErrWithCtx(t, e, harness, ctx, "RENAME TABLE mydb.emptytable2 TO emptytable3", sql.ErrNoDatabaseSelected) }) } func TestRenameColumn(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.MydbData, setup.MytableData, setup.TabletestData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(err) - - // Error cases - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i2 TO iX", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i TO iX, RENAME COLUMN iX TO i2", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i TO iX, RENAME COLUMN i TO i2", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i TO S", sql.ErrColumnExists) - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i TO n, RENAME COLUMN s TO N", sql.ErrColumnExists) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - require.Equal(sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - }, tbl.Schema()) - - RunQuery(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i TO i2, RENAME COLUMN s TO s2") - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - require.Equal(sql.Schema{ - {Name: "i2", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from mytable order by i2 limit 1", []sql.Row{ - {1, "first row"}, - }, nil, nil) - - t.Run("rename column preserves table checks", func(t *testing.T) { - RunQuery(t, e, harness, "ALTER TABLE mytable ADD CONSTRAINT test_check CHECK (i2 < 12345)") - - AssertErr(t, e, harness, "ALTER TABLE mytable RENAME COLUMN i2 TO i3", sql.ErrCheckConstraintInvalidatedByColumnAlter) - RunQuery(t, e, harness, "ALTER TABLE mytable RENAME COLUMN s2 TO s3") - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - - checkTable, ok := tbl.(sql.CheckTable) - require.True(ok) - checks, err := checkTable.GetChecks(NewContext(harness)) - require.NoError(err) - require.Equal(1, len(checks)) - require.Equal("test_check", checks[0].Name) - require.Equal("(i2 < 12345)", checks[0].CheckExpression) - }) + for _, tt := range queries.RenameColumnScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") - - beforeDropTbl, _, _ := db.GetTableInsensitive(NewContext(harness), "tabletest") - + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mydb.tabletest RENAME COLUMN s TO i1", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "tabletest") - require.NoError(err) - require.True(ok) - assert.NotEqual(t, beforeDropTbl, tbl.Schema()) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int32, DatabaseSource: "mydb", Source: "tabletest", PrimaryKey: true}, - {Name: "i1", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "tabletest"}, - }, tbl.Schema()) + TestQueryWithContext(t, ctx, e, harness, "SHOW FULL COLUMNS FROM mydb.tabletest", []sql.Row{ + {"i", "int", nil, "NO", "PRI", "NULL", "", "", ""}, + {"i1", "varchar(20)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", ""}, + }, nil, nil) }) } -// todo(max): convert to WriteQueryTest func TestAddColumn(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.MydbData, setup.MytableData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(err) - - t.Run("column at end with default", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable ADD COLUMN i2 INT COMMENT 'hello' default 42", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow(int64(1), "first row", int32(42)), - sql.NewRow(int64(2), "second row", int32(42)), - sql.NewRow(int64(3), "third row", int32(42)), - }, nil, nil) - }) - - t.Run("in middle, no default", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable ADD COLUMN s2 TEXT COMMENT 'hello' AFTER i", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.Text, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow(int64(1), nil, "first row", int32(42)), - sql.NewRow(int64(2), nil, "second row", int32(42)), - sql.NewRow(int64(3), nil, "third row", int32(42)), - }, nil, nil) - - TestQueryWithContext(t, ctx, e, harness, "insert into mytable values (4, 's2', 'fourth row', 11)", []sql.Row{ - {types.NewOkResult(1)}, - }, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "update mytable set s2 = 'updated s2' where i2 = 42", []sql.Row{ - {types.OkResult{RowsAffected: 3, Info: plan.UpdateInfo{ - Matched: 3, Updated: 3, - }}}, - }, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow(int64(1), "updated s2", "first row", int32(42)), - sql.NewRow(int64(2), "updated s2", "second row", int32(42)), - sql.NewRow(int64(3), "updated s2", "third row", int32(42)), - sql.NewRow(int64(4), "s2", "fourth row", int32(11)), - }, nil, nil) - }) - - t.Run("first with default", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable ADD COLUMN s3 VARCHAR(25) COMMENT 'hello' default 'yay' FIRST", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "s3", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), `"yay"`, types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), true)}, - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.Text, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow("yay", int64(1), "updated s2", "first row", int32(42)), - sql.NewRow("yay", int64(2), "updated s2", "second row", int32(42)), - sql.NewRow("yay", int64(3), "updated s2", "third row", int32(42)), - sql.NewRow("yay", int64(4), "s2", "fourth row", int32(11)), - }, nil, nil) - }) - - t.Run("middle, no default, non null", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable ADD COLUMN s4 VARCHAR(1) not null after s3", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "s3", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), `"yay"`, types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), true)}, - {Name: "s4", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 1), DatabaseSource: "mydb", Source: "mytable"}, - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.Text, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow("yay", "", int64(1), "updated s2", "first row", int32(42)), - sql.NewRow("yay", "", int64(2), "updated s2", "second row", int32(42)), - sql.NewRow("yay", "", int64(3), "updated s2", "third row", int32(42)), - sql.NewRow("yay", "", int64(4), "s2", "fourth row", int32(11)), - }, nil, nil) - }) - - t.Run("multiple in one statement", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable ADD COLUMN s5 VARCHAR(26), ADD COLUMN s6 VARCHAR(27)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "s3", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), `"yay"`, types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), true)}, - {Name: "s4", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 1), DatabaseSource: "mydb", Source: "mytable"}, - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.Text, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - {Name: "s5", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 26), DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - {Name: "s6", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 27), DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "SELECT * FROM mytable ORDER BY i", []sql.Row{ - sql.NewRow("yay", "", int64(1), "updated s2", "first row", int32(42), nil, nil), - sql.NewRow("yay", "", int64(2), "updated s2", "second row", int32(42), nil, nil), - sql.NewRow("yay", "", int64(3), "updated s2", "third row", int32(42), nil, nil), - sql.NewRow("yay", "", int64(4), "s2", "fourth row", int32(11), nil, nil), - }, nil, nil) - }) - t.Run("error cases", func(t *testing.T) { - AssertErr(t, e, harness, "ALTER TABLE not_exist ADD COLUMN i2 INT COMMENT 'hello'", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable ADD COLUMN b BIGINT COMMENT 'ok' AFTER not_exist", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable ADD COLUMN i BIGINT COMMENT 'ok'", sql.ErrColumnExists) - AssertErr(t, e, harness, "ALTER TABLE mytable ADD COLUMN b INT NOT NULL DEFAULT 'yes'", sql.ErrIncompatibleDefaultType) - AssertErr(t, e, harness, "ALTER TABLE mytable ADD COLUMN c int, add c int", sql.ErrColumnExists) - }) + for _, tt := range queries.AddColumnScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") - + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mydb.mytable ADD COLUMN s10 VARCHAR(26)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(err) - require.True(ok) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "s3", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), `"yay"`, types.MustCreateStringWithDefaults(sqltypes.VarChar, 25), true)}, - {Name: "s4", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 1), DatabaseSource: "mydb", Source: "mytable"}, - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - {Name: "s2", Type: types.Text, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i2", Type: types.Int32, DatabaseSource: "mydb", Source: "mytable", Comment: "hello", Nullable: true, Default: planbuilder.MustStringToColumnDefaultValue(NewContext(harness), "42", types.Int32, true)}, - {Name: "s5", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 26), DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - {Name: "s6", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 27), DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - {Name: "s10", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 26), DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - }, tbl.Schema()) + TestQueryWithContext(t, ctx, e, harness, "SHOW FULL COLUMNS FROM mydb.mytable", []sql.Row{ + {"s3", "varchar(25)", "utf8mb4_0900_bin", "YES", "", "'yay'", "", "", "hello"}, + {"s4", "varchar(1)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", ""}, + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "text", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "hello"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + {"s5", "varchar(26)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + {"s6", "varchar(27)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + {"s10", "varchar(26)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + }, nil, nil) }) } -// todo(max): convert to WriteQueryTest func TestModifyColumn(t *testing.T, harness Harness) { harness.Setup(setup.MydbData, setup.MytableData, setup.Mytable_del_idxData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable MODIFY COLUMN i bigint NOT NULL COMMENT 'modified'", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - require.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", Comment: "modified", PrimaryKey: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable MODIFY COLUMN i TINYINT NOT NULL COMMENT 'yes' AFTER s", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - require.Equal(t, sql.Schema{ - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - {Name: "i", Type: types.Int8, DatabaseSource: "mydb", Source: "mytable", Comment: "yes", PrimaryKey: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable MODIFY COLUMN i BIGINT NOT NULL COMMENT 'ok' FIRST", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - require.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", Comment: "ok", PrimaryKey: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), DatabaseSource: "mydb", Source: "mytable", Comment: "column s"}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable MODIFY COLUMN s VARCHAR(20) NULL COMMENT 'changed'", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - require.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", Comment: "ok", PrimaryKey: true}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), Nullable: true, DatabaseSource: "mydb", Source: "mytable", Comment: "changed"}, - }, tbl.Schema()) - - AssertErr(t, e, harness, "ALTER TABLE mytable MODIFY not_exist BIGINT NOT NULL COMMENT 'ok' FIRST", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable MODIFY i BIGINT NOT NULL COMMENT 'ok' AFTER not_exist", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "ALTER TABLE not_exist MODIFY COLUMN i INT NOT NULL COMMENT 'hello'", sql.ErrTableNotFound) - - t.Run("auto increment attribute", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable MODIFY i BIGINT auto_increment", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true, AutoIncrement: true, Nullable: false, Extra: "auto_increment"}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), Nullable: true, DatabaseSource: "mydb", Source: "mytable", Comment: "changed"}, - }, tbl.Schema()) - - RunQuery(t, e, harness, "insert into mytable (s) values ('new row')") - TestQueryWithContext(t, ctx, e, harness, "select i from mytable where s = 'new row'", []sql.Row{{4}}, nil, nil) - - AssertErr(t, e, harness, "ALTER TABLE mytable add column i2 bigint auto_increment", sql.ErrInvalidAutoIncCols) - - RunQuery(t, e, harness, "alter table mytable add column i2 bigint") - AssertErr(t, e, harness, "ALTER TABLE mytable modify column i2 bigint auto_increment", sql.ErrInvalidAutoIncCols) - - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true, AutoIncrement: true, Extra: "auto_increment"}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 20), Nullable: true, DatabaseSource: "mydb", Source: "mytable", Comment: "changed"}, - {Name: "i2", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - }, tbl.Schema()) - }) + for _, tt := range queries.ModifyColumnScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") - + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mydb.mytable MODIFY COLUMN s VARCHAR(21) NULL COMMENT 'changed again'", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err = db.GetTableInsensitive(NewContext(harness), "mytable") - require.NoError(t, err) - require.True(t, ok) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true, AutoIncrement: true, Extra: "auto_increment"}, - {Name: "s", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 21), Nullable: true, DatabaseSource: "mydb", Source: "mytable", Comment: "changed again"}, - {Name: "i2", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", Nullable: true}, - }, tbl.Schema()) + TestQueryWithContext(t, ctx, e, harness, "SHOW FULL COLUMNS FROM mydb.mytable", []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "ok"}, + {"s", "varchar(21)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed again"}, + {"i2", "bigint", nil, "YES", "", "NULL", "", "", ""}, + }, nil, nil) }) } -// todo(max): convert to WriteQueryTest func TestDropColumn(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.MydbData, setup.MytableData, setup.TabletestData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "mydb") - require.NoError(err) - - t.Run("drop last column", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mytable DROP COLUMN s", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - tbl, ok, err := db.GetTableInsensitive(ctx, "mytable") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "mytable", PrimaryKey: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from mytable order by i", []sql.Row{ - {1}, {2}, {3}, - }, nil, nil) - }) - - t.Run("drop first column", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t1 (a int, b varchar(10), c bigint, k bigint primary key)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - RunQuery(t, e, harness, "insert into t1 values (1, 'abc', 2, 3), (4, 'def', 5, 6)") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t1 DROP COLUMN a", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "b", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 10), DatabaseSource: "mydb", Source: "t1", Nullable: true}, - {Name: "c", Type: types.Int64, DatabaseSource: "mydb", Source: "t1", Nullable: true}, - {Name: "k", Type: types.Int64, DatabaseSource: "mydb", Source: "t1", PrimaryKey: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from t1 order by b", []sql.Row{ - {"abc", 2, 3}, - {"def", 5, 6}, - }, nil, nil) - }) - - t.Run("drop middle column", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t2 (a int, b varchar(10), c bigint, k bigint primary key)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - RunQuery(t, e, harness, "insert into t2 values (1, 'abc', 2, 3), (4, 'def', 5, 6)") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t2 DROP COLUMN b", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(ctx, "t2") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "a", Type: types.Int32, DatabaseSource: "mydb", Source: "t2", Nullable: true}, - {Name: "c", Type: types.Int64, DatabaseSource: "mydb", Source: "t2", Nullable: true}, - {Name: "k", Type: types.Int64, DatabaseSource: "mydb", Source: "t2", PrimaryKey: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from t2 order by c", []sql.Row{ - {1, 2, 3}, - {4, 5, 6}, - }, nil, nil) - }) - - t.Run("drop primary key column", func(t *testing.T) { - t.Skip("primary key column drops not well supported yet") - - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t3 (a int primary key, b varchar(10), c bigint)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - RunQuery(t, e, harness, "insert into t3 values (1, 'abc', 2), (3, 'def', 4)") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t3 DROP COLUMN a", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - tbl, ok, err := db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "b", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 10), DatabaseSource: "mydb", Source: "t3", Nullable: true}, - {Name: "c", Type: types.Int64, DatabaseSource: "mydb", Source: "t3", Nullable: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from t3 order by b", []sql.Row{ - {"abc", 2, 3}, - {"def", 4, 5}, - }, nil, nil) - }) + for _, tt := range queries.DropColumnScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } - beforeDropTbl, _, _ := db.GetTableInsensitive(NewContext(harness), "tabletest") - + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mydb.tabletest DROP COLUMN s", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "tabletest") - require.NoError(err) - require.True(ok) - assert.NotEqual(t, beforeDropTbl, tbl.Schema()) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int32, DatabaseSource: "mydb", Source: "tabletest", PrimaryKey: true}, - }, tbl.Schema()) - }) - - t.Run("error cases", func(t *testing.T) { - AssertErr(t, e, harness, "ALTER TABLE not_exist DROP COLUMN s", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE mytable DROP COLUMN s", sql.ErrTableColumnNotFound) - - // Dropping a column referred to in another column's default - RunQuery(t, e, harness, "create table t3 (a int primary key, b int, c int default (b+10))") - AssertErr(t, e, harness, "ALTER TABLE t3 DROP COLUMN b", sql.ErrDropColumnReferencedInDefault) + TestQueryWithContext(t, ctx, e, harness, "SHOW FULL COLUMNS FROM mydb.tabletest", []sql.Row{{"i", "int", nil, "NO", "PRI", "NULL", "", "", ""}}, nil, nil) }) } func TestDropColumnKeylessTables(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.MydbData, setup.TabletestData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "mydb") - require.NoError(err) - t.Run("drop last column", func(t *testing.T) { - RunQuery(t, e, harness, "create table t0 (i bigint, s varchar(20))") - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t0 DROP COLUMN s", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(ctx, "t0") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int64, DatabaseSource: "mydb", Source: "t0", Nullable: true}, - }, tbl.Schema()) - }) - - t.Run("drop first column", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t1 (a int, b varchar(10), c bigint)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - RunQuery(t, e, harness, "insert into t1 values (1, 'abc', 2), (4, 'def', 5)") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t1 DROP COLUMN a", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "b", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 10), DatabaseSource: "mydb", Source: "t1", Nullable: true}, - {Name: "c", Type: types.Int64, DatabaseSource: "mydb", Source: "t1", Nullable: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from t1 order by b", []sql.Row{ - {"abc", 2}, - {"def", 5}, - }, nil, nil) - }) - - t.Run("drop middle column", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t2 (a int, b varchar(10), c bigint)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - RunQuery(t, e, harness, "insert into t2 values (1, 'abc', 2), (4, 'def', 5)") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE t2 DROP COLUMN b", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(ctx, "t2") - require.NoError(err) - require.True(ok) - assert.Equal(t, sql.Schema{ - {Name: "a", Type: types.Int32, DatabaseSource: "mydb", Source: "t2", Nullable: true}, - {Name: "c", Type: types.Int64, DatabaseSource: "mydb", Source: "t2", Nullable: true}, - }, tbl.Schema()) - - TestQueryWithContext(t, ctx, e, harness, "select * from t2 order by c", []sql.Row{ - {1, 2}, - {4, 5}, - }, nil, nil) - }) + for _, tt := range queries.DropColumnKeylessTablesScripts { + TestScriptWithEngine(t, e, harness, tt) + } t.Run("no database selected", func(t *testing.T) { ctx := NewContext(harness) ctx.SetCurrentDatabase("") + if se, ok := e.(*ServerQueryEngine); ok { + se.NewConnection(ctx) + } - beforeDropTbl, _, _ := db.GetTableInsensitive(NewContext(harness), "tabletest") - + TestQueryWithContext(t, ctx, e, harness, "select database()", []sql.Row{{nil}}, nil, nil) TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE mydb.tabletest DROP COLUMN s", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - tbl, ok, err := db.GetTableInsensitive(NewContext(harness), "tabletest") - require.NoError(err) - require.True(ok) - assert.NotEqual(t, beforeDropTbl, tbl.Schema()) - assert.Equal(t, sql.Schema{ - {Name: "i", Type: types.Int32, DatabaseSource: "mydb", Source: "tabletest", PrimaryKey: true}, - }, tbl.Schema()) - }) - - t.Run("error cases", func(t *testing.T) { - AssertErr(t, e, harness, "ALTER TABLE not_exist DROP COLUMN s", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE t0 DROP COLUMN s", sql.ErrTableColumnNotFound) + TestQueryWithContext(t, ctx, e, harness, "SHOW FULL COLUMNS FROM mydb.tabletest", []sql.Row{{"i", "int", nil, "NO", "PRI", "NULL", "", "", ""}}, nil, nil) }) } @@ -3077,89 +2607,10 @@ func TestCreateDatabase(t *testing.T, harness Harness) { harness.Setup() e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - t.Run("CREATE DATABASE and create table", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE DATABASE testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "testdb") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "USE testdb", []sql.Row(nil), nil, nil) - - require.Equal(t, ctx.GetCurrentDatabase(), "testdb") - - ctx = NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE test (pk int primary key)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - db, err = e.EngineAnalyzer().Catalog.Database(ctx, "testdb") - require.NoError(t, err) - - _, ok, err := db.GetTableInsensitive(ctx, "test") - - require.NoError(t, err) - require.True(t, ok) - }) - - t.Run("CREATE DATABASE IF NOT EXISTS", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE DATABASE IF NOT EXISTS testdb2", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "testdb2") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "USE testdb2", []sql.Row(nil), nil, nil) - - require.Equal(t, ctx.GetCurrentDatabase(), "testdb2") - - ctx = NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE test (pk int primary key)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - db, err = e.EngineAnalyzer().Catalog.Database(ctx, "testdb2") - require.NoError(t, err) - - _, ok, err := db.GetTableInsensitive(ctx, "test") - - require.NoError(t, err) - require.True(t, ok) - }) - - t.Run("CREATE SCHEMA", func(t *testing.T) { - TestQueryWithContext(t, ctx, e, harness, "CREATE SCHEMA testdb3", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "testdb3") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "USE testdb3", []sql.Row(nil), nil, nil) - require.Equal(t, ctx.GetCurrentDatabase(), "testdb3") - - ctx = NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE test (pk int primary key)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - db, err = e.EngineAnalyzer().Catalog.Database(ctx, "testdb3") - require.NoError(t, err) - - _, ok, err := db.GetTableInsensitive(ctx, "test") - - require.NoError(t, err) - require.True(t, ok) - }) - - t.Run("CREATE DATABASE error handling", func(t *testing.T) { - AssertWarningAndTestQuery(t, e, ctx, harness, "CREATE DATABASE newtestdb CHARACTER SET utf8mb4 ENCRYPTION='N'", - []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 0, Info: nil}}}, nil, mysql.ERNotSupportedYet, 1, - "", false) - - AssertWarningAndTestQuery(t, e, ctx, harness, "CREATE DATABASE newtest1db DEFAULT COLLATE binary ENCRYPTION='Y'", - []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 0, Info: nil}}}, nil, mysql.ERNotSupportedYet, 1, - "", false) - - AssertErr(t, e, harness, "CREATE DATABASE mydb", sql.ErrDatabaseExists) - - AssertWarningAndTestQuery(t, e, nil, harness, "CREATE DATABASE IF NOT EXISTS mydb", - []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, mysql.ERDbCreateExists, - -1, "", false) - }) + for _, tt := range queries.CreateDatabaseScripts { + TestScriptWithEngine(t, e, harness, tt) + } } func TestPkOrdinalsDDL(t *testing.T, harness Harness) { @@ -3273,362 +2724,88 @@ func TestPkOrdinalsDML(t *testing.T, harness Harness) { exp: []sql.Row{{1, nil, 1, 1}, {2, 2, 2, 2}}, }, { - create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", - insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", - mutate: "DELETE FROM a WHERE y in (2,-1)", - sel: "select * from a", - exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, - }, - { - create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", - insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", - mutate: "DELETE FROM a WHERE y < 3", - sel: "select * from a", - exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, - }, - { - create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", - insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", - mutate: "DELETE FROM a WHERE y > 0 and z = 2", - sel: "select * from a", - exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, - }, - { - create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", - insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", - mutate: "DELETE FROM a WHERE y = 2", - sel: "select y from a", - exp: []sql.Row{{nil}, {nil}}, - }, - { - create: "CREATE TABLE a (x int, y int, z int, w int, index idx1 (y))", - insert: "INSERT INTO a values (0,0,0,0), (1,1,1,1), (2,2,2,2)", - mutate: "", - sel: "select * from a where y = 3", - exp: []sql.Row{}, - }, - } - - harness.Setup(setup.MydbData, setup.MytableData) - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - RunQuery(t, e, harness, "create table b (y char(6) primary key)") - RunQuery(t, e, harness, "insert into b values ('aaaaaa'),('bbbbbb'),('cccccc')") - for _, tt := range dml { - t.Run(fmt.Sprintf("%s", tt.mutate), func(t *testing.T) { - defer RunQuery(t, e, harness, "DROP TABLE IF EXISTS a") - if tt.create != "" { - RunQuery(t, e, harness, tt.create) - } - if tt.insert != "" { - RunQuery(t, e, harness, tt.insert) - } - if tt.mutate != "" { - RunQuery(t, e, harness, tt.mutate) - } - TestQueryWithContext(t, ctx, e, harness, tt.sel, tt.exp, nil, nil) - }) - } -} - -func TestDropDatabase(t *testing.T, harness Harness) { - harness.Setup(setup.MydbData) - t.Run("DROP DATABASE correctly works", func(t *testing.T) { - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - - TestQueryWithContext(t, ctx, e, harness, "DROP DATABASE mydb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - _, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.Error(t, err) - - // TODO: Deal with handling this error. - //AssertErr(t, e, harness, "SHOW TABLES", sql.ErrNoDatabaseSelected) - }) - - t.Run("DROP DATABASE works on newly created databases.", func(t *testing.T) { - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE DATABASE testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - _, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "testdb") - require.NoError(t, err) - - ctx.SetCurrentDatabase("testdb") - TestQueryWithContext(t, ctx, e, harness, "DROP DATABASE testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - AssertErr(t, e, harness, "USE testdb", sql.ErrDatabaseNotFound) - }) - - t.Run("DROP DATABASE works on current database and sets current database to empty.", func(t *testing.T) { - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE DATABASE testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - RunQueryWithContext(t, e, harness, ctx, "USE TESTdb") - - _, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "testdb") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "DROP DATABASE TESTDB", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "SELECT DATABASE()", []sql.Row{{nil}}, nil, nil) - AssertErr(t, e, harness, "USE testdb", sql.ErrDatabaseNotFound) - }) - - t.Run("DROP SCHEMA works on newly created databases.", func(t *testing.T) { - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE SCHEMA testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - _, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "testdb") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "DROP SCHEMA testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - AssertErr(t, e, harness, "USE testdb", sql.ErrDatabaseNotFound) - }) - - t.Run("DROP DATABASE IF EXISTS correctly works.", func(t *testing.T) { - e := mustNewEngine(t, harness) - defer e.Close() - - // The test setup sets a database name, which interferes with DROP DATABASE tests - ctx := NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "DROP DATABASE mydb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - AssertWarningAndTestQuery(t, e, ctx, harness, "DROP DATABASE IF EXISTS mydb", - []sql.Row{{types.OkResult{RowsAffected: 0}}}, nil, mysql.ERDbDropExists, - -1, "", false) - - TestQueryWithContext(t, ctx, e, harness, "CREATE DATABASE testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - _, err := e.EngineAnalyzer().Catalog.Database(ctx, "testdb") - require.NoError(t, err) - - TestQueryWithContext(t, ctx, e, harness, "DROP DATABASE IF EXISTS testdb", []sql.Row{{types.OkResult{RowsAffected: 1}}}, nil, nil) - - // After dropping the selected database, the current db field should be cleared out - require.Equal(t, "", ctx.GetCurrentDatabase()) - - sch, iter, err := e.Query(ctx, "USE testdb") - if err == nil { - _, err = sql.RowIterToRows(ctx, sch, iter) - } - require.Error(t, err) - require.True(t, sql.ErrDatabaseNotFound.Is(err), "Expected error of type %s but got %s", sql.ErrDatabaseNotFound, err) - - AssertWarningAndTestQuery(t, e, ctx, harness, "DROP DATABASE IF EXISTS testdb", - []sql.Row{{types.OkResult{RowsAffected: 0}}}, nil, mysql.ERDbDropExists, - -1, "", false) - }) -} - -func TestCreateForeignKeys(t *testing.T, harness Harness) { - require := require.New(t) - - harness.Setup(setup.MydbData, setup.MytableData) - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE parent(a INTEGER PRIMARY KEY, b INTEGER)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE parent ADD INDEX pb (b)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE child(c INTEGER PRIMARY KEY, d INTEGER, "+ - "CONSTRAINT fk1 FOREIGN KEY (D) REFERENCES parent(B) ON DELETE CASCADE"+ - ")", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child ADD CONSTRAINT fk4 FOREIGN KEY (D) REFERENCES child(C)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "mydb") - require.NoError(err) - - child, ok, err := db.GetTableInsensitive(ctx, "child") - require.NoError(err) - require.True(ok) - - fkt, ok := child.(sql.ForeignKeyTable) - require.True(ok) - - fks, err := fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - - expected := []sql.ForeignKeyConstraint{ - { - Name: "fk1", - Database: "mydb", - Table: "child", - Columns: []string{"d"}, - ParentDatabase: "mydb", - ParentTable: "parent", - ParentColumns: []string{"b"}, - OnUpdate: sql.ForeignKeyReferentialAction_DefaultAction, - OnDelete: sql.ForeignKeyReferentialAction_Cascade, - IsResolved: true, + create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", + insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", + mutate: "DELETE FROM a WHERE y in (2,-1)", + sel: "select * from a", + exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, }, { - Name: "fk4", - Database: "mydb", - Table: "child", - Columns: []string{"d"}, - ParentDatabase: "mydb", - ParentTable: "child", - ParentColumns: []string{"c"}, - OnUpdate: sql.ForeignKeyReferentialAction_DefaultAction, - OnDelete: sql.ForeignKeyReferentialAction_DefaultAction, - IsResolved: true, + create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", + insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", + mutate: "DELETE FROM a WHERE y < 3", + sel: "select * from a", + exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, + }, + { + create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", + insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", + mutate: "DELETE FROM a WHERE y > 0 and z = 2", + sel: "select * from a", + exp: []sql.Row{{0, nil, 0, 0}, {1, nil, 1, 1}}, }, - } - assert.Equal(t, expected, fks) - - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE child2(e INTEGER PRIMARY KEY, f INTEGER)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child2 ADD CONSTRAINT fk2 FOREIGN KEY (f) REFERENCES parent(b) ON DELETE RESTRICT", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child2 ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - child, ok, err = db.GetTableInsensitive(ctx, "child2") - require.NoError(err) - require.True(ok) - - fkt, ok = child.(sql.ForeignKeyTable) - require.True(ok) - - fks, err = fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - - expected = []sql.ForeignKeyConstraint{ { - Name: "fk2", - Database: "mydb", - Table: "child2", - Columns: []string{"f"}, - ParentDatabase: "mydb", - ParentTable: "parent", - ParentColumns: []string{"b"}, - OnUpdate: sql.ForeignKeyReferentialAction_DefaultAction, - OnDelete: sql.ForeignKeyReferentialAction_Restrict, - IsResolved: true, + create: "CREATE TABLE a (x int, y int, z int, w int, primary key (z,x))", + insert: "INSERT INTO a values (0,NULL,0,0), (1,NULL,1,1), (2,2,2,2)", + mutate: "DELETE FROM a WHERE y = 2", + sel: "select y from a", + exp: []sql.Row{{nil}, {nil}}, }, { - Name: "fk3", - Database: "mydb", - Table: "child2", - Columns: []string{"f"}, - ParentDatabase: "mydb", - ParentTable: "child", - ParentColumns: []string{"d"}, - OnUpdate: sql.ForeignKeyReferentialAction_SetNull, - OnDelete: sql.ForeignKeyReferentialAction_DefaultAction, - IsResolved: true, + create: "CREATE TABLE a (x int, y int, z int, w int, index idx1 (y))", + insert: "INSERT INTO a values (0,0,0,0), (1,1,1,1), (2,2,2,2)", + mutate: "", + sel: "select * from a where y = 3", + exp: []sql.Row{}, }, } - assert.Equal(t, expected, fks) - - // Some faulty create statements - _, _, err = e.Query(NewContext(harness), "ALTER TABLE child2 ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES dne(d) ON UPDATE SET NULL") - require.Error(err) - _, _, err = e.Query(NewContext(harness), "ALTER TABLE child2 ADD CONSTRAINT fk4 FOREIGN KEY (f) REFERENCES dne(d) ON UPDATE SET NULL") - require.Error(err) - assert.True(t, sql.ErrTableNotFound.Is(err)) - - _, _, err = e.Query(NewContext(harness), "ALTER TABLE dne ADD CONSTRAINT fk4 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL") - require.Error(err) - assert.True(t, sql.ErrTableNotFound.Is(err)) - - _, _, err = e.Query(NewContext(harness), "ALTER TABLE child2 ADD CONSTRAINT fk5 FOREIGN KEY (f) REFERENCES child(dne) ON UPDATE SET NULL") - require.Error(err) - assert.True(t, sql.ErrTableColumnNotFound.Is(err)) + harness.Setup(setup.MydbData, setup.MytableData) + e := mustNewEngine(t, harness) + defer e.Close() + ctx := NewContext(harness) + RunQuery(t, e, harness, "create table b (y char(6) primary key)") + RunQuery(t, e, harness, "insert into b values ('aaaaaa'),('bbbbbb'),('cccccc')") + for _, tt := range dml { + t.Run(fmt.Sprintf("%s", tt.mutate), func(t *testing.T) { + defer RunQuery(t, e, harness, "DROP TABLE IF EXISTS a") + if tt.create != "" { + RunQuery(t, e, harness, tt.create) + } + if tt.insert != "" { + RunQuery(t, e, harness, tt.insert) + } + if tt.mutate != "" { + RunQuery(t, e, harness, tt.mutate) + } + TestQueryWithContext(t, ctx, e, harness, tt.sel, tt.exp, nil, nil) + }) + } +} - t.Run("Add a column then immediately add a foreign key", func(t *testing.T) { - RunQuery(t, e, harness, "CREATE TABLE parent3 (pk BIGINT PRIMARY KEY, v1 BIGINT, INDEX (v1))") - RunQuery(t, e, harness, "CREATE TABLE child3 (pk BIGINT PRIMARY KEY);") - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child3 ADD COLUMN v1 BIGINT NULL, ADD CONSTRAINT fk_child3 FOREIGN KEY (v1) REFERENCES parent3(v1);", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - }) +func TestDropDatabase(t *testing.T, harness Harness) { + harness.Setup(setup.MydbData) + for _, tt := range queries.DropDatabaseScripts { + TestScript(t, harness, tt) + } +} - TestScript(t, harness, queries.ScriptTest{ - Name: "Do not validate foreign keys if FOREIGN_KEY_CHECKS is set to zero", - Assertions: []queries.ScriptTestAssertion{ - { - Query: "SET FOREIGN_KEY_CHECKS=0;", - Expected: []sql.Row{{}}, - }, - { - Query: "CREATE TABLE child4 (pk BIGINT PRIMARY KEY, CONSTRAINT fk_child4 FOREIGN KEY (pk) REFERENCES delayed_parent4 (pk))", - Expected: []sql.Row{{types.NewOkResult(0)}}, - }, - { - Query: "CREATE TABLE delayed_parent4 (pk BIGINT PRIMARY KEY)", - Expected: []sql.Row{{types.NewOkResult(0)}}, - }, - }, - }) +func TestCreateForeignKeys(t *testing.T, harness Harness) { + harness.Setup(setup.MydbData, setup.MytableData) + e := mustNewEngine(t, harness) + defer e.Close() + for _, tt := range queries.CreateForeignKeyTests { + TestScriptWithEngine(t, e, harness, tt) + } } func TestDropForeignKeys(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.MydbData, setup.MytableData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE parent(a INTEGER PRIMARY KEY, b INTEGER)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE parent ADD INDEX pb (b)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE child(c INTEGER PRIMARY KEY, d INTEGER, "+ - "CONSTRAINT fk1 FOREIGN KEY (d) REFERENCES parent(b) ON DELETE CASCADE"+ - ")", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE child2(e INTEGER PRIMARY KEY, f INTEGER)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child2 ADD CONSTRAINT fk2 FOREIGN KEY (f) REFERENCES parent(b) ON DELETE RESTRICT, "+ - "ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child2 DROP CONSTRAINT fk2", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(err) - - child, ok, err := db.GetTableInsensitive(NewContext(harness), "child2") - require.NoError(err) - require.True(ok) - - fkt, ok := child.(sql.ForeignKeyTable) - require.True(ok) - - fks, err := fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - - expected := []sql.ForeignKeyConstraint{ - { - Name: "fk3", - Database: "mydb", - Table: "child2", - Columns: []string{"f"}, - ParentDatabase: "mydb", - ParentTable: "child", - ParentColumns: []string{"d"}, - OnUpdate: sql.ForeignKeyReferentialAction_SetNull, - OnDelete: sql.ForeignKeyReferentialAction_DefaultAction, - IsResolved: true, - }, + for _, tt := range queries.DropForeignKeyTests { + TestScriptWithEngine(t, e, harness, tt) } - assert.Equal(t, expected, fks) - - TestQueryWithContext(t, ctx, e, harness, "ALTER TABLE child2 DROP FOREIGN KEY fk3", []sql.Row{{types.NewOkResult(0)}}, nil, nil) - - child, ok, err = db.GetTableInsensitive(NewContext(harness), "child2") - require.NoError(err) - require.True(ok) - - fkt, ok = child.(sql.ForeignKeyTable) - require.True(ok) - - fks, err = fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - assert.Len(t, fks, 0) - - // Some error queries - AssertErr(t, e, harness, "ALTER TABLE child3 DROP CONSTRAINT dne", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE child2 DROP CONSTRAINT fk3", sql.ErrUnknownConstraint) - AssertErr(t, e, harness, "ALTER TABLE child2 DROP FOREIGN KEY fk3", sql.ErrForeignKeyNotFound) } func TestForeignKeys(t *testing.T, harness Harness) { @@ -3667,126 +2844,10 @@ func TestFulltextIndexes(t *testing.T, harness Harness) { }) } -// todo(max): rewrite this using info schema and []QueryTest func TestCreateCheckConstraints(t *testing.T, harness Harness) { - require := require.New(t) - harness.Setup(setup.ChecksSetup...) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - db, err := e.EngineAnalyzer().Catalog.Database(NewContext(harness), "mydb") - require.NoError(err) - - table, ok, err := db.GetTableInsensitive(ctx, "checks") - require.NoError(err) - require.True(ok) - - cht, ok := table.(sql.CheckTable) - require.True(ok) - - checks, err := cht.GetChecks(NewContext(harness)) - require.NoError(err) - - expected := []sql.CheckDefinition{ - { - Name: "chk1", - CheckExpression: "(B > 0)", - Enforced: true, - }, - { - Name: "chk2", - CheckExpression: "(b > 0)", - Enforced: false, - }, - { - Name: "chk3", - CheckExpression: "(B > 1)", - Enforced: true, - }, - { - Name: "chk4", - CheckExpression: "(upper(C) = c)", - Enforced: true, - }, - } - assert.Equal(t, expected, checks) - - // Unnamed constraint - RunQuery(t, e, harness, "ALTER TABLE checks ADD CONSTRAINT CHECK (b > 100)") - - table, ok, err = db.GetTableInsensitive(NewContext(harness), "checks") - require.NoError(err) - require.True(ok) - - cht, ok = table.(sql.CheckTable) - require.True(ok) - - checks, err = cht.GetChecks(NewContext(harness)) - require.NoError(err) - - foundChk4 := false - for _, check := range checks { - if check.CheckExpression == "(b > 100)" { - assert.True(t, len(check.Name) > 0, "empty check name") - foundChk4 = true - break - } - } - assert.True(t, foundChk4, "check b > 100 not found") - - // Check statements in CREATE TABLE statements - // TODO: <> gets parsed / serialized as NOT(=), needs to be fixed for full round trip compatibility - RunQuery(t, e, harness, ` -CREATE TABLE T2 -( - CHECK (c1 = c2), - c1 INT CHECK (c1 > 10), - c2 INT CONSTRAINT c2_positive CHECK (c2 > 0), - c3 INT CHECK (c3 < 100), - CONSTRAINT c1_nonzero CHECK (c1 = 0), - CHECK (C1 > C3) -);`) - - table, ok, err = db.GetTableInsensitive(NewContext(harness), "t2") - require.NoError(err) - require.True(ok) - - cht, ok = table.(sql.CheckTable) - require.True(ok) - - checks, err = cht.GetChecks(NewContext(harness)) - require.NoError(err) - - expectedCheckConds := []string{ - "(c1 = c2)", - "(c1 > 10)", - "(c2 > 0)", - "(c3 < 100)", - "(c1 = 0)", - "(C1 > C3)", - } - - var checkConds []string - for _, check := range checks { - checkConds = append(checkConds, check.CheckExpression) - } - - assert.Equal(t, expectedCheckConds, checkConds) - - // Some faulty create statements - AssertErr(t, e, harness, "ALTER TABLE t3 ADD CONSTRAINT chk2 CHECK (c > 0)", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE checks ADD CONSTRAINT chk3 CHECK (d > 0)", sql.ErrColumnNotFound) - - AssertErr(t, e, harness, ` -CREATE TABLE t4 -( - CHECK (c1 = c2), - c1 INT CHECK (c1 > 10), - c2 INT CONSTRAINT c2_positive CHECK (c2 > 0), - CHECK (c1 > c3) -);`, sql.ErrColumnNotFound) // Test any scripts relevant to CheckConstraints. We do this separately from the rest of the scripts // as certain integrators might not implement check constraints. @@ -3795,60 +2856,13 @@ CREATE TABLE t4 } } -// todo(max): rewrite into []ScriptTest func TestChecksOnInsert(t *testing.T, harness Harness) { harness.Setup(setup.MydbData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - - RunQuery(t, e, harness, "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER, c varchar(20))") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk1 CHECK (b > 10) NOT ENFORCED") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (b > 0)") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk3 CHECK ((a + b) / 2 >= 1) ENFORCED") - - // TODO: checks get serialized as strings, which means that the String() method of functions is load-bearing. - // We do not have tests for all of them. Write some. - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk4 CHECK (upper(c) = c) ENFORCED") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk5 CHECK (trim(c) = c) ENFORCED") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk6 CHECK (trim(leading ' ' from c) = c) ENFORCED") - - RunQuery(t, e, harness, "INSERT INTO t1 VALUES (1,1,'ABC')") - - TestQueryWithContext(t, ctx, e, harness, `SELECT * FROM t1`, []sql.Row{ - {1, 1, "ABC"}, - }, nil, nil) - AssertErr(t, e, harness, "INSERT INTO t1 (a,b) VALUES (0,0)", sql.ErrCheckConstraintViolated) - AssertErr(t, e, harness, "INSERT INTO t1 (a,b) VALUES (0,1)", sql.ErrCheckConstraintViolated) - AssertErr(t, e, harness, "INSERT INTO t1 (a,b,c) VALUES (2,2,'abc')", sql.ErrCheckConstraintViolated) - AssertErr(t, e, harness, "INSERT INTO t1 (a,b,c) VALUES (2,2,'ABC ')", sql.ErrCheckConstraintViolated) - AssertErr(t, e, harness, "INSERT INTO t1 (a,b,c) VALUES (2,2,' ABC')", sql.ErrCheckConstraintViolated) - - RunQuery(t, e, harness, "INSERT INTO t1 VALUES (2,2,'ABC')") - RunQuery(t, e, harness, "INSERT INTO t1 (a,b) VALUES (4,NULL)") - - TestQueryWithContext(t, ctx, e, harness, `SELECT * FROM t1`, []sql.Row{ - {1, 1, "ABC"}, - {2, 2, "ABC"}, - {4, nil, nil}, - }, nil, nil) - - RunQuery(t, e, harness, "CREATE TABLE t2 (a INTEGER PRIMARY KEY, b INTEGER)") - RunQuery(t, e, harness, "INSERT INTO t2 VALUES (2,2),(3,3)") - RunQuery(t, e, harness, "DELETE FROM t1") - - AssertErr(t, e, harness, "INSERT INTO t1 (a,b) select a - 2, b - 1 from t2", sql.ErrCheckConstraintViolated) - RunQuery(t, e, harness, "INSERT INTO t1 (a,b) select a, b from t2") - - // Check that INSERT IGNORE correctly drops errors with check constraints and does not update the actual table. - RunQuery(t, e, harness, "INSERT IGNORE INTO t1 VALUES (5,2, 'abc')") - TestQueryWithContext(t, ctx, e, harness, `SELECT count(*) FROM t1 where a = 5`, []sql.Row{{0}}, nil, nil) - - // One value is correctly accepted and the other value is not accepted due to a check constraint violation. - // The accepted value is correctly added to the table. - RunQuery(t, e, harness, "INSERT IGNORE INTO t1 VALUES (4,4, null), (5,2, 'abc')") - TestQueryWithContext(t, ctx, e, harness, `SELECT count(*) FROM t1 where a = 5`, []sql.Row{{0}}, nil, nil) - TestQueryWithContext(t, ctx, e, harness, `SELECT count(*) FROM t1 where a = 4`, []sql.Row{{1}}, nil, nil) + for _, tt := range queries.ChecksOnInsertScripts { + TestScriptWithEngine(t, e, harness, tt) + } } func TestChecksOnUpdate(t *testing.T, harness Harness) { @@ -3863,229 +2877,20 @@ func TestDisallowedCheckConstraints(t *testing.T, harness Harness) { e := mustNewEngine(t, harness) defer e.Close() - RunQuery(t, e, harness, "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER)") - - // non-deterministic functions - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_user = \"root@\")", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (user() = \"root@\")", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (now() > '2021')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_date() > '2021')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (uuid() > 'a')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (database() = 'foo')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (schema() = 'foo')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (version() = 'foo')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (last_insert_id() = 0)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (rand() < .8)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (row_count() = 0)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (found_rows() = 0)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (curdate() > '2021')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (curtime() > '2021')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_timestamp() > '2021')", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (connection_id() = 2)", sql.ErrInvalidConstraintFunctionNotSupported) - - // locks - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (get_lock('abc', 0) is null)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (release_all_locks() is null)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (release_lock('abc') is null)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (is_free_lock('abc') is null)", sql.ErrInvalidConstraintFunctionNotSupported) - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (is_used_lock('abc') is null)", sql.ErrInvalidConstraintFunctionNotSupported) - - // subqueries - AssertErr(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK ((select count(*) from t1) = 0)", sql.ErrInvalidConstraintSubqueryNotSupported) - // TODO: need checks for stored procedures, also not allowed - - // Some spot checks on create table forms of the above - AssertErr(t, e, harness, ` -CREATE TABLE t3 ( - a int primary key CONSTRAINT chk2 CHECK (current_user = "root@") -) -`, sql.ErrInvalidConstraintFunctionNotSupported) - - AssertErr(t, e, harness, ` -CREATE TABLE t3 ( - a int primary key, - CHECK (current_user = "root@") -) -`, sql.ErrInvalidConstraintFunctionNotSupported) - - AssertErr(t, e, harness, ` -CREATE TABLE t3 ( - a int primary key CONSTRAINT chk2 CHECK (a = (select count(*) from t1)) -) -`, sql.ErrInvalidConstraintSubqueryNotSupported) - - AssertErr(t, e, harness, ` -CREATE TABLE t3 ( - a int primary key, - CHECK (a = (select count(*) from t1)) -) -`, sql.ErrInvalidConstraintSubqueryNotSupported) -} - -// todo(max): rewrite with []ScriptTest -func TestDropCheckConstraints(t *testing.T, harness Harness) { - require := require.New(t) - - harness.Setup(setup.MydbData) - e := mustNewEngine(t, harness) - defer e.Close() - ctx := NewContext(harness) - - RunQuery(t, e, harness, "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER, c integer)") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk1 CHECK (a > 0)") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (b > 0) NOT ENFORCED") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk3 CHECK (c > 0)") - RunQuery(t, e, harness, "ALTER TABLE t1 DROP CONSTRAINT chk2") - RunQuery(t, e, harness, "ALTER TABLE t1 DROP CHECK chk1") - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "mydb") - require.NoError(err) - - table, ok, err := db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - - cht, ok := table.(sql.CheckTable) - require.True(ok) - - checks, err := cht.GetChecks(NewContext(harness)) - require.NoError(err) - - expected := []sql.CheckDefinition{ - { - Name: "chk3", - CheckExpression: "(c > 0)", - Enforced: true, - }, + for _, tt := range queries.DisallowedCheckConstraintsScripts { + TestScriptWithEngine(t, e, harness, tt) } - - assert.Equal(t, expected, checks) - - RunQuery(t, e, harness, "ALTER TABLE t1 DROP CHECK chk3") - - // Some faulty drop statements - AssertErr(t, e, harness, "ALTER TABLE t2 DROP CONSTRAINT chk2", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE t1 DROP CONSTRAINT dne", sql.ErrUnknownConstraint) } -func TestDropConstraints(t *testing.T, harness Harness) { - require := require.New(t) - +func TestDropCheckConstraints(t *testing.T, harness Harness) { harness.Setup(setup.MydbData) e := mustNewEngine(t, harness) defer e.Close() - ctx := NewContext(harness) - RunQuery(t, e, harness, "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER, c integer)") - RunQuery(t, e, harness, "CREATE TABLE t2 (a INTEGER PRIMARY KEY, b INTEGER, c integer, INDEX (b))") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT chk1 CHECK (a > 0)") - RunQuery(t, e, harness, "ALTER TABLE t1 ADD CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t2(b)") - - db, err := e.EngineAnalyzer().Catalog.Database(ctx, "mydb") - require.NoError(err) - - table, ok, err := db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - - cht, ok := table.(sql.CheckTable) - require.True(ok) - - checks, err := cht.GetChecks(NewContext(harness)) - require.NoError(err) - - expected := []sql.CheckDefinition{ - { - Name: "chk1", - CheckExpression: "(a > 0)", - Enforced: true, - }, - } - assert.Equal(t, expected, checks) - - fkt, ok := table.(sql.ForeignKeyTable) - require.True(ok) - - fks, err := fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - - expectedFks := []sql.ForeignKeyConstraint{ - { - Name: "fk1", - Database: "mydb", - Table: "t1", - Columns: []string{"a"}, - ParentDatabase: "mydb", - ParentTable: "t2", - ParentColumns: []string{"b"}, - OnUpdate: "DEFAULT", - OnDelete: "DEFAULT", - IsResolved: true, - }, - } - assert.Equal(t, expectedFks, fks) - - RunQuery(t, e, harness, "ALTER TABLE t1 DROP CONSTRAINT chk1") - - table, ok, err = db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - - cht, ok = table.(sql.CheckTable) - require.True(ok) - - checks, err = cht.GetChecks(NewContext(harness)) - require.NoError(err) - - expected = []sql.CheckDefinition{} - assert.Equal(t, expected, checks) - - fkt, ok = table.(sql.ForeignKeyTable) - require.True(ok) - - fks, err = fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - - expectedFks = []sql.ForeignKeyConstraint{ - { - Name: "fk1", - Database: "mydb", - Table: "t1", - Columns: []string{"a"}, - ParentDatabase: "mydb", - ParentTable: "t2", - ParentColumns: []string{"b"}, - OnUpdate: "DEFAULT", - OnDelete: "DEFAULT", - IsResolved: true, - }, + for _, tt := range queries.DropCheckConstraintsScripts { + TestScriptWithEngine(t, e, harness, tt) } - assert.Equal(t, expectedFks, fks) - - RunQuery(t, e, harness, "ALTER TABLE t1 DROP CONSTRAINT fk1") - - table, ok, err = db.GetTableInsensitive(ctx, "t1") - require.NoError(err) - require.True(ok) - - cht, ok = table.(sql.CheckTable) - require.True(ok) - - checks, err = cht.GetChecks(NewContext(harness)) - require.NoError(err) - assert.Len(t, checks, 0) - - fkt, ok = table.(sql.ForeignKeyTable) - require.True(ok) - - fks, err = fkt.GetDeclaredForeignKeys(NewContext(harness)) - require.NoError(err) - assert.Len(t, fks, 0) - - // Some error statements - AssertErr(t, e, harness, "ALTER TABLE t3 DROP CONSTRAINT fk1", sql.ErrTableNotFound) - AssertErr(t, e, harness, "ALTER TABLE t1 DROP CONSTRAINT fk1", sql.ErrUnknownConstraint) } func TestWindowFunctions(t *testing.T, harness Harness) { @@ -5469,82 +4274,6 @@ func TestAlterTable(t *testing.T, harness Harness) { e := mustNewEngine(t, harness) defer e.Close() - t.Run("variety of alter column statements in a single statement", func(t *testing.T) { - RunQuery(t, e, harness, "CREATE TABLE t32(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int default (v1), toRename int)") - RunQuery(t, e, harness, `alter table t32 add column v4 int after pk, - drop column v2, modify v1 varchar(100) not null, - alter column v3 set default 100, rename column toRename to newName`) - - ctx := NewContext(harness) - t32, _, err := e.EngineAnalyzer().Catalog.Table(ctx, ctx.GetCurrentDatabase(), "t32") - require.NoError(t, err) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "pk", Type: types.Int64, Nullable: false, DatabaseSource: "mydb", Source: "t32", PrimaryKey: true}, - {Name: "v4", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32"}, - {Name: "v1", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 100), DatabaseSource: "mydb", Source: "t32"}, - {Name: "v3", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32", Default: NewColumnDefaultValue(expression.NewLiteral(int8(100), types.Int8), types.Int32, true, false, true)}, - {Name: "newName", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32"}, - }, t32.Schema()) - - RunQuery(t, e, harness, "CREATE TABLE t32_2(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int)") - RunQuery(t, e, harness, `alter table t32_2 drop v1, add v1 int`) - - t32, _, err = e.EngineAnalyzer().Catalog.Table(ctx, ctx.GetCurrentDatabase(), "t32_2") - require.NoError(t, err) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "pk", Type: types.Int64, Nullable: false, DatabaseSource: "mydb", Source: "t32_2", PrimaryKey: true}, - {Name: "v2", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_2"}, - {Name: "v3", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_2"}, - {Name: "v1", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_2"}, - }, t32.Schema()) - - RunQuery(t, e, harness, "CREATE TABLE t32_3(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int)") - RunQuery(t, e, harness, `alter table t32_3 rename column v1 to v5, add v1 int`) - - t32, _, err = e.EngineAnalyzer().Catalog.Table(ctx, ctx.GetCurrentDatabase(), "t32_3") - require.NoError(t, err) - assertSchemasEqualWithDefaults(t, sql.Schema{ - {Name: "pk", Type: types.Int64, Nullable: false, DatabaseSource: "mydb", Source: "t32_3", PrimaryKey: true}, - {Name: "v5", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_3"}, - {Name: "v2", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_3"}, - {Name: "v3", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_3"}, - {Name: "v1", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t32_3"}, - }, t32.Schema()) - - // Error cases: dropping a column added in the same statement, dropping a column not present in the original schema, - // dropping a column renamed away - AssertErr(t, e, harness, "alter table t32 add column vnew int, drop column vnew", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "alter table t32 rename column v3 to v5, drop column v5", sql.ErrTableColumnNotFound) - AssertErr(t, e, harness, "alter table t32 rename column v3 to v5, drop column v3", sql.ErrTableColumnNotFound) - }) - - t.Run("mix of alter column, add and drop constraints in one statement", func(t *testing.T) { - RunQuery(t, e, harness, "CREATE TABLE t33(pk BIGINT PRIMARY KEY, v1 int, v2 int)") - RunQuery(t, e, harness, `alter table t33 add column v4 int after pk, - drop column v2, add constraint v1gt0 check (v1 > 0)`) - - ctx := NewContext(harness) - t33, _, err := e.EngineAnalyzer().Catalog.Table(ctx, ctx.GetCurrentDatabase(), "t33") - require.NoError(t, err) - assert.Equal(t, sql.Schema{ - {Name: "pk", Type: types.Int64, Nullable: false, DatabaseSource: "mydb", Source: "t33", PrimaryKey: true}, - {Name: "v4", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t33"}, - {Name: "v1", Type: types.Int32, Nullable: true, DatabaseSource: "mydb", Source: "t33"}, - }, t33.Schema()) - - ct, ok := t33.(sql.CheckTable) - require.True(t, ok, "CheckTable required for this test") - checks, err := ct.GetChecks(ctx) - require.NoError(t, err) - assert.Equal(t, []sql.CheckDefinition{ - { - Name: "v1gt0", - CheckExpression: "(v1 > 0)", - Enforced: true, - }, - }, checks) - }) - for _, script := range queries.AlterTableScripts { TestScript(t, harness, script) } @@ -5571,6 +4300,10 @@ func TestColumnDefaults(t *testing.T, harness Harness) { // Some tests can't currently be run with as a script because they do additional checks t.Run("DATETIME/TIMESTAMP NOW/CURRENT_TIMESTAMP current_timestamp", func(t *testing.T) { + // TODO: fix result formatting for server engine tests + if IsServerEngine(e) { + t.Skip() + } // ctx = NewContext(harness) // e.Query(ctx, "set @@session.time_zone='SYSTEM';") // TODO: NOW() and CURRENT_TIMESTAMP() are supposed to be the same function in MySQL, but we have two different @@ -5594,6 +4327,10 @@ func TestColumnDefaults(t *testing.T, harness Harness) { // TODO: zero timestamps work slightly differently than they do in MySQL, where the zero time is "0000-00-00 00:00:00" // We use "0000-01-01 00:00:00" t.Run("DATETIME/TIMESTAMP NOW/CURRENT_TIMESTAMP literals", func(t *testing.T) { + // TODO: fix result formatting for server engine tests + if IsServerEngine(e) { + t.Skip() + } TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t10zero(pk BIGINT PRIMARY KEY, v1 DATETIME DEFAULT '2020-01-01 01:02:03', v2 DATETIME DEFAULT 0,"+ "v3 TIMESTAMP DEFAULT '2020-01-01 01:02:03', v4 TIMESTAMP DEFAULT 0)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) diff --git a/enginetest/evaluation.go b/enginetest/evaluation.go index 46c4963929..d3408a552f 100644 --- a/enginetest/evaluation.go +++ b/enginetest/evaluation.go @@ -602,11 +602,11 @@ func checkResults( widenedExpected[i][j] = actual // ensure it passes equality check later } - // TODO: in MySQL, boolean values sent over the wire are tinyint. - // Current engine tests assert on go boolean type values. Should - // remove this conversion in the future when we match the return - // type for boolean results as MySQL. if IsServerEngine(e) { + // TODO: in MySQL, boolean values sent over the wire are tinyint. + // Current engine tests assert on go boolean type values. Should + // remove this conversion in the future when we match the return + // type for boolean results as MySQL. if b, isBool := widenedExpected[i][j].(bool); isBool { if b { widenedExpected[i][j] = int64(1) @@ -614,6 +614,16 @@ func checkResults( widenedExpected[i][j] = int64(0) } } + // The result received from go sql driver does not have 'Info' + // data returned, so we set it to 'nil' for server engine tests only. + if okRes, ok := widenedExpected[i][j].(types.OkResult); ok { + okResult := types.OkResult{ + RowsAffected: okRes.RowsAffected, + InsertID: okRes.InsertID, + Info: nil, + } + widenedExpected[i][j] = okResult + } } } } diff --git a/enginetest/memory_engine_test.go b/enginetest/memory_engine_test.go index 9c30a67651..538ff51cbe 100644 --- a/enginetest/memory_engine_test.go +++ b/enginetest/memory_engine_test.go @@ -704,10 +704,6 @@ func TestDropCheckConstraints(t *testing.T) { enginetest.TestDropCheckConstraints(t, enginetest.NewDefaultMemoryHarness()) } -func TestDropConstraints(t *testing.T) { - enginetest.TestDropConstraints(t, enginetest.NewDefaultMemoryHarness()) -} - func TestReadOnly(t *testing.T) { enginetest.TestReadOnly(t, enginetest.NewDefaultMemoryHarness(), true /* testStoredProcedures */) } diff --git a/enginetest/memory_harness.go b/enginetest/memory_harness.go index e98bc683a7..253c8d9ab1 100644 --- a/enginetest/memory_harness.go +++ b/enginetest/memory_harness.go @@ -64,7 +64,7 @@ var _ ClientHarness = (*MemoryHarness)(nil) var _ ServerHarness = (*MemoryHarness)(nil) var _ sql.ExternalStoredProcedureProvider = (*MemoryHarness)(nil) -func NewMemoryHarness(name string, parallelism int, numTablePartitions int, useNativeIndexes bool, driverInitalizer IndexDriverInitializer) *MemoryHarness { +func NewMemoryHarness(name string, parallelism int, numTablePartitions int, useNativeIndexes bool, driverInitializer IndexDriverInitializer) *MemoryHarness { externalProcedureRegistry := sql.NewExternalStoredProcedureRegistry() for _, esp := range memory.ExternalStoredProcedures { externalProcedureRegistry.Register(esp) @@ -73,13 +73,12 @@ func NewMemoryHarness(name string, parallelism int, numTablePartitions int, useN return &MemoryHarness{ name: name, numTablePartitions: numTablePartitions, - indexDriverInitializer: driverInitalizer, + indexDriverInitializer: driverInitializer, parallelism: parallelism, nativeIndexSupport: useNativeIndexes, skippedQueries: make(map[string]struct{}), externalProcedureRegistry: externalProcedureRegistry, mu: &sync.Mutex{}, - //server: true, } } diff --git a/enginetest/queries/alter_table_queries.go b/enginetest/queries/alter_table_queries.go index 91210a800b..4777580d87 100644 --- a/enginetest/queries/alter_table_queries.go +++ b/enginetest/queries/alter_table_queries.go @@ -17,11 +17,95 @@ package queries import ( "github.com/dolthub/vitess/go/mysql" + "github.com/dolthub/go-mysql-server/sql/plan" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" ) var AlterTableScripts = []ScriptTest{ + { + Name: "variety of alter column statements in a single statement", + SetUpScript: []string{ + "CREATE TABLE t32(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int default (v1), toRename int)", + `alter table t32 add column v4 int after pk, + drop column v2, modify v1 varchar(100) not null, + alter column v3 set default 100, rename column toRename to newName`, + "CREATE TABLE t32_2(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int)", + `alter table t32_2 drop v1, add v1 int`, + "CREATE TABLE t32_3(pk BIGINT PRIMARY KEY, v1 int, v2 int, v3 int)", + `alter table t32_3 rename column v1 to v5, add v1 int`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SHOW FULL COLUMNS FROM t32", + // | Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment | + Expected: []sql.Row{ + {"pk", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"v4", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v1", "varchar(100)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", ""}, + {"v3", "int", nil, "YES", "", "100", "", "", ""}, + {"newName", "int", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "SHOW FULL COLUMNS FROM t32_2", + Expected: []sql.Row{ + {"pk", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"v2", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v3", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v1", "int", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "SHOW FULL COLUMNS FROM t32_3", + Expected: []sql.Row{ + {"pk", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"v5", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v2", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v3", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v1", "int", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "alter table t32 add column vnew int, drop column vnew", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "alter table t32 rename column v3 to v5, drop column v5", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "alter table t32 rename column v3 to v5, drop column v3", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + }, + }, + { + Name: "mix of alter column, add and drop constraints in one statement", + SetUpScript: []string{ + "CREATE TABLE t33(pk BIGINT PRIMARY KEY, v1 int, v2 int)", + `alter table t33 add column v4 int after pk, + drop column v2, add constraint v1gt0 check (v1 > 0)`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SHOW FULL COLUMNS FROM t33", + // | Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment | + Expected: []sql.Row{ + {"pk", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"v4", "int", nil, "YES", "", "NULL", "", "", ""}, + {"v1", "int", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "SELECT * FROM information_schema.CHECK_CONSTRAINTS", + Expected: []sql.Row{ + {"def", "mydb", "v1gt0", "(v1 > 0)"}, + }, + }, + }, + }, { // This script relies on setup.Pk_tablesData Name: "Error queries", @@ -812,6 +896,64 @@ var AlterTableScripts = []ScriptTest{ }, } +var RenameTableScripts = []ScriptTest{ + { + Name: "simple rename table", + Assertions: []ScriptTestAssertion{ + { + Query: "RENAME TABLE mytable TO newTableName", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SELECT COUNT(*) FROM mytable", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "SELECT COUNT(*) FROM newTableName", + Expected: []sql.Row{{3}}, + }, + }, + }, + { + Name: "rename multiple tables in one stmt", + Assertions: []ScriptTestAssertion{ + { + Query: "RENAME TABLE othertable to othertable2, newTableName to mytable", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SELECT COUNT(*) FROM othertable", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "SELECT COUNT(*) FROM newTableName", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "SELECT COUNT(*) FROM mytable", + Expected: []sql.Row{{3}}, + }, + { + Query: "SELECT COUNT(*) FROM othertable2", + Expected: []sql.Row{{3}}, + }, + }, + }, + { + Name: "error cases", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE not_exist RENAME foo", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE emptytable RENAME niltable", + ExpectedErr: sql.ErrTableAlreadyExists, + }, + }, + }, +} + var AlterTableAddAutoIncrementScripts = []ScriptTest{ { Name: "Add primary key column with auto increment", @@ -1190,3 +1332,616 @@ var AddDropPrimaryKeyScripts = []ScriptTest{ }, }, } + +var AddColumnScripts = []ScriptTest{ + { + Name: "column at end with default", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable ADD COLUMN i2 INT COMMENT 'hello' default 42", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + // | Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment | + // TODO: missing privileges + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + }, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow(int64(1), "first row", int32(42)), + sql.NewRow(int64(2), "second row", int32(42)), + sql.NewRow(int64(3), "third row", int32(42)), + }, + }, + }, + }, + { + Name: "in middle, no default", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable ADD COLUMN s2 TEXT COMMENT 'hello' AFTER i;", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "text", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "hello"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + }, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow(int64(1), nil, "first row", int32(42)), + sql.NewRow(int64(2), nil, "second row", int32(42)), + sql.NewRow(int64(3), nil, "third row", int32(42)), + }, + }, + { + Query: "insert into mytable values (4, 's2', 'fourth row', 11);", + Expected: []sql.Row{{types.NewOkResult(1)}}, + }, + { + Query: "update mytable set s2 = 'updated s2' where i2 = 42;", + Expected: []sql.Row{{types.OkResult{RowsAffected: 3, Info: plan.UpdateInfo{Matched: 3, Updated: 3}}}}, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow(int64(1), "updated s2", "first row", int32(42)), + sql.NewRow(int64(2), "updated s2", "second row", int32(42)), + sql.NewRow(int64(3), "updated s2", "third row", int32(42)), + sql.NewRow(int64(4), "s2", "fourth row", int32(11)), + }, + }, + }, + }, + { + Name: "first with default", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable ADD COLUMN s3 VARCHAR(25) COMMENT 'hello' default 'yay' FIRST", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{ + {"s3", "varchar(25)", "utf8mb4_0900_bin", "YES", "", "'yay'", "", "", "hello"}, + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "text", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "hello"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + }, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow("yay", int64(1), "updated s2", "first row", int32(42)), + sql.NewRow("yay", int64(2), "updated s2", "second row", int32(42)), + sql.NewRow("yay", int64(3), "updated s2", "third row", int32(42)), + sql.NewRow("yay", int64(4), "s2", "fourth row", int32(11)), + }, + }, + }, + }, + { + Name: "middle, no default, non null", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable ADD COLUMN s4 VARCHAR(1) not null after s3", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{ + {"s3", "varchar(25)", "utf8mb4_0900_bin", "YES", "", "'yay'", "", "", "hello"}, + {"s4", "varchar(1)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", ""}, + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "text", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "hello"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + }, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow("yay", "", int64(1), "updated s2", "first row", int32(42)), + sql.NewRow("yay", "", int64(2), "updated s2", "second row", int32(42)), + sql.NewRow("yay", "", int64(3), "updated s2", "third row", int32(42)), + sql.NewRow("yay", "", int64(4), "s2", "fourth row", int32(11)), + }, + }, + }, + }, + { + Name: "multiple in one statement", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable ADD COLUMN s5 VARCHAR(26), ADD COLUMN s6 VARCHAR(27)", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{ + {"s3", "varchar(25)", "utf8mb4_0900_bin", "YES", "", "'yay'", "", "", "hello"}, + {"s4", "varchar(1)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", ""}, + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "text", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "hello"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + {"i2", "int", nil, "YES", "", "42", "", "", "hello"}, + {"s5", "varchar(26)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + {"s6", "varchar(27)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "SELECT * FROM mytable ORDER BY i;", + Expected: []sql.Row{ + sql.NewRow("yay", "", int64(1), "updated s2", "first row", int32(42), nil, nil), + sql.NewRow("yay", "", int64(2), "updated s2", "second row", int32(42), nil, nil), + sql.NewRow("yay", "", int64(3), "updated s2", "third row", int32(42), nil, nil), + sql.NewRow("yay", "", int64(4), "s2", "fourth row", int32(11), nil, nil), + }, + }, + }, + }, + { + Name: "error cases", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE not_exist ADD COLUMN i2 INT COMMENT 'hello'", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN b BIGINT COMMENT 'ok' AFTER not_exist", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN i BIGINT COMMENT 'ok'", + ExpectedErr: sql.ErrColumnExists, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN b INT NOT NULL DEFAULT 'yes'", + ExpectedErr: sql.ErrIncompatibleDefaultType, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN c int, add c int", + ExpectedErr: sql.ErrColumnExists, + }, + }, + }, +} + +var RenameColumnScripts = []ScriptTest{ + { + Name: "error cases", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable RENAME COLUMN i2 TO iX", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE mytable RENAME COLUMN i TO iX, RENAME COLUMN iX TO i2", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE mytable RENAME COLUMN i TO iX, RENAME COLUMN i TO i2", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE mytable RENAME COLUMN i TO S", + ExpectedErr: sql.ErrColumnExists, + }, + { + Query: "ALTER TABLE mytable RENAME COLUMN i TO n, RENAME COLUMN s TO N", + ExpectedErr: sql.ErrColumnExists, + }, + }, + }, + { + Name: "simple rename column", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable RENAME COLUMN i TO i2, RENAME COLUMN s TO s2", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{ + {"i2", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + {"s2", "varchar(20)", "utf8mb4_0900_bin", "NO", "UNI", "NULL", "", "", "column s"}, + }, + }, + { + Query: "select * from mytable order by i2 limit 1", + Expected: []sql.Row{ + {1, "first row"}, + }, + }, + }, + }, + { + Name: "rename column preserves table checks", + SetUpScript: []string{ + "ALTER TABLE mytable ADD CONSTRAINT test_check CHECK (i2 < 12345)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable RENAME COLUMN i2 TO i3", + ExpectedErr: sql.ErrCheckConstraintInvalidatedByColumnAlter, + }, + { + Query: "ALTER TABLE mytable RENAME COLUMN s2 TO s3", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: `SELECT TC.CONSTRAINT_NAME, CC.CHECK_CLAUSE, TC.ENFORCED +FROM information_schema.TABLE_CONSTRAINTS TC, information_schema.CHECK_CONSTRAINTS CC +WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'mytable' AND TC.TABLE_SCHEMA = CC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'CHECK';`, + Expected: []sql.Row{{"test_check", "(i2 < 12345)", "YES"}}, + }, + }, + }, +} + +var ModifyColumnScripts = []ScriptTest{ + { + Name: "column at end with default", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable MODIFY COLUMN i bigint NOT NULL COMMENT 'modified'", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 1 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "modified"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", "column s"}, + }, + }, + { + Query: "ALTER TABLE mytable MODIFY COLUMN i TINYINT NOT NULL COMMENT 'yes' AFTER s", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 2 */", + Expected: []sql.Row{ + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", "column s"}, + {"i", "tinyint", nil, "NO", "PRI", "NULL", "", "", "yes"}, + }, + }, + { + Query: "ALTER TABLE mytable MODIFY COLUMN i BIGINT NOT NULL COMMENT 'ok' FIRST", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 3 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "ok"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "NO", "", "NULL", "", "", "column s"}, + }, + }, + { + Query: "ALTER TABLE mytable MODIFY COLUMN s VARCHAR(20) NULL COMMENT 'changed'", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 4 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "ok"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed"}, + }, + }, + }, + }, + { + Name: "auto increment attribute", + SetUpScript: []string{}, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable MODIFY i BIGINT auto_increment", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 1 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "auto_increment", "", ""}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed"}, + }, + }, + { + Query: "insert into mytable (s) values ('new row')", + }, + { + Query: "ALTER TABLE mytable add column i2 bigint auto_increment", + ExpectedErr: sql.ErrInvalidAutoIncCols, + }, + { + Query: "alter table mytable add column i2 bigint", + }, + { + Query: "ALTER TABLE mytable modify column i2 bigint auto_increment", + ExpectedErr: sql.ErrInvalidAutoIncCols, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 2 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "auto_increment", "", ""}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed"}, + {"i2", "bigint", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "ALTER TABLE mytable MODIFY COLUMN i BIGINT NOT NULL COMMENT 'ok' FIRST", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 3 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "ok"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed"}, + {"i2", "bigint", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Query: "ALTER TABLE mytable MODIFY COLUMN s VARCHAR(20) NULL COMMENT 'changed'", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM mytable /* 4 */", + Expected: []sql.Row{ + {"i", "bigint", nil, "NO", "PRI", "NULL", "", "", "ok"}, + {"s", "varchar(20)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", "changed"}, + {"i2", "bigint", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + }, + }, + { + Name: "error cases", + SetUpScript: []string{}, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE mytable MODIFY not_exist BIGINT NOT NULL COMMENT 'ok' FIRST", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE mytable MODIFY i BIGINT NOT NULL COMMENT 'ok' AFTER not_exist", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE not_exist MODIFY COLUMN i INT NOT NULL COMMENT 'hello'", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN b INT NOT NULL DEFAULT 'yes'", + ExpectedErr: sql.ErrIncompatibleDefaultType, + }, + { + Query: "ALTER TABLE mytable ADD COLUMN c int, add c int", + ExpectedErr: sql.ErrColumnExists, + }, + }, + }, +} + +var DropColumnScripts = []ScriptTest{ + { + Name: "drop last column", + SetUpScript: []string{ + "ALTER TABLE mytable DROP COLUMN s", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SHOW FULL COLUMNS FROM mytable", + Expected: []sql.Row{{"i", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}}, + }, + { + Query: "select * from mytable order by i", + Expected: []sql.Row{{1}, {2}, {3}}, + }, + }, + }, + { + Name: "drop first column", + SetUpScript: []string{ + "CREATE TABLE t1 (a int, b varchar(10), c bigint, k bigint primary key)", + "insert into t1 values (1, 'abc', 2, 3), (4, 'def', 5, 6)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t1 DROP COLUMN a", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM t1", + Expected: []sql.Row{ + {"b", "varchar(10)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + {"c", "bigint", nil, "YES", "", "NULL", "", "", ""}, + {"k", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + }, + }, + { + Query: "SELECT * FROM t1 ORDER BY b", + Expected: []sql.Row{ + {"abc", 2, 3}, + {"def", 5, 6}, + }, + }, + }, + }, + { + Name: "drop middle column", + SetUpScript: []string{ + "CREATE TABLE t2 (a int, b varchar(10), c bigint, k bigint primary key)", + "insert into t2 values (1, 'abc', 2, 3), (4, 'def', 5, 6)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t2 DROP COLUMN b", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM t2", + Expected: []sql.Row{ + {"a", "int", nil, "YES", "", "NULL", "", "", ""}, + {"c", "bigint", nil, "YES", "", "NULL", "", "", ""}, + {"k", "bigint", nil, "NO", "PRI", "NULL", "", "", ""}, + }, + }, + { + Query: "SELECT * FROM t2 ORDER BY c", + Expected: []sql.Row{ + {1, 2, 3}, + {4, 5, 6}, + }, + }, + }, + }, + { + // TODO: primary key column drops not well supported yet + Name: "drop primary key column", + SetUpScript: []string{ + "CREATE TABLE t3 (a int primary key, b varchar(10), c bigint)", + "insert into t3 values (1, 'abc', 2), (3, 'def', 4)", + }, + Assertions: []ScriptTestAssertion{ + { + Skip: true, + Query: "ALTER TABLE t3 DROP COLUMN a", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Skip: true, + Query: "SHOW FULL COLUMNS FROM t3", + Expected: []sql.Row{ + {"b", "varchar(10)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, + {"c", "bigint", nil, "YES", "", "NULL", "", "", ""}, + }, + }, + { + Skip: true, + Query: "SELECT * FROM t3 ORDER BY b", + Expected: []sql.Row{ + {"abc", 2}, + {"def", 4}, + }, + }, + }, + }, + { + Name: "error cases", + SetUpScript: []string{ + "create table t4 (a int primary key, b int, c int default (b+10))", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE not_exist DROP COLUMN s", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE mytable DROP COLUMN s", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "ALTER TABLE t4 DROP COLUMN b", + ExpectedErr: sql.ErrDropColumnReferencedInDefault, + }, + }, + }, +} + +var DropColumnKeylessTablesScripts = []ScriptTest{ + { + Name: "drop last column", + SetUpScript: []string{ + "create table t0 (i bigint, s varchar(20))", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t0 DROP COLUMN s", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM t0", + Expected: []sql.Row{{"i", "bigint", nil, "YES", "", "NULL", "", "", ""}}, + }, + }, + }, + { + Name: "drop first column", + SetUpScript: []string{ + "CREATE TABLE t1 (a int, b varchar(10), c bigint)", + "insert into t1 values (1, 'abc', 2), (4, 'def', 5)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t1 DROP COLUMN a", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM t1", + Expected: []sql.Row{{"b", "varchar(10)", "utf8mb4_0900_bin", "YES", "", "NULL", "", "", ""}, {"c", "bigint", nil, "YES", "", "NULL", "", "", ""}}, + }, + { + Query: "SELECT * FROM t1 ORDER BY b", + Expected: []sql.Row{ + {"abc", 2}, + {"def", 5}, + }, + }, + }, + }, + { + Name: "drop middle column", + SetUpScript: []string{ + "CREATE TABLE t2 (a int, b varchar(10), c bigint)", + "insert into t2 values (1, 'abc', 2), (4, 'def', 5)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t2 DROP COLUMN b", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW FULL COLUMNS FROM t2", + Expected: []sql.Row{{"a", "int", nil, "YES", "", "NULL", "", "", ""}, {"c", "bigint", nil, "YES", "", "NULL", "", "", ""}}, + }, + { + Query: "SELECT * FROM t2 ORDER BY c", + Expected: []sql.Row{ + {1, 2}, + {4, 5}, + }, + }, + }, + }, + { + Name: "error cases", + SetUpScript: []string{}, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE not_exist DROP COLUMN s", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE t0 DROP COLUMN s", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + { + Query: "SELECT * FROM t2 ORDER BY c", + Expected: []sql.Row{ + {1, 2}, + {4, 5}, + }, + }, + }, + }, +} diff --git a/enginetest/queries/check_scripts.go b/enginetest/queries/check_scripts.go index e8323f62e0..9c0378c853 100644 --- a/enginetest/queries/check_scripts.go +++ b/enginetest/queries/check_scripts.go @@ -20,6 +20,447 @@ import ( "github.com/dolthub/go-mysql-server/sql/types" ) +var CreateCheckConstraintsScripts = []ScriptTest{ + { + Name: "simple check constraint check on ChecksSetup data", + SetUpScript: []string{}, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT TC.CONSTRAINT_NAME, CC.CHECK_CLAUSE, TC.ENFORCED +FROM information_schema.TABLE_CONSTRAINTS TC, information_schema.CHECK_CONSTRAINTS CC +WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'checks' AND TC.TABLE_SCHEMA = CC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'CHECK';`, + Expected: []sql.Row{{"chk1", "(B > 0)", "YES"}, {"chk2", "(b > 0)", "NO"}, {"chk3", "(B > 1)", "YES"}, {"chk4", "(upper(C) = c)", "YES"}}, + }, + }, + }, + { + Name: "unnamed constraint", + SetUpScript: []string{ + "ALTER TABLE checks ADD CONSTRAINT CHECK (b > 100)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT LENGTH(TC.CONSTRAINT_NAME) > 0 +FROM information_schema.TABLE_CONSTRAINTS TC, information_schema.CHECK_CONSTRAINTS CC +WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'checks' AND TC.TABLE_SCHEMA = CC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'CHECK' AND CC.CHECK_CLAUSE = '(b > 100)';`, + Expected: []sql.Row{{true}}, + }, + }, + }, + { + Name: "check statements in CREATE TABLE statements", + SetUpScript: []string{ + ` +CREATE TABLE T2 +( + CHECK (c1 = c2), + c1 INT CHECK (c1 > 10), + c2 INT CONSTRAINT c2_positive CHECK (c2 > 0), + c3 INT CHECK (c3 < 100), + CONSTRAINT c1_nonzero CHECK (c1 = 0), + CHECK (C1 > C3) +);`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT CC.CHECK_CLAUSE +FROM information_schema.TABLE_CONSTRAINTS TC, information_schema.CHECK_CONSTRAINTS CC +WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't2' AND TC.TABLE_SCHEMA = CC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'CHECK';`, + Expected: []sql.Row{{"(c1 = c2)"}, {"(c1 > 10)"}, {"(c2 > 0)"}, {"(c3 < 100)"}, {"(c1 = 0)"}, {"(C1 > C3)"}}, + }, + }, + }, + { + Name: "error cases", + SetUpScript: []string{}, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t3 ADD CONSTRAINT chk2 CHECK (c > 0)", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE checks ADD CONSTRAINT chk3 CHECK (d > 0)", + ExpectedErr: sql.ErrColumnNotFound, + }, + { + Query: ` +CREATE TABLE t4 +( + CHECK (c1 = c2), + c1 INT CHECK (c1 > 10), + c2 INT CONSTRAINT c2_positive CHECK (c2 > 0), + CHECK (c1 > c3) +);`, + ExpectedErr: sql.ErrColumnNotFound, + }, + }, + }, + { + Name: "Run SHOW CREATE TABLE with different types of check constraints", + SetUpScript: []string{ + "CREATE TABLE mytable1(pk int PRIMARY KEY, CONSTRAINT check1 CHECK (pk = 5))", + "ALTER TABLE mytable1 ADD CONSTRAINT check11 CHECK (pk < 6)", + "CREATE TABLE mytable2(pk int PRIMARY KEY, v int, CONSTRAINT check2 CHECK (v < 5))", + "ALTER TABLE mytable2 ADD CONSTRAINT check12 CHECK (pk + v = 6)", + "CREATE TABLE mytable3(pk int PRIMARY KEY, v int, CONSTRAINT check3 CHECK (pk > 2 AND v < 5))", + "ALTER TABLE mytable3 ADD CONSTRAINT check13 CHECK (pk BETWEEN 2 AND 100)", + "CREATE TABLE mytable4(pk int PRIMARY KEY, v int, CONSTRAINT check4 CHECK (pk > 2 AND v < 5 AND pk < 9))", + "CREATE TABLE mytable5(pk int PRIMARY KEY, v int, CONSTRAINT check5 CHECK (pk > 2 OR (v < 5 AND pk < 9)))", + "CREATE TABLE mytable6(pk int PRIMARY KEY, v int, CONSTRAINT check6 CHECK (NOT pk))", + "CREATE TABLE mytable7(pk int PRIMARY KEY, v int, CONSTRAINT check7 CHECK (pk != v))", + "CREATE TABLE mytable8(pk int PRIMARY KEY, v int, CONSTRAINT check8 CHECK (pk > 2 OR v < 5 OR pk < 10))", + "CREATE TABLE mytable9(pk int PRIMARY KEY, v int, CONSTRAINT check9 CHECK ((pk + v) / 2 >= 1))", + "CREATE TABLE mytable10(pk int PRIMARY KEY, v int, CONSTRAINT check10 CHECK (v < 5) NOT ENFORCED)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SHOW CREATE TABLE mytable1", + Expected: []sql.Row{ + { + "mytable1", + "CREATE TABLE `mytable1` (\n `pk` int NOT NULL,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check1` CHECK ((`pk` = 5)),\n" + + " CONSTRAINT `check11` CHECK ((`pk` < 6))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable2", + Expected: []sql.Row{ + { + "mytable2", + "CREATE TABLE `mytable2` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check2` CHECK ((`v` < 5)),\n" + + " CONSTRAINT `check12` CHECK (((`pk` + `v`) = 6))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable3", + Expected: []sql.Row{ + { + "mytable3", + "CREATE TABLE `mytable3` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check3` CHECK (((`pk` > 2) AND (`v` < 5))),\n" + + " CONSTRAINT `check13` CHECK ((`pk` BETWEEN 2 AND 100))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable4", + Expected: []sql.Row{ + { + "mytable4", + "CREATE TABLE `mytable4` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check4` CHECK ((((`pk` > 2) AND (`v` < 5)) AND (`pk` < 9)))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable5", + Expected: []sql.Row{ + { + "mytable5", + "CREATE TABLE `mytable5` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check5` CHECK (((`pk` > 2) OR ((`v` < 5) AND (`pk` < 9))))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable6", + Expected: []sql.Row{ + { + "mytable6", + "CREATE TABLE `mytable6` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check6` CHECK ((NOT(`pk`)))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable7", + Expected: []sql.Row{ + { + "mytable7", + "CREATE TABLE `mytable7` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check7` CHECK ((NOT((`pk` = `v`))))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable8", + Expected: []sql.Row{ + { + "mytable8", + "CREATE TABLE `mytable8` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check8` CHECK ((((`pk` > 2) OR (`v` < 5)) OR (`pk` < 10)))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable9", + Expected: []sql.Row{ + { + "mytable9", + "CREATE TABLE `mytable9` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check9` CHECK ((((`pk` + `v`) / 2) >= 1))\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + { + Query: "SHOW CREATE TABLE mytable10", + Expected: []sql.Row{ + { + "mytable10", + "CREATE TABLE `mytable10` (\n `pk` int NOT NULL,\n" + + " `v` int,\n" + + " PRIMARY KEY (`pk`),\n" + + " CONSTRAINT `check10` CHECK ((`v` < 5)) /*!80016 NOT ENFORCED */\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + }, + }, + }, + }, + }, + { + Name: "Create a table with a check and validate that it appears in check_constraints and table_constraints", + SetUpScript: []string{ + "CREATE TABLE mytable (pk int primary key, test_score int, height int, CONSTRAINT mycheck CHECK (test_score >= 50), CONSTRAINT hcheck CHECK (height < 10), CONSTRAINT vcheck CHECK (height > 0))", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT * from information_schema.check_constraints where constraint_name IN ('mycheck', 'hcheck') ORDER BY constraint_name", + Expected: []sql.Row{ + {"def", "mydb", "hcheck", "(height < 10)"}, + {"def", "mydb", "mycheck", "(test_score >= 50)"}, + }, + }, + { + Query: "SELECT * FROM information_schema.table_constraints where table_name='mytable' ORDER BY constraint_type,constraint_name", + Expected: []sql.Row{ + {"def", "mydb", "hcheck", "mydb", "mytable", "CHECK", "YES"}, + {"def", "mydb", "mycheck", "mydb", "mytable", "CHECK", "YES"}, + {"def", "mydb", "vcheck", "mydb", "mytable", "CHECK", "YES"}, + {"def", "mydb", "PRIMARY", "mydb", "mytable", "PRIMARY KEY", "YES"}, + }, + }, + }, + }, + { + Name: "multi column index, lower()", + SetUpScript: []string{ + "CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 varchar(100), v2 varchar(100), INDEX (v1,v2));", + "INSERT INTO test VALUES (1,'happy','birthday'), (2,'HAPPY','BIRTHDAY'), (3,'hello','sailor');", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT pk FROM test where lower(v1) = 'happy' and lower(v2) = 'birthday' order by 1", + Expected: []sql.Row{{1}, {2}}, + }, + }, + }, + { + Name: "adding check constraint to a table that violates said constraint correctly throws an error", + SetUpScript: []string{ + "CREATE TABLE test (pk int)", + "INSERT INTO test VALUES (1),(2),(300)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE test ADD CONSTRAINT bad_check CHECK (pk < 5)", + ExpectedErr: plan.ErrCheckViolated, + }, + }, + }, + { + Name: "duplicate indexes still returns correct results", + SetUpScript: []string{ + "CREATE TABLE test (i int)", + "CREATE INDEX test_idx1 on test (i)", + "CREATE INDEX test_idx2 on test (i)", + "INSERT INTO test values (1), (2), (3)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT * FROM test ORDER BY i", + Expected: []sql.Row{{1}, {2}, {3}}, + }, + { + Query: "SELECT * FROM test where i = 2", + Expected: []sql.Row{ + {2}, + }, + }, + }, + }, +} + +var DropCheckConstraintsScripts = []ScriptTest{ + { + Name: "basic drop check constraints", + SetUpScript: []string{ + "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER, c integer)", + "ALTER TABLE t1 ADD CONSTRAINT chk1 CHECK (a > 0)", + "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (b > 0) NOT ENFORCED", + "ALTER TABLE t1 ADD CONSTRAINT chk3 CHECK (c > 0)", + "ALTER TABLE t1 DROP CONSTRAINT chk2", + "ALTER TABLE t1 DROP CHECK chk1", + }, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT TC.CONSTRAINT_NAME, CC.CHECK_CLAUSE, TC.ENFORCED +FROM information_schema.TABLE_CONSTRAINTS TC, information_schema.CHECK_CONSTRAINTS CC +WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't1' AND TC.TABLE_SCHEMA = CC.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE = 'CHECK';`, + Expected: []sql.Row{{"chk3", "(c > 0)", "YES"}}, + }, + }, + }, + { + Name: "error cases", + SetUpScript: []string{ + "ALTER TABLE t1 DROP CHECK chk3", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE t2 DROP CONSTRAINT chk2", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE t1 DROP CONSTRAINT dne", + ExpectedErr: sql.ErrUnknownConstraint, + }, + }, + }, +} + +var ChecksOnInsertScripts = []ScriptTest{ + { + Name: "basic checks constraints violations on insert", + SetUpScript: []string{ + "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER, c varchar(20))", + "ALTER TABLE t1 ADD CONSTRAINT chk1 CHECK (b > 10) NOT ENFORCED", + "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (b > 0)", + "ALTER TABLE t1 ADD CONSTRAINT chk3 CHECK ((a + b) / 2 >= 1) ENFORCED", + // TODO(Zach on 1/6/22): checks get serialized as strings, which means that the String() method of functions is load-bearing. + // We do not have tests for all of them. Write some. + "ALTER TABLE t1 ADD CONSTRAINT chk4 CHECK (upper(c) = c) ENFORCED", + "ALTER TABLE t1 ADD CONSTRAINT chk5 CHECK (trim(c) = c) ENFORCED", + "ALTER TABLE t1 ADD CONSTRAINT chk6 CHECK (trim(leading ' ' from c) = c) ENFORCED", + + "INSERT INTO t1 VALUES (1,1,'ABC')", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT * FROM t1;", + Expected: []sql.Row{{1, 1, "ABC"}}, + }, + { + Query: "INSERT INTO t1 (a,b) VALUES (0,0)", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + { + Query: "INSERT INTO t1 (a,b) VALUES (0,1)", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + { + Query: "INSERT INTO t1 (a,b,c) VALUES (2,2,'abc')", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + { + Query: "INSERT INTO t1 (a,b,c) VALUES (2,2,'ABC ')", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + { + Query: "INSERT INTO t1 (a,b,c) VALUES (2,2,' ABC')", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + }, + }, + { + Name: "simple insert with check constraint", + SetUpScript: []string{ + "INSERT INTO t1 VALUES (2,2,'ABC')", + "INSERT INTO t1 (a,b) VALUES (4,NULL)", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "SELECT * FROM t1;", + Expected: []sql.Row{ + {1, 1, "ABC"}, + {2, 2, "ABC"}, + {4, nil, nil}, + }, + }, + }, + }, + { + Name: "insert into table from table", + SetUpScript: []string{ + "CREATE TABLE t2 (a INTEGER PRIMARY KEY, b INTEGER)", + "INSERT INTO t2 VALUES (2,2),(3,3)", + "DELETE FROM t1", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "INSERT INTO t1 (a,b) select a - 2, b - 1 from t2", + ExpectedErr: sql.ErrCheckConstraintViolated, + }, + { + Query: "INSERT INTO t1 (a,b) select a, b from t2", + Expected: []sql.Row{{types.OkResult{RowsAffected: 2}}}, + }, + { + // Check that INSERT IGNORE correctly drops errors with check constraints and does not update the actual table. + Query: "INSERT IGNORE INTO t1 VALUES (5,2, 'abc')", + Expected: []sql.Row{{types.OkResult{RowsAffected: 0}}}, + }, + { + Query: "SELECT count(*) FROM t1 where a = 5", + Expected: []sql.Row{{0}}, + }, + { + // One value is correctly accepted and the other value is not accepted due to a check constraint violation. + // The accepted value is correctly added to the table. + Query: "INSERT IGNORE INTO t1 VALUES (4,4, null), (5,2, 'abc')", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "SELECT count(*) FROM t1 where a = 5", + Expected: []sql.Row{{0}}, + }, + { + Query: "SELECT count(*) FROM t1 where a = 4", + Expected: []sql.Row{{1}}, + }, + }, + }, +} + var ChecksOnUpdateScriptTests = []ScriptTest{ { Name: "Single table updates", @@ -95,3 +536,140 @@ var ChecksOnUpdateScriptTests = []ScriptTest{ }, }, } + +var DisallowedCheckConstraintsScripts = []ScriptTest{ + { + Name: "error cases", + SetUpScript: []string{ + "CREATE TABLE t1 (a INTEGER PRIMARY KEY, b INTEGER)", + }, + Assertions: []ScriptTestAssertion{ + // non-deterministic functions + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_user = \"root@\")", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (user() = \"root@\")", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (now() > '2021')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_date() > '2021')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (uuid() > 'a')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (database() = 'foo')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (schema() = 'foo')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (version() = 'foo')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (last_insert_id() = 0)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (rand() < .8)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (row_count() = 0)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (found_rows() = 0)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (curdate() > '2021')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (curtime() > '2021')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (current_timestamp() > '2021')", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (connection_id() = 2)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + // locks + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (get_lock('abc', 0) is null)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (release_all_locks() is null)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (release_lock('abc') is null)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (is_free_lock('abc') is null)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK (is_used_lock('abc') is null)", + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + // subqueries + { + Query: "ALTER TABLE t1 ADD CONSTRAINT chk2 CHECK ((select count(*) from t1) = 0)", + ExpectedErr: sql.ErrInvalidConstraintSubqueryNotSupported, + }, + // Some spot checks on create table forms of the above + { + Query: ` +CREATE TABLE t3 ( + a int primary key CONSTRAINT chk2 CHECK (current_user = "root@") +) +`, + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: ` +CREATE TABLE t3 ( + a int primary key, + CHECK (current_user = "root@") +) +`, + ExpectedErr: sql.ErrInvalidConstraintFunctionNotSupported, + }, + { + Query: ` +CREATE TABLE t3 ( + a int primary key CONSTRAINT chk2 CHECK (a = (select count(*) from t1)) +) +`, + ExpectedErr: sql.ErrInvalidConstraintSubqueryNotSupported, + }, + { + Query: ` +CREATE TABLE t3 ( + a int primary key, + CHECK (a = (select count(*) from t1)) +) +`, + ExpectedErr: sql.ErrInvalidConstraintSubqueryNotSupported, + }, + }, + }, +} diff --git a/enginetest/queries/foreign_key_queries.go b/enginetest/queries/foreign_key_queries.go index 2a0a93002f..e53bdbb4d9 100644 --- a/enginetest/queries/foreign_key_queries.go +++ b/enginetest/queries/foreign_key_queries.go @@ -2067,3 +2067,152 @@ var ForeignKeyTests = []ScriptTest{ }, }, } + +var CreateForeignKeyTests = []ScriptTest{ + { + Name: "basic create foreign key tests", + SetUpScript: []string{ + "CREATE TABLE parent(a INTEGER PRIMARY KEY, b INTEGER)", + "ALTER TABLE parent ADD INDEX pb (b)", + `CREATE TABLE child(c INTEGER PRIMARY KEY, d INTEGER, + CONSTRAINT fk1 FOREIGN KEY (D) REFERENCES parent(B) ON DELETE CASCADE + )`, + "ALTER TABLE child ADD CONSTRAINT fk4 FOREIGN KEY (D) REFERENCES child(C)", + "CREATE TABLE child2(e INTEGER PRIMARY KEY, f INTEGER)", + "ALTER TABLE child2 ADD CONSTRAINT fk2 FOREIGN KEY (f) REFERENCES parent(b) ON DELETE RESTRICT", + "ALTER TABLE child2 ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL", + }, + Assertions: []ScriptTestAssertion{ + { + Query: `SELECT RC.CONSTRAINT_NAME, RC.CONSTRAINT_SCHEMA, RC.TABLE_NAME, KCU.COLUMN_NAME, + KCU.REFERENCED_TABLE_SCHEMA, KCU.REFERENCED_TABLE_NAME, KCU.REFERENCED_COLUMN_NAME, RC.UPDATE_RULE, RC.DELETE_RULE + FROM information_schema.REFERENTIAL_CONSTRAINTS RC, information_schema.KEY_COLUMN_USAGE KCU + WHERE RC.TABLE_NAME = 'child' AND RC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND + RC.TABLE_NAME = KCU.TABLE_NAME AND RC.REFERENCED_TABLE_NAME = KCU.REFERENCED_TABLE_NAME;`, + Expected: []sql.Row{ + {"fk1", "mydb", "child", "d", "mydb", "parent", "b", "NO ACTION", "CASCADE"}, + {"fk4", "mydb", "child", "d", "mydb", "child", "c", "NO ACTION", "NO ACTION"}, + }, + }, + { + Query: `SELECT RC.CONSTRAINT_NAME, RC.CONSTRAINT_SCHEMA, RC.TABLE_NAME, KCU.COLUMN_NAME, + KCU.REFERENCED_TABLE_SCHEMA, KCU.REFERENCED_TABLE_NAME, KCU.REFERENCED_COLUMN_NAME, RC.UPDATE_RULE, RC.DELETE_RULE + FROM information_schema.REFERENTIAL_CONSTRAINTS RC, information_schema.KEY_COLUMN_USAGE KCU + WHERE RC.TABLE_NAME = 'child2' AND RC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND + RC.TABLE_NAME = KCU.TABLE_NAME AND RC.REFERENCED_TABLE_NAME = KCU.REFERENCED_TABLE_NAME;`, + Expected: []sql.Row{ + {"fk2", "mydb", "child2", "f", "mydb", "parent", "b", "NO ACTION", "RESTRICT"}, + {"fk3", "mydb", "child2", "f", "mydb", "child", "d", "SET NULL", "NO ACTION"}, + }, + }, + }, + }, + { + Name: "error cases", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE child2 ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES dne(d) ON UPDATE SET NULL", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE dne ADD CONSTRAINT fk4 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE child2 ADD CONSTRAINT fk5 FOREIGN KEY (f) REFERENCES child(dne) ON UPDATE SET NULL", + ExpectedErr: sql.ErrTableColumnNotFound, + }, + }, + }, + { + Name: "Add a column then immediately add a foreign key", + SetUpScript: []string{ + "CREATE TABLE parent3 (pk BIGINT PRIMARY KEY, v1 BIGINT, INDEX (v1))", + "CREATE TABLE child3 (pk BIGINT PRIMARY KEY);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE child3 ADD COLUMN v1 BIGINT NULL, ADD CONSTRAINT fk_child3 FOREIGN KEY (v1) REFERENCES parent3(v1);", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + }, + }, + { + Name: "Do not validate foreign keys if FOREIGN_KEY_CHECKS is set to zero", + Assertions: []ScriptTestAssertion{ + { + Query: "SET FOREIGN_KEY_CHECKS=0;", + Expected: []sql.Row{{}}, + }, + { + Query: "CREATE TABLE child4 (pk BIGINT PRIMARY KEY, CONSTRAINT fk_child4 FOREIGN KEY (pk) REFERENCES delayed_parent4 (pk))", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "CREATE TABLE delayed_parent4 (pk BIGINT PRIMARY KEY)", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + }, + }, +} + +var DropForeignKeyTests = []ScriptTest{ + { + Name: "basic drop foreign key tests", + SetUpScript: []string{ + "CREATE TABLE parent(a INTEGER PRIMARY KEY, b INTEGER)", + "ALTER TABLE parent ADD INDEX pb (b)", + `CREATE TABLE child(c INTEGER PRIMARY KEY, d INTEGER, + CONSTRAINT fk1 FOREIGN KEY (D) REFERENCES parent(B) ON DELETE CASCADE + )`, + "CREATE TABLE child2(e INTEGER PRIMARY KEY, f INTEGER)", + `ALTER TABLE child2 ADD CONSTRAINT fk2 FOREIGN KEY (f) REFERENCES parent(b) ON DELETE RESTRICT, + ADD CONSTRAINT fk3 FOREIGN KEY (f) REFERENCES child(d) ON UPDATE SET NULL`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE child2 DROP CONSTRAINT fk2", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: `SELECT RC.CONSTRAINT_NAME, RC.CONSTRAINT_SCHEMA, RC.TABLE_NAME, KCU.COLUMN_NAME, + KCU.REFERENCED_TABLE_SCHEMA, KCU.REFERENCED_TABLE_NAME, KCU.REFERENCED_COLUMN_NAME, RC.UPDATE_RULE, RC.DELETE_RULE + FROM information_schema.REFERENTIAL_CONSTRAINTS RC, information_schema.KEY_COLUMN_USAGE KCU + WHERE RC.TABLE_NAME = 'child2' AND RC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND + RC.TABLE_NAME = KCU.TABLE_NAME AND RC.REFERENCED_TABLE_NAME = KCU.REFERENCED_TABLE_NAME;`, + Expected: []sql.Row{ + {"fk3", "mydb", "child2", "f", "mydb", "child", "d", "SET NULL", "NO ACTION"}, + }, + }, + { + Query: "ALTER TABLE child2 DROP CONSTRAINT fk3", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: `SELECT RC.CONSTRAINT_NAME, RC.CONSTRAINT_SCHEMA, RC.TABLE_NAME, KCU.COLUMN_NAME, + KCU.REFERENCED_TABLE_SCHEMA, KCU.REFERENCED_TABLE_NAME, KCU.REFERENCED_COLUMN_NAME, RC.UPDATE_RULE, RC.DELETE_RULE + FROM information_schema.REFERENTIAL_CONSTRAINTS RC, information_schema.KEY_COLUMN_USAGE KCU + WHERE RC.TABLE_NAME = 'child2' AND RC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME AND + RC.TABLE_NAME = KCU.TABLE_NAME AND RC.REFERENCED_TABLE_NAME = KCU.REFERENCED_TABLE_NAME;`, + Expected: []sql.Row{}, + }, + }, + }, + { + Name: "error cases", + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE child3 DROP CONSTRAINT dne", + ExpectedErr: sql.ErrTableNotFound, + }, + { + Query: "ALTER TABLE child2 DROP CONSTRAINT fk3", + ExpectedErr: sql.ErrUnknownConstraint, + }, + { + Query: "ALTER TABLE child2 DROP FOREIGN KEY fk3", + ExpectedErr: sql.ErrForeignKeyNotFound, + }, + }, + }, +} diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index 8199609108..9cff15c5b8 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -9218,7 +9218,9 @@ var ErrorQueries = []QueryErrorTest{ ExpectedErrStr: "length is 123456789 but max allowed is 65535", }, { - Query: `SELECT ST_GEOMFROMTEXT(ST_ASWKT(POINT(1,2)), 1234)`, + // Note: cannot use SRID `1234` because it is created in another test, + // which affects this test to not return error + Query: `SELECT ST_GEOMFROMTEXT(ST_ASWKT(POINT(1,2)), 1235)`, ExpectedErr: sql.ErrNoSRID, }, { diff --git a/enginetest/queries/script_queries.go b/enginetest/queries/script_queries.go index 7be8d47691..d130f9dce6 100644 --- a/enginetest/queries/script_queries.go +++ b/enginetest/queries/script_queries.go @@ -4698,232 +4698,6 @@ var SpatialIndexScriptTests = []ScriptTest{ }, } -var CreateCheckConstraintsScripts = []ScriptTest{ - { - Name: "Run SHOW CREATE TABLE with different types of check constraints", - SetUpScript: []string{ - "CREATE TABLE mytable1(pk int PRIMARY KEY, CONSTRAINT check1 CHECK (pk = 5))", - "ALTER TABLE mytable1 ADD CONSTRAINT check11 CHECK (pk < 6)", - "CREATE TABLE mytable2(pk int PRIMARY KEY, v int, CONSTRAINT check2 CHECK (v < 5))", - "ALTER TABLE mytable2 ADD CONSTRAINT check12 CHECK (pk + v = 6)", - "CREATE TABLE mytable3(pk int PRIMARY KEY, v int, CONSTRAINT check3 CHECK (pk > 2 AND v < 5))", - "ALTER TABLE mytable3 ADD CONSTRAINT check13 CHECK (pk BETWEEN 2 AND 100)", - "CREATE TABLE mytable4(pk int PRIMARY KEY, v int, CONSTRAINT check4 CHECK (pk > 2 AND v < 5 AND pk < 9))", - "CREATE TABLE mytable5(pk int PRIMARY KEY, v int, CONSTRAINT check5 CHECK (pk > 2 OR (v < 5 AND pk < 9)))", - "CREATE TABLE mytable6(pk int PRIMARY KEY, v int, CONSTRAINT check6 CHECK (NOT pk))", - "CREATE TABLE mytable7(pk int PRIMARY KEY, v int, CONSTRAINT check7 CHECK (pk != v))", - "CREATE TABLE mytable8(pk int PRIMARY KEY, v int, CONSTRAINT check8 CHECK (pk > 2 OR v < 5 OR pk < 10))", - "CREATE TABLE mytable9(pk int PRIMARY KEY, v int, CONSTRAINT check9 CHECK ((pk + v) / 2 >= 1))", - "CREATE TABLE mytable10(pk int PRIMARY KEY, v int, CONSTRAINT check10 CHECK (v < 5) NOT ENFORCED)", - }, - Assertions: []ScriptTestAssertion{ - { - Query: "SHOW CREATE TABLE mytable1", - Expected: []sql.Row{ - { - "mytable1", - "CREATE TABLE `mytable1` (\n `pk` int NOT NULL,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check1` CHECK ((`pk` = 5)),\n" + - " CONSTRAINT `check11` CHECK ((`pk` < 6))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable2", - Expected: []sql.Row{ - { - "mytable2", - "CREATE TABLE `mytable2` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check2` CHECK ((`v` < 5)),\n" + - " CONSTRAINT `check12` CHECK (((`pk` + `v`) = 6))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable3", - Expected: []sql.Row{ - { - "mytable3", - "CREATE TABLE `mytable3` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check3` CHECK (((`pk` > 2) AND (`v` < 5))),\n" + - " CONSTRAINT `check13` CHECK ((`pk` BETWEEN 2 AND 100))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable4", - Expected: []sql.Row{ - { - "mytable4", - "CREATE TABLE `mytable4` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check4` CHECK ((((`pk` > 2) AND (`v` < 5)) AND (`pk` < 9)))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable5", - Expected: []sql.Row{ - { - "mytable5", - "CREATE TABLE `mytable5` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check5` CHECK (((`pk` > 2) OR ((`v` < 5) AND (`pk` < 9))))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable6", - Expected: []sql.Row{ - { - "mytable6", - "CREATE TABLE `mytable6` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check6` CHECK ((NOT(`pk`)))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable7", - Expected: []sql.Row{ - { - "mytable7", - "CREATE TABLE `mytable7` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check7` CHECK ((NOT((`pk` = `v`))))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable8", - Expected: []sql.Row{ - { - "mytable8", - "CREATE TABLE `mytable8` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check8` CHECK ((((`pk` > 2) OR (`v` < 5)) OR (`pk` < 10)))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable9", - Expected: []sql.Row{ - { - "mytable9", - "CREATE TABLE `mytable9` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check9` CHECK ((((`pk` + `v`) / 2) >= 1))\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - { - Query: "SHOW CREATE TABLE mytable10", - Expected: []sql.Row{ - { - "mytable10", - "CREATE TABLE `mytable10` (\n `pk` int NOT NULL,\n" + - " `v` int,\n" + - " PRIMARY KEY (`pk`),\n" + - " CONSTRAINT `check10` CHECK ((`v` < 5)) /*!80016 NOT ENFORCED */\n" + - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", - }, - }, - }, - }, - }, - { - Name: "Create a table with a check and validate that it appears in check_constraints and table_constraints", - SetUpScript: []string{ - "CREATE TABLE mytable (pk int primary key, test_score int, height int, CONSTRAINT mycheck CHECK (test_score >= 50), CONSTRAINT hcheck CHECK (height < 10), CONSTRAINT vcheck CHECK (height > 0))", - }, - Assertions: []ScriptTestAssertion{ - { - Query: "SELECT * from information_schema.check_constraints where constraint_name IN ('mycheck', 'hcheck') ORDER BY constraint_name", - Expected: []sql.Row{ - {"def", "mydb", "hcheck", "(height < 10)"}, - {"def", "mydb", "mycheck", "(test_score >= 50)"}, - }, - }, - { - Query: "SELECT * FROM information_schema.table_constraints where table_name='mytable' ORDER BY constraint_type,constraint_name", - Expected: []sql.Row{ - {"def", "mydb", "hcheck", "mydb", "mytable", "CHECK", "YES"}, - {"def", "mydb", "mycheck", "mydb", "mytable", "CHECK", "YES"}, - {"def", "mydb", "vcheck", "mydb", "mytable", "CHECK", "YES"}, - {"def", "mydb", "PRIMARY", "mydb", "mytable", "PRIMARY KEY", "YES"}, - }, - }, - }, - }, - { - Name: "multi column index, lower()", - SetUpScript: []string{ - "CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 varchar(100), v2 varchar(100), INDEX (v1,v2));", - "INSERT INTO test VALUES (1,'happy','birthday'), (2,'HAPPY','BIRTHDAY'), (3,'hello','sailor');", - }, - Assertions: []ScriptTestAssertion{ - { - Query: "SELECT pk FROM test where lower(v1) = 'happy' and lower(v2) = 'birthday' order by 1", - Expected: []sql.Row{{1}, {2}}, - }, - }, - }, - { - Name: "adding check constraint to a table that violates said constraint correctly throws an error", - SetUpScript: []string{ - "CREATE TABLE test (pk int)", - "INSERT INTO test VALUES (1),(2),(300)", - }, - Assertions: []ScriptTestAssertion{ - { - Query: "ALTER TABLE test ADD CONSTRAINT bad_check CHECK (pk < 5)", - ExpectedErr: plan.ErrCheckViolated, - }, - }, - }, - { - Name: "duplicate indexes still returns correct results", - SetUpScript: []string{ - "CREATE TABLE test (i int)", - "CREATE INDEX test_idx1 on test (i)", - "CREATE INDEX test_idx2 on test (i)", - "INSERT INTO test values (1), (2), (3)", - }, - Assertions: []ScriptTestAssertion{ - { - Query: "SELECT * FROM test ORDER BY i", - Expected: []sql.Row{{1}, {2}, {3}}, - }, - { - Query: "SELECT * FROM test where i = 2", - Expected: []sql.Row{ - {2}, - }, - }, - }, - }, -} - var PreparedScriptTests = []ScriptTest{ { Name: "table_count optimization refreshes result", @@ -5516,3 +5290,237 @@ var BrokenScriptTests = []ScriptTest{ }, }, } + +var CreateDatabaseScripts = []ScriptTest{ + { + Name: "CREATE DATABASE and create table", + Assertions: []ScriptTestAssertion{ + { + Query: "CREATE DATABASE testdb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "USE testdb", + Expected: []sql.Row{}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{"testdb"}}, + }, + { + Query: "CREATE TABLE test (pk int primary key)", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW TABLES", + Expected: []sql.Row{{"test"}}, + }, + }, + }, + { + Name: "CREATE DATABASE IF NOT EXISTS", + Assertions: []ScriptTestAssertion{ + { + Query: "CREATE DATABASE IF NOT EXISTS testdb2", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "USE testdb2", + Expected: []sql.Row{}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{"testdb2"}}, + }, + { + Query: "CREATE TABLE test (pk int primary key)", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW TABLES", + Expected: []sql.Row{{"test"}}, + }, + }, + }, + { + Name: "CREATE SCHEMA", + Assertions: []ScriptTestAssertion{ + { + Query: "CREATE SCHEMA testdb3", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "USE testdb3", + Expected: []sql.Row{}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{"testdb3"}}, + }, + { + Query: "CREATE TABLE test (pk int primary key)", + Expected: []sql.Row{{types.NewOkResult(0)}}, + }, + { + Query: "SHOW TABLES", + Expected: []sql.Row{{"test"}}, + }, + }, + }, + { + Name: "CREATE DATABASE error handling", + Assertions: []ScriptTestAssertion{ + { + Query: "CREATE DATABASE newtestdb CHARACTER SET utf8mb4 ENCRYPTION='N'", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 0, Info: nil}}}, + }, + { + Query: "SHOW WARNINGS /* 1 */", + Expected: []sql.Row{{"Warning", 1235, "Setting CHARACTER SET, COLLATION and ENCRYPTION are not supported yet"}}, + }, + { + Query: "CREATE DATABASE newtest1db DEFAULT COLLATE binary ENCRYPTION='Y'", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1, InsertID: 0, Info: nil}}}, + }, + { + // TODO: There should only be one warning (the warnings are not clearing for create database query) AND 'PREPARE' statements should not create warning from its query + Query: "SHOW WARNINGS /* 2 */", + Expected: []sql.Row{{"Warning", 1235, "Setting CHARACTER SET, COLLATION and ENCRYPTION are not supported yet"}, {"Warning", 1235, "Setting CHARACTER SET, COLLATION and ENCRYPTION are not supported yet"}}, + }, + { + Query: "CREATE DATABASE mydb", + ExpectedErr: sql.ErrDatabaseExists, + }, + { + Query: "CREATE DATABASE IF NOT EXISTS mydb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "SHOW WARNINGS /* 3 */", + Expected: []sql.Row{{"Note", 1007, "Can't create database mydb; database exists "}}, + }, + }, + }, +} + +var DropDatabaseScripts = []ScriptTest{ + { + Name: "DROP DATABASE correctly works", + Assertions: []ScriptTestAssertion{ + { + Query: "DROP DATABASE mydb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{nil}}, + }, + { + // TODO: incorrect error returned because the currentdb is not set to empty + Skip: true, + Query: "SHOW TABLES", + ExpectedErr: sql.ErrNoDatabaseSelected, + }, + }, + }, + { + Name: "DROP DATABASE works on newly created databases.", + SetUpScript: []string{ + "CREATE DATABASE testdb", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "USE testdb", + Expected: []sql.Row{}, + }, + { + Query: "DROP DATABASE testdb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "USE testdb", + ExpectedErr: sql.ErrDatabaseNotFound, + }, + }, + }, + { + Name: "DROP DATABASE works on current database and sets current database to empty.", + SetUpScript: []string{ + "CREATE DATABASE testdb", + "USE TESTdb", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "DROP DATABASE TESTDB", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{nil}}, + }, + { + Query: "USE testdb", + ExpectedErr: sql.ErrDatabaseNotFound, + }, + }, + }, + { + Name: "DROP SCHEMA works on newly created databases.", + SetUpScript: []string{ + "CREATE SCHEMA testdb", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "DROP SCHEMA TESTDB", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + Query: "USE testdb", + ExpectedErr: sql.ErrDatabaseNotFound, + }, + }, + }, + { + Name: "DROP DATABASE IF EXISTS correctly works.", + SetUpScript: []string{ + "DROP DATABASE mydb", + "CREATE DATABASE testdb", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "DROP DATABASE IF EXISTS mydb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 0}}}, + }, + { + Query: "SHOW WARNINGS", + Expected: []sql.Row{{"Note", 1008, "Can't drop database mydb; database doesn't exist "}}, + }, + { + Query: "DROP DATABASE IF EXISTS testdb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 1}}}, + }, + { + // TODO: there should not be warning + // https://github.com/dolthub/dolt/issues/6921 + Query: "SHOW WARNINGS", + Expected: []sql.Row{{"Note", 1008, "Can't drop database mydb; database doesn't exist "}}, + }, + { + Query: "SELECT DATABASE()", + Expected: []sql.Row{{nil}}, + }, + { + Query: "USE testdb", + ExpectedErr: sql.ErrDatabaseNotFound, + }, + { + Query: "DROP DATABASE IF EXISTS testdb", + Expected: []sql.Row{{types.OkResult{RowsAffected: 0}}}, + }, + { + Query: "SHOW WARNINGS", + Expected: []sql.Row{{"Note", 1008, "Can't drop database testdb; database doesn't exist "}}, + }, + }, + }, +} diff --git a/enginetest/server_engine.go b/enginetest/server_engine.go index 5be277ce0a..f2bf7435b4 100644 --- a/enginetest/server_engine.go +++ b/enginetest/server_engine.go @@ -286,6 +286,7 @@ func convertValue(sch sql.Schema, row sql.Row) sql.Row { r, err := attemptUnmarshalJSON(string(row[i].([]byte))) if err != nil { //t.Skip(fmt.Sprintf("received error unmarshalling returned json result")) + row[i] = nil } else { row[i] = r } diff --git a/sql/expression/arithmetic.go b/sql/expression/arithmetic.go index ec2bc3d877..8939aa8522 100644 --- a/sql/expression/arithmetic.go +++ b/sql/expression/arithmetic.go @@ -18,6 +18,7 @@ import ( "fmt" "reflect" "regexp" + "strconv" "strings" "time" @@ -630,6 +631,13 @@ func (e *UnaryMinus) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { return -int64(n), nil case decimal.Decimal: return n.Neg(), err + case string: + // try getting int out of string value + i, iErr := strconv.ParseInt(n, 10, 64) + if iErr != nil { + return nil, sql.ErrInvalidType.New(reflect.TypeOf(n)) + } + return -i, nil default: return nil, sql.ErrInvalidType.New(reflect.TypeOf(n)) } diff --git a/sql/planbuilder/ddl.go b/sql/planbuilder/ddl.go index 24f5f0674b..13ba5f68ea 100644 --- a/sql/planbuilder/ddl.go +++ b/sql/planbuilder/ddl.go @@ -1020,9 +1020,6 @@ func (b *Builder) tableSpecToSchema(inScope, outScope *scope, db sql.Database, t defaults[i] = cd.Type.Default generated[i] = cd.Type.GeneratedExpr - cd.Type.Default = nil - cd.Type.GeneratedExpr = nil - column := b.columnDefinitionToColumn(inScope, cd, tableSpec.Indexes) column.DatabaseSource = db.Name() From 422c3fee20f6eb401f972efc4de2e6c088095a79 Mon Sep 17 00:00:00 2001 From: James Cor Date: Sun, 5 Nov 2023 00:17:09 -0700 Subject: [PATCH 02/11] fix panic when calling `ST_POINTFROMWKB()` with no arguments (#2121) --- sql/expression/function/spatial/wkb.go | 2 +- sql/expression/function/spatial/wkb_test.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/sql/expression/function/spatial/wkb.go b/sql/expression/function/spatial/wkb.go index 960d5efa0c..2d669ee882 100644 --- a/sql/expression/function/spatial/wkb.go +++ b/sql/expression/function/spatial/wkb.go @@ -266,7 +266,7 @@ var _ sql.CollationCoercible = (*PointFromWKB)(nil) // NewPointFromWKB creates a new point expression. func NewPointFromWKB(args ...sql.Expression) (sql.Expression, error) { - if len(args) < 1 && len(args) > 3 { + if len(args) < 1 || len(args) > 3 { return nil, sql.ErrInvalidArgumentNumber.New("ST_POINTFROMWKB", "1, 2, or 3", len(args)) } return &PointFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil diff --git a/sql/expression/function/spatial/wkb_test.go b/sql/expression/function/spatial/wkb_test.go index 15ca7297ce..0a72c83ebe 100644 --- a/sql/expression/function/spatial/wkb_test.go +++ b/sql/expression/function/spatial/wkb_test.go @@ -592,4 +592,24 @@ func TestGeomFromWKB(t *testing.T) { require.NoError(err) require.Equal(nil, v) }) + + t.Run("empty args errors", func(t *testing.T) { + require := require.New(t) + _, err := NewPointFromWKB() + require.Error(err) + _, err = NewLineFromWKB() + require.Error(err) + _, err = NewPolyFromWKB() + require.Error(err) + _, err = NewMultiPoint() + require.Error(err) + _, err = NewMultiLineString() + require.Error(err) + _, err = NewMultiPolygon() + require.Error(err) + _, err = NewGeomFromWKB() + require.Error(err) + _, err = NewGeomCollFromWKB() + require.Error(err) + }) } From 6a1f4c4f7ffb462b3f58cc9a86714c7f9cb31620 Mon Sep 17 00:00:00 2001 From: Max Hoffman Date: Mon, 6 Nov 2023 07:41:31 -0800 Subject: [PATCH 03/11] Switch generateIndexScan rule to costing version --- enginetest/enginetests.go | 2 +- enginetest/evaluation.go | 86 +- enginetest/mysqlshim/table.go | 4 + enginetest/mysqlshim/table_editor.go | 4 + enginetest/queries/fulltext_queries.go | 519 +- enginetest/queries/imdb_plans.go | 220 +- enginetest/queries/index_query_plans.go | 11742 +++------------- .../queries/information_schema_queries.go | 67 +- enginetest/queries/integration_plans.go | 238 +- enginetest/queries/queries.go | 22 + enginetest/queries/query_plans.go | 497 +- enginetest/queries/script_queries.go | 3 + enginetest/queries/tpcc_plans.go | 36 +- enginetest/queries/tpch_plans.go | 48 +- enginetest/query_engine.go | 7 +- enginetest/server_engine.go | 4 + memory/index.go | 2 +- memory/point_lookup_table.go | 4 + memory/sequence_table.go | 4 + memory/stats.go | 2 +- memory/table.go | 9 + memory/table_editor.go | 4 + sql/analyzer/analyzer.go | 2 + sql/analyzer/costed_index_scan.go | 796 +- sql/analyzer/costed_index_scan_test.go | 58 +- sql/analyzer/indexscanop_string.go | 22 +- sql/analyzer/match_against.go | 183 - sql/analyzer/optimization_rules.go | 5 + sql/analyzer/rules.go | 2 +- sql/col_set.go | 4 + sql/expression/comparison.go | 6 +- sql/fulltext/multi_editor.go | 4 + sql/func_deps.go | 4 + sql/memo/rel_props_test.go | 4 + sql/plan/histogram.go | 9 +- sql/planbuilder/analyze.go | 9 +- sql/planbuilder/parse_test.go | 2 +- sql/planbuilder/scalar.go | 2 + sql/rowexec/ddl_iters.go | 7 + sql/statistics.go | 13 + sql/stats/statistic.go | 30 +- sql/stats/union.go | 58 +- sql/tables.go | 2 + 43 files changed, 3657 insertions(+), 11089 deletions(-) delete mode 100644 sql/analyzer/match_against.go diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index be538dc7df..0450d8d9bb 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -3637,7 +3637,7 @@ func TestForeignKeys(t *testing.T, harness Harness) { TestScript(t, harness, script) } } - + func TestFulltextIndexes(t *testing.T, harness Harness) { harness.Setup(setup.MydbData) for _, script := range queries.FulltextTests { diff --git a/enginetest/evaluation.go b/enginetest/evaluation.go index 46c4963929..394ea3a262 100644 --- a/enginetest/evaluation.go +++ b/enginetest/evaluation.go @@ -35,6 +35,7 @@ import ( "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/planbuilder" + "github.com/dolthub/go-mysql-server/sql/transform" "github.com/dolthub/go-mysql-server/sql/types" ) @@ -128,6 +129,8 @@ func TestScriptWithEngine(t *testing.T, e QueryEngine, harness Harness, script q assertion.ExpectedWarningMessageSubstring, assertion.SkipResultsCheck) } else if assertion.SkipResultsCheck { RunQuery(t, e, harness, assertion.Query) + } else if assertion.CheckIndexedAccess { + TestQueryWithIndexCheck(t, ctx, e, harness, assertion.Query, assertion.Expected, assertion.ExpectedColumns, assertion.Bindings) } else { TestQueryWithContext(t, ctx, e, harness, assertion.Query, assertion.Expected, assertion.ExpectedColumns, assertion.Bindings) } @@ -214,11 +217,11 @@ func TestScriptWithEnginePrepared(t *testing.T, e QueryEngine, harness Harness, assertion.ExpectedWarningMessageSubstring, assertion.SkipResultsCheck) } else if assertion.SkipResultsCheck { ctx = NewContext(harness).WithQuery(assertion.Query) - _, _, err := runQueryPreparedWithCtx(t, ctx, e, assertion.Query, assertion.Bindings) + _, _, err := runQueryPreparedWithCtx(t, ctx, e, assertion.Query, assertion.Bindings, false) require.NoError(t, err) } else { ctx = NewContext(harness).WithQuery(assertion.Query) - TestPreparedQueryWithContext(t, ctx, e, harness, assertion.Query, assertion.Expected, nil, assertion.Bindings) + TestPreparedQueryWithContext(t, ctx, e, harness, assertion.Query, assertion.Expected, nil, assertion.Bindings, assertion.CheckIndexedAccess) } if assertion.ExpectedIndexes != nil { evalIndexTest(t, harness, e, assertion.Query, assertion.ExpectedIndexes, assertion.Skip) @@ -343,6 +346,48 @@ func TestQueryWithContext(t *testing.T, ctx *sql.Context, e QueryEngine, harness validateEngine(t, ctx, harness, e) } +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) { + ctx = ctx.WithQuery(q) + require := require.New(t) + if len(bindings) > 0 { + _, err := e.PrepareQuery(ctx, q) + require.NoError(err) + } + + node, err := e.AnalyzeQuery(ctx, q) + require.NoError(err, "Unexpected error for query %s: %s", q, err) + + require.True(CheckIndexedAccess(node), "expected plan to have index, but found: %s", sql.DebugString(node)) + + sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindings) + require.NoError(err, "Unexpected error for query %s: %s", q, err) + + rows, err := sql.RowIterToRows(ctx, sch, iter) + require.NoError(err, "Unexpected error for query %s: %s", q, err) + + if expected != nil { + checkResults(t, expected, expectedCols, sch, rows, q, e) + } + + require.Equal( + 0, ctx.Memory.NumCaches()) + validateEngine(t, ctx, harness, e) +} + +func CheckIndexedAccess(n sql.Node) bool { + var hasIndex bool + transform.Inspect(n, func(n sql.Node) bool { + if n == nil { + return false + } + if _, ok := n.(*plan.IndexedTableAccess); ok { + hasIndex = true + } + return true + }) + return hasIndex +} + // TestPreparedQuery runs a prepared query on the engine given and asserts that results are as expected. func TestPreparedQuery(t *testing.T, harness Harness, q string, expected []sql.Row, expectedCols []*sql.Column) { t.Run(q, func(t *testing.T) { @@ -354,7 +399,7 @@ func TestPreparedQuery(t *testing.T, harness Harness, q string, expected []sql.R e := mustNewEngine(t, harness) defer e.Close() ctx := NewContext(harness) - TestPreparedQueryWithContext(t, ctx, e, harness, q, expected, expectedCols, nil) + TestPreparedQueryWithContext(t, ctx, e, harness, q, expected, expectedCols, nil, false) }) } @@ -366,22 +411,13 @@ func TestPreparedQueryWithEngine(t *testing.T, harness Harness, e QueryEngine, t } } ctx := NewContext(harness) - TestPreparedQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil) + TestPreparedQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil, false) }) } -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, -) { +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) { require := require.New(t) - rows, sch, err := runQueryPreparedWithCtx(t, ctx, e, q, bindVars) + rows, sch, err := runQueryPreparedWithCtx(t, ctx, e, q, bindVars, false) if err != nil { print(q) } @@ -511,13 +547,7 @@ func injectBindVarsAndPrepare( return buf.String(), bindVars, nil } -func runQueryPreparedWithCtx( - t *testing.T, - ctx *sql.Context, - e QueryEngine, - q string, - bindVars map[string]*querypb.BindVariable, -) ([]sql.Row, sql.Schema, error) { +func runQueryPreparedWithCtx(t *testing.T, ctx *sql.Context, e QueryEngine, q string, bindVars map[string]*querypb.BindVariable, checkIndexedAccess bool) ([]sql.Row, sql.Schema, error) { // If bindvars were not provided, try to inject some if bindVars == nil || len(bindVars) == 0 { var err error @@ -527,6 +557,12 @@ func runQueryPreparedWithCtx( } } + if checkIndexedAccess { + n, err := e.AnalyzeQuery(ctx, q) + require.NoError(t, err) + require.True(t, CheckIndexedAccess(n), "expected plan to have index, but found: %s", sql.DebugString(n)) + } + sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindVars) if err != nil { return nil, nil, err @@ -825,7 +861,7 @@ func AssertErrPrepared(t *testing.T, e QueryEngine, harness Harness, query strin // AssertErrPreparedWithCtx is the same as AssertErr, but uses the context given instead of creating one from a harness func AssertErrPreparedWithCtx(t *testing.T, e QueryEngine, harness Harness, ctx *sql.Context, query string, expectedErrKind *errors.Kind, errStrs ...string) { ctx = ctx.WithQuery(query) - _, _, err := runQueryPreparedWithCtx(t, ctx, e, query, nil) + _, _, err := runQueryPreparedWithCtx(t, ctx, e, query, nil, false) require.Error(t, err) if expectedErrKind != nil { err = sql.UnwrapError(err) @@ -979,8 +1015,8 @@ func runWriteQueryTestPrepared(t *testing.T, harness Harness, tt queries.WriteQu e := mustNewEngine(t, harness) defer e.Close() ctx := NewContext(harness) - TestPreparedQueryWithContext(t, ctx, e, harness, tt.WriteQuery, tt.ExpectedWriteResult, nil, tt.Bindings) - TestPreparedQueryWithContext(t, ctx, e, harness, tt.SelectQuery, tt.ExpectedSelect, nil, tt.Bindings) + TestPreparedQueryWithContext(t, ctx, e, harness, tt.WriteQuery, tt.ExpectedWriteResult, nil, tt.Bindings, false) + TestPreparedQueryWithContext(t, ctx, e, harness, tt.SelectQuery, tt.ExpectedSelect, nil, tt.Bindings, false) }) } diff --git a/enginetest/mysqlshim/table.go b/enginetest/mysqlshim/table.go index 0a8a905bee..c8923e2784 100644 --- a/enginetest/mysqlshim/table.go +++ b/enginetest/mysqlshim/table.go @@ -51,6 +51,10 @@ func (t Table) IndexedAccess(sql.IndexLookup) sql.IndexedTable { panic("not implemented") } +func (t Table) PreciseMatch() bool { + return true +} + func (t Table) IndexedPartitions(ctx *sql.Context, _ sql.IndexLookup) (sql.PartitionIter, error) { return t.Partitions(ctx) } diff --git a/enginetest/mysqlshim/table_editor.go b/enginetest/mysqlshim/table_editor.go index 552534911c..3155af6a3a 100644 --- a/enginetest/mysqlshim/table_editor.go +++ b/enginetest/mysqlshim/table_editor.go @@ -34,6 +34,10 @@ func (t *tableEditor) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable { panic("implement me") } +func (t *tableEditor) PreciseMatch() bool { + return true +} + func (t *tableEditor) GetIndexes(ctx *sql.Context) ([]sql.Index, error) { //TODO implement me panic("implement me") diff --git a/enginetest/queries/fulltext_queries.go b/enginetest/queries/fulltext_queries.go index ee04facaed..03cd6d3fa4 100644 --- a/enginetest/queries/fulltext_queries.go +++ b/enginetest/queries/fulltext_queries.go @@ -29,52 +29,64 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT pk, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi"}}, + Query: "SELECT pk, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi"}}, }, { - Query: "SELECT v1, v2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"ghi", "jkl"}}, + Query: "SELECT v1, v2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{"ghi", "jkl"}}, }, { - Query: "SELECT pk, v1, v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT pk, v1, v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT pk, v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{uint64(2), "jkl"}}, + Query: "SELECT pk, v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "jkl"}}, }, { - Query: "SELECT v1 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{"ghi"}}, + Query: "SELECT v1 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{"ghi"}}, }, { - Query: "SELECT v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{"jkl"}}, + Query: "SELECT v2 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{"jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl') > 0;", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl') > 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", - Expected: []sql.Row{{uint64(3), "mno", "mno"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(3), "mno", "mno"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno') OR pk = 1;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno') OR pk = 1;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -86,20 +98,24 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT uk, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi"}}, + Query: "SELECT uk, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi"}}, }, { - Query: "SELECT uk, v2, v1 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{uint64(2), "jkl", "ghi"}}, + Query: "SELECT uk, v2, v1 FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "jkl", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -111,28 +127,34 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"ghi", "jkl"}}, }, { - Query: "SELECT v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"ghi"}}, + Query: "SELECT v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"ghi"}}, }, { - Query: "SELECT v2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"jkl"}}, + Query: "SELECT v2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"jkl"}}, }, { - Query: "SELECT v2, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"jkl", "ghi"}}, + Query: "SELECT v2, v1 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"jkl", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", - Expected: []sql.Row{{"ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{"ghi", "jkl"}, {"mno", "mno"}, {"ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"ghi", "jkl"}, {"mno", "mno"}, {"ghs", "mno shg"}}, }, }, }, @@ -144,12 +166,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, }, }, }, @@ -161,12 +185,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, }, }, }, @@ -178,12 +204,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}, {uint64(3), "mno", uint64(1), "mno"}, {uint64(5), "ghs", uint64(1), "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}, {uint64(3), "mno", uint64(1), "mno"}, {uint64(5), "ghs", uint64(1), "mno shg"}}, }, }, }, @@ -195,16 +223,19 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, }, { - Query: "SELECT v2, uk2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"jkl", uint64(1)}}, + Query: "SELECT v2, uk2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{"jkl", uint64(1)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, }, }, }, @@ -216,12 +247,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), uint64(1), "ghi", "jkl"}, {uint64(3), uint64(1), "mno", "mno"}, {uint64(5), uint64(1), "ghs", "mno shg"}}, }, }, }, @@ -233,16 +266,19 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}}, }, { - Query: "SELECT v2, uk2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{"jkl", uint64(1)}}, + Query: "SELECT v2, uk2 FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{"jkl", uint64(1)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}, {uint64(3), "mno", uint64(1), "mno"}, {uint64(5), "ghs", uint64(1), "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", uint64(1), "jkl"}, {uint64(3), "mno", uint64(1), "mno"}, {uint64(5), "ghs", uint64(1), "mno shg"}}, }, }, }, @@ -254,36 +290,41 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { Query: "UPDATE test SET v1 = 'rgb' WHERE pk = 2;", Expected: []sql.Row{{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('rgb');", - Expected: []sql.Row{{uint64(2), "rgb", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('rgb');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "rgb", "jkl"}}, }, { Query: "UPDATE test SET v2 = 'mno' WHERE pk = 2;", Expected: []sql.Row{{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('mno');", - Expected: []sql.Row{{uint64(2), "rgb", "mno"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "rgb", "mno"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, { Query: "DELETE FROM test WHERE pk = 3;", Expected: []sql.Row{{types.NewOkResult(1)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('mno');", - Expected: []sql.Row{{uint64(2), "rgb", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "rgb", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -295,31 +336,37 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { // Full-Text handles NULL values by ignoring them, meaning non-null values are still added to the document - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{{uint64(1), "abc", nil}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", nil}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { Query: "UPDATE test SET v1 = NULL WHERE pk = 2;", Expected: []sql.Row{{types.OkResult{RowsAffected: 1, Info: plan.UpdateInfo{Matched: 1, Updated: 1}}}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('jkl');", - Expected: []sql.Row{{uint64(2), nil, "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('jkl');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), nil, "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST (NULL);", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST (NULL);", + CheckIndexedAccess: true, + Expected: []sql.Row{}, }, { - Query: "SELECT pk, v1, v2, MATCH(v1, v2) AGAINST (NULL) FROM test;", + Query: "SELECT pk, v1, v2, MATCH(v1, v2) AGAINST (NULL) FROM test;", + CheckIndexedAccess: false, Expected: []sql.Row{ {uint64(1), "abc", nil, float32(0)}, {uint64(2), nil, "jkl", float32(0)}, @@ -348,52 +395,64 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", - Expected: []sql.Row{{uint64(3), "mno", "mno"}}, + Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(3), "mno", "mno"}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('GHI');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('GHI');", + CheckIndexedAccess: true, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('JKL') = 0;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('JKL') = 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('JKL MNO') AND pk = 3;", - Expected: []sql.Row{}, + Query: "SELECT * FROM test1 WHERE MATCH(v2, v1) AGAINST ('JKL MNO') AND pk = 3;", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('jkl') = 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", - Expected: []sql.Row{{uint64(3), "mno", "mno"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('jkl mno') AND pk = 3;", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(3), "mno", "mno"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('GHI');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('GHI');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('JKL') = 0;", - Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('JKL') = 0;", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(1), "abc", "def pqr"}, {uint64(3), "mno", "mno"}, {uint64(4), "stu vwx", "xyz zyx yzx"}, {uint64(5), "ghs", "mno shg"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('JKL MNO') AND pk = 3;", - Expected: []sql.Row{{uint64(3), "mno", "mno"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v2, v1) AGAINST ('JKL MNO') AND pk = 3;", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(3), "mno", "mno"}}, }, }, }, @@ -529,12 +588,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -547,12 +608,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -565,12 +628,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -583,12 +648,14 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('jkl mno');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}, {uint64(3), "mno", "mno"}, {uint64(5), "ghs", "mno shg"}}, }, }, }, @@ -600,16 +667,18 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { Query: "DROP INDEX idx ON test;", Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - ExpectedErr: sql.ErrNoFullTextIndexFound, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrNoFullTextIndexFound, }, }, }, @@ -622,16 +691,18 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { Query: "ALTER TABLE test DROP INDEX idx;", Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - ExpectedErr: sql.ErrNoFullTextIndexFound, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrNoFullTextIndexFound, }, }, }, @@ -647,8 +718,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{float32(7), uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{float32(7), uint64(2), "ghi", "jkl"}}, }, }, }, @@ -664,8 +736,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), float32(7), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), float32(7), "ghi", "jkl"}}, }, }, }, @@ -681,8 +754,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, }, }, @@ -711,8 +785,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, }, }, @@ -724,16 +799,19 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2) AGAINST ('def');", - Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v2) AGAINST ('def');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", "def", "ghi"}}, }, { Query: "SHOW CREATE TABLE test;", @@ -744,24 +822,29 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", - ExpectedErr: sql.ErrColumnNotFound, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrColumnNotFound, }, { - Query: "SELECT * FROM test WHERE MATCH(v2) AGAINST ('def');", - ExpectedErr: sql.ErrColumnNotFound, + Query: "SELECT * FROM test WHERE MATCH(v2) AGAINST ('def');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrColumnNotFound, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", - ExpectedErr: sql.ErrColumnNotFound, + Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrColumnNotFound, }, { - Query: "SELECT * FROM test WHERE MATCH(v1) AGAINST ('abc');", - Expected: []sql.Row{{uint64(1), "abc", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1) AGAINST ('abc');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v3) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(1), "abc", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v3) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc", "ghi"}}, }, { Query: "SHOW CREATE TABLE test;", @@ -772,12 +855,14 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1) AGAINST ('abc');", - Expected: []sql.Row{{uint64(1), "abc"}}, + Query: "SELECT * FROM test WHERE MATCH(v1) AGAINST ('abc');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(1), "abc"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v3) AGAINST ('ghi');", - ExpectedErr: sql.ErrColumnNotFound, + Query: "SELECT * FROM test WHERE MATCH(v3) AGAINST ('ghi');", + CheckIndexedAccess: true, + ExpectedErr: sql.ErrColumnNotFound, }, { Query: "SHOW CREATE TABLE test;", @@ -797,8 +882,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, }, }, @@ -814,8 +900,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, }, }, @@ -840,16 +927,18 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{{uint64(2), "ghi", "jkl"}}, }, { Query: "TRUNCATE TABLE test;", Expected: []sql.Row{{types.NewOkResult(5)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: true, + Expected: []sql.Row{}, }, }, }, @@ -882,8 +971,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{{"abc", "def"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def"}}, }, { Query: "CREATE TABLE test1 (v1 VARCHAR(200), v2 VARCHAR(200), FULLTEXT idx (v1, v2));", @@ -894,20 +984,24 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(1)}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{{"abc", "def"}}, + Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def"}}, }, { - Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('jkl');", - Expected: []sql.Row{{"ghi", "jkl"}}, + Query: "SELECT * FROM test1 WHERE MATCH(v1, v2) AGAINST ('jkl');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"ghi", "jkl"}}, }, { - Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('jkl');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test2 WHERE MATCH(v1, v2) AGAINST ('jkl');", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, }, }, @@ -927,8 +1021,9 @@ var FulltextTests = []ScriptTest{ Expected: []sql.Row{{types.NewOkResult(0)}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('abc');", - Expected: []sql.Row{{"abc", "def"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v1) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def"}}, }, { Query: "SHOW CREATE TABLE test;", @@ -944,40 +1039,50 @@ var FulltextTests = []ScriptTest{ }, Assertions: []ScriptTestAssertion{ { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('abc');", + // TODO keyColumns are null type, blocks index access + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('def');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('def');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v2) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('abc');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('def');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('def');", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('ghi');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v1, v3) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('abc');", - Expected: []sql.Row{}, + Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('abc');", + CheckIndexedAccess: false, + Expected: []sql.Row{}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('def');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('def');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, { - Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", - Expected: []sql.Row{{"abc", "def", "ghi"}}, + Query: "SELECT * FROM test WHERE MATCH(v2, v3) AGAINST ('ghi');", + CheckIndexedAccess: false, + Expected: []sql.Row{{"abc", "def", "ghi"}}, }, }, }, diff --git a/enginetest/queries/imdb_plans.go b/enginetest/queries/imdb_plans.go index 74fd62f5a5..f3d926682e 100644 --- a/enginetest/queries/imdb_plans.go +++ b/enginetest/queries/imdb_plans.go @@ -481,7 +481,13 @@ WHERE cn.country_code !='[pl]' " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1950 (smallint) AND 2000 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1950 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2000 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -1092,7 +1098,13 @@ WHERE cn.country_code = '[us]' " │ ├─ name: movie_info_idx\n" + " │ └─ columns: [movie_id info_type_id info]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2005 (smallint) AND 2008 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2008 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -1401,7 +1413,13 @@ WHERE cn.country_code = '[us]' " │ ├─ name: movie_info_idx\n" + " │ └─ columns: [movie_id info_type_id info]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2000 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -2872,7 +2890,13 @@ WHERE cn.country_code = '[us]' " │ ├─ name: movie_keyword\n" + " │ └─ columns: [movie_id keyword_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2005 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -4688,7 +4712,13 @@ WHERE ci.note IN ('(writer)', " │ ├─ name: name\n" + " │ └─ columns: [id gender]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2008 (smallint) AND 2014 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2008 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2014 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -5017,7 +5047,13 @@ WHERE ci.note IN ('(voice)', " │ ├─ name: role_type\n" + " │ └─ columns: [id role]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2005 (smallint) AND 2009 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2009 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -5208,7 +5244,13 @@ WHERE ci.note = '(voice)' " │ └─ columns: [id role]\n" + " └─ Filter\n" + " ├─ AND\n" + - " │ ├─ (t.production_year:2 BETWEEN 2007 (smallint) AND 2008 (smallint))\n" + + " │ ├─ AND\n" + + " │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ ├─ t.production_year:2\n" + + " │ │ │ └─ 2007 (smallint)\n" + + " │ │ └─ LessThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2008 (smallint)\n" + " │ └─ t.title LIKE '%Kung%Fu%Panda%'\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + @@ -5743,7 +5785,13 @@ WHERE ct.kind = 'production companies' " │ ├─ name: movie_info_idx\n" + " │ └─ columns: [movie_id info_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2005 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -6636,7 +6684,13 @@ WHERE cn.country_code !='[pl]' " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1950 (smallint) AND 2000 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1950 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2000 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -6814,7 +6868,13 @@ WHERE cn.country_code !='[pl]' " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2000 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -6999,7 +7059,13 @@ WHERE cn.country_code !='[pl]' " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1950 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1950 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -10437,7 +10503,13 @@ WHERE cct1.kind IN ('cast', " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1950 (smallint) AND 2000 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1950 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2000 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -10935,7 +11007,13 @@ WHERE cct1.kind = 'cast' " │ ├─ name: movie_link\n" + " │ └─ columns: [movie_id link_type_id]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1950 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1950 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -12125,10 +12203,16 @@ WHERE cct1.kind ='cast' " │ └─ columns: [id role]\n" + " └─ Filter\n" + " ├─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t.title:1!null\n" + - " │ │ └─ Shrek 2 (longtext)\n" + - " │ └─ (t.production_year:2 BETWEEN 2000 (smallint) AND 2010 (smallint))\n" + + " │ ├─ AND\n" + + " │ │ ├─ Eq\n" + + " │ │ │ ├─ t.title:1!null\n" + + " │ │ │ └─ Shrek 2 (longtext)\n" + + " │ │ └─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -12451,10 +12535,16 @@ WHERE cct1.kind ='cast' " │ └─ columns: [id role]\n" + " └─ Filter\n" + " ├─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t.title:1!null\n" + - " │ │ └─ Shrek 2 (longtext)\n" + - " │ └─ (t.production_year:2 BETWEEN 2000 (smallint) AND 2005 (smallint))\n" + + " │ ├─ AND\n" + + " │ │ ├─ Eq\n" + + " │ │ │ ├─ t.title:1!null\n" + + " │ │ │ └─ Shrek 2 (longtext)\n" + + " │ │ └─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2005 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -12778,7 +12868,13 @@ WHERE cct1.kind ='cast' " │ ├─ name: role_type\n" + " │ └─ columns: [id role]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2000 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -14984,7 +15080,13 @@ WHERE cn1.country_code = '[us]' " │ ├─ name: title\n" + " │ └─ columns: [id title kind_id]\n" + " └─ Filter\n" + - " ├─ (t2.production_year:3 BETWEEN 2005 (smallint) AND 2008 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t2.production_year:3\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t2.production_year:3\n" + + " │ └─ 2008 (smallint)\n" + " └─ TableAlias(t2)\n" + " └─ Table\n" + " ├─ name: title\n" + @@ -15457,7 +15559,13 @@ WHERE cn1.country_code != '[us]' " │ ├─ name: title\n" + " │ └─ columns: [id title kind_id]\n" + " └─ Filter\n" + - " ├─ (t2.production_year:3 BETWEEN 2000 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t2.production_year:3\n" + + " │ │ └─ 2000 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t2.production_year:3\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t2)\n" + " └─ Table\n" + " ├─ name: title\n" + @@ -16876,7 +16984,13 @@ WHERE an.name LIKE '%a%' " │ │ │ └─ columns: [linked_movie_id link_type_id]\n" + " │ │ └─ Filter\n" + " │ │ ├─ AND\n" + - " │ │ │ ├─ (n.name_pcode_cf:3 BETWEEN A (longtext) AND F (longtext))\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ n.name_pcode_cf:3\n" + + " │ │ │ │ │ └─ A (longtext)\n" + + " │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ ├─ n.name_pcode_cf:3\n" + + " │ │ │ │ └─ F (longtext)\n" + " │ │ │ └─ Or\n" + " │ │ │ ├─ Eq\n" + " │ │ │ │ ├─ n.gender:2\n" + @@ -16907,7 +17021,13 @@ WHERE an.name LIKE '%a%' " │ ├─ name: person_info\n" + " │ └─ columns: [person_id info_type_id note]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1980 (smallint) AND 1995 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1980 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 1995 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -17059,7 +17179,13 @@ WHERE an.name LIKE '%a%' " │ ├─ name: person_info\n" + " │ └─ columns: [person_id info_type_id note]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 1980 (smallint) AND 1984 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 1980 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 1984 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -17204,7 +17330,13 @@ WHERE an.name IS NOT NULL " │ │ │ └─ columns: [linked_movie_id link_type_id]\n" + " │ │ └─ Filter\n" + " │ │ ├─ AND\n" + - " │ │ │ ├─ (n.name_pcode_cf:3 BETWEEN A (longtext) AND F (longtext))\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ n.name_pcode_cf:3\n" + + " │ │ │ │ │ └─ A (longtext)\n" + + " │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ ├─ n.name_pcode_cf:3\n" + + " │ │ │ │ └─ F (longtext)\n" + " │ │ │ └─ Or\n" + " │ │ │ ├─ Eq\n" + " │ │ │ │ ├─ n.gender:2\n" + @@ -17234,7 +17366,13 @@ WHERE an.name IS NOT NULL " │ ├─ name: person_info\n" + " │ └─ columns: [person_id info_type_id info note]\n" + " └─ Filter\n" + - " ├─ (t.production_year:1 BETWEEN 1980 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:1\n" + + " │ │ └─ 1980 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:1\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -17494,7 +17632,13 @@ WHERE ci.note ='(voice: English version)' " │ └─ columns: [id role]\n" + " └─ Filter\n" + " ├─ AND\n" + - " │ ├─ (t.production_year:2 BETWEEN 2006 (smallint) AND 2007 (smallint))\n" + + " │ ├─ AND\n" + + " │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ ├─ t.production_year:2\n" + + " │ │ │ └─ 2006 (smallint)\n" + + " │ │ └─ LessThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2007 (smallint)\n" + " │ └─ Or\n" + " │ ├─ AND\n" + " │ │ ├─ GreaterThanOrEqual\n" + @@ -17865,7 +18009,13 @@ WHERE ci.note IN ('(voice)', " │ ├─ name: role_type\n" + " │ └─ columns: [id role]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2005 (smallint) AND 2015 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2005 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2015 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + @@ -18008,7 +18158,13 @@ WHERE ci.note = '(voice)' " │ ├─ name: role_type\n" + " │ └─ columns: [id role]\n" + " └─ Filter\n" + - " ├─ (t.production_year:2 BETWEEN 2007 (smallint) AND 2010 (smallint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ t.production_year:2\n" + + " │ │ └─ 2007 (smallint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ t.production_year:2\n" + + " │ └─ 2010 (smallint)\n" + " └─ TableAlias(t)\n" + " └─ ProcessTable\n" + " └─ Table\n" + diff --git a/enginetest/queries/index_query_plans.go b/enginetest/queries/index_query_plans.go index ece7850a3c..8e02a94703 100644 --- a/enginetest/queries/index_query_plans.go +++ b/enginetest/queries/index_query_plans.go @@ -513,63 +513,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>75) OR (v1<=11));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 75 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 11 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 75), [NULL, ∞)}, {(75, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 75), [NULL, ∞)}, {(75, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<=86) OR (v1<>9)) AND (v1=87 AND v2<=45);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 86 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 9 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{[87, 87], (NULL, 45]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{[87, 87], (NULL, 45]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<=5) OR (v1=71)) OR (v1<>96));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 71 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 96 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 96), [NULL, ∞)}, {(96, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 96), [NULL, ∞)}, {(96, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -594,30 +563,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<>22 AND v2>18) OR (v1<>12)) OR (v1<=34));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ └─ 18 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 34 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -682,34 +633,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1>=46) AND (v1>=28 AND v2<>68) OR (v1>=33 AND v2<>39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 28 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 68 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 33 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v2:2\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{[33, 46), (NULL, 39)}, {[33, 46), (39, ∞)}, {[46, ∞), (NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{[33, 46), (NULL, 39)}, {[33, 46), (39, ∞)}, {[46, ∞), (NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -764,26 +693,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>74) OR (v1<>40 AND v2>=54));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 74 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t0.v2:2\n" + - " │ └─ 54 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 74), [NULL, ∞)}, {[74, 74], [54, ∞)}, {(74, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 74), [NULL, ∞)}, {[74, 74], [54, ∞)}, {(74, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -808,21 +723,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>94) OR (v1<=52));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 94 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 52 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 94), [NULL, ∞)}, {(94, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 94), [NULL, ∞)}, {(94, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -877,23 +783,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1>35) OR (v1 BETWEEN 11 AND 21)) OR (v1<>98));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 35 (tinyint)\n" + - " │ │ └─ (comp_index_t0.v1:1 BETWEEN 11 (tinyint) AND 21 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 98 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -908,67 +803,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<53 AND v2<10) AND (v1<>37) OR (v1>23));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 37 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 23 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 23], (NULL, 10)}, {(23, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 23], (NULL, 10)}, {(23, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE (((((v1<>30) OR (v1>=6 AND v2 BETWEEN 62 AND 65)) OR (v1<>89)) OR (v1<=40 AND v2>=73)) OR (v1<99));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t0.v2:2 BETWEEN 62 (tinyint) AND 65 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 40 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 73 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 99 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -993,31 +843,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1 BETWEEN 17 AND 54 AND v2>=37) AND (v1<42 AND v2=96) OR (v1<>50));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t0.v1:1 BETWEEN 17 (tinyint) AND 54 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ └─ 37 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 42 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 96 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 50 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 50), [NULL, ∞)}, {(50, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 50), [NULL, ∞)}, {(50, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1092,40 +923,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<=52 AND v2<40) AND (v1<30) OR (v1<=75 AND v2 BETWEEN 54 AND 54)) OR (v1<>31 AND v2<>56));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 30 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 75 (tinyint)\n" + - " │ │ └─ (comp_index_t0.v2:2 BETWEEN 54 (tinyint) AND 54 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v2:2\n" + - " │ └─ 56 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 31), (NULL, 56)}, {(NULL, 31), (56, ∞)}, {[31, 31], [54, 54]}, {(31, ∞), (NULL, 56)}, {(31, ∞), (56, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 31), (NULL, 56)}, {(NULL, 31), (56, ∞)}, {[31, 31], [54, 54]}, {(31, ∞), (NULL, 56)}, {(31, ∞), (56, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1180,21 +983,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>39) OR (v1=55)) AND (v1=67);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 39 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 55 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{[67, 67], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{[67, 67], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1219,58 +1013,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((((((v1<>99 AND v2 BETWEEN 12 AND 31) OR (v1<56 AND v2<>69)) OR (v1>=37 AND v2<47)) OR (v1<=98 AND v2=50)) AND (v1 BETWEEN 15 AND 47) OR (v1>55 AND v2>85)) OR (v1>86));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ Or\n" + - " │ │ │ │ │ ├─ Or\n" + - " │ │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ │ │ │ │ └─ (comp_index_t0.v2:2 BETWEEN 12 (tinyint) AND 31 (tinyint))\n" + - " │ │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ │ │ └─ 56 (tinyint)\n" + - " │ │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ │ │ └─ 69 (tinyint)\n" + - " │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ └─ 98 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ └─ (comp_index_t0.v1:1 BETWEEN 15 (tinyint) AND 47 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 55 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 85 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 86 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{[15, 47], (NULL, 69)}, {[15, 47], (69, ∞)}, {(55, 86], (85, ∞)}, {(86, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{[15, 47], (NULL, 69)}, {[15, 47], (69, ∞)}, {(55, 86], (85, ∞)}, {(86, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1285,72 +1033,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<>31) OR (v1<>43)) OR (v1>37 AND v2>5));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 37 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t0.v2:2\n" + - " │ └─ 5 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<=91) OR (v1<>79)) OR (v1<64));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 91 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 79 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 64 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>48) OR (v1>11));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 48 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 11 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1365,32 +1073,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((((v1<40) OR (v1<=59)) OR (v1<99)) AND (v1>=83) OR (v1>9));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 99 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 83 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 9 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(9, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(9, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1405,27 +1093,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1 BETWEEN 27 AND 84) OR (v1<98 AND v2>38)) OR (v1<>30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ (comp_index_t0.v1:1 BETWEEN 27 (tinyint) AND 84 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 30 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1470,21 +1143,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1=30) OR (v1<>67));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 30 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 67 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 67), [NULL, ∞)}, {(67, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 67), [NULL, ∞)}, {(67, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1529,26 +1193,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1=15 AND v2=8) AND (v1>2) OR (v1 BETWEEN 50 AND 97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ └─ 15 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ (comp_index_t0.v1:1 BETWEEN 50 (tinyint) AND 97 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{[15, 15], [8, 8]}, {[50, 97], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{[15, 15], [8, 8]}, {[50, 97], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1563,21 +1213,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE ((v1<>66) OR (v1<50));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 66 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t0.v1:1\n" + - " │ └─ 50 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 66), [NULL, ∞)}, {(66, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 66), [NULL, ∞)}, {(66, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1622,77 +1263,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t0 WHERE (((((v1=37 AND v2>32) OR (v1>13 AND v2>51)) AND (v1 BETWEEN 8 AND 19) OR (v1<>4)) OR (v1<=58 AND v2<>70)) OR (v1<87 AND v2>=24));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Or\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t0.v1:1 BETWEEN 8 (tinyint) AND 19 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 58 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t0.v2:2\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 87 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t0.v2:2\n" + - " │ └─ 24 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, 4), [NULL, ∞)}, {[4, 4], (NULL, ∞)}, {(4, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, 4), [NULL, ∞)}, {[4, 4], (NULL, ∞)}, {(4, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { Query: `SELECT * FROM comp_index_t0 WHERE (((v1<>50) OR (v1<=88)) OR (v1>=28 AND v2 BETWEEN 30 AND 85));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 88 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t0.v1:1\n" + - " │ │ └─ 28 (tinyint)\n" + - " │ └─ (comp_index_t0.v2:2 BETWEEN 30 (tinyint) AND 85 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t0)\n" + - " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t0)\n" + + " ├─ index: [comp_index_t0.v1,comp_index_t0.v2]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t0\n" + + " └─ columns: [pk v1 v2]\n" + "", }, { @@ -1877,58 +1463,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>87 AND v2 BETWEEN 8 AND 33) OR (v1 BETWEEN 39 AND 69 AND v3<4));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 87 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 8 (tinyint) AND 33 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 39 (tinyint) AND 69 (tinyint))\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 4 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 39), [8, 33], [NULL, ∞)}, {[39, 69], [NULL, ∞), [NULL, ∞)}, {(69, 87), [8, 33], [NULL, ∞)}, {(87, ∞), [8, 33], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 87), [8, 33], [NULL, ∞)}, {[39, 69], [NULL, 8), (NULL, 4)}, {[39, 69], (33, ∞), (NULL, 4)}, {(87, ∞), [8, 33], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=55 AND v2>=72 AND v3=63) AND (v1<>54 AND v2 BETWEEN 3 AND 80) OR (v1=15)) AND (v1<>50);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 3 (tinyint) AND 80 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 15 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[15, 15], [NULL, ∞), [NULL, ∞)}, {[55, ∞), [72, 80], [63, 63]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[15, 15], [NULL, ∞), [NULL, ∞)}, {[55, ∞), [72, 80], [63, 63]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -1953,63 +1503,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<3 AND v2<>23 AND v3<>11) OR (v1<>49)) AND (v1<=41 AND v2>40);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 49 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 41], (40, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 41], (40, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1 BETWEEN 28 AND 38 AND v3<33) OR (v1 BETWEEN 75 AND 85)) AND (v1>=60) OR (v1>=53 AND v2 BETWEEN 36 AND 53 AND v3>48));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 28 (tinyint) AND 38 (tinyint))\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 33 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v1:1 BETWEEN 75 (tinyint) AND 85 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 60 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 36 (tinyint) AND 53 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 48 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[53, 75), [36, 53], (48, ∞)}, {[75, 85], [NULL, ∞), [NULL, ∞)}, {(85, ∞), [36, 53], (48, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[53, 75), [36, 53], (48, ∞)}, {[75, 85], [NULL, ∞), [NULL, ∞)}, {(85, ∞), [36, 53], (48, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2034,214 +1543,62 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>6 AND v2 BETWEEN 0 AND 97) OR (v1<>40 AND v3<10 AND v2<>10));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 6 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 0 (tinyint) AND 97 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 40 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 10 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 6), (NULL, 0), (NULL, 10)}, {(NULL, 6), [0, 97], [NULL, ∞)}, {(NULL, 6), (97, ∞), (NULL, 10)}, {[6, 6], (NULL, 10), (NULL, 10)}, {[6, 6], (10, ∞), (NULL, 10)}, {(6, 40), (NULL, 0), (NULL, 10)}, {(6, 40), (97, ∞), (NULL, 10)}, {(6, ∞), [0, 97], [NULL, ∞)}, {(40, ∞), (NULL, 0), (NULL, 10)}, {(40, ∞), (97, ∞), (NULL, 10)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 6), (NULL, 0), (NULL, 10)}, {(NULL, 6), [0, 97], [NULL, ∞)}, {(NULL, 6), (97, ∞), (NULL, 10)}, {[6, 6], (NULL, 10), (NULL, 10)}, {[6, 6], (10, ∞), (NULL, 10)}, {(6, 40), (NULL, 0), (NULL, 10)}, {(6, 40), (97, ∞), (NULL, 10)}, {(6, ∞), [0, 97], [NULL, ∞)}, {(40, ∞), (NULL, 0), (NULL, 10)}, {(40, ∞), (97, ∞), (NULL, 10)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1>=35) OR (v1=86)) OR (v1>41 AND v2>=92)) OR (v1<>28));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 86 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 41 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 92 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 28 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 28), [NULL, ∞), [NULL, ∞)}, {(28, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 28), [NULL, ∞), [NULL, ∞)}, {(28, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<16 AND v3=63 AND v2>=20) OR (v1<>41)) OR (v1<=74 AND v3 BETWEEN 14 AND 74 AND v2<>13));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 16 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 20 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 74 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 14 (tinyint) AND 74 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 13 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 41), [NULL, ∞), [NULL, ∞)}, {[41, 41], (NULL, 13), [14, 74]}, {[41, 41], (13, ∞), [14, 74]}, {(41, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 41), [NULL, ∞), [NULL, ∞)}, {[41, 41], (NULL, 13), [14, 74]}, {[41, 41], (13, ∞), [14, 74]}, {(41, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1 BETWEEN 1 AND 11) OR (v1>2 AND v3<=93 AND v2 BETWEEN 28 AND 84)) OR (v1 BETWEEN 34 AND 52 AND v2=73)) OR (v1<>80 AND v2<=32 AND v3 BETWEEN 3 AND 7));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 1 (tinyint) AND 11 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 28 (tinyint) AND 84 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 34 (tinyint) AND 52 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 73 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 80 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ (comp_index_t1.v3:3 BETWEEN 3 (tinyint) AND 7 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 1), (NULL, 32], [3, 7]}, {[1, 11], [NULL, ∞), [NULL, ∞)}, {(11, 34), [28, 84], (NULL, 93]}, {(11, 80), (NULL, 28), [3, 7]}, {[34, 52], [28, 73), (NULL, 93]}, {[34, 52], [73, 73], [NULL, ∞)}, {[34, 52], (73, 84], (NULL, 93]}, {(52, ∞), [28, 84], (NULL, 93]}, {(80, ∞), (NULL, 28), [3, 7]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + - "", - }, + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 1), (NULL, 32], [3, 7]}, {[1, 11], [NULL, ∞), [NULL, ∞)}, {(11, 34), [28, 84], (NULL, 93]}, {(11, 52], (NULL, 28), [3, 7]}, {[34, 52], [28, 73), (NULL, 93]}, {[34, 52], [73, 73], [NULL, ∞)}, {[34, 52], (73, 84], (NULL, 93]}, {(52, 80), (NULL, 28), [3, 7]}, {(52, ∞), [28, 84], (NULL, 93]}, {(80, ∞), (NULL, 28), [3, 7]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + + "", + }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1<45) OR (v1<>72)) OR (v1 BETWEEN 10 AND 86 AND v2=92)) OR (v1 BETWEEN 32 AND 81 AND v2>59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 45 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 10 (tinyint) AND 86 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 92 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 32 (tinyint) AND 81 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 72), [NULL, ∞), [NULL, ∞)}, {[72, 72], (59, ∞), [NULL, ∞)}, {(72, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 72), [NULL, ∞), [NULL, ∞)}, {[72, 72], (59, ∞), [NULL, ∞)}, {(72, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=11 AND v2>50 AND v3 BETWEEN 5 AND 67) AND (v1>74 AND v2 BETWEEN 6 AND 63 AND v3<=1) OR (v1>=53 AND v2>69 AND v3>54));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 5 (tinyint) AND 67 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 74 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 6 (tinyint) AND 63 (tinyint))\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 69 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 54 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[53, ∞), (69, ∞), (54, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[53, ∞), (69, ∞), (54, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2256,66 +1613,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<=39 AND v2 BETWEEN 17 AND 34) OR (v1=89 AND v3>49 AND v2>58)) OR (v1>97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 17 (tinyint) AND 34 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 49 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 58 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 39], [17, 34], [NULL, ∞)}, {[89, 89], (58, ∞), (49, ∞)}, {(97, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 39], [17, 34], [NULL, ∞)}, {[89, 89], (58, ∞), (49, ∞)}, {(97, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<7 AND v2<>43) OR (v1<>5 AND v3<0 AND v2<1));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 7 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 1 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 7), (NULL, 43), [NULL, ∞)}, {(NULL, 7), (43, ∞), [NULL, ∞)}, {[7, ∞), (NULL, 1), (NULL, 0)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 7), (NULL, 43), [NULL, ∞)}, {(NULL, 7), (43, ∞), [NULL, ∞)}, {[7, ∞), (NULL, 1), (NULL, 0)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2350,72 +1663,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>12 AND v2<60 AND v3=91) OR (v1>63 AND v2>=8 AND v3<>32)) OR (v1>35 AND v3>=98));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 60 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 91 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 98 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 12), (NULL, 60), [91, 91]}, {(12, 35], (NULL, 60), [91, 91]}, {(35, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 12), (NULL, 60), [91, 91]}, {(12, 63], (NULL, 60), [91, 91]}, {(35, 63], [NULL, ∞), [98, ∞)}, {(63, ∞), [NULL, 8), [98, ∞)}, {(63, ∞), (NULL, 8), [91, 91]}, {(63, ∞), [8, ∞), (NULL, 32)}, {(63, ∞), [8, ∞), (32, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>27 AND v3=10) OR (v1>=25 AND v2<26)) AND (v1>=62 AND v2<=96 AND v3>28);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 27 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 26 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[62, ∞), (NULL, 96], (28, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[62, ∞), (NULL, 26), (28, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2430,55 +1693,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((((v1<=92 AND v3=0 AND v2>=9) OR (v1 BETWEEN 48 AND 79)) OR (v1>70 AND v2<=26 AND v3 BETWEEN 14 AND 82)) OR (v1>=29 AND v2<>21 AND v3 BETWEEN 37 AND 55)) OR (v1>=6 AND v3<=47));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ │ └─ 92 (tinyint)\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v1:1 BETWEEN 48 (tinyint) AND 79 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 14 (tinyint) AND 82 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 37 (tinyint) AND 55 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 6 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 47 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 6), [9, ∞), [0, 0]}, {[6, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 6), [9, ∞), [0, 0]}, {[6, 29), [NULL, ∞), (NULL, 47]}, {[29, 48), [NULL, NULL], (NULL, 47]}, {[29, 48), (NULL, 21), (NULL, 55]}, {[29, 48), [21, 21], (NULL, 47]}, {[29, 48), (21, ∞), (NULL, 55]}, {[48, 79], [NULL, ∞), [NULL, ∞)}, {(79, ∞), [NULL, NULL], (NULL, 47]}, {(79, ∞), (NULL, 26], (NULL, 82]}, {(79, ∞), (26, ∞), (NULL, 55]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2533,21 +1753,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>43) OR (v1=14));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 14 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 43), [NULL, ∞), [NULL, ∞)}, {(43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 43), [NULL, ∞), [NULL, ∞)}, {(43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2592,52 +1803,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>79) OR (v1>66)) AND (v1<>81 AND v2<34 AND v3>=25) AND (v1<42) OR (v1<>12 AND v2<>17 AND v3<=23));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 66 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 25 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 42 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 12 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 23 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 12), (NULL, 17), (NULL, 23]}, {(NULL, 12), (17, ∞), (NULL, 23]}, {(NULL, 42), (NULL, 34), [25, ∞)}, {(12, ∞), (NULL, 17), (NULL, 23]}, {(12, ∞), (17, ∞), (NULL, 23]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 12), (NULL, 17), (NULL, 23]}, {(NULL, 12), (17, ∞), (NULL, 23]}, {(NULL, 42), (NULL, 34), [25, ∞)}, {(12, ∞), (NULL, 17), (NULL, 23]}, {(12, ∞), (17, ∞), (NULL, 23]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2662,21 +1833,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>47) OR (v1<>25));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 47 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 25 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 25), [NULL, ∞), [NULL, ∞)}, {(25, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 25), [NULL, ∞), [NULL, ∞)}, {(25, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2691,37 +1853,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>65 AND v2>=52) OR (v1<=85)) OR (v1<=64 AND v3=9 AND v2>=36));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 85 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 64 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 9 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 36 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 85], [NULL, ∞), [NULL, ∞)}, {(85, ∞), [52, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 85], [NULL, ∞), [NULL, ∞)}, {(85, ∞), [52, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2746,53 +1883,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>0) OR (v1<81 AND v2>=70)) OR (v1>=52));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 0 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 81 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 52 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 0), [NULL, ∞), [NULL, ∞)}, {[0, 0], [70, ∞), [NULL, ∞)}, {(0, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 0), [NULL, ∞), [NULL, ∞)}, {[0, 0], [70, ∞), [NULL, ∞)}, {(0, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>5 AND v3<=32) OR (v1 BETWEEN 77 AND 85 AND v3 BETWEEN 16 AND 21 AND v2 BETWEEN 10 AND 42));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 77 (tinyint) AND 85 (tinyint))\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 16 (tinyint) AND 21 (tinyint))\n" + - " │ └─ (comp_index_t1.v2:2 BETWEEN 10 (tinyint) AND 42 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(5, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(5, ∞), [NULL, ∞), (NULL, 32]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2817,114 +1923,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<77 AND v2<35 AND v3=73) OR (v1=85 AND v2>0 AND v3<65)) AND (v1>=20 AND v3<23 AND v2<=81) OR (v1<34 AND v2<=21 AND v3<=45));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 77 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 85 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 65 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 20 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 81 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 34 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 21 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 45 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 34), (NULL, 21], (NULL, 45]}, {[85, 85], (0, 81], (NULL, 23)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 34), (NULL, 21], (NULL, 45]}, {[85, 85], (0, 81], (NULL, 23)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((((v1<=69) AND (v1>=60 AND v2<18 AND v3=15) OR (v1<=75)) OR (v1>=52 AND v2<10)) OR (v1<37 AND v2<=64)) OR (v1>38 AND v2=27));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 69 (tinyint)\n" + - " │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ │ └─ 60 (tinyint)\n" + - " │ │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ └─ 15 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 75 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 37 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 64 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 27 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 75], [NULL, ∞), [NULL, ∞)}, {(75, ∞), (NULL, 10), [NULL, ∞)}, {(75, ∞), [27, 27], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 75], [NULL, ∞), [NULL, ∞)}, {(75, ∞), (NULL, 10), [NULL, ∞)}, {(75, ∞), [27, 27], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2999,32 +2013,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>3 AND v2>32) OR (v1<=26 AND v3>=27 AND v2>=5));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 26 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 27 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 5 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 3], [5, ∞), [27, ∞)}, {(3, 26], [5, 32], [27, ∞)}, {(3, ∞), (32, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 3], [5, ∞), [27, ∞)}, {(3, 26], [5, 32], [27, ∞)}, {(3, ∞), (32, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3049,47 +2043,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>68 AND v2<=57) AND (v1<>84 AND v3 BETWEEN 24 AND 98 AND v2 BETWEEN 28 AND 45) OR (v1>0 AND v2<>47 AND v3>=69)) OR (v1>=44));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 57 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 24 (tinyint) AND 98 (tinyint))\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 28 (tinyint) AND 45 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 69 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 44 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 0], [28, 45], [24, 98]}, {(0, 44), (NULL, 28), [69, ∞)}, {(0, 44), [28, 45], [24, ∞)}, {(0, 44), (45, 47), [69, ∞)}, {(0, 44), (47, ∞), [69, ∞)}, {[44, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 0], [28, 45], [24, 98]}, {(0, 44), (NULL, 28), [69, ∞)}, {(0, 44), [28, 45], [24, ∞)}, {(0, 44), (45, 47), [69, ∞)}, {(0, 44), (47, ∞), [69, ∞)}, {[44, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3104,43 +2063,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1 BETWEEN 17 AND 52 AND v2<96) OR (v1<=12 AND v2<>4 AND v3>53)) OR (v1<98 AND v3<94 AND v2=5));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 17 (tinyint) AND 52 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 53 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 94 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 5 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 12], (NULL, 4), (53, ∞)}, {(NULL, 12], (4, 5), (53, ∞)}, {(NULL, 12], [5, 5], (NULL, ∞)}, {(NULL, 12], (5, ∞), (53, ∞)}, {(12, 17), [5, 5], (NULL, 94)}, {[17, 52], (NULL, 96), [NULL, ∞)}, {(52, 98), [5, 5], (NULL, 94)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 12], (NULL, 4), (53, ∞)}, {(NULL, 12], (4, 5), (53, ∞)}, {(NULL, 12], [5, 5], (NULL, ∞)}, {(NULL, 12], (5, ∞), (53, ∞)}, {(12, 17), [5, 5], (NULL, 94)}, {[17, 52], (NULL, 96), [NULL, ∞)}, {(52, 98), [5, 5], (NULL, 94)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3215,30 +2143,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1=95 AND v3<47 AND v2>=97) OR (v1 BETWEEN 11 AND 36 AND v2<=83));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 97 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 11 (tinyint) AND 36 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 83 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[11, 36], (NULL, 83], [NULL, ∞)}, {[95, 95], [97, ∞), (NULL, 47)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[11, 36], (NULL, 83], [NULL, ∞)}, {[95, 95], [97, ∞), (NULL, 47)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3253,80 +2163,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1>71 AND v2=33) OR (v1<>85 AND v2<>50 AND v3 BETWEEN 34 AND 67)) OR (v1 BETWEEN 5 AND 47 AND v3 BETWEEN 13 AND 76 AND v2=4)) OR (v1=16 AND v2>=29 AND v3<>80));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 71 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 33 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 85 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 34 (tinyint) AND 67 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 5 (tinyint) AND 47 (tinyint))\n" + - " │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 13 (tinyint) AND 76 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 4 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 16 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 29 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 80 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 5), (NULL, 50), [34, 67]}, {(NULL, 16), (50, ∞), [34, 67]}, {[5, 16), (4, 50), [34, 67]}, {[5, 47], (NULL, 4), [34, 67]}, {[5, 47], [4, 4], [13, 76]}, {[16, 16], (4, 29), [34, 67]}, {[16, 16], [29, ∞), (NULL, 80)}, {[16, 16], [29, ∞), (80, ∞)}, {(16, 47], (4, 50), [34, 67]}, {(16, 85), (50, ∞), [34, 67]}, {(47, 71], (NULL, 50), [34, 67]}, {(71, 85), (NULL, 33), [34, 67]}, {(71, 85), (33, 50), [34, 67]}, {(71, ∞), [33, 33], [NULL, ∞)}, {(85, ∞), (NULL, 33), [34, 67]}, {(85, ∞), (33, 50), [34, 67]}, {(85, ∞), (50, ∞), [34, 67]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 5), (NULL, 50), [34, 67]}, {(NULL, 16), (50, ∞), [34, 67]}, {[5, 16), (4, 50), [34, 67]}, {[5, 47], (NULL, 4), [34, 67]}, {[5, 47], [4, 4], [13, 76]}, {[16, 16], (4, 29), [34, 67]}, {[16, 16], [29, ∞), (NULL, 80)}, {[16, 16], [29, ∞), (80, ∞)}, {(16, 47], (4, 50), [34, 67]}, {(16, 85), (50, ∞), [34, 67]}, {(47, 71], (NULL, 50), [34, 67]}, {(71, 85), (NULL, 33), [34, 67]}, {(71, 85), (33, 50), [34, 67]}, {(71, ∞), [33, 33], [NULL, ∞)}, {(85, ∞), (NULL, 33), [34, 67]}, {(85, ∞), (33, 50), [34, 67]}, {(85, ∞), (50, ∞), [34, 67]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<=17 AND v2>38) AND (v1>=79) OR (v1<>38));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 17 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 38 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 79 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 38 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 38), [NULL, ∞), [NULL, ∞)}, {(38, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 38), [NULL, ∞), [NULL, ∞)}, {(38, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3341,29 +2193,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>50) OR (v1<=58 AND v2<=95)) OR (v1=10));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 58 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 95 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 10 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 50), [NULL, ∞), [NULL, ∞)}, {[50, 50], (NULL, 95], [NULL, ∞)}, {(50, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 50), [NULL, ∞), [NULL, ∞)}, {[50, 50], (NULL, 95], [NULL, ∞)}, {(50, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3458,30 +2293,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>48 AND v2<=80) OR (v1=72 AND v3 BETWEEN 45 AND 52 AND v2=98));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 48 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 80 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 45 (tinyint) AND 52 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 98 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(48, ∞), (NULL, 80], [NULL, ∞)}, {[72, 72], [98, 98], [45, 52]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(48, ∞), (NULL, 80], [NULL, ∞)}, {[72, 72], [98, 98], [45, 52]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3506,22 +2323,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>19) OR (v1<>48));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 48 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3566,33 +2373,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<37 AND v3>77) OR (v1>38 AND v3<>57 AND v2=87));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 37 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 77 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 38 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 57 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 87 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 37), [NULL, ∞), [NULL, ∞)}, {(38, ∞), [87, 87], (NULL, 57)}, {(38, ∞), [87, 87], (57, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 37), [NULL, ∞), (77, ∞)}, {(38, ∞), [87, 87], (NULL, 57)}, {(38, ∞), [87, 87], (57, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3607,30 +2393,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>23 AND v3<=52) OR (v1<>19 AND v2=25));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 52 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 25 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 23), [NULL, ∞), [NULL, ∞)}, {[23, 23], [25, 25], [NULL, ∞)}, {(23, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 19), [NULL, 25), (NULL, 52]}, {(NULL, 19), [25, 25], [NULL, ∞)}, {(NULL, 19), (25, ∞), (NULL, 52]}, {[19, 19], [NULL, ∞), (NULL, 52]}, {(19, 23), [NULL, 25), (NULL, 52]}, {(19, 23), (25, ∞), (NULL, 52]}, {(19, ∞), [25, 25], [NULL, ∞)}, {(23, ∞), [NULL, 25), (NULL, 52]}, {(23, ∞), (25, ∞), (NULL, 52]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3665,36 +2433,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1=61 AND v2 BETWEEN 10 AND 22 AND v3<34) OR (v1=68)) OR (v1<=97 AND v3 BETWEEN 7 AND 63 AND v2<67));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 10 (tinyint) AND 22 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 34 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 68 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 97 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 7 (tinyint) AND 63 (tinyint))\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 67 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 61), (NULL, 67), [7, 63]}, {[61, 61], (NULL, 10), [7, 63]}, {[61, 61], [10, 22], (NULL, 63]}, {[61, 61], (22, 67), [7, 63]}, {(61, 68), (NULL, 67), [7, 63]}, {[68, 68], [NULL, ∞), [NULL, ∞)}, {(68, 97], (NULL, 67), [7, 63]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 61), (NULL, 67), [7, 63]}, {[61, 61], (NULL, 10), [7, 63]}, {[61, 61], [10, 22], (NULL, 63]}, {[61, 61], (22, 67), [7, 63]}, {(61, 68), (NULL, 67), [7, 63]}, {[68, 68], [NULL, ∞), [NULL, ∞)}, {(68, 97], (NULL, 67), [7, 63]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3729,52 +2473,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((((v1>=26) OR (v1>=13 AND v2 BETWEEN 35 AND 95 AND v3>=29)) OR (v1<>54 AND v2 BETWEEN 0 AND 54)) OR (v1 BETWEEN 17 AND 17 AND v2<=71)) OR (v1>50 AND v3>=42)) OR (v1<>0));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ Or\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 35 (tinyint) AND 95 (tinyint))\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 0 (tinyint) AND 54 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 17 (tinyint) AND 17 (tinyint))\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 71 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 42 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 0 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 0), [NULL, ∞), [NULL, ∞)}, {[0, 0], [0, 54], [NULL, ∞)}, {(0, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 0), [NULL, ∞), [NULL, ∞)}, {[0, 0], [0, 54], [NULL, ∞)}, {(0, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3789,33 +2493,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>9 AND v2<74) AND (v1<=63 AND v2=18) OR (v1<46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 74 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 46), [NULL, ∞), [NULL, ∞)}, {[46, 63], [18, 18], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 46), [NULL, ∞), [NULL, ∞)}, {[46, 63], [18, 18], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -3830,150 +2513,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1<=55 AND v2 BETWEEN 82 AND 96 AND v3>=13) OR (v1>=89 AND v2<18 AND v3<19)) OR (v1=98 AND v3>=40)) OR (v1 BETWEEN 7 AND 74 AND v2<=73));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 82 (tinyint) AND 96 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 7 (tinyint) AND 74 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 73 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 55], [82, 96], [13, ∞)}, {[7, 74], (NULL, 73], [NULL, ∞)}, {[89, 98), (NULL, 18), (NULL, 19)}, {[98, 98], [NULL, ∞), [NULL, ∞)}, {(98, ∞), (NULL, 18), (NULL, 19)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 55], [82, 96], [13, ∞)}, {[7, 74], (NULL, 73], [NULL, ∞)}, {[89, ∞), (NULL, 18), (NULL, 19)}, {[98, 98], [NULL, ∞), [40, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=26 AND v2 BETWEEN 6 AND 80) AND (v1=47 AND v2<67 AND v3<7) OR (v1>63));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 6 (tinyint) AND 80 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 67 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 7 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 63 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[47, 47], [6, 67), (NULL, 7)}, {(63, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[47, 47], [6, 67), (NULL, 7)}, {(63, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<11) OR (v1<>33));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 33 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 33), [NULL, ∞), [NULL, ∞)}, {(33, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 33), [NULL, ∞), [NULL, ∞)}, {(33, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1<=35) AND (v1=44 AND v2<78 AND v3>=40) OR (v1<>88 AND v2=8)) AND (v1>=99 AND v2=62) OR (v1<=94)) OR (v1 BETWEEN 22 AND 23 AND v2 BETWEEN 14 AND 46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ │ └─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 88 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 62 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 94 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 22 (tinyint) AND 23 (tinyint))\n" + - " │ └─ (comp_index_t1.v2:2 BETWEEN 14 (tinyint) AND 46 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 94], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 94], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4008,41 +2583,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>77) OR (v1<=54 AND v2<=71 AND v3>=49)) OR (v1>54 AND v2<30 AND v3=6));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 71 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 30 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 6 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 77), [NULL, ∞), [NULL, ∞)}, {[77, 77], (NULL, 30), [6, 6]}, {(77, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 77), [NULL, ∞), [NULL, ∞)}, {[77, 77], (NULL, 30), [6, 6]}, {(77, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4057,21 +2603,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>50) OR (v1<=71));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 71 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4086,111 +2623,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<88 AND v2<91 AND v3>9) AND (v1>=5 AND v2 BETWEEN 21 AND 29 AND v3>18) OR (v1>=40));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 88 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 21 (tinyint) AND 29 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 40 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[5, 40), [21, 29], (18, ∞)}, {[40, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[5, 40), [21, 29], (18, ∞)}, {[40, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>2 AND v2<76 AND v3<=35) OR (v1<=12 AND v3 BETWEEN 25 AND 30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ (comp_index_t1.v3:3 BETWEEN 25 (tinyint) AND 30 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 12], [NULL, ∞), [NULL, ∞)}, {(12, ∞), (NULL, 76), (NULL, 35]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 2], [NULL, ∞), [25, 30]}, {(2, 12], [NULL, NULL], [25, 30]}, {(2, 12], [76, ∞), [25, 30]}, {(2, ∞), (NULL, 76), (NULL, 35]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1 BETWEEN 25 AND 84 AND v2<=94) OR (v1>66 AND v2>4 AND v3>=57)) OR (v1=78 AND v2>66 AND v3=19)) OR (v1<>48));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 25 (tinyint) AND 84 (tinyint))\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 66 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 57 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 66 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 48 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 48), [NULL, ∞), [NULL, ∞)}, {[48, 48], (NULL, 94], [NULL, ∞)}, {(48, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 48), [NULL, ∞), [NULL, ∞)}, {[48, 48], (NULL, 94], [NULL, ∞)}, {(48, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4235,40 +2693,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=43 AND v2<>39) AND (v1<=32 AND v2<=15 AND v3>=54) OR (v1<>68 AND v2 BETWEEN 42 AND 46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 39 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 54 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 68 (tinyint)\n" + - " │ └─ (comp_index_t1.v2:2 BETWEEN 42 (tinyint) AND 46 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 68), [42, 46], [NULL, ∞)}, {(68, ∞), [42, 46], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 68), [42, 46], [NULL, ∞)}, {(68, ∞), [42, 46], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4303,43 +2733,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>45) OR (v1>=91 AND v2>=8 AND v3<=38)) OR (v1<>58 AND v3<=32 AND v2<>45));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 45 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 58 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 45 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 45), [NULL, ∞), [NULL, ∞)}, {[45, 45], (NULL, 45), (NULL, 32]}, {[45, 45], (45, ∞), (NULL, 32]}, {(45, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 45), [NULL, ∞), [NULL, ∞)}, {[45, 45], (NULL, 45), (NULL, 32]}, {[45, 45], (45, ∞), (NULL, 32]}, {(45, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4414,27 +2813,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<1 AND v3<=34) OR (v1 BETWEEN 2 AND 57 AND v2<>70));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 34 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 2 (tinyint) AND 57 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 70 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 1), [NULL, ∞), [NULL, ∞)}, {[2, 57], (NULL, 70), [NULL, ∞)}, {[2, 57], (70, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 1), [NULL, ∞), (NULL, 34]}, {[2, 57], (NULL, 70), [NULL, ∞)}, {[2, 57], (70, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4449,41 +2833,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1<=93 AND v3<>47) OR (v1>=93 AND v2 BETWEEN 15 AND 42 AND v3<=6)) OR (v1>15)) OR (v1 BETWEEN 0 AND 1 AND v2>33));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 15 (tinyint) AND 42 (tinyint))\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 6 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 0 (tinyint) AND 1 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 33 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 0), [NULL, ∞), (NULL, 47)}, {(NULL, 0), [NULL, ∞), (47, ∞)}, {[0, 1], [NULL, 33], (NULL, 47)}, {[0, 1], [NULL, 33], (47, ∞)}, {[0, 1], (33, ∞), [NULL, ∞)}, {(1, 15], [NULL, ∞), (NULL, 47)}, {(1, 15], [NULL, ∞), (47, ∞)}, {(15, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4538,37 +2893,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>63) AND (v1<=44 AND v2<>43 AND v3=29) OR (v1=38 AND v2>45));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 43 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 29 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 45 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[38, 38], (45, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[38, 38], (45, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4593,76 +2923,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<50) AND (v1<19 AND v2>=10) OR (v1<36 AND v2>10 AND v3<>65));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 36 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 65 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 19), [10, ∞), [NULL, ∞)}, {[19, 36), (10, ∞), (NULL, 65)}, {[19, 36), (10, ∞), (65, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 19), [10, ∞), [NULL, ∞)}, {[19, 36), (10, ∞), (NULL, 65)}, {[19, 36), (10, ∞), (65, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1=56 AND v3<=4 AND v2=46) OR (v1 BETWEEN 21 AND 53 AND v2<>63)) OR (v1 BETWEEN 10 AND 62 AND v2>=62)) OR (v1>31));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 56 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 21 (tinyint) AND 53 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 10 (tinyint) AND 62 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 62 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 31 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[10, 21), [62, ∞), [NULL, ∞)}, {[21, 31], (NULL, ∞), [NULL, ∞)}, {(31, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[10, 21), [62, ∞), [NULL, ∞)}, {[21, 31], (NULL, ∞), [NULL, ∞)}, {(31, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4677,38 +2953,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<>51) AND (v1<>4 AND v2<47 AND v3>=77) OR (v1>41 AND v3>62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 77 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 62 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 4), (NULL, 47), [77, ∞)}, {(4, 41], (NULL, 47), [77, ∞)}, {(41, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 4), (NULL, 47), [77, ∞)}, {(4, 41], (NULL, 47), [77, ∞)}, {(41, ∞), [NULL, ∞), (62, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4763,36 +3013,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=46) AND (v1<22 AND v2<>42 AND v3<>54) OR (v1>=55 AND v2 BETWEEN 11 AND 84));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 42 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 54 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 55 (tinyint)\n" + - " │ └─ (comp_index_t1.v2:2 BETWEEN 11 (tinyint) AND 84 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[55, ∞), [11, 84], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[55, ∞), [11, 84], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4817,44 +3043,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1=51 AND v2<=9) OR (v1<>50)) OR (v1<>4 AND v2>56)) OR (v1 BETWEEN 3 AND 18 AND v2>10 AND v3=12));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 56 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 3 (tinyint) AND 18 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 12 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 50), [NULL, ∞), [NULL, ∞)}, {[50, 50], (56, ∞), [NULL, ∞)}, {(50, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 50), [NULL, ∞), [NULL, ∞)}, {[50, 50], (56, ∞), [NULL, ∞)}, {(50, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4869,27 +3063,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1 BETWEEN 50 AND 59) OR (v1>=23 AND v3>=87 AND v2<>46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 50 (tinyint) AND 59 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 87 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[23, 50), (NULL, 46), [87, ∞)}, {[23, 50), (46, ∞), [87, ∞)}, {[50, 59], [NULL, ∞), [NULL, ∞)}, {(59, ∞), (NULL, 46), [87, ∞)}, {(59, ∞), (46, ∞), [87, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[23, 50), (NULL, 46), [87, ∞)}, {[23, 50), (46, ∞), [87, ∞)}, {[50, 59], [NULL, ∞), [NULL, ∞)}, {(59, ∞), (NULL, 46), [87, ∞)}, {(59, ∞), (46, ∞), [87, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -4904,150 +3083,52 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1>=16 AND v2 BETWEEN 66 AND 94) OR (v1>70 AND v2<=3)) AND (v1<>91) OR (v1=17 AND v2>=7));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 16 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 66 (tinyint) AND 94 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 91 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 7 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[16, 17), [66, 94], [NULL, ∞)}, {[17, 17], [7, ∞), [NULL, ∞)}, {(17, 91), [66, 94], [NULL, ∞)}, {(70, 91), (NULL, 3], [NULL, ∞)}, {(91, ∞), (NULL, 3], [NULL, ∞)}, {(91, ∞), [66, 94], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[16, 17), [66, 94], [NULL, ∞)}, {[17, 17], [7, ∞), [NULL, ∞)}, {(17, 91), [66, 94], [NULL, ∞)}, {(70, 91), (NULL, 3], [NULL, ∞)}, {(91, ∞), (NULL, 3], [NULL, ∞)}, {(91, ∞), [66, 94], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1<29 AND v3>=33 AND v2=43) OR (v1<59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 59), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 59), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>19 AND v2>84 AND v3>94) OR (v1>=42 AND v3=41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 84 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 94 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 42 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(19, 42), (84, ∞), (94, ∞)}, {[42, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(19, ∞), (84, ∞), (94, ∞)}, {[42, ∞), [NULL, ∞), [41, 41]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1>=8 AND v2<=97 AND v3>=77) OR (v1<>4)) OR (v1<=41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 97 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 4 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>33) OR (v1<=28)) OR (v1<>68));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 28 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 68 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5082,30 +3163,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1=60 AND v3 BETWEEN 2 AND 13 AND v2 BETWEEN 10 AND 69) OR (v1 BETWEEN 1 AND 49)) OR (v1=8 AND v2<26));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 60 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 2 (tinyint) AND 13 (tinyint))\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 10 (tinyint) AND 69 (tinyint))\n" + - " │ │ └─ (comp_index_t1.v1:1 BETWEEN 1 (tinyint) AND 49 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 8 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 26 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[1, 49], [NULL, ∞), [NULL, ∞)}, {[60, 60], [10, 69], [2, 13]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[1, 49], [NULL, ∞), [NULL, ∞)}, {[60, 60], [10, 69], [2, 13]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5130,102 +3193,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1>=24 AND v2=62) OR (v1<=24 AND v3<>22 AND v2 BETWEEN 12 AND 25)) OR (v1 BETWEEN 48 AND 49 AND v3>=90)) AND (v1<15 AND v2<>55 AND v3=51);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 24 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 62 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 24 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 12 (tinyint) AND 25 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t1.v1:1 BETWEEN 48 (tinyint) AND 49 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 90 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 15), [12, 25], [51, 51]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 15), [12, 25], [51, 51]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<66 AND v2>=11 AND v3<90) OR (v1<>90)) OR (v1<=7 AND v2=52));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 66 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 90 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 90 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 7 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 52 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 90), [NULL, ∞), [NULL, ∞)}, {(90, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 90), [NULL, ∞), [NULL, ∞)}, {(90, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1 BETWEEN 6 AND 74 AND v2=52) OR (v1>44 AND v3>=15 AND v2 BETWEEN 17 AND 94)) OR (v1>84));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 6 (tinyint) AND 74 (tinyint))\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 17 (tinyint) AND 94 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 84 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[6, 74], [52, 52], [NULL, ∞)}, {(44, 74], [17, 52), [15, ∞)}, {(44, 74], (52, 94], [15, ∞)}, {(74, 84], [17, 94], [15, ∞)}, {(84, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[6, 74], [52, 52], [NULL, ∞)}, {(44, 74], [17, 52), [15, ∞)}, {(44, 74], (52, 94], [15, ∞)}, {(74, 84], [17, 94], [15, ∞)}, {(84, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5280,42 +3273,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<>1 AND v2=88 AND v3<33) OR (v1<=38)) OR (v1>74 AND v3<>55 AND v2>=9));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 88 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 74 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 55 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 9 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 38], [NULL, ∞), [NULL, ∞)}, {(38, 74], [88, 88], (NULL, 33)}, {(74, ∞), [9, ∞), (NULL, 55)}, {(74, ∞), [9, ∞), (55, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 38], [NULL, ∞), [NULL, ∞)}, {(38, 74], [88, 88], (NULL, 33)}, {(74, ∞), [9, ∞), (NULL, 55)}, {(74, ∞), [9, ∞), (55, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5340,74 +3303,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1>28 AND v2>=73 AND v3=79) AND (v1<=70 AND v2 BETWEEN 5 AND 36) OR (v1<=31)) OR (v1<36)) OR (v1=47 AND v2 BETWEEN 0 AND 92 AND v3<=43));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 5 (tinyint) AND 36 (tinyint))\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 0 (tinyint) AND 92 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 43 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 36), [NULL, ∞), [NULL, ∞)}, {[47, 47], [0, 92], (NULL, 43]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 36), [NULL, ∞), [NULL, ∞)}, {[47, 47], [0, 92], (NULL, 43]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>24) AND (v1>68 AND v2 BETWEEN 1 AND 79 AND v3 BETWEEN 23 AND 44) OR (v1>78));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 24 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 1 (tinyint) AND 79 (tinyint))\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 23 (tinyint) AND 44 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 78 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(68, 78], [1, 79], [23, 44]}, {(78, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(68, 78], [1, 79], [23, 44]}, {(78, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5422,58 +3333,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1>=49 AND v2>53 AND v3<>12) OR (v1=95 AND v2<1 AND v3<>89)) OR (v1=62 AND v3>=37 AND v2<=22)) OR (v1>30 AND v2>=66));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 49 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 37 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 22 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 30 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 66 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(30, ∞), [66, ∞), [NULL, ∞)}, {[49, ∞), (53, 66), (NULL, 12)}, {[49, ∞), (53, 66), (12, ∞)}, {[62, 62], (NULL, 22], [37, ∞)}, {[95, 95], (NULL, 1), (NULL, 89)}, {[95, 95], (NULL, 1), (89, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(30, ∞), [66, ∞), [NULL, ∞)}, {[49, ∞), (53, 66), (NULL, 12)}, {[49, ∞), (53, 66), (12, ∞)}, {[62, 62], (NULL, 22], [37, ∞)}, {[95, 95], (NULL, 1), (NULL, 89)}, {[95, 95], (NULL, 1), (89, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5498,83 +3363,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((((v1>40 AND v2 BETWEEN 26 AND 30) OR (v1<3 AND v2>=62 AND v3<=8)) OR (v1<>57)) OR (v1=16 AND v2>92 AND v3<=74));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 26 (tinyint) AND 30 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 57 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 16 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ └─ 92 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 74 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 57), [NULL, ∞), [NULL, ∞)}, {[57, 57], [26, 30], [NULL, ∞)}, {(57, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 57), [NULL, ∞), [NULL, ∞)}, {[57, 57], [26, 30], [NULL, ∞)}, {(57, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<=34 AND v2 BETWEEN 29 AND 35 AND v3>=64) OR (v1<>47)) AND (v1>=11) OR (v1<>46 AND v2 BETWEEN 4 AND 26));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t1.v2:2 BETWEEN 29 (tinyint) AND 35 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 64 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 46 (tinyint)\n" + - " │ └─ (comp_index_t1.v2:2 BETWEEN 4 (tinyint) AND 26 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 11), [4, 26], [NULL, ∞)}, {[11, 47), [NULL, ∞), [NULL, ∞)}, {[47, 47], [4, 26], [NULL, ∞)}, {(47, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 11), [4, 26], [NULL, ∞)}, {[11, 47), [NULL, ∞), [NULL, ∞)}, {[47, 47], [4, 26], [NULL, ∞)}, {(47, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5589,66 +3393,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE ((v1>=79 AND v3 BETWEEN 9 AND 95) OR (v1 BETWEEN 50 AND 50 AND v2 BETWEEN 16 AND 38 AND v3<>94));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 79 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v3:3 BETWEEN 9 (tinyint) AND 95 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t1.v1:1 BETWEEN 50 (tinyint) AND 50 (tinyint))\n" + - " │ │ └─ (comp_index_t1.v2:2 BETWEEN 16 (tinyint) AND 38 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t1.v3:3\n" + - " │ └─ 94 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{[50, 50], [16, 38], (NULL, 94)}, {[50, 50], [16, 38], (94, ∞)}, {[79, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{[50, 50], [16, 38], (NULL, 94)}, {[50, 50], [16, 38], (94, ∞)}, {[79, ∞), [NULL, ∞), [9, 95]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { Query: `SELECT * FROM comp_index_t1 WHERE (((((v1<>79) OR (v1 BETWEEN 9 AND 11 AND v2<48 AND v3<=73)) OR (v1<=46)) OR (v1 BETWEEN 66 AND 67)) OR (v1<=86 AND v2<4));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t1.v1:1 BETWEEN 9 (tinyint) AND 11 (tinyint))\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ (comp_index_t1.v1:1 BETWEEN 66 (tinyint) AND 67 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ └─ 86 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t1.v2:2\n" + - " │ └─ 4 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 79), [NULL, ∞), [NULL, ∞)}, {[79, 79], (NULL, 4), [NULL, ∞)}, {(79, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 79), [NULL, ∞), [NULL, ∞)}, {[79, 79], (NULL, 4), [NULL, ∞)}, {(79, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5673,43 +3433,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t1 WHERE (((v1<62) AND (v1<=57 AND v2>51 AND v3 BETWEEN 29 AND 30) OR (v1>=28 AND v2<=62 AND v3<>76)) OR (v1>=94));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ │ └─ 57 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ └─ (comp_index_t1.v3:3 BETWEEN 29 (tinyint) AND 30 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t1.v1:1\n" + - " │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t1.v2:2\n" + - " │ │ │ └─ 62 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t1.v3:3\n" + - " │ │ └─ 76 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t1.v1:1\n" + - " │ └─ 94 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t1)\n" + - " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + - " ├─ static: [{(NULL, 28), (51, ∞), [29, 30]}, {[28, 57], (62, ∞), [29, 30]}, {[28, 94), (NULL, 62], (NULL, 76)}, {[28, 94), (NULL, 62], (76, ∞)}, {[94, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t1\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t1)\n" + + " ├─ index: [comp_index_t1.v1,comp_index_t1.v2,comp_index_t1.v3]\n" + + " ├─ static: [{(NULL, 28), (51, ∞), [29, 30]}, {[28, 57], (62, ∞), [29, 30]}, {[28, 94), (NULL, 62], (NULL, 76)}, {[28, 94), (NULL, 62], (76, ∞)}, {[94, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t1\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -5774,84 +3503,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=51 AND v4 BETWEEN 36 AND 55 AND v2>62 AND v3<43) OR (v1 BETWEEN 5 AND 60 AND v2<1)) OR (v1=51 AND v2>=98 AND v3>=94));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 36 (tinyint) AND 55 (tinyint))\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 43 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 5 (tinyint) AND 60 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 98 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 94 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 60], (NULL, 1), [NULL, ∞), [NULL, ∞)}, {[51, 51], (62, ∞), (NULL, 43), [36, 55]}, {[51, 51], [98, ∞), [94, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 60], (NULL, 1), [NULL, ∞), [NULL, ∞)}, {[51, 51], (62, ∞), (NULL, 43), [36, 55]}, {[51, 51], [98, ∞), [94, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=6 AND v4<95 AND v2<41 AND v3<=4) AND (v1>=81 AND v4>44 AND v2 BETWEEN 6 AND 11) OR (v1<=98));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 44 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 6 (tinyint) AND 11 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 98 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 98], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(98, ∞), [6, 11], (NULL, 4], (44, 95)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 98], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(98, ∞), [6, 11], (NULL, 4], (44, 95)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -5876,49 +3543,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=70) OR (v1>=38 AND v3 BETWEEN 25 AND 30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ (comp_index_t2.v3:3 BETWEEN 25 (tinyint) AND 30 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[38, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[38, 70), [NULL, ∞), [25, 30], [NULL, ∞)}, {[70, 70], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(70, ∞), [NULL, ∞), [25, 30], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=33) OR (v1<=31 AND v4<>35 AND v2=38));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 33 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 38 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 33], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 33], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -5943,54 +3583,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((((v1>=91 AND v4<=47 AND v2>=43) OR (v1=75)) OR (v1<41 AND v4>=64 AND v2>83)) OR (v1 BETWEEN 72 AND 88 AND v2=48 AND v3<=10)) OR (v1<=44));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 75 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 64 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 83 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 72 (tinyint) AND 88 (tinyint))\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 48 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 44 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 44], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[72, 75), [48, 48], (NULL, 10], [NULL, ∞)}, {[75, 75], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(75, 88], [48, 48], (NULL, 10], [NULL, ∞)}, {[91, ∞), [43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 44], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[72, 75), [48, 48], (NULL, 10], [NULL, ∞)}, {[75, 75], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(75, 88], [48, 48], (NULL, 10], [NULL, ∞)}, {[91, ∞), [43, ∞), [NULL, ∞), (NULL, 47]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6015,49 +3613,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<52 AND v3 BETWEEN 39 AND 57 AND v4 BETWEEN 13 AND 13 AND v2 BETWEEN 76 AND 99) OR (v1>44)) OR (v1<71 AND v4>7 AND v2<98)) OR (v1<>5 AND v2 BETWEEN 35 AND 40 AND v3<=10));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 39 (tinyint) AND 57 (tinyint))\n" + - " │ │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 13 (tinyint) AND 13 (tinyint))\n" + - " │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 76 (tinyint) AND 99 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 44 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 71 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 7 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 98 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 35 (tinyint) AND 40 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 10 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 44], (NULL, 98), [NULL, ∞), [NULL, ∞)}, {(NULL, 44], [98, 99], [39, 57], [13, 13]}, {(44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 5), (NULL, 35), [NULL, ∞), (7, ∞)}, {(NULL, 5), [35, 40], [NULL, NULL], (7, ∞)}, {(NULL, 5), [35, 40], (NULL, 10], [NULL, ∞)}, {(NULL, 5), [35, 40], (10, ∞), (7, ∞)}, {(NULL, 5), (40, 76), [NULL, ∞), (7, ∞)}, {(NULL, 5], [76, 98), [NULL, ∞), (7, ∞)}, {(NULL, 44], [98, 99], [39, 57], [13, 13]}, {[5, 5], (NULL, 76), [NULL, ∞), (7, ∞)}, {(5, 44], (NULL, 35), [NULL, ∞), (7, ∞)}, {(5, 44], [35, 40], [NULL, NULL], (7, ∞)}, {(5, 44], [35, 40], (NULL, 10], [NULL, ∞)}, {(5, 44], [35, 40], (10, ∞), (7, ∞)}, {(5, 44], (40, 98), [NULL, ∞), (7, ∞)}, {(44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6072,14 +3633,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (v1<=92 AND v4 BETWEEN 8 AND 90) AND (v1 BETWEEN 39 AND 42);`, - ExpectedPlan: "Filter\n" + - " ├─ (comp_index_t2.v4:4 BETWEEN 8 (tinyint) AND 90 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[39, 42], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[39, 42], [NULL, ∞), [NULL, ∞), [8, 90]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6104,204 +3663,62 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>77 AND v4>82 AND v2>=96) OR (v1 BETWEEN 41 AND 80 AND v2<>21 AND v3>60));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 77 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 82 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 96 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 41 (tinyint) AND 80 (tinyint))\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 21 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 60 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[41, 77], (21, ∞), (60, ∞), [NULL, ∞)}, {[41, 80], (NULL, 21), (60, ∞), [NULL, ∞)}, {(77, 80], (21, 96), (60, ∞), [NULL, ∞)}, {(77, ∞), [96, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[41, 80], (NULL, 21), (60, ∞), [NULL, ∞)}, {[41, 80], (21, ∞), (60, ∞), [NULL, ∞)}, {(77, 80], [96, ∞), [NULL, 60], (82, ∞)}, {(80, ∞), [96, ∞), [NULL, ∞), (82, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (v1=28 AND v4 BETWEEN 44 AND 50) AND (v1>=49);`, - ExpectedPlan: "Filter\n" + - " ├─ (comp_index_t2.v4:4 BETWEEN 44 (tinyint) AND 50 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 81 AND 87 AND v3<>81 AND v4<30) AND (v1=17) OR (v1<27 AND v2<>8 AND v3>35)) OR (v1>28 AND v2<62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 81 (tinyint) AND 87 (tinyint))\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 27 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 28 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 62 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 27), (NULL, 8), (35, ∞), [NULL, ∞)}, {(NULL, 27), (8, ∞), (35, ∞), [NULL, ∞)}, {(28, ∞), (NULL, 62), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 27), (NULL, 8), (35, ∞), [NULL, ∞)}, {(NULL, 27), (8, ∞), (35, ∞), [NULL, ∞)}, {(28, ∞), (NULL, 62), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>65 AND v2=64) OR (v1=82 AND v3<>99)) OR (v1>=68 AND v2=3 AND v3 BETWEEN 1 AND 51 AND v4<=73));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 64 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 82 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 99 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 1 (tinyint) AND 51 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 73 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(65, 82), [64, 64], [NULL, ∞), [NULL, ∞)}, {[68, 82), [3, 3], [1, 51], (NULL, 73]}, {[82, 82], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(82, ∞), [3, 3], [1, 51], (NULL, 73]}, {(82, ∞), [64, 64], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(65, ∞), [64, 64], [NULL, ∞), [NULL, ∞)}, {[68, 82), [3, 3], [1, 51], (NULL, 73]}, {[82, 82], [NULL, 64), (NULL, 99), [NULL, ∞)}, {[82, 82], [NULL, 64), (99, ∞), [NULL, ∞)}, {[82, 82], (64, ∞), (NULL, 99), [NULL, ∞)}, {[82, 82], (64, ∞), (99, ∞), [NULL, ∞)}, {(82, ∞), [3, 3], [1, 51], (NULL, 73]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=27 AND v3>23) OR (v1<70 AND v2<>43));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 27 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 43 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 27], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(27, 70), (NULL, 43), [NULL, ∞), [NULL, ∞)}, {(27, 70), (43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 27], [NULL, NULL], (23, ∞), [NULL, ∞)}, {(NULL, 27], [43, 43], (23, ∞), [NULL, ∞)}, {(NULL, 70), (NULL, 43), [NULL, ∞), [NULL, ∞)}, {(NULL, 70), (43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>34 AND v2>=89 AND v3>=14) OR (v1<=42 AND v3<1)) OR (v1<59 AND v2>=23 AND v3 BETWEEN 17 AND 37 AND v4 BETWEEN 21 AND 38));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 42 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 17 (tinyint) AND 37 (tinyint))\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 21 (tinyint) AND 38 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 42], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(42, 59), [23, 89), [17, 37], [21, 38]}, {(42, ∞), [89, ∞), [14, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 34), [23, 89), [17, 37], [21, 38]}, {(NULL, 34), [89, ∞), [14, ∞), [NULL, ∞)}, {(NULL, 42], [NULL, ∞), (NULL, 1), [NULL, ∞)}, {[34, 34], [23, ∞), [17, 37], [21, 38]}, {(34, 59), [23, 89), [17, 37], [21, 38]}, {(34, ∞), [89, ∞), [14, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6326,25 +3743,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<83 AND v4>51) OR (v1<>30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 83 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 51 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 30 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 30), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[30, 30], [NULL, ∞), [NULL, ∞), (51, ∞)}, {(30, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6369,54 +3773,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>29 AND v4=40 AND v2>=63) OR (v1<70 AND v2<70 AND v3<=20)) OR (v1 BETWEEN 7 AND 61 AND v2>=33 AND v3>78)) OR (v1>=4 AND v2<=22));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 20 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 7 (tinyint) AND 61 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 78 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 4 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 22 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 4), (NULL, 70), (NULL, 20], [NULL, ∞)}, {[4, 29], (22, 70), (NULL, 20], [NULL, ∞)}, {[4, ∞), (NULL, 22], [NULL, ∞), [NULL, ∞)}, {[7, 29], [33, ∞), (78, ∞), [NULL, ∞)}, {(29, 61], [33, 63), (78, ∞), [NULL, ∞)}, {(29, 70), (22, 63), (NULL, 20], [NULL, ∞)}, {(29, ∞), [63, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 4), (NULL, 70), (NULL, 20], [NULL, ∞)}, {[4, 70), (22, 70), (NULL, 20], [NULL, ∞)}, {[4, ∞), (NULL, 22], [NULL, ∞), [NULL, ∞)}, {[7, 61], [33, ∞), (78, ∞), [NULL, ∞)}, {(29, 61], [63, 70), (20, 78], [40, 40]}, {(29, 61], [70, ∞), [NULL, 78], [40, 40]}, {(29, 70), [63, 70), [NULL, NULL], [40, 40]}, {(61, 70), [63, 70), (20, ∞), [40, 40]}, {(61, 70), [70, ∞), [NULL, ∞), [40, 40]}, {[70, ∞), [63, ∞), [NULL, ∞), [40, 40]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6431,44 +3793,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=94 AND v2>=13 AND v3<=46 AND v4<>36) AND (v1=84) OR (v1 BETWEEN 52 AND 98 AND v2<71 AND v3<>45));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 36 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 84 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 52 (tinyint) AND 98 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 71 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 45 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[52, 98], (NULL, 71), (NULL, 45), [NULL, ∞)}, {[52, 98], (NULL, 71), (45, ∞), [NULL, ∞)}, {[84, 84], [13, 71), [45, 45], (NULL, 36)}, {[84, 84], [13, 71), [45, 45], (36, ∞)}, {[84, 84], [71, ∞), (NULL, 46], (NULL, 36)}, {[84, 84], [71, ∞), (NULL, 46], (36, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[52, 98], (NULL, 71), (NULL, 45), [NULL, ∞)}, {[52, 98], (NULL, 71), (45, ∞), [NULL, ∞)}, {[84, 84], [13, 71), [45, 45], (NULL, 36)}, {[84, 84], [13, 71), [45, 45], (36, ∞)}, {[84, 84], [71, ∞), (NULL, 46], (NULL, 36)}, {[84, 84], [71, ∞), (NULL, 46], (36, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6483,45 +3813,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1 BETWEEN 54 AND 87 AND v2<78 AND v3<33) OR (v1<>52)) OR (v1 BETWEEN 3 AND 61 AND v4<=49)) OR (v1>3 AND v2<73 AND v3>59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 54 (tinyint) AND 87 (tinyint))\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 33 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 3 (tinyint) AND 61 (tinyint))\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 73 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 52), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[52, 52], [NULL, NULL], [NULL, ∞), (NULL, 49]}, {[52, 52], (NULL, 73), [NULL, 59], (NULL, 49]}, {[52, 52], (NULL, 73), (59, ∞), [NULL, ∞)}, {[52, 52], [73, ∞), [NULL, ∞), (NULL, 49]}, {(52, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6536,48 +3833,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=31 AND v2>44) OR (v1<44 AND v4<>6 AND v2<>10 AND v3<>14)) AND (v1=96 AND v3>25 AND v4<>32);`, - ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 32 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6592,35 +3853,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=0) OR (v1=31)) OR (v1<>73 AND v4>9 AND v2 BETWEEN 27 AND 69 AND v3=14));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 0 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 27 (tinyint) AND 69 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 14 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 0), [27, 69], [14, 14], (9, ∞)}, {[0, 0], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(0, 31), [27, 69], [14, 14], (9, ∞)}, {[31, 31], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(31, 73), [27, 69], [14, 14], (9, ∞)}, {(73, ∞), [27, 69], [14, 14], (9, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 0), [27, 69], [14, 14], (9, ∞)}, {[0, 0], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(0, 31), [27, 69], [14, 14], (9, ∞)}, {[31, 31], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(31, 73), [27, 69], [14, 14], (9, ∞)}, {(73, ∞), [27, 69], [14, 14], (9, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6635,157 +3873,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<=3 AND v2<57 AND v3<>74 AND v4>=69) OR (v1<>66 AND v2=16)) OR (v1=44 AND v3=58));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 57 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 74 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 69 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 66 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 16 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 44 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 58 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 3], (NULL, 16), (NULL, 74), [69, ∞)}, {(NULL, 3], (NULL, 16), (74, ∞), [69, ∞)}, {(NULL, 3], (16, 57), (NULL, 74), [69, ∞)}, {(NULL, 3], (16, 57), (74, ∞), [69, ∞)}, {(NULL, 44), [16, 16], [NULL, ∞), [NULL, ∞)}, {[44, 44], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(44, 66), [16, 16], [NULL, ∞), [NULL, ∞)}, {(66, ∞), [16, 16], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 3], (NULL, 16), (NULL, 74), [69, ∞)}, {(NULL, 3], (NULL, 16), (74, ∞), [69, ∞)}, {(NULL, 3], (16, 57), (NULL, 74), [69, ∞)}, {(NULL, 3], (16, 57), (74, ∞), [69, ∞)}, {(NULL, 66), [16, 16], [NULL, ∞), [NULL, ∞)}, {[44, 44], [NULL, 16), [58, 58], [NULL, ∞)}, {[44, 44], (16, ∞), [58, 58], [NULL, ∞)}, {(66, ∞), [16, 16], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=22 AND v2<=41) OR (v1=61 AND v2>21)) OR (v1<>10)) OR (v1 BETWEEN 43 AND 44 AND v2>=35 AND v3<>87));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 43 (tinyint) AND 44 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 87 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 10), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[10, 10], (NULL, 41], [NULL, ∞), [NULL, ∞)}, {(10, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 10), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[10, 10], (NULL, 41], [NULL, ∞), [NULL, ∞)}, {(10, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=13 AND v3>20) OR (v1 BETWEEN 18 AND 26 AND v2>11 AND v3>22)) OR (v1<18 AND v2>=47 AND v3<11)) OR (v1>19));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 20 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 18 (tinyint) AND 26 (tinyint))\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 19 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 13], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(13, 18), [47, ∞), (NULL, 11), [NULL, ∞)}, {[18, 19], (11, ∞), (22, ∞), [NULL, ∞)}, {(19, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 13], [NULL, ∞), (20, ∞), [NULL, ∞)}, {(NULL, 18), [47, ∞), (NULL, 11), [NULL, ∞)}, {[18, 19], (11, ∞), (22, ∞), [NULL, ∞)}, {(19, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 42 AND 54 AND v2>20) OR (v1<>68 AND v3>32));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 42 (tinyint) AND 54 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 20 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 68 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 32 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 68), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(68, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 42), [NULL, ∞), (32, ∞), [NULL, ∞)}, {[42, 54], [NULL, 20], (32, ∞), [NULL, ∞)}, {[42, 54], (20, ∞), [NULL, ∞), [NULL, ∞)}, {(54, 68), [NULL, ∞), (32, ∞), [NULL, ∞)}, {(68, ∞), [NULL, ∞), (32, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6810,140 +3933,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=44 AND v2<=98) AND (v1>15) OR (v1<=45 AND v2=1 AND v3<>54));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 45 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 54 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 44), [1, 1], (NULL, 54), [NULL, ∞)}, {(NULL, 44), [1, 1], (54, ∞), [NULL, ∞)}, {[44, 44], (NULL, 98], [NULL, ∞), [NULL, ∞)}, {(44, 45], [1, 1], (NULL, 54), [NULL, ∞)}, {(44, 45], [1, 1], (54, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 44), [1, 1], (NULL, 54), [NULL, ∞)}, {(NULL, 44), [1, 1], (54, ∞), [NULL, ∞)}, {[44, 44], (NULL, 98], [NULL, ∞), [NULL, ∞)}, {(44, 45], [1, 1], (NULL, 54), [NULL, ∞)}, {(44, 45], [1, 1], (54, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<38 AND v2>24) OR (v1<20 AND v3>=3 AND v4 BETWEEN 59 AND 81)) OR (v1<31 AND v4 BETWEEN 2 AND 16 AND v2=6 AND v3<=69));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 38 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 24 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 20 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 59 (tinyint) AND 81 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 2 (tinyint) AND 16 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 6 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 69 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 20), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[20, 31), [6, 6], (NULL, 69], [2, 16]}, {[20, 38), (24, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 20), [NULL, 24], [3, ∞), [59, 81]}, {(NULL, 31), [6, 6], (NULL, 69], [2, 16]}, {(NULL, 38), (24, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((((v1<43 AND v4<=22) OR (v1<=72 AND v2>=35 AND v3>=96)) OR (v1=63 AND v2=55 AND v3<>46)) OR (v1>=9 AND v2=52 AND v3=86 AND v4<=27)) OR (v1 BETWEEN 37 AND 62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 96 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 86 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 27 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 37 (tinyint) AND 62 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 62], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(62, 63), [35, ∞), [96, ∞), [NULL, ∞)}, {(62, ∞), [52, 52], [86, 86], (NULL, 27]}, {[63, 63], [35, 55), [96, ∞), [NULL, ∞)}, {[63, 63], [55, 55], (NULL, 46), [NULL, ∞)}, {[63, 63], [55, 55], (46, ∞), [NULL, ∞)}, {[63, 63], (55, ∞), [96, ∞), [NULL, ∞)}, {(63, 72], [35, ∞), [96, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 9), [35, ∞), [NULL, 96), (NULL, 22]}, {(NULL, 37), [NULL, 35), [NULL, ∞), (NULL, 22]}, {(NULL, 37), [35, ∞), [96, ∞), [NULL, ∞)}, {[9, 37), [35, 52), [NULL, 96), (NULL, 22]}, {[9, 37), [52, 52], [NULL, 86), (NULL, 22]}, {[9, 37), [52, 52], [86, 86], (NULL, 27]}, {[9, 37), [52, 52], (86, 96), (NULL, 22]}, {[9, 37), (52, ∞), [NULL, 96), (NULL, 22]}, {[37, 62], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(62, 63), [35, ∞), [96, ∞), [NULL, ∞)}, {(62, ∞), [52, 52], [86, 86], (NULL, 27]}, {[63, 63], [35, 55), [96, ∞), [NULL, ∞)}, {[63, 63], [55, 55], (NULL, 46), [NULL, ∞)}, {[63, 63], [55, 55], (46, ∞), [NULL, ∞)}, {[63, 63], (55, ∞), [96, ∞), [NULL, ∞)}, {(63, 72], [35, ∞), [96, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -6958,221 +3973,52 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=37 AND v3>=74 AND v4=54) OR (v1>=36 AND v3<=42 AND v4<=94)) AND (v1=59 AND v2<=56) OR (v1>=83 AND v2<=11));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 74 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 94 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 59 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 56 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 83 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 11 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[59, 59], (NULL, 56], [NULL, ∞), [NULL, ∞)}, {[83, ∞), (NULL, 11], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[59, 59], (NULL, 56], (NULL, 42], (NULL, 94]}, {[59, 59], (NULL, 56], [74, ∞), [54, 54]}, {[83, ∞), (NULL, 11], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>39 AND v3<44 AND v4 BETWEEN 3 AND 31 AND v2>16) OR (v1>72 AND v2=73 AND v3<37 AND v4<=43)) OR (v1=9 AND v2<50));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 3 (tinyint) AND 31 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 16 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 37 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 9 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 50 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 9), (16, ∞), (NULL, 44), [3, 31]}, {[9, 9], (NULL, 50), [NULL, ∞), [NULL, ∞)}, {[9, 9], [50, ∞), (NULL, 44), [3, 31]}, {(9, 39), (16, ∞), (NULL, 44), [3, 31]}, {(39, 72], (16, ∞), (NULL, 44), [3, 31]}, {(72, ∞), (16, 73), (NULL, 44), [3, 31]}, {(72, ∞), [73, 73], (NULL, 37), (NULL, 43]}, {(72, ∞), [73, 73], [37, 44), [3, 31]}, {(72, ∞), (73, ∞), (NULL, 44), [3, 31]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 9), (16, ∞), (NULL, 44), [3, 31]}, {[9, 9], (NULL, 50), [NULL, ∞), [NULL, ∞)}, {[9, 9], [50, ∞), (NULL, 44), [3, 31]}, {(9, 39), (16, ∞), (NULL, 44), [3, 31]}, {(39, 72], (16, ∞), (NULL, 44), [3, 31]}, {(72, ∞), (16, 73), (NULL, 44), [3, 31]}, {(72, ∞), [73, 73], (NULL, 37), (NULL, 43]}, {(72, ∞), [73, 73], [37, 44), [3, 31]}, {(72, ∞), (73, ∞), (NULL, 44), [3, 31]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<31 AND v2<>14 AND v3 BETWEEN 0 AND 10 AND v4>=95) OR (v1<>91)) OR (v1<>35));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 0 (tinyint) AND 10 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 95 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 91 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 35 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>13) OR (v1<>3 AND v4<=42 AND v2 BETWEEN 89 AND 94));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 42 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 89 (tinyint) AND 94 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 3), [89, 94], [NULL, ∞), [NULL, ∞)}, {(3, 13], [89, 94], [NULL, ∞), [NULL, ∞)}, {(13, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 3), [89, 94], [NULL, ∞), (NULL, 42]}, {(3, 13], [89, 94], [NULL, ∞), (NULL, 42]}, {(13, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<29 AND v2<=19) AND (v1>=26) OR (v1>=87 AND v2<=12 AND v3=36 AND v4<20)) AND (v1<=24 AND v4>85 AND v2 BETWEEN 1 AND 64) OR (v1>27 AND v2>=8 AND v3<24));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 20 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 24 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 1 (tinyint) AND 64 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 27 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 8 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 24 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(27, ∞), [8, ∞), (NULL, 24), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(27, ∞), [8, ∞), (NULL, 24), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7197,169 +4043,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>61 AND v2 BETWEEN 46 AND 51) OR (v1 BETWEEN 32 AND 75 AND v4<=32)) AND (v1>97) OR (v1<97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 46 (tinyint) AND 51 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 32 (tinyint) AND 75 (tinyint))\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 32 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 97 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 97), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(97, ∞), [46, 51], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 97), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(97, ∞), [46, 51], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 4 AND 71 AND v2<=70) AND (v1<>47 AND v2 BETWEEN 19 AND 65) OR (v1=59 AND v2 BETWEEN 25 AND 58));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 4 (tinyint) AND 71 (tinyint))\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 70 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 19 (tinyint) AND 65 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 59 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 25 (tinyint) AND 58 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[4, 47), [19, 65], [NULL, ∞), [NULL, ∞)}, {(47, 71], [19, 65], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[4, 47), [19, 65], [NULL, ∞), [NULL, ∞)}, {(47, 71], [19, 65], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<70 AND v2<=90) OR (v1<5 AND v2<>13 AND v3 BETWEEN 20 AND 96 AND v4>92)) OR (v1<>76)) OR (v1 BETWEEN 12 AND 88 AND v2 BETWEEN 53 AND 67 AND v3>=39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 90 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 20 (tinyint) AND 96 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 92 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 76 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 12 (tinyint) AND 88 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 53 (tinyint) AND 67 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 76), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[76, 76], [53, 67], [39, ∞), [NULL, ∞)}, {(76, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 76), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[76, 76], [53, 67], [39, ∞), [NULL, ∞)}, {(76, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1 BETWEEN 8 AND 38 AND v2<=31 AND v3 BETWEEN 30 AND 46 AND v4>=28) OR (v1<=22 AND v4<>40 AND v2>76 AND v3 BETWEEN 38 AND 42)) OR (v1<=52 AND v2<93 AND v3>=83)) OR (v1>=33 AND v3>13 AND v4>34));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 8 (tinyint) AND 38 (tinyint))\n" + - " │ │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 30 (tinyint) AND 46 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 76 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 38 (tinyint) AND 42 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 93 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 83 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 34 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 22], (76, ∞), [38, 42], (NULL, 40)}, {(NULL, 22], (76, ∞), [38, 42], (40, ∞)}, {(NULL, 33), (NULL, 93), [83, ∞), [NULL, ∞)}, {[8, 33), (NULL, 31], [30, 46], [28, ∞)}, {[33, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 22], (76, ∞), [38, 42], (NULL, 40)}, {(NULL, 22], (76, ∞), [38, 42], (40, ∞)}, {(NULL, 52], (NULL, 93), [83, ∞), [NULL, ∞)}, {[8, 38], (NULL, 31], [30, 46], [28, ∞)}, {[33, 38], (NULL, 31], (13, 30), (34, ∞)}, {[33, 38], (NULL, 31], (46, 83), (34, ∞)}, {[33, 38], (31, 93), (13, 83), (34, ∞)}, {[33, 52], [NULL, NULL], (13, ∞), (34, ∞)}, {[33, 52], [93, ∞), (13, ∞), (34, ∞)}, {(38, 52], (NULL, 93), (13, 83), (34, ∞)}, {(52, ∞), [NULL, ∞), (13, ∞), (34, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7374,139 +4093,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>35 AND v2<>26) OR (v1<=30 AND v2 BETWEEN 6 AND 61 AND v3<=95 AND v4>5)) AND (v1<>97) OR (v1>31));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 6 (tinyint) AND 61 (tinyint))\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 97 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 31 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 30], [6, 61], (NULL, 95], (5, ∞)}, {(31, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 30], [6, 61], (NULL, 95], (5, ∞)}, {(31, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1=43 AND v2>=64) OR (v1>6 AND v3=92 AND v4>=15)) OR (v1<=55 AND v3=6 AND v4<=77 AND v2<=3)) OR (v1=96 AND v3<=80 AND v4<=13));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 64 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 92 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 3 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 80 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 13 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 6], (NULL, 3], [6, 6], (NULL, 77]}, {(6, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 55], (NULL, 3], [6, 6], (NULL, 77]}, {(6, 43), [NULL, ∞), [92, 92], [15, ∞)}, {[43, 43], [NULL, 64), [92, 92], [15, ∞)}, {[43, 43], [64, ∞), [NULL, ∞), [NULL, ∞)}, {(43, ∞), [NULL, ∞), [92, 92], [15, ∞)}, {[96, 96], [NULL, ∞), (NULL, 80], (NULL, 13]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>8 AND v3 BETWEEN 14 AND 75 AND v4=28) AND (v1>=95 AND v2<>72 AND v3=22) OR (v1=5));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 14 (tinyint) AND 75 (tinyint))\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 28 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 22 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 5 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 5], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[95, ∞), (NULL, 72), [22, 22], [28, 28]}, {[95, ∞), (72, ∞), [22, 22], [28, 28]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 5], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[95, ∞), (NULL, 72), [22, 22], [28, 28]}, {[95, ∞), (72, ∞), [22, 22], [28, 28]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7531,36 +4143,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=89 AND v2<=1 AND v3<=7 AND v4>=4) AND (v1<=87) OR (v1 BETWEEN 10 AND 46 AND v2 BETWEEN 18 AND 76));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 7 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 87 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 10 (tinyint) AND 46 (tinyint))\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 18 (tinyint) AND 76 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[10, 46], [18, 76], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[10, 46], [18, 76], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7585,41 +4173,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 49 AND 53 AND v4 BETWEEN 22 AND 96) OR (v1 BETWEEN 7 AND 79)) AND (v1<=45 AND v2<=11) OR (v1 BETWEEN 16 AND 65 AND v2<53 AND v3<>15 AND v4>22));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 49 (tinyint) AND 53 (tinyint))\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 22 (tinyint) AND 96 (tinyint))\n" + - " │ │ │ └─ (comp_index_t2.v1:1 BETWEEN 7 (tinyint) AND 79 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 45 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 16 (tinyint) AND 65 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 22 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[7, 45], (NULL, 11], [NULL, ∞), [NULL, ∞)}, {[16, 45], (11, 53), (NULL, 15), (22, ∞)}, {[16, 45], (11, 53), (15, ∞), (22, ∞)}, {(45, 65], (NULL, 53), (NULL, 15), (22, ∞)}, {(45, 65], (NULL, 53), (15, ∞), (22, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[7, 45], (NULL, 11], [NULL, ∞), [NULL, ∞)}, {[16, 45], (11, 53), (NULL, 15), (22, ∞)}, {[16, 45], (11, 53), (15, ∞), (22, ∞)}, {(45, 65], (NULL, 53), (NULL, 15), (22, ∞)}, {(45, 65], (NULL, 53), (15, ∞), (22, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7634,62 +4193,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=97 AND v3<>2) OR (v1=49 AND v2 BETWEEN 29 AND 30 AND v3<>97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 97 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 49 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 29 (tinyint) AND 30 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 97], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 49), [NULL, ∞), (NULL, 2), [NULL, ∞)}, {(NULL, 49), [NULL, ∞), (2, ∞), [NULL, ∞)}, {[49, 49], [NULL, 29), (NULL, 2), [NULL, ∞)}, {[49, 49], [NULL, 29), (2, ∞), [NULL, ∞)}, {[49, 49], [29, 30], (NULL, ∞), [NULL, ∞)}, {[49, 49], (30, ∞), (NULL, 2), [NULL, ∞)}, {[49, 49], (30, ∞), (2, ∞), [NULL, ∞)}, {(49, 97], [NULL, ∞), (NULL, 2), [NULL, ∞)}, {(49, 97], [NULL, ∞), (2, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<=64) OR (v1>21 AND v2 BETWEEN 0 AND 58)) OR (v1<15 AND v4 BETWEEN 63 AND 76 AND v2>84));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 64 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 0 (tinyint) AND 58 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 63 (tinyint) AND 76 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 84 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 64], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(64, ∞), [0, 58], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 64], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(64, ∞), [0, 58], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7704,54 +4223,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<>37) OR (v1<=94 AND v2 BETWEEN 53 AND 65 AND v3>=9)) OR (v1<10 AND v3<>26 AND v4<91)) OR (v1<>21 AND v2<>24 AND v3<46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 53 (tinyint) AND 65 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 26 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 91 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 24 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 37), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[37, 37], (NULL, 24), (NULL, 46), [NULL, ∞)}, {[37, 37], (24, 53), (NULL, 46), [NULL, ∞)}, {[37, 37], [53, 65], (NULL, ∞), [NULL, ∞)}, {[37, 37], (65, ∞), (NULL, 46), [NULL, ∞)}, {(37, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 37), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[37, 37], (NULL, 24), (NULL, 46), [NULL, ∞)}, {[37, 37], (24, 53), (NULL, 46), [NULL, ∞)}, {[37, 37], [53, 65], (NULL, ∞), [NULL, ∞)}, {[37, 37], (65, ∞), (NULL, 46), [NULL, ∞)}, {(37, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7776,111 +4253,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>91 AND v2=91 AND v3>=15) OR (v1 BETWEEN 16 AND 30)) OR (v1<>27 AND v4=62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v1:1 BETWEEN 16 (tinyint) AND 30 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 27 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 62 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 16), [NULL, 91), [NULL, ∞), [62, 62]}, {(NULL, 16), [91, 91], [NULL, 15), [62, 62]}, {(NULL, 16), [91, 91], [15, ∞), [NULL, ∞)}, {(NULL, 16), (91, ∞), [NULL, ∞), [62, 62]}, {[16, 30], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(30, 91), [NULL, 91), [NULL, ∞), [62, 62]}, {(30, 91), [91, 91], [NULL, 15), [62, 62]}, {(30, 91), [91, 91], [15, ∞), [NULL, ∞)}, {(30, 91), (91, ∞), [NULL, ∞), [62, 62]}, {[91, 91], [NULL, ∞), [NULL, ∞), [62, 62]}, {(91, ∞), [NULL, 91), [NULL, ∞), [62, 62]}, {(91, ∞), [91, 91], [NULL, 15), [62, 62]}, {(91, ∞), [91, 91], [15, ∞), [NULL, ∞)}, {(91, ∞), (91, ∞), [NULL, ∞), [62, 62]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=54 AND v3>26 AND v4>30 AND v2 BETWEEN 3 AND 8) OR (v1>8 AND v2<=43 AND v3<>97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 30 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 3 (tinyint) AND 8 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(8, ∞), (NULL, 43], (NULL, 97), [NULL, ∞)}, {(8, ∞), (NULL, 43], (97, ∞), [NULL, ∞)}, {[54, 54], [3, 8], [97, 97], (30, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(8, ∞), (NULL, 43], (NULL, 97), [NULL, ∞)}, {(8, ∞), (NULL, 43], (97, ∞), [NULL, ∞)}, {[54, 54], [3, 8], [97, 97], (30, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=38 AND v2<>11 AND v3>=26) OR (v1 BETWEEN 37 AND 90 AND v4<85 AND v2<0)) OR (v1<>23));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 38 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 26 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 37 (tinyint) AND 90 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 23 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 23), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(23, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 23), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(23, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7915,71 +4313,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>5 AND v2>8) OR (v1>78 AND v2<=39 AND v3>=41 AND v4<=35)) AND (v1<=11 AND v2<35 AND v3<=10 AND v4<76) OR (v1>=22)) OR (v1=1 AND v4<>29 AND v2 BETWEEN 64 AND 81 AND v3>46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 22 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 29 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 64 (tinyint) AND 81 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[1, 1], [64, 81], (46, ∞), (NULL, 29)}, {[1, 1], [64, 81], (46, ∞), (29, ∞)}, {(5, 11], (8, 35), (NULL, 10], (NULL, 76)}, {[22, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[1, 1], [64, 81], (46, ∞), (NULL, 29)}, {[1, 1], [64, 81], (46, ∞), (29, ∞)}, {(5, 11], (8, 35), (NULL, 10], (NULL, 76)}, {[22, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -7994,48 +4333,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>=72) OR (v1<>17)) OR (v1=47 AND v2<>1 AND v3 BETWEEN 75 AND 78 AND v4 BETWEEN 10 AND 44)) OR (v1>=64 AND v2>=74 AND v3=10 AND v4 BETWEEN 11 AND 93));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 75 (tinyint) AND 78 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 10 (tinyint) AND 44 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 64 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 74 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 11 (tinyint) AND 93 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 17), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(17, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 17), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(17, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8050,184 +4353,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<>11 AND v2>47 AND v3>=67 AND v4=29) OR (v1>=59 AND v3 BETWEEN 4 AND 29 AND v4>=65 AND v2<>96)) OR (v1<=62)) OR (v1<61 AND v2<>28 AND v3<>8 AND v4<>30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 67 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 29 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 4 (tinyint) AND 29 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 62 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 28 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 8 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 30 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 62], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(62, ∞), (NULL, 96), [4, 29], [65, ∞)}, {(62, ∞), (47, ∞), [67, ∞), [29, 29]}, {(62, ∞), (96, ∞), [4, 29], [65, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 62], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(62, ∞), (NULL, 96), [4, 29], [65, ∞)}, {(62, ∞), (47, ∞), [67, ∞), [29, 29]}, {(62, ∞), (96, ∞), [4, 29], [65, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 36 AND 72) OR (v1<>48 AND v4>91 AND v2<5 AND v3>=38)) OR (v1<>17 AND v3=50));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 36 (tinyint) AND 72 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 50 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 17), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[17, 17], (NULL, 5), [38, ∞), (91, ∞)}, {(17, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 17), [NULL, ∞), [50, 50], [NULL, ∞)}, {(NULL, 17), (NULL, 5), [38, 50), (91, ∞)}, {(NULL, 17), (NULL, 5), (50, ∞), (91, ∞)}, {[17, 17], (NULL, 5), [38, ∞), (91, ∞)}, {(17, 36), [NULL, ∞), [50, 50], [NULL, ∞)}, {(17, 36), (NULL, 5), [38, 50), (91, ∞)}, {(17, 36), (NULL, 5), (50, ∞), (91, ∞)}, {[36, 72], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(72, ∞), [NULL, ∞), [50, 50], [NULL, ∞)}, {(72, ∞), (NULL, 5), [38, 50), (91, ∞)}, {(72, ∞), (NULL, 5), (50, ∞), (91, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<86) OR (v1<=5 AND v2<25 AND v3<>24)) OR (v1<32 AND v3 BETWEEN 51 AND 54 AND v4<=70));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 86 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 25 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 24 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 32 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 51 (tinyint) AND 54 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 70 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 86), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 86), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=6) OR (v1 BETWEEN 24 AND 89)) OR (v1<87 AND v2=35 AND v3=19)) AND (v1>94 AND v2=33 AND v3>28) OR (v1 BETWEEN 36 AND 40));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v1:1 BETWEEN 24 (tinyint) AND 89 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 28 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 36 (tinyint) AND 40 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[36, 40], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[36, 40], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8242,44 +4403,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 0 AND 87 AND v2>=44 AND v3<>68 AND v4=50) OR (v1<1 AND v4<66 AND v2<11 AND v3<>44));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 0 (tinyint) AND 87 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 68 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 66 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 44 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 1), (NULL, 11), (NULL, 44), (NULL, 66)}, {(NULL, 1), (NULL, 11), (44, ∞), (NULL, 66)}, {[0, 87], [44, ∞), (NULL, 68), [50, 50]}, {[0, 87], [44, ∞), (68, ∞), [50, 50]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 1), (NULL, 11), (NULL, 44), (NULL, 66)}, {(NULL, 1), (NULL, 11), (44, ∞), (NULL, 66)}, {[0, 87], [44, ∞), (NULL, 68), [50, 50]}, {[0, 87], [44, ∞), (68, ∞), [50, 50]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8304,61 +4433,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 0 AND 39) OR (v1<18 AND v4>=90));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 0 (tinyint) AND 39 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 90 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 39], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 0), [NULL, ∞), [NULL, ∞), [90, ∞)}, {[0, 39], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<99 AND v2>1 AND v3<=56) OR (v1>36 AND v2=53 AND v3>17)) OR (v1<>71)) AND (v1 BETWEEN 2 AND 86 AND v2<>78 AND v3<>29 AND v4<>63);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 56 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 71 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[2, 71), (NULL, 78), (NULL, 29), (NULL, 63)}, {[2, 71), (NULL, 78), (NULL, 29), (63, ∞)}, {[2, 71), (NULL, 78), (29, ∞), (NULL, 63)}, {[2, 71), (NULL, 78), (29, ∞), (63, ∞)}, {[2, 71), (78, ∞), (29, ∞), (NULL, 63)}, {[2, 71), (78, ∞), (29, ∞), (63, ∞)}, {[2, 86], (78, ∞), (NULL, 29), (NULL, 63)}, {[2, 86], (78, ∞), (NULL, 29), (63, ∞)}, {[71, 71], (1, 53), (29, 56], (NULL, 63)}, {[71, 71], (1, 53), (29, 56], (63, ∞)}, {[71, 71], (1, 78), (NULL, 29), (NULL, 63)}, {[71, 71], (1, 78), (NULL, 29), (63, ∞)}, {[71, 71], [53, 53], (29, ∞), (NULL, 63)}, {[71, 71], [53, 53], (29, ∞), (63, ∞)}, {[71, 71], (53, 78), (29, 56], (NULL, 63)}, {[71, 71], (53, 78), (29, 56], (63, ∞)}, {[71, 71], (78, ∞), (29, 56], (NULL, 63)}, {[71, 71], (78, ∞), (29, 56], (63, ∞)}, {(71, 86], (NULL, 78), (NULL, 29), (NULL, 63)}, {(71, 86], (NULL, 78), (NULL, 29), (63, ∞)}, {(71, 86], (NULL, 78), (29, ∞), (NULL, 63)}, {(71, 86], (NULL, 78), (29, ∞), (63, ∞)}, {(71, 86], (78, ∞), (29, ∞), (NULL, 63)}, {(71, 86], (78, ∞), (29, ∞), (63, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[2, 71), (NULL, 78), (NULL, 29), (NULL, 63)}, {[2, 71), (NULL, 78), (NULL, 29), (63, ∞)}, {[2, 71), (NULL, 78), (29, ∞), (NULL, 63)}, {[2, 71), (NULL, 78), (29, ∞), (63, ∞)}, {[2, 71), (78, ∞), (29, ∞), (NULL, 63)}, {[2, 71), (78, ∞), (29, ∞), (63, ∞)}, {[2, 86], (78, ∞), (NULL, 29), (NULL, 63)}, {[2, 86], (78, ∞), (NULL, 29), (63, ∞)}, {[71, 71], (1, 53), (29, 56], (NULL, 63)}, {[71, 71], (1, 53), (29, 56], (63, ∞)}, {[71, 71], (1, 78), (NULL, 29), (NULL, 63)}, {[71, 71], (1, 78), (NULL, 29), (63, ∞)}, {[71, 71], [53, 53], (29, ∞), (NULL, 63)}, {[71, 71], [53, 53], (29, ∞), (63, ∞)}, {[71, 71], (53, 78), (29, 56], (NULL, 63)}, {[71, 71], (53, 78), (29, 56], (63, ∞)}, {[71, 71], (78, ∞), (29, 56], (NULL, 63)}, {[71, 71], (78, ∞), (29, 56], (63, ∞)}, {(71, 86], (NULL, 78), (NULL, 29), (NULL, 63)}, {(71, 86], (NULL, 78), (NULL, 29), (63, ∞)}, {(71, 86], (NULL, 78), (29, ∞), (NULL, 63)}, {(71, 86], (NULL, 78), (29, ∞), (63, ∞)}, {(71, 86], (78, ∞), (29, ∞), (NULL, 63)}, {(71, 86], (78, ∞), (29, ∞), (63, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8373,16 +4463,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<>12 AND v2 BETWEEN 27 AND 46 AND v3 BETWEEN 19 AND 27 AND v4>=50) OR (v1 BETWEEN 17 AND 88)) OR (v1<=36 AND v2<=37 AND v3<64)) OR (v1<>82 AND v2>84 AND v3>=90)) AND (v1>34 AND v3>4);`, - ExpectedPlan: "Filter\n" + - " ├─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 4 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(34, 88], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(88, ∞), [27, 46], [19, 27], [50, ∞)}, {(88, ∞), (84, ∞), [90, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(34, 88], [NULL, ∞), (4, ∞), [NULL, ∞)}, {(88, ∞), [27, 46], [19, 27], [50, ∞)}, {(88, ∞), (84, ∞), [90, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8397,447 +4483,112 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=51) AND (v1=55 AND v2>=59 AND v3>=49) OR (v1>5 AND v2<34));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 59 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 5 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 34 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(5, ∞), (NULL, 34), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(5, ∞), (NULL, 34), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>4 AND v2<=21 AND v3>=15) OR (v1=93 AND v2>=1 AND v3<>63)) OR (v1 BETWEEN 24 AND 86 AND v3<=5));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 21 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 63 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 24 (tinyint) AND 86 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 5 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(4, 24), (NULL, 21], [15, ∞), [NULL, ∞)}, {[24, 86], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(86, 93), (NULL, 21], [15, ∞), [NULL, ∞)}, {[93, 93], (NULL, 1), [15, ∞), [NULL, ∞)}, {[93, 93], [1, 21], (NULL, ∞), [NULL, ∞)}, {[93, 93], (21, ∞), (NULL, 63), [NULL, ∞)}, {[93, 93], (21, ∞), (63, ∞), [NULL, ∞)}, {(93, ∞), (NULL, 21], [15, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(4, 93), (NULL, 21], [15, ∞), [NULL, ∞)}, {[24, 86], [NULL, ∞), (NULL, 5], [NULL, ∞)}, {[93, 93], (NULL, 1), [15, ∞), [NULL, ∞)}, {[93, 93], [1, 21], (NULL, ∞), [NULL, ∞)}, {[93, 93], (21, ∞), (NULL, 63), [NULL, ∞)}, {[93, 93], (21, ∞), (63, ∞), [NULL, ∞)}, {(93, ∞), (NULL, 21], [15, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<63 AND v2<>32 AND v3>=14) OR (v1=18 AND v3 BETWEEN 4 AND 42 AND v4>10)) OR (v1<23 AND v2>=21));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 4 (tinyint) AND 42 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 21 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 18), (NULL, 21), [14, ∞), [NULL, ∞)}, {(NULL, 18), [21, ∞), [NULL, ∞), [NULL, ∞)}, {[18, 18], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(18, 23), (NULL, 21), [14, ∞), [NULL, ∞)}, {(18, 23), [21, ∞), [NULL, ∞), [NULL, ∞)}, {[23, 63), (NULL, 32), [14, ∞), [NULL, ∞)}, {[23, 63), (32, ∞), [14, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 23), (NULL, 21), [14, ∞), [NULL, ∞)}, {(NULL, 23), [21, ∞), [NULL, ∞), [NULL, ∞)}, {[18, 18], [NULL, NULL], [4, 42], (10, ∞)}, {[18, 18], (NULL, 21), [4, 14), (10, ∞)}, {[23, 63), (NULL, 32), [14, ∞), [NULL, ∞)}, {[23, 63), (32, ∞), [14, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>34 AND v3 BETWEEN 27 AND 48 AND v4<=11 AND v2>42) AND (v1<>47 AND v2<48 AND v3<=47 AND v4<>12) OR (v1<=36 AND v2<>17));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 27 (tinyint) AND 48 (tinyint))\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 42 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 17 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 36], (NULL, 17), [NULL, ∞), [NULL, ∞)}, {(NULL, 36], (17, ∞), [NULL, ∞), [NULL, ∞)}, {(36, 47), (42, 48), [27, 47], (NULL, 11]}, {(47, ∞), (42, 48), [27, 47], (NULL, 11]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 36], (NULL, 17), [NULL, ∞), [NULL, ∞)}, {(NULL, 36], (17, ∞), [NULL, ∞), [NULL, ∞)}, {(36, 47), (42, 48), [27, 47], (NULL, 11]}, {(47, ∞), (42, 48), [27, 47], (NULL, 11]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=34 AND v2<=80 AND v3<=27) AND (v1 BETWEEN 0 AND 33) OR (v1<=56 AND v2=50 AND v3 BETWEEN 0 AND 5 AND v4<>31));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 80 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 27 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v1:1 BETWEEN 0 (tinyint) AND 33 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 56 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 0 (tinyint) AND 5 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 31 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 56], [50, 50], [0, 5], (NULL, 31)}, {(NULL, 56], [50, 50], [0, 5], (31, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 56], [50, 50], [0, 5], (NULL, 31)}, {(NULL, 56], [50, 50], [0, 5], (31, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=93 AND v2<>5) OR (v1>=81 AND v4=9 AND v2>33 AND v3<99));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 93 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 5 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 33 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 99 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 93], (NULL, 5), [NULL, ∞), [NULL, ∞)}, {(NULL, 93], (5, ∞), [NULL, ∞), [NULL, ∞)}, {(93, ∞), (33, ∞), (NULL, 99), [9, 9]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 93], (NULL, 5), [NULL, ∞), [NULL, ∞)}, {(NULL, 93], (5, ∞), [NULL, ∞), [NULL, ∞)}, {(93, ∞), (33, ∞), (NULL, 99), [9, 9]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=37 AND v2=4 AND v3=3) AND (v1=12 AND v2>9 AND v3<89 AND v4<>12) OR (v1=1 AND v2=43 AND v3<=2));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 2 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[1, 1], [43, 43], (NULL, 2], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[1, 1], [43, 43], (NULL, 2], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=82) OR (v1<=4 AND v2>=51)) OR (v1=58 AND v4<86));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 82 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 51 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 58 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 86 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 4], [51, ∞), [NULL, ∞), [NULL, ∞)}, {[58, 58], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[82, 82], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 4], [51, ∞), [NULL, ∞), [NULL, ∞)}, {[58, 58], [NULL, ∞), [NULL, ∞), (NULL, 86)}, {[82, 82], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>=42 AND v4<85 AND v2<8 AND v3<3) OR (v1>=78 AND v2<>28 AND v3<52)) OR (v1<8 AND v2<>76 AND v3 BETWEEN 36 AND 70)) OR (v1=70));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ │ └─ 85 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 36 (tinyint) AND 70 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 70 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 8), (NULL, 76), [36, 70], [NULL, ∞)}, {(NULL, 8), (76, ∞), [36, 70], [NULL, ∞)}, {[42, 70), (NULL, 8), (NULL, 3), (NULL, 85)}, {[70, 70], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(70, 78), (NULL, 8), (NULL, 3), (NULL, 85)}, {[78, ∞), (NULL, 28), (NULL, 52), [NULL, ∞)}, {[78, ∞), (28, ∞), (NULL, 52), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 8), (NULL, 76), [36, 70], [NULL, ∞)}, {(NULL, 8), (76, ∞), [36, 70], [NULL, ∞)}, {[42, 70), (NULL, 8), (NULL, 3), (NULL, 85)}, {[70, 70], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(70, 78), (NULL, 8), (NULL, 3), (NULL, 85)}, {[78, ∞), (NULL, 28), (NULL, 52), [NULL, ∞)}, {[78, ∞), (28, ∞), (NULL, 52), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>69) OR (v1>=43));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 69 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 43 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 39 AND 76 AND v4>16 AND v2<>15 AND v3<>35) AND (v1<>50 AND v2>21 AND v3 BETWEEN 27 AND 90 AND v4>18) OR (v1<25 AND v4=58));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 39 (tinyint) AND 76 (tinyint))\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 16 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 15 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 35 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 21 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 27 (tinyint) AND 90 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 58 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 25), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[39, 50), (21, ∞), [27, 35), (18, ∞)}, {[39, 50), (21, ∞), (35, 90], (18, ∞)}, {(50, 76], (21, ∞), [27, 35), (18, ∞)}, {(50, 76], (21, ∞), (35, 90], (18, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 25), [NULL, ∞), [NULL, ∞), [58, 58]}, {[39, 50), (21, ∞), [27, 35), (18, ∞)}, {[39, 50), (21, ∞), (35, 90], (18, ∞)}, {(50, 76], (21, ∞), [27, 35), (18, ∞)}, {(50, 76], (21, ∞), (35, 90], (18, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -8882,179 +4633,52 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=19) AND (v1<=20 AND v2>=2) OR (v1 BETWEEN 12 AND 53 AND v4>=1 AND v2<43 AND v3<59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 20 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 12 (tinyint) AND 53 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[12, 19), (NULL, 43), (NULL, 59), [1, ∞)}, {[19, 19], (NULL, 2), (NULL, 59), [1, ∞)}, {[19, 19], [2, ∞), [NULL, ∞), [NULL, ∞)}, {(19, 53], (NULL, 43), (NULL, 59), [1, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[12, 19), (NULL, 43), (NULL, 59), [1, ∞)}, {[19, 19], (NULL, 2), (NULL, 59), [1, ∞)}, {[19, 19], [2, ∞), [NULL, ∞), [NULL, ∞)}, {(19, 53], (NULL, 43), (NULL, 59), [1, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=42 AND v2<=65) AND (v1<=21) OR (v1<=14 AND v2<>1 AND v3<62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 65 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 21 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 62 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 14], (NULL, 1), (NULL, 62), [NULL, ∞)}, {(NULL, 14], (1, ∞), (NULL, 62), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 14], (NULL, 1), (NULL, 62), [NULL, ∞)}, {(NULL, 14], (1, ∞), (NULL, 62), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>5) OR (v1<96 AND v2>=14)) OR (v1<>96)) AND (v1<>51 AND v3>41);`, - ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 96 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 96 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 51), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(51, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 51), [NULL, ∞), (41, ∞), [NULL, ∞)}, {(51, ∞), [NULL, ∞), (41, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>97 AND v3<>77 AND v4=30 AND v2<>45) OR (v1=36 AND v2<77 AND v3>94)) OR (v1=26));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 97 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 77 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 45 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 94 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 26 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[26, 26], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[36, 36], (NULL, 77), (94, ∞), [NULL, ∞)}, {(97, ∞), (NULL, 45), (NULL, 77), [30, 30]}, {(97, ∞), (NULL, 45), (77, ∞), [30, 30]}, {(97, ∞), (45, ∞), (NULL, 77), [30, 30]}, {(97, ∞), (45, ∞), (77, ∞), [30, 30]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[26, 26], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[36, 36], (NULL, 77), (94, ∞), [NULL, ∞)}, {(97, ∞), (NULL, 45), (NULL, 77), [30, 30]}, {(97, ∞), (NULL, 45), (77, ∞), [30, 30]}, {(97, ∞), (45, ∞), (NULL, 77), [30, 30]}, {(97, ∞), (45, ∞), (77, ∞), [30, 30]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 34 AND 37 AND v3>23 AND v4>31) OR (v1 BETWEEN 43 AND 81 AND v3>=54 AND v4>=72));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 34 (tinyint) AND 37 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 43 (tinyint) AND 81 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 54 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 72 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[34, 37], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[43, 81], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[34, 37], [NULL, ∞), (23, ∞), (31, ∞)}, {[43, 81], [NULL, ∞), [54, ∞), [72, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9079,187 +4703,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=23 AND v2<=48) OR (v1>41 AND v2>=46 AND v3 BETWEEN 11 AND 29)) AND (v1<>11) OR (v1=70 AND v3<54 AND v4<=47 AND v2<>62));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 23 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 11 (tinyint) AND 29 (tinyint))\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 47 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 62 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[23, 23], (NULL, 48], [NULL, ∞), [NULL, ∞)}, {(41, ∞), [46, ∞), [11, 29], [NULL, ∞)}, {[70, 70], (NULL, 46), (NULL, 54), (NULL, 47]}, {[70, 70], [46, 62), (NULL, 11), (NULL, 47]}, {[70, 70], [46, 62), (29, 54), (NULL, 47]}, {[70, 70], (62, ∞), (NULL, 11), (NULL, 47]}, {[70, 70], (62, ∞), (29, 54), (NULL, 47]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[23, 23], (NULL, 48], [NULL, ∞), [NULL, ∞)}, {(41, ∞), [46, ∞), [11, 29], [NULL, ∞)}, {[70, 70], (NULL, 46), (NULL, 54), (NULL, 47]}, {[70, 70], [46, 62), (NULL, 11), (NULL, 47]}, {[70, 70], [46, 62), (29, 54), (NULL, 47]}, {[70, 70], (62, ∞), (NULL, 11), (NULL, 47]}, {[70, 70], (62, ∞), (29, 54), (NULL, 47]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>73) OR (v1>5 AND v2>=7 AND v3>=43 AND v4<=53)) OR (v1<34 AND v2<95 AND v3 BETWEEN 9 AND 81 AND v4<>8)) AND (v1<=68 AND v4>48 AND v2>11 AND v3 BETWEEN 17 AND 89) OR (v1=41 AND v2 BETWEEN 56 AND 93));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 7 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 9 (tinyint) AND 81 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 11 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 17 (tinyint) AND 89 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 56 (tinyint) AND 93 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 34), (11, 95), [17, 81], (48, ∞)}, {(5, 34), (11, 95), (81, 89], (48, 53]}, {(5, 34), [95, ∞), [43, 89], (48, 53]}, {[34, 41), (11, ∞), [43, 89], (48, 53]}, {[41, 41], (11, 56), [43, 89], (48, 53]}, {[41, 41], [56, 93], [NULL, ∞), [NULL, ∞)}, {[41, 41], (93, ∞), [43, 89], (48, 53]}, {(41, 68], (11, ∞), [43, 89], (48, 53]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 34), (11, 95), [17, 81], (48, ∞)}, {(5, 34), (11, 95), (81, 89], (48, 53]}, {(5, 34), [95, ∞), [43, 89], (48, 53]}, {[34, 41), (11, ∞), [43, 89], (48, 53]}, {[41, 41], (11, 56), [43, 89], (48, 53]}, {[41, 41], [56, 93], [NULL, ∞), [NULL, ∞)}, {[41, 41], (93, ∞), [43, 89], (48, 53]}, {(41, 68], (11, ∞), [43, 89], (48, 53]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>3 AND v3>=34) OR (v1<>31 AND v2<16 AND v3<8));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 3 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 34 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 16 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 8 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 3), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[3, 3], (NULL, 16), (NULL, 8), [NULL, ∞)}, {(3, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 3), [NULL, ∞), [34, ∞), [NULL, ∞)}, {(NULL, 31), (NULL, 16), (NULL, 8), [NULL, ∞)}, {(3, ∞), [NULL, ∞), [34, ∞), [NULL, ∞)}, {(31, ∞), (NULL, 16), (NULL, 8), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 88 AND 97) OR (v1>67 AND v4<=27 AND v2<5 AND v3>40)) OR (v1 BETWEEN 5 AND 83 AND v2>=34 AND v3=59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 88 (tinyint) AND 97 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 67 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 27 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 5 (tinyint) AND 83 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 34 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 83], [34, ∞), [59, 59], [NULL, ∞)}, {(67, 88), (NULL, 5), (40, ∞), (NULL, 27]}, {[88, 97], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(97, ∞), (NULL, 5), (40, ∞), (NULL, 27]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 83], [34, ∞), [59, 59], [NULL, ∞)}, {(67, 88), (NULL, 5), (40, ∞), (NULL, 27]}, {[88, 97], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(97, ∞), (NULL, 5), (40, ∞), (NULL, 27]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9304,124 +4783,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>70) OR (v1<>2 AND v2>79 AND v3<>6 AND v4<>42));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 79 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 6 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 42 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 70), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[70, 70], (79, ∞), (NULL, 6), (NULL, 42)}, {[70, 70], (79, ∞), (NULL, 6), (42, ∞)}, {[70, 70], (79, ∞), (6, ∞), (NULL, 42)}, {[70, 70], (79, ∞), (6, ∞), (42, ∞)}, {(70, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 70), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[70, 70], (79, ∞), (NULL, 6), (NULL, 42)}, {[70, 70], (79, ∞), (NULL, 6), (42, ∞)}, {[70, 70], (79, ∞), (6, ∞), (NULL, 42)}, {[70, 70], (79, ∞), (6, ∞), (42, ∞)}, {(70, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>46 AND v2>93 AND v3>19) AND (v1<51 AND v2=39) OR (v1<61)) AND (v1<>22);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 39 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 61 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 22), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(22, 61), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 22), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(22, 61), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<=53 AND v2>0 AND v3=95 AND v4<=2) OR (v1<41 AND v4<10 AND v2 BETWEEN 11 AND 35)) OR (v1=11 AND v2<20 AND v3=51 AND v4<>30));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 2 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 11 (tinyint) AND 35 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 20 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 51 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 30 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 41), (0, 11), [95, 95], (NULL, 2]}, {(NULL, 41), [11, 35], [NULL, ∞), [NULL, ∞)}, {(NULL, 41), (35, ∞), [95, 95], (NULL, 2]}, {[11, 11], (NULL, 11), [51, 51], (NULL, 30)}, {[11, 11], (NULL, 11), [51, 51], (30, ∞)}, {[41, 53], (0, ∞), [95, 95], (NULL, 2]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 11), [11, 35], [NULL, ∞), (NULL, 10)}, {(NULL, 41), (0, 11), [95, 95], (NULL, 2]}, {(NULL, 41), (35, ∞), [95, 95], (NULL, 2]}, {[11, 11], (NULL, 20), [51, 51], (NULL, 30)}, {[11, 11], (NULL, 20), [51, 51], (30, ∞)}, {[11, 11], [11, 20), [NULL, 51), (NULL, 10)}, {[11, 11], [11, 20), (51, ∞), (NULL, 10)}, {[11, 11], [20, 35], [NULL, ∞), (NULL, 10)}, {(11, 41), [11, 35], [NULL, ∞), (NULL, 10)}, {[41, 53], (0, ∞), [95, 95], (NULL, 2]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9456,65 +4843,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=59) OR (v1<>85 AND v4<6 AND v2 BETWEEN 14 AND 82));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 59 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 6 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 14 (tinyint) AND 82 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 59), [14, 82], [NULL, ∞), [NULL, ∞)}, {[59, 59], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(59, 85), [14, 82], [NULL, ∞), [NULL, ∞)}, {(85, ∞), [14, 82], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 59), [14, 82], [NULL, ∞), (NULL, 6)}, {[59, 59], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(59, 85), [14, 82], [NULL, ∞), (NULL, 6)}, {(85, ∞), [14, 82], [NULL, ∞), (NULL, 6)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=94 AND v2>32 AND v3>61) OR (v1>51 AND v4>84 AND v2>=46)) OR (v1=39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 61 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 84 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 46 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[39, 39], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(51, ∞), [46, ∞), [NULL, ∞), [NULL, ∞)}, {[94, ∞), (32, 46), (61, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[39, 39], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(51, 94), [46, ∞), [NULL, ∞), (84, ∞)}, {[94, ∞), (32, ∞), (61, ∞), [NULL, ∞)}, {[94, ∞), [46, ∞), [NULL, 61], (84, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9539,146 +4883,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<=31 AND v4>30 AND v2<>38) OR (v1<>35)) OR (v1<=8 AND v2<43 AND v3<=50 AND v4<=33));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 38 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 43 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 33 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 35), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(35, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 35), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(35, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((((v1>65 AND v2=89 AND v3>12) OR (v1 BETWEEN 37 AND 75 AND v2=42 AND v3<=14)) OR (v1>=87 AND v2=85)) OR (v1<>48 AND v4 BETWEEN 32 AND 33 AND v2>21 AND v3<=25)) OR (v1 BETWEEN 51 AND 88 AND v2<>67));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 37 (tinyint) AND 75 (tinyint))\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 32 (tinyint) AND 33 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 51 (tinyint) AND 88 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 67 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 37), (21, ∞), (NULL, 25], [32, 33]}, {[37, 48), (21, 42), (NULL, 25], [32, 33]}, {[37, 48), [42, 42], (14, 25], [32, 33]}, {[37, 48), (42, ∞), (NULL, 25], [32, 33]}, {[37, 51), [42, 42], (NULL, 14], [NULL, ∞)}, {(48, 51), (21, 42), (NULL, 25], [32, 33]}, {(48, 51), [42, 42], (14, 25], [32, 33]}, {(48, 51), (42, ∞), (NULL, 25], [32, 33]}, {[51, 88], (NULL, 67), [NULL, ∞), [NULL, ∞)}, {[51, 88], [67, 67], (NULL, 25], [32, 33]}, {[51, 88], (67, ∞), [NULL, ∞), [NULL, ∞)}, {(88, ∞), (21, 85), (NULL, 25], [32, 33]}, {(88, ∞), [85, 85], [NULL, ∞), [NULL, ∞)}, {(88, ∞), (85, 89), (NULL, 25], [32, 33]}, {(88, ∞), [89, 89], (NULL, 12], [32, 33]}, {(88, ∞), [89, 89], (12, ∞), [NULL, ∞)}, {(88, ∞), (89, ∞), (NULL, 25], [32, 33]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 37), (21, ∞), (NULL, 25], [32, 33]}, {[37, 48), (21, 42), (NULL, 25], [32, 33]}, {[37, 48), [42, 42], (14, 25], [32, 33]}, {[37, 48), (42, ∞), (NULL, 25], [32, 33]}, {[37, 51), [42, 42], (NULL, 14], [NULL, ∞)}, {(48, 51), (21, 42), (NULL, 25], [32, 33]}, {(48, 51), [42, 42], (14, 25], [32, 33]}, {(48, 51), (42, ∞), (NULL, 25], [32, 33]}, {[51, 88], (NULL, 67), [NULL, ∞), [NULL, ∞)}, {[51, 88], [67, 67], (NULL, 25], [32, 33]}, {[51, 88], (67, ∞), [NULL, ∞), [NULL, ∞)}, {(88, ∞), (21, 85), (NULL, 25], [32, 33]}, {(88, ∞), [85, 85], [NULL, ∞), [NULL, ∞)}, {(88, ∞), (85, 89), (NULL, 25], [32, 33]}, {(88, ∞), [89, 89], (NULL, 12], [32, 33]}, {(88, ∞), [89, 89], (12, ∞), [NULL, ∞)}, {(88, ∞), (89, ∞), (NULL, 25], [32, 33]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>82) OR (v1<1 AND v3>=22)) AND (v1=4) OR (v1>27 AND v2 BETWEEN 7 AND 79 AND v3 BETWEEN 9 AND 29 AND v4<85));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 4 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 27 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 7 (tinyint) AND 79 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 9 (tinyint) AND 29 (tinyint))\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 85 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(27, ∞), [7, 79], [9, 29], (NULL, 85)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(27, ∞), [7, 79], [9, 29], (NULL, 85)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9703,35 +4933,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<59) OR (v1 BETWEEN 6 AND 86 AND v4<97)) OR (v1<>90 AND v2=43 AND v3=29));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 59 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 6 (tinyint) AND 86 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 97 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 90 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 29 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 86], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(86, 90), [43, 43], [29, 29], [NULL, ∞)}, {(90, ∞), [43, 43], [29, 29], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 59), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[59, 86], [NULL, 43), [NULL, ∞), (NULL, 97)}, {[59, 86], [43, 43], [NULL, 29), (NULL, 97)}, {[59, 86], [43, 43], (29, ∞), (NULL, 97)}, {[59, 86], (43, ∞), [NULL, ∞), (NULL, 97)}, {[59, 90), [43, 43], [29, 29], [NULL, ∞)}, {(90, ∞), [43, 43], [29, 29], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9756,83 +4963,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>35 AND v2>=14 AND v3<65 AND v4<>9) OR (v1<>14 AND v3<51 AND v4<32)) OR (v1>=21 AND v3<>25 AND v4<>16));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 16 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 14), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[14, 14], [14, ∞), (NULL, 65), (NULL, 9)}, {[14, 14], [14, ∞), (NULL, 65), (9, ∞)}, {(14, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 14), [NULL, 14), (NULL, 51), (NULL, 32)}, {(NULL, 14), [14, ∞), (NULL, 51), (NULL, ∞)}, {(NULL, 14), [14, ∞), [51, 65), (NULL, 9)}, {(NULL, 14), [14, ∞), [51, 65), (9, ∞)}, {[14, 14], [14, ∞), (NULL, 65), (NULL, 9)}, {[14, 14], [14, ∞), (NULL, 65), (9, ∞)}, {(14, 21), [NULL, 14), (NULL, 51), (NULL, 32)}, {(14, 21), [14, ∞), (NULL, 51), (NULL, ∞)}, {(14, 21), [14, ∞), [51, 65), (NULL, 9)}, {(14, 21), [14, ∞), [51, 65), (9, ∞)}, {[21, 35), [NULL, 14), [25, 25], (NULL, 32)}, {[21, 35), [NULL, 14), (25, 51), (NULL, ∞)}, {[21, 35), [NULL, 14), [51, ∞), (NULL, 16)}, {[21, 35), [NULL, 14), [51, ∞), (16, ∞)}, {[21, 35), [14, ∞), [25, 65), (NULL, ∞)}, {[21, 35), [14, ∞), [65, ∞), (NULL, 16)}, {[21, 35), [14, ∞), [65, ∞), (16, ∞)}, {[21, 35], [NULL, ∞), (NULL, 25), (NULL, ∞)}, {[35, 35], [NULL, ∞), [25, 25], (NULL, 32)}, {[35, 35], [NULL, ∞), (25, 51), (NULL, ∞)}, {[35, 35], [NULL, ∞), [51, ∞), (NULL, 16)}, {[35, 35], [NULL, ∞), [51, ∞), (16, ∞)}, {(35, ∞), [NULL, 14), (NULL, 25), (NULL, ∞)}, {(35, ∞), [NULL, 14), [25, 25], (NULL, 32)}, {(35, ∞), [NULL, 14), (25, 51), (NULL, ∞)}, {(35, ∞), [NULL, 14), [51, ∞), (NULL, 16)}, {(35, ∞), [NULL, 14), [51, ∞), (16, ∞)}, {(35, ∞), [14, ∞), (NULL, 65), (NULL, ∞)}, {(35, ∞), [14, ∞), [65, ∞), (NULL, 16)}, {(35, ∞), [14, ∞), [65, ∞), (16, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>12 AND v2<0) OR (v1=36 AND v3<37));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 12 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 37 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(12, 36), (NULL, 0), [NULL, ∞), [NULL, ∞)}, {[36, 36], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(36, ∞), (NULL, 0), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(12, ∞), (NULL, 0), [NULL, ∞), [NULL, ∞)}, {[36, 36], [NULL, NULL], (NULL, 37), [NULL, ∞)}, {[36, 36], [0, ∞), (NULL, 37), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9877,39 +5023,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=19 AND v4<>62 AND v2<>19 AND v3<>29) OR (v1 BETWEEN 37 AND 75 AND v4<23 AND v2 BETWEEN 6 AND 43));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 19 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 29 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 37 (tinyint) AND 75 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 6 (tinyint) AND 43 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[19, 37), (NULL, 19), (NULL, 29), (NULL, 62)}, {[19, 37), (NULL, 19), (NULL, 29), (62, ∞)}, {[19, 37), (NULL, 19), (29, ∞), (NULL, 62)}, {[19, 37), (NULL, 19), (29, ∞), (62, ∞)}, {[19, 37), (19, ∞), (NULL, 29), (NULL, 62)}, {[19, 37), (19, ∞), (NULL, 29), (62, ∞)}, {[19, 37), (19, ∞), (29, ∞), (NULL, 62)}, {[19, 37), (19, ∞), (29, ∞), (62, ∞)}, {[37, 75], (NULL, 6), (NULL, 29), (NULL, 62)}, {[37, 75], (NULL, 6), (NULL, 29), (62, ∞)}, {[37, 75], (NULL, 6), (29, ∞), (NULL, 62)}, {[37, 75], (NULL, 6), (29, ∞), (62, ∞)}, {[37, 75], [6, 43], [NULL, ∞), [NULL, ∞)}, {[37, 75], (43, ∞), (NULL, 29), (NULL, 62)}, {[37, 75], (43, ∞), (NULL, 29), (62, ∞)}, {[37, 75], (43, ∞), (29, ∞), (NULL, 62)}, {[37, 75], (43, ∞), (29, ∞), (62, ∞)}, {(75, ∞), (NULL, 19), (NULL, 29), (NULL, 62)}, {(75, ∞), (NULL, 19), (NULL, 29), (62, ∞)}, {(75, ∞), (NULL, 19), (29, ∞), (NULL, 62)}, {(75, ∞), (NULL, 19), (29, ∞), (62, ∞)}, {(75, ∞), (19, ∞), (NULL, 29), (NULL, 62)}, {(75, ∞), (19, ∞), (NULL, 29), (62, ∞)}, {(75, ∞), (19, ∞), (29, ∞), (NULL, 62)}, {(75, ∞), (19, ∞), (29, ∞), (62, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[19, ∞), (NULL, 19), (NULL, 29), (NULL, 62)}, {[19, ∞), (NULL, 19), (NULL, 29), (62, ∞)}, {[19, ∞), (NULL, 19), (29, ∞), (NULL, 62)}, {[19, ∞), (NULL, 19), (29, ∞), (62, ∞)}, {[19, ∞), (19, ∞), (NULL, 29), (NULL, 62)}, {[19, ∞), (19, ∞), (NULL, 29), (62, ∞)}, {[19, ∞), (19, ∞), (29, ∞), (NULL, 62)}, {[19, ∞), (19, ∞), (29, ∞), (62, ∞)}, {[37, 75], [6, 19), [NULL, NULL], (NULL, 23)}, {[37, 75], [6, 19), [29, 29], (NULL, 23)}, {[37, 75], [19, 19], [NULL, ∞), (NULL, 23)}, {[37, 75], (19, 43], [NULL, NULL], (NULL, 23)}, {[37, 75], (19, 43], [29, 29], (NULL, 23)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -9924,71 +5043,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=69 AND v2<8) AND (v1>=34 AND v2>=99 AND v3>96 AND v4 BETWEEN 36 AND 99) OR (v1=0 AND v2>=71));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 69 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 36 (tinyint) AND 99 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 71 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[0, 0], [71, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[0, 0], [71, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 20 AND 54 AND v2<>31 AND v3 BETWEEN 15 AND 21) OR (v1<=46 AND v3>76)) OR (v1 BETWEEN 31 AND 71));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 20 (tinyint) AND 54 (tinyint))\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 15 (tinyint) AND 21 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 76 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 31 (tinyint) AND 71 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 71], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 31), [NULL, ∞), (76, ∞), [NULL, ∞)}, {[20, 31), (NULL, 31), [15, 21], [NULL, ∞)}, {[20, 31), (31, ∞), [15, 21], [NULL, ∞)}, {[31, 71], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10013,42 +5083,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=99 AND v2>=85) AND (v1<=83 AND v2=99) OR (v1<=6 AND v2 BETWEEN 36 AND 68 AND v3>62 AND v4=79));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 83 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 99 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 36 (tinyint) AND 68 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 62 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 79 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 6], [36, 68], (62, ∞), [79, 79]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 6], [36, 68], (62, ∞), [79, 79]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10083,33 +5123,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>18) OR (v1>=42 AND v2<=65 AND v3=87 AND v4=80));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 65 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 87 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 80 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 18), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(18, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 18), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(18, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10124,95 +5143,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>71 AND v4>0) OR (v1<48 AND v2=89 AND v3>=46 AND v4<=32)) OR (v1<62 AND v2>=33 AND v3>58)) OR (v1>=31 AND v3<>71));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 71 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 32 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 58 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 71 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 31), [33, ∞), (58, ∞), [NULL, ∞)}, {(NULL, 31), [89, 89], [46, 58], (NULL, 32]}, {[31, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 31), [33, ∞), (58, ∞), [NULL, ∞)}, {(NULL, 31), [89, 89], [46, 58], (NULL, 32]}, {[31, 62), [NULL, 33), (NULL, 71), [NULL, ∞)}, {[31, 62), [NULL, 33), (71, ∞), [NULL, ∞)}, {[31, 62), [33, ∞), (NULL, ∞), [NULL, ∞)}, {[62, ∞), [NULL, ∞), (NULL, 71), [NULL, ∞)}, {[62, ∞), [NULL, ∞), (71, ∞), [NULL, ∞)}, {(71, ∞), [NULL, ∞), [NULL, NULL], (0, ∞)}, {(71, ∞), [NULL, ∞), [71, 71], (0, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 9 AND 40 AND v3<=43 AND v4=62 AND v2>=43) OR (v1=61 AND v2>12 AND v3 BETWEEN 0 AND 13 AND v4>=8));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 9 (tinyint) AND 40 (tinyint))\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 62 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 12 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 0 (tinyint) AND 13 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 8 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[9, 40], [43, ∞), (NULL, 43], [62, 62]}, {[61, 61], (12, ∞), [0, 13], [8, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[9, 40], [43, ∞), (NULL, 43], [62, 62]}, {[61, 61], (12, ∞), [0, 13], [8, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10237,90 +5183,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=9 AND v4=22 AND v2>=95) OR (v1>96));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 95 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 96 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 9], [95, ∞), [NULL, ∞), [NULL, ∞)}, {(96, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 9], [95, ∞), [NULL, ∞), [22, 22]}, {(96, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<=56) OR (v1>=31 AND v4<38 AND v2>20)) OR (v1=91 AND v2<48));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 56 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 38 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 20 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 91 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 48 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 56], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(56, 91), (20, ∞), [NULL, ∞), [NULL, ∞)}, {[91, 91], (NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(91, ∞), (20, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 56], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(56, 91), (20, ∞), [NULL, ∞), (NULL, 38)}, {[91, 91], (NULL, 48), [NULL, ∞), [NULL, ∞)}, {[91, 91], [48, ∞), [NULL, ∞), (NULL, 38)}, {(91, ∞), (20, ∞), [NULL, ∞), (NULL, 38)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=75 AND v4<=30) OR (v1>=41 AND v2 BETWEEN 16 AND 25 AND v3>=99));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 75 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 30 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 41 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 16 (tinyint) AND 25 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 99 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 75], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(75, ∞), [16, 25], [99, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 41), [NULL, ∞), [NULL, ∞), (NULL, 30]}, {[41, 75], [NULL, 16), [NULL, ∞), (NULL, 30]}, {[41, 75], [16, 25], [NULL, 99), (NULL, 30]}, {[41, 75], (25, ∞), [NULL, ∞), (NULL, 30]}, {[41, ∞), [16, 25], [99, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10385,71 +5273,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>84 AND v4<=53 AND v2=77 AND v3>=40) OR (v1>78 AND v2<>1 AND v3=98 AND v4>=76));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 98 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 76 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(78, ∞), (NULL, 1), [98, 98], [76, ∞)}, {(78, ∞), (1, ∞), [98, 98], [76, ∞)}, {(84, ∞), [77, 77], [40, ∞), (NULL, 53]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(78, ∞), (NULL, 1), [98, 98], [76, ∞)}, {(78, ∞), (1, ∞), [98, 98], [76, ∞)}, {(84, ∞), [77, 77], [40, ∞), (NULL, 53]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>79 AND v2<=85) OR (v1<>13)) OR (v1 BETWEEN 4 AND 67));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 4 (tinyint) AND 67 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10464,147 +5303,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((((v1<65) OR (v1<>44)) OR (v1<=39 AND v3>=14)) OR (v1<=33 AND v2<>11)) OR (v1=75 AND v2=0 AND v3<28));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 75 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 28 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>50 AND v2>=46) AND (v1<>17 AND v2=45 AND v3<=79) OR (v1=10 AND v2>=35)) AND (v1=44 AND v2=38);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 17 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 45 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 79 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 10 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 35 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<34) OR (v1<=62 AND v4<>18 AND v2 BETWEEN 1 AND 41)) OR (v1>=65 AND v2>=93 AND v3 BETWEEN 34 AND 41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 34 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 18 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 1 (tinyint) AND 41 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 65 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 93 (tinyint)\n" + - " │ └─ (comp_index_t2.v3:3 BETWEEN 34 (tinyint) AND 41 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 34), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[34, 62], [1, 41], [NULL, ∞), [NULL, ∞)}, {[65, ∞), [93, ∞), [34, 41], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 34), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[34, 62], [1, 41], [NULL, ∞), (NULL, 18)}, {[34, 62], [1, 41], [NULL, ∞), (18, ∞)}, {[65, ∞), [93, ∞), [34, 41], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>8) OR (v1>20 AND v4>=99));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 8 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 20 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 99 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(8, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(8, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10639,34 +5373,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>5 AND v3<>53 AND v4>=49) OR (v1<18 AND v2<94));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 94 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 5), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[5, 5], (NULL, 94), [NULL, ∞), [NULL, ∞)}, {(5, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 5), [NULL, NULL], (NULL, 53), [49, ∞)}, {(NULL, 5), [NULL, NULL], (53, ∞), [49, ∞)}, {(NULL, 5), [94, ∞), (NULL, 53), [49, ∞)}, {(NULL, 5), [94, ∞), (53, ∞), [49, ∞)}, {(NULL, 18), (NULL, 94), [NULL, ∞), [NULL, ∞)}, {(5, 18), [NULL, NULL], (NULL, 53), [49, ∞)}, {(5, 18), [NULL, NULL], (53, ∞), [49, ∞)}, {(5, 18), [94, ∞), (NULL, 53), [49, ∞)}, {(5, 18), [94, ∞), (53, ∞), [49, ∞)}, {[18, ∞), [NULL, ∞), (NULL, 53), [49, ∞)}, {[18, ∞), [NULL, ∞), (53, ∞), [49, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10681,51 +5393,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>28 AND v4>57 AND v2<62 AND v3 BETWEEN 14 AND 41) AND (v1<>72 AND v2>=13 AND v3>29 AND v4>38) OR (v1<=22 AND v2>58));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 57 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 14 (tinyint) AND 41 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 29 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 22 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 58 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 22], (58, ∞), [NULL, ∞), [NULL, ∞)}, {(28, 72), [13, 62), (29, 41], (57, ∞)}, {(72, ∞), [13, 62), (29, 41], (57, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 22], (58, ∞), [NULL, ∞), [NULL, ∞)}, {(28, 72), [13, 62), (29, 41], (57, ∞)}, {(72, ∞), [13, 62), (29, 41], (57, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10740,37 +5413,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>35 AND v4<>20 AND v2<81 AND v3=27) OR (v1>13 AND v3=27));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 20 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 81 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 27 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 27 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(13, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(13, ∞), [NULL, ∞), [27, 27], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10805,47 +5453,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=86 AND v2<5 AND v3<36 AND v4<81) OR (v1>=52 AND v2>24 AND v3<5)) OR (v1 BETWEEN 5 AND 80 AND v3<>80));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 86 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 81 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 24 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 5 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 5 (tinyint) AND 80 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 80 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 80], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(80, ∞), (24, ∞), (NULL, 5), [NULL, ∞)}, {[86, 86], (NULL, 5), (NULL, 36), (NULL, 81)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 80], [NULL, ∞), (NULL, 80), [NULL, ∞)}, {[5, 80], [NULL, ∞), (80, ∞), [NULL, ∞)}, {(80, ∞), (24, ∞), (NULL, 5), [NULL, ∞)}, {[86, 86], (NULL, 5), (NULL, 36), (NULL, 81)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -10860,129 +5473,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>31) OR (v1 BETWEEN 27 AND 87 AND v2=71 AND v3=38 AND v4=1));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 27 (tinyint) AND 87 (tinyint))\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 71 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 38 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 1 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 31), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[31, 31], [71, 71], [38, 38], [1, 1]}, {(31, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 31), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[31, 31], [71, 71], [38, 38], [1, 1]}, {(31, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>2 AND v4=0 AND v2 BETWEEN 6 AND 23 AND v3 BETWEEN 46 AND 52) OR (v1<=63 AND v2>=71 AND v3=28)) AND (v1<=52);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 0 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 6 (tinyint) AND 23 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 46 (tinyint) AND 52 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 71 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 28 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 52], [71, ∞), [28, 28], [NULL, ∞)}, {(2, 52], [6, 23], [46, 52], [0, 0]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 52], [71, ∞), [28, 28], [NULL, ∞)}, {(2, 52], [6, 23], [46, 52], [0, 0]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (v1 BETWEEN 10 AND 90) AND (v1=86 AND v4>=4) AND (v1 BETWEEN 6 AND 58 AND v2=85);`, - ExpectedPlan: "Filter\n" + - " ├─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 4 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=46 AND v4>41 AND v2<>12) OR (v1>17 AND v2>=34 AND v3<>68 AND v4<=13)) OR (v1>=98 AND v4 BETWEEN 3 AND 62 AND v2=39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 12 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 17 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 68 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 3 (tinyint) AND 62 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(17, 46), [34, ∞), (NULL, 68), (NULL, 13]}, {(17, 46), [34, ∞), (68, ∞), (NULL, 13]}, {[46, 46], (NULL, 12), [NULL, ∞), [NULL, ∞)}, {[46, 46], (12, ∞), [NULL, ∞), [NULL, ∞)}, {(46, 98), [34, ∞), (NULL, 68), (NULL, 13]}, {(46, 98), [34, ∞), (68, ∞), (NULL, 13]}, {[98, ∞), [34, 39), (NULL, 68), (NULL, 13]}, {[98, ∞), [34, 39), (68, ∞), (NULL, 13]}, {[98, ∞), [39, 39], [NULL, ∞), [NULL, ∞)}, {[98, ∞), (39, ∞), (NULL, 68), (NULL, 13]}, {[98, ∞), (39, ∞), (68, ∞), (NULL, 13]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(17, 98), [34, ∞), (NULL, 68), (NULL, 13]}, {(17, 98), [34, ∞), (68, ∞), (NULL, 13]}, {[46, 46], (NULL, 12), [NULL, ∞), (41, ∞)}, {[46, 46], (12, ∞), [NULL, ∞), (41, ∞)}, {[98, ∞), [34, 39), (NULL, 68), (NULL, 13]}, {[98, ∞), [34, 39), (68, ∞), (NULL, 13]}, {[98, ∞), [39, 39], [NULL, NULL], [3, 62]}, {[98, ∞), [39, 39], (NULL, 68), (NULL, 62]}, {[98, ∞), [39, 39], [68, 68], [3, 62]}, {[98, ∞), [39, 39], (68, ∞), (NULL, 62]}, {[98, ∞), (39, ∞), (NULL, 68), (NULL, 13]}, {[98, ∞), (39, ∞), (68, ∞), (NULL, 13]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11007,49 +5533,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 66 AND 76 AND v2>=84 AND v3>1 AND v4 BETWEEN 71 AND 95) AND (v1>36 AND v2<>41) OR (v1<44 AND v2<=50 AND v3=36 AND v4<=42));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 66 (tinyint) AND 76 (tinyint))\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 71 (tinyint) AND 95 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 36 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 44 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 42 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 44), (NULL, 50], [36, 36], (NULL, 42]}, {[66, 76], [84, ∞), (1, ∞), [71, 95]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 44), (NULL, 50], [36, 36], (NULL, 42]}, {[66, 76], [84, ∞), (1, ∞), [71, 95]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11084,64 +5573,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>22 AND v3<>49) OR (v1>=41 AND v2<=74 AND v3<=46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 41 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 74 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 22), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(22, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 22), [NULL, ∞), (NULL, 49), [NULL, ∞)}, {(NULL, 22), [NULL, ∞), (49, ∞), [NULL, ∞)}, {(22, ∞), [NULL, ∞), (NULL, 49), [NULL, ∞)}, {(22, ∞), [NULL, ∞), (49, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=82 AND v4<=67 AND v2=40) OR (v1>63)) OR (v1<=16));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 67 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 40 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 63 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 16 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 16], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(63, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 16], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(63, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11176,30 +5623,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 4 AND 8 AND v3>=12) OR (v1>=12 AND v2>=0 AND v3=18));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 4 (tinyint) AND 8 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 12 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 18 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[4, 8], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[12, ∞), [0, ∞), [18, 18], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[4, 8], [NULL, ∞), [12, ∞), [NULL, ∞)}, {[12, ∞), [0, ∞), [18, 18], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11224,36 +5653,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>9 AND v4<>61 AND v2=98 AND v3<1) OR (v1<2 AND v2 BETWEEN 3 AND 70));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 61 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 3 (tinyint) AND 70 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 2), [3, 70], [NULL, ∞), [NULL, ∞)}, {(NULL, 9), [98, 98], (NULL, 1), (NULL, 61)}, {(NULL, 9), [98, 98], (NULL, 1), (61, ∞)}, {(9, ∞), [98, 98], (NULL, 1), (NULL, 61)}, {(9, ∞), [98, 98], (NULL, 1), (61, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 2), [3, 70], [NULL, ∞), [NULL, ∞)}, {(NULL, 9), [98, 98], (NULL, 1), (NULL, 61)}, {(NULL, 9), [98, 98], (NULL, 1), (61, ∞)}, {(9, ∞), [98, 98], (NULL, 1), (NULL, 61)}, {(9, ∞), [98, 98], (NULL, 1), (61, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11288,67 +5693,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>53 AND v4<99 AND v2<>31) OR (v1<>5 AND v2>70 AND v3>=71));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 99 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 70 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 71 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 53), (NULL, 31), [NULL, ∞), [NULL, ∞)}, {(NULL, 53), (31, ∞), [NULL, ∞), [NULL, ∞)}, {[53, 53], (70, ∞), [71, ∞), [NULL, ∞)}, {(53, ∞), (NULL, 31), [NULL, ∞), [NULL, ∞)}, {(53, ∞), (31, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 5), (31, 70], [NULL, ∞), (NULL, 99)}, {(NULL, 5), (70, ∞), [NULL, 71), (NULL, 99)}, {(NULL, 5), (70, ∞), [71, ∞), [NULL, ∞)}, {(NULL, 53), (NULL, 31), [NULL, ∞), (NULL, 99)}, {[5, 5], (31, ∞), [NULL, ∞), (NULL, 99)}, {(5, 53), (31, 70], [NULL, ∞), (NULL, 99)}, {(5, 53), (70, ∞), [NULL, 71), (NULL, 99)}, {(5, ∞), (70, ∞), [71, ∞), [NULL, ∞)}, {(53, ∞), (NULL, 31), [NULL, ∞), (NULL, 99)}, {(53, ∞), (31, 70], [NULL, ∞), (NULL, 99)}, {(53, ∞), (70, ∞), [NULL, 71), (NULL, 99)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>1 AND v4=93) OR (v1<10 AND v2 BETWEEN 40 AND 74 AND v3>=27));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 93 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 40 (tinyint) AND 74 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 27 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 1], [40, 74], [27, ∞), [NULL, ∞)}, {(1, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 10), [40, 74], [27, ∞), [NULL, ∞)}, {(1, 10), [NULL, 40), [NULL, ∞), [93, 93]}, {(1, 10), [40, 74], [NULL, 27), [93, 93]}, {(1, 10), (74, ∞), [NULL, ∞), [93, 93]}, {[10, ∞), [NULL, ∞), [NULL, ∞), [93, 93]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11363,72 +5723,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 16 AND 31 AND v4 BETWEEN 18 AND 96) OR (v1=40 AND v2<=35 AND v3>=51 AND v4>=83));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 16 (tinyint) AND 31 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 18 (tinyint) AND 96 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 35 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 51 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 83 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[16, 31], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[40, 40], (NULL, 35], [51, ∞), [83, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[16, 31], [NULL, ∞), [NULL, ∞), [18, 96]}, {[40, 40], (NULL, 35], [51, ∞), [83, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 68 AND 78 AND v2>96 AND v3<58 AND v4<14) OR (v1=71)) AND (v1>15 AND v2>=19) OR (v1>36));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 68 (tinyint) AND 78 (tinyint))\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 96 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 58 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 71 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 36 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(36, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(36, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11453,68 +5763,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=47 AND v4=13) AND (v1<=27 AND v3<54 AND v4 BETWEEN 27 AND 40) OR (v1>=40 AND v4=98 AND v2=25 AND v3>66));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 13 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 27 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 27 (tinyint) AND 40 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 40 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 66 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[40, ∞), [25, 25], (66, ∞), [98, 98]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[40, ∞), [25, 25], (66, ∞), [98, 98]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<98 AND v3 BETWEEN 80 AND 82) OR (v1 BETWEEN 31 AND 38 AND v2=39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 80 (tinyint) AND 82 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 31 (tinyint) AND 38 (tinyint))\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 98), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 31), [NULL, ∞), [80, 82], [NULL, ∞)}, {[31, 38], [NULL, 39), [80, 82], [NULL, ∞)}, {[31, 38], [39, 39], [NULL, ∞), [NULL, ∞)}, {[31, 38], (39, ∞), [80, 82], [NULL, ∞)}, {(38, 98), [NULL, ∞), [80, 82], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11529,53 +5793,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=40) OR (v1<>32 AND v4<=37));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 37 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 32), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(32, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 32), [NULL, ∞), [NULL, ∞), (NULL, 37]}, {(32, 40), [NULL, ∞), [NULL, ∞), (NULL, 37]}, {[40, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>63 AND v3 BETWEEN 43 AND 50 AND v4<29 AND v2>=89) OR (v1>80));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 43 (tinyint) AND 50 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 29 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 89 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 80 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(63, 80], [89, ∞), [43, 50], (NULL, 29)}, {(80, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(63, 80], [89, ∞), [43, 50], (NULL, 29)}, {(80, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11610,109 +5843,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 15 AND 69 AND v4=83 AND v2<=43) OR (v1<51 AND v2<24 AND v3<>27 AND v4<>50)) OR (v1<>37));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 15 (tinyint) AND 69 (tinyint))\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 83 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 43 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 24 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 27 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 37 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 37), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[37, 37], (NULL, 43], [NULL, ∞), [NULL, ∞)}, {(37, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 37), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[37, 37], (NULL, 24), [NULL, NULL], [83, 83]}, {[37, 37], (NULL, 24), (NULL, 27), (NULL, 50)}, {[37, 37], (NULL, 24), (NULL, 27), (50, ∞)}, {[37, 37], (NULL, 24), [27, 27], [83, 83]}, {[37, 37], (NULL, 24), (27, ∞), (NULL, 50)}, {[37, 37], (NULL, 24), (27, ∞), (50, ∞)}, {[37, 37], [24, 43], [NULL, ∞), [83, 83]}, {(37, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 55 AND 66 AND v2<>81 AND v3=6 AND v4<=19) OR (v1<>91));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 55 (tinyint) AND 66 (tinyint))\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 6 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 91 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 91), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(91, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 91), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(91, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=21 AND v2<50 AND v3>=39) OR (v1<=79 AND v4>62 AND v2=31));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 21 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 39 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 79 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 62 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 31 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 79], [31, 31], [NULL, ∞), [NULL, ∞)}, {[21, 21], (NULL, 31), [39, ∞), [NULL, ∞)}, {[21, 21], (31, 50), [39, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 21), [31, 31], [NULL, ∞), (62, ∞)}, {[21, 21], (NULL, 50), [39, ∞), [NULL, ∞)}, {[21, 21], [31, 31], [NULL, 39), (62, ∞)}, {(21, 79], [31, 31], [NULL, ∞), (62, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11727,29 +5883,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>16 AND v3>=29) OR (v1>=47 AND v2<>63));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 16 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 29 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 47 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 63 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(16, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(16, 47), [NULL, ∞), [29, ∞), [NULL, ∞)}, {[47, ∞), [NULL, NULL], [29, ∞), [NULL, ∞)}, {[47, ∞), (NULL, 63), [NULL, ∞), [NULL, ∞)}, {[47, ∞), [63, 63], [29, ∞), [NULL, ∞)}, {[47, ∞), (63, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11764,54 +5903,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=35 AND v2>67) OR (v1<>55));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 35 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 67 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 55 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 55), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(55, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 55), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(55, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<89 AND v2<5 AND v3 BETWEEN 53 AND 61) OR (v1<>72 AND v3<20));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 5 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 53 (tinyint) AND 61 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 72 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 20 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 72), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[72, 72], (NULL, 5), [53, 61], [NULL, ∞)}, {(72, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 72), [NULL, ∞), (NULL, 20), [NULL, ∞)}, {(NULL, 89), (NULL, 5), [53, 61], [NULL, ∞)}, {(72, ∞), [NULL, ∞), (NULL, 20), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11866,67 +5973,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<47 AND v2 BETWEEN 22 AND 85) AND (v1=73) OR (v1<42));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 22 (tinyint) AND 85 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 73 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 42 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 42), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 42), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<29) AND (v1<41 AND v2>52 AND v3<>55) OR (v1 BETWEEN 16 AND 28 AND v2>=9 AND v3=43 AND v4<6));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 29 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 55 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 16 (tinyint) AND 28 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 6 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 29), (52, ∞), (NULL, 55), [NULL, ∞)}, {(NULL, 29), (52, ∞), (55, ∞), [NULL, ∞)}, {[16, 28], [9, 52], [43, 43], (NULL, 6)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 29), (52, ∞), (NULL, 55), [NULL, ∞)}, {(NULL, 29), (52, ∞), (55, ∞), [NULL, ∞)}, {[16, 28], [9, 52], [43, 43], (NULL, 6)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -11961,58 +6023,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>86) OR (v1>=48 AND v4>9));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 86 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 48 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 9 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[48, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[48, 86], [NULL, ∞), [NULL, ∞), (9, ∞)}, {(86, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=41 AND v2=79 AND v3<16 AND v4>=2) OR (v1<16 AND v4>59));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 16 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 16 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 59 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 16), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[41, 41], [79, 79], (NULL, 16), [2, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 16), [NULL, ∞), [NULL, ∞), (59, ∞)}, {[41, 41], [79, 79], (NULL, 16), [2, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12027,121 +6053,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=93 AND v2<=10 AND v3 BETWEEN 21 AND 83) AND (v1<>5 AND v2>59 AND v3<>17) OR (v1<69 AND v3<>65 AND v4>=51 AND v2<=48)) OR (v1 BETWEEN 37 AND 57 AND v2 BETWEEN 44 AND 57 AND v3<40 AND v4=98));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 21 (tinyint) AND 83 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 69 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 48 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 37 (tinyint) AND 57 (tinyint))\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 44 (tinyint) AND 57 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 98 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 69), (NULL, 48], (NULL, 65), [51, ∞)}, {(NULL, 69), (NULL, 48], (65, ∞), [51, ∞)}, {[37, 57], (48, 57], (NULL, 40), [98, 98]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 69), (NULL, 48], (NULL, 65), [51, ∞)}, {(NULL, 69), (NULL, 48], (65, ∞), [51, ∞)}, {[37, 57], (48, 57], (NULL, 40), [98, 98]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<46) OR (v1<>60));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 46 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 60 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 60), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(60, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 60), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(60, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<97 AND v2<=47 AND v3=91) OR (v1=74 AND v4>72 AND v2<>44 AND v3 BETWEEN 4 AND 51));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 97 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 91 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 74 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 44 (tinyint)\n" + - " │ └─ (comp_index_t2.v3:3 BETWEEN 4 (tinyint) AND 51 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 97), (NULL, 47], [91, 91], [NULL, ∞)}, {[74, 74], (NULL, 44), [4, 51], (72, ∞)}, {[74, 74], (44, ∞), [4, 51], (72, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 97), (NULL, 47], [91, 91], [NULL, ∞)}, {[74, 74], (NULL, 44), [4, 51], (72, ∞)}, {[74, 74], (44, ∞), [4, 51], (72, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12156,51 +6093,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=33 AND v2<2 AND v3<>63) OR (v1 BETWEEN 20 AND 95 AND v2<>7 AND v3 BETWEEN 95 AND 96 AND v4 BETWEEN 34 AND 41)) OR (v1 BETWEEN 27 AND 44 AND v4<>28 AND v2<=43 AND v3<=64));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 33 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 20 (tinyint) AND 95 (tinyint))\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 7 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 95 (tinyint) AND 96 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 34 (tinyint) AND 41 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 27 (tinyint) AND 44 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 28 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 64 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[20, 33), (NULL, 7), [95, 96], [34, 41]}, {[20, 95], (7, ∞), [95, 96], [34, 41]}, {[27, 33), (NULL, 43], (NULL, 64], (NULL, 28)}, {[27, 33), (NULL, 43], (NULL, 64], (28, ∞)}, {[33, 33], (NULL, 2), (NULL, 63), [NULL, ∞)}, {[33, 33], (NULL, 2), [63, 63], (NULL, 28)}, {[33, 33], (NULL, 2), [63, 63], (28, ∞)}, {[33, 33], (NULL, 2), (63, ∞), [NULL, ∞)}, {[33, 33], [2, 7), [95, 96], [34, 41]}, {[33, 33], [2, 43], (NULL, 64], (NULL, 28)}, {[33, 33], [2, 43], (NULL, 64], (28, ∞)}, {(33, 44], (NULL, 43], (NULL, 64], (NULL, 28)}, {(33, 44], (NULL, 43], (NULL, 64], (28, ∞)}, {(33, 95], (NULL, 7), [95, 96], [34, 41]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[20, 33), (NULL, 7), [95, 96], [34, 41]}, {[20, 95], (7, ∞), [95, 96], [34, 41]}, {[27, 33), (NULL, 43], (NULL, 64], (NULL, 28)}, {[27, 33), (NULL, 43], (NULL, 64], (28, ∞)}, {[33, 33], (NULL, 2), (NULL, 63), [NULL, ∞)}, {[33, 33], (NULL, 2), [63, 63], (NULL, 28)}, {[33, 33], (NULL, 2), [63, 63], (28, ∞)}, {[33, 33], (NULL, 2), (63, ∞), [NULL, ∞)}, {[33, 33], [2, 7), [95, 96], [34, 41]}, {[33, 33], [2, 43], (NULL, 64], (NULL, 28)}, {[33, 33], [2, 43], (NULL, 64], (28, ∞)}, {(33, 44], (NULL, 43], (NULL, 64], (NULL, 28)}, {(33, 44], (NULL, 43], (NULL, 64], (28, ∞)}, {(33, 95], (NULL, 7), [95, 96], [34, 41]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12225,28 +6123,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>33) OR (v1<23 AND v4<=23 AND v2>=41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 33 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 23), [41, ∞), [NULL, ∞), [NULL, ∞)}, {(33, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 23), [41, ∞), [NULL, ∞), (NULL, 23]}, {(33, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12261,151 +6143,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=51 AND v2=3 AND v3>48 AND v4>=49) OR (v1>25 AND v3=37));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 48 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 49 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 37 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(25, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(25, ∞), [NULL, ∞), [37, 37], [NULL, ∞)}, {[51, ∞), [3, 3], (48, ∞), [49, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<4 AND v2<>1 AND v3<=34) OR (v1>=63)) OR (v1<58 AND v2=33)) AND (v1<=55) OR (v1 BETWEEN 1 AND 80 AND v2<=51));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 63 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 58 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 55 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 1 (tinyint) AND 80 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 51 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 1), (NULL, 1), (NULL, 34], [NULL, ∞)}, {(NULL, 1), (1, 33), (NULL, 34], [NULL, ∞)}, {(NULL, 1), [33, 33], [NULL, ∞), [NULL, ∞)}, {(NULL, 1), (33, ∞), (NULL, 34], [NULL, ∞)}, {[1, 4), (51, ∞), (NULL, 34], [NULL, ∞)}, {[1, 80], (NULL, 51], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 1), (NULL, 1), (NULL, 34], [NULL, ∞)}, {(NULL, 1), (1, 33), (NULL, 34], [NULL, ∞)}, {(NULL, 1), [33, 33], [NULL, ∞), [NULL, ∞)}, {(NULL, 1), (33, ∞), (NULL, 34], [NULL, ∞)}, {[1, 4), (51, ∞), (NULL, 34], [NULL, ∞)}, {[1, 80], (NULL, 51], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 33 AND 82 AND v2<26) OR (v1>=98 AND v4>30 AND v2 BETWEEN 47 AND 67 AND v3 BETWEEN 9 AND 54)) OR (v1>=5)) AND (v1<>85 AND v4<>31);`, - ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 33 (tinyint) AND 82 (tinyint))\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 98 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 47 (tinyint) AND 67 (tinyint))\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 9 (tinyint) AND 54 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 5 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 31 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 85), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(85, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 85), [NULL, ∞), [NULL, ∞), (NULL, 31)}, {[5, 85), [NULL, ∞), [NULL, ∞), (31, ∞)}, {(85, ∞), [NULL, ∞), [NULL, ∞), (NULL, 31)}, {(85, ∞), [NULL, ∞), [NULL, ∞), (31, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=82 AND v3<>55 AND v4>26) OR (v1=35)) OR (v1 BETWEEN 18 AND 70 AND v2>=17));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 26 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 35 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 18 (tinyint) AND 70 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 17 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[18, 35), [17, ∞), [NULL, ∞), [NULL, ∞)}, {[35, 35], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(35, 70], [17, ∞), [NULL, ∞), [NULL, ∞)}, {[82, 82], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[18, 35), [17, ∞), [NULL, ∞), [NULL, ∞)}, {[35, 35], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(35, 70], [17, ∞), [NULL, ∞), [NULL, ∞)}, {[82, 82], [NULL, ∞), (NULL, 55), (26, ∞)}, {[82, 82], [NULL, ∞), (55, ∞), (26, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12430,130 +6203,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<90 AND v4=77) OR (v1<>32 AND v2<=17 AND v3=68)) OR (v1<41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 90 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 68 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 90), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[90, ∞), (NULL, 17], [68, 68], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 41), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[41, 90), [NULL, NULL], [NULL, ∞), [77, 77]}, {[41, 90), (NULL, 17], [NULL, 68), [77, 77]}, {[41, 90), (NULL, 17], (68, ∞), [77, 77]}, {[41, 90), (17, ∞), [NULL, ∞), [77, 77]}, {[41, ∞), (NULL, 17], [68, 68], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=2) AND (v1>=13 AND v2<=23 AND v3<=23) OR (v1 BETWEEN 18 AND 57));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 2 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 23 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 18 (tinyint) AND 57 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[18, 57], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[18, 57], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 32 AND 72 AND v2<>89 AND v3>=39) OR (v1>50 AND v4>80));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 32 (tinyint) AND 72 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 39 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 80 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[32, 50], (NULL, 89), [39, ∞), [NULL, ∞)}, {[32, 50], (89, ∞), [39, ∞), [NULL, ∞)}, {(50, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[32, 72], (NULL, 89), [39, ∞), [NULL, ∞)}, {[32, 72], (89, ∞), [39, ∞), [NULL, ∞)}, {(50, 72], [NULL, NULL], [NULL, ∞), (80, ∞)}, {(50, 72], (NULL, 89), [NULL, 39), (80, ∞)}, {(50, 72], [89, 89], [NULL, ∞), (80, ∞)}, {(50, 72], (89, ∞), [NULL, 39), (80, ∞)}, {(72, ∞), [NULL, ∞), [NULL, ∞), (80, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<44) OR (v1<>37 AND v2<=12 AND v3>65 AND v4<47)) OR (v1<>76));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 44 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 65 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 47 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 76 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 76), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[76, 76], (NULL, 12], (65, ∞), (NULL, 47)}, {(76, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 76), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[76, 76], (NULL, 12], (65, ∞), (NULL, 47)}, {(76, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12578,184 +6263,52 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>10 AND v2<43 AND v3<>15) OR (v1<=71 AND v4<>22));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 43 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 71 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 22 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 71], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(71, ∞), (NULL, 43), (NULL, 15), [NULL, ∞)}, {(71, ∞), (NULL, 43), (15, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 10], [NULL, ∞), [NULL, ∞), (NULL, 22)}, {(NULL, 10], [NULL, ∞), [NULL, ∞), (22, ∞)}, {(10, 71], [NULL, NULL], [NULL, ∞), (NULL, 22)}, {(10, 71], [NULL, NULL], [NULL, ∞), (22, ∞)}, {(10, 71], (NULL, 43), [NULL, NULL], (NULL, 22)}, {(10, 71], (NULL, 43), [NULL, NULL], (22, ∞)}, {(10, 71], (NULL, 43), [15, 15], (NULL, 22)}, {(10, 71], (NULL, 43), [15, 15], (22, ∞)}, {(10, 71], [43, ∞), [NULL, ∞), (NULL, 22)}, {(10, 71], [43, ∞), [NULL, ∞), (22, ∞)}, {(10, ∞), (NULL, 43), (NULL, 15), [NULL, ∞)}, {(10, ∞), (NULL, 43), (15, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 18 AND 36 AND v4<>87 AND v2>=13) OR (v1>=63 AND v3<=89)) AND (v1<76 AND v4<49 AND v2<=96);`, - ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 18 (tinyint) AND 36 (tinyint))\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 13 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 63 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 89 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 49 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[18, 36], [13, 96], [NULL, ∞), [NULL, ∞)}, {[63, 76), (NULL, 96], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[18, 36], [13, 96], [NULL, ∞), (NULL, 49)}, {[63, 76), (NULL, 96], (NULL, 89], (NULL, 49)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<93 AND v2<>16) OR (v1>=23 AND v4>=19)) OR (v1<48 AND v2<=45 AND v3<>46 AND v4>76)) AND (v1=22 AND v3=41) OR (v1<=17 AND v2>=41));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 93 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 16 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 23 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 45 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 41 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 17], [41, ∞), [NULL, ∞), [NULL, ∞)}, {[22, 22], (NULL, 16), [NULL, ∞), [NULL, ∞)}, {[22, 22], [16, 16], (NULL, 46), (76, ∞)}, {[22, 22], [16, 16], (46, ∞), (76, ∞)}, {[22, 22], (16, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 17], [41, ∞), [NULL, ∞), [NULL, ∞)}, {[22, 22], (NULL, 16), [41, 41], [NULL, ∞)}, {[22, 22], [16, 16], [41, 41], (76, ∞)}, {[22, 22], (16, ∞), [41, 41], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>17 AND v4>50 AND v2 BETWEEN 11 AND 23 AND v3=23) OR (v1<73));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 17 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 11 (tinyint) AND 23 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 73 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 73), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[73, ∞), [11, 23], [23, 23], (50, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 73), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[73, ∞), [11, 23], [23, 23], (50, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 5 AND 41 AND v3<78 AND v4<41) OR (v1>84 AND v2<>43));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 5 (tinyint) AND 41 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 78 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 41 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 84 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 43 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 41], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(84, ∞), (NULL, 43), [NULL, ∞), [NULL, ∞)}, {(84, ∞), (43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 41], [NULL, ∞), (NULL, 78), (NULL, 41)}, {(84, ∞), (NULL, 43), [NULL, ∞), [NULL, ∞)}, {(84, ∞), (43, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12770,58 +6323,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=18 AND v2<=70) OR (v1>55 AND v2>52 AND v3<>70)) OR (v1=58)) AND (v1<>22 AND v4>76) OR (v1>14 AND v2<32 AND v3>97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 55 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 58 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 76 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 18], (NULL, 70], [NULL, ∞), [NULL, ∞)}, {(18, 58), (NULL, 32), (97, ∞), [NULL, ∞)}, {(55, 58), (52, ∞), (NULL, 70), [NULL, ∞)}, {(55, 58), (52, ∞), (70, ∞), [NULL, ∞)}, {[58, 58], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(58, ∞), (NULL, 32), (97, ∞), [NULL, ∞)}, {(58, ∞), (52, ∞), (NULL, 70), [NULL, ∞)}, {(58, ∞), (52, ∞), (70, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 14], (NULL, 70], [NULL, ∞), (76, ∞)}, {(14, 18], (NULL, 32), [NULL, 97], (76, ∞)}, {(14, 18], [32, 70], [NULL, ∞), (76, ∞)}, {(14, ∞), (NULL, 32), (97, ∞), [NULL, ∞)}, {(55, 58), (52, ∞), (NULL, 70), (76, ∞)}, {(55, 58), (52, ∞), (70, ∞), (76, ∞)}, {[58, 58], [NULL, NULL], [NULL, ∞), (76, ∞)}, {[58, 58], (NULL, 32), [NULL, 97], (76, ∞)}, {[58, 58], [32, ∞), [NULL, ∞), (76, ∞)}, {(58, ∞), (52, ∞), (NULL, 70), (76, ∞)}, {(58, ∞), (52, ∞), (70, ∞), (76, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12846,40 +6353,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=9 AND v4>=68 AND v2>21) OR (v1=5 AND v2<69 AND v3<=15 AND v4>=61));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 68 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 21 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 69 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 61 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[5, 5], (NULL, 69), (NULL, 15], [61, ∞)}, {[9, 9], (21, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[5, 5], (NULL, 69), (NULL, 15], [61, ∞)}, {[9, 9], (21, ∞), [NULL, ∞), [68, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -12924,60 +6403,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>74) OR (v1<>86 AND v2<=91)) AND (v1>=8);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 74 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 86 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 91 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[8, 74), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[74, 74], (NULL, 91], [NULL, ∞), [NULL, ∞)}, {(74, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[8, 74), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[74, 74], (NULL, 91], [NULL, ∞), [NULL, ∞)}, {(74, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>25 AND v2 BETWEEN 23 AND 54) OR (v1<>40 AND v3>90)) OR (v1<>7 AND v4<=78));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 25 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 23 (tinyint) AND 54 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 40 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 90 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 7 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 78 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 7), [NULL, ∞), [NULL, 90], (NULL, 78]}, {(NULL, 40), [NULL, ∞), (90, ∞), [NULL, ∞)}, {(7, 25], [NULL, ∞), [NULL, 90], (NULL, 78]}, {(25, 40), [NULL, 23), [NULL, 90], (NULL, 78]}, {(25, 40), (54, ∞), [NULL, 90], (NULL, 78]}, {(25, ∞), [23, 54], [NULL, ∞), [NULL, ∞)}, {[40, 40], [NULL, 23), [NULL, ∞), (NULL, 78]}, {[40, 40], (54, ∞), [NULL, ∞), (NULL, 78]}, {(40, ∞), [NULL, 23), [NULL, 90], (NULL, 78]}, {(40, ∞), [NULL, 23), (90, ∞), [NULL, ∞)}, {(40, ∞), (54, ∞), [NULL, 90], (NULL, 78]}, {(40, ∞), (54, ∞), (90, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13032,24 +6473,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>75) OR (v1<>74 AND v3 BETWEEN 29 AND 73));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 75 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 74 (tinyint)\n" + - " │ └─ (comp_index_t2.v3:3 BETWEEN 29 (tinyint) AND 73 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 75), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[75, 75], [NULL, ∞), [29, 73], [NULL, ∞)}, {(75, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13064,95 +6493,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<>18 AND v2<>90 AND v3>95) OR (v1>=44)) OR (v1<4 AND v3<=26 AND v4<>67 AND v2>=37)) OR (v1<36 AND v2<=15 AND v3 BETWEEN 25 AND 36 AND v4<=14));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 90 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 44 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 26 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 67 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 37 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 25 (tinyint) AND 36 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 14 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 4), [37, ∞), (NULL, 26], (NULL, 67)}, {(NULL, 4), [37, ∞), (NULL, 26], (67, ∞)}, {(NULL, 18), (NULL, 90), (95, ∞), [NULL, ∞)}, {(NULL, 18), (90, ∞), (95, ∞), [NULL, ∞)}, {(NULL, 36), (NULL, 15], [25, 36], (NULL, 14]}, {(18, 44), (NULL, 90), (95, ∞), [NULL, ∞)}, {(18, 44), (90, ∞), (95, ∞), [NULL, ∞)}, {[44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 4), [37, ∞), (NULL, 26], (NULL, 67)}, {(NULL, 4), [37, ∞), (NULL, 26], (67, ∞)}, {(NULL, 18), (NULL, 90), (95, ∞), [NULL, ∞)}, {(NULL, 18), (90, ∞), (95, ∞), [NULL, ∞)}, {(NULL, 36), (NULL, 15], [25, 36], (NULL, 14]}, {(18, 44), (NULL, 90), (95, ∞), [NULL, ∞)}, {(18, 44), (90, ∞), (95, ∞), [NULL, ∞)}, {[44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 44 AND 87 AND v2<52 AND v3<52 AND v4<1) OR (v1<30 AND v4 BETWEEN 8 AND 97 AND v2<=24));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 44 (tinyint) AND 87 (tinyint))\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 30 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v4:4 BETWEEN 8 (tinyint) AND 97 (tinyint))\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 24 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 30), (NULL, 24], [NULL, ∞), [NULL, ∞)}, {[44, 87], (NULL, 52), (NULL, 52), (NULL, 1)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 30), (NULL, 24], [NULL, ∞), [8, 97]}, {[44, 87], (NULL, 52), (NULL, 52), (NULL, 1)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13167,24 +6523,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>8 AND v2 BETWEEN 34 AND 48) OR (v1<>54));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 34 (tinyint) AND 48 (tinyint))\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 54 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 54), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[54, 54], [34, 48], [NULL, ∞), [NULL, ∞)}, {(54, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 54), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[54, 54], [34, 48], [NULL, ∞), [NULL, ∞)}, {(54, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13219,89 +6563,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>47 AND v3>47 AND v4 BETWEEN 51 AND 86 AND v2=26) OR (v1<82 AND v2<=17 AND v3<17 AND v4>=46));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 51 (tinyint) AND 86 (tinyint))\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 26 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 46 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 82), (NULL, 17], (NULL, 17), [46, ∞)}, {(47, ∞), [26, 26], (47, ∞), [51, 86]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 82), (NULL, 17], (NULL, 17), [46, ∞)}, {(47, ∞), [26, 26], (47, ∞), [51, 86]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>87) OR (v1>82 AND v4>=22)) OR (v1>=52 AND v2<>47 AND v3=37)) OR (v1<=14 AND v2<57 AND v3<10));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 22 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 37 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 57 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 10 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 14], (NULL, 57), (NULL, 10), [NULL, ∞)}, {[52, 82], (NULL, 47), [37, 37], [NULL, ∞)}, {[52, 82], (47, ∞), [37, 37], [NULL, ∞)}, {(82, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 14], (NULL, 57), (NULL, 10), [NULL, ∞)}, {[52, 82], (NULL, 47), [37, 37], [NULL, ∞)}, {[52, 87], (47, ∞), [37, 37], [NULL, ∞)}, {(82, 87], [NULL, NULL], [NULL, ∞), [22, ∞)}, {(82, 87], (NULL, 47), [NULL, 37), [22, ∞)}, {(82, 87], (NULL, 47), [37, 37], [NULL, ∞)}, {(82, 87], (NULL, 47), (37, ∞), [22, ∞)}, {(82, 87], [47, 47], [NULL, ∞), [22, ∞)}, {(82, 87], (47, ∞), [NULL, 37), [22, ∞)}, {(82, 87], (47, ∞), (37, ∞), [22, ∞)}, {(87, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13346,52 +6623,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>=12 AND v3>=45 AND v4<98) OR (v1<>51 AND v3=79 AND v4<=24)) OR (v1 BETWEEN 4 AND 59 AND v4<82)) OR (v1>=29 AND v2<>21));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 45 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 98 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 51 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 24 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 4 (tinyint) AND 59 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 82 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 29 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 21 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 4), [NULL, ∞), [79, 79], (NULL, 24]}, {[4, 12), [NULL, ∞), [NULL, ∞), (NULL, 82)}, {[12, 29), [NULL, ∞), [NULL, 45), (NULL, 82)}, {[12, 29), [NULL, ∞), [45, ∞), (NULL, 98)}, {[29, 59], [NULL, NULL], [NULL, 45), (NULL, 82)}, {[29, 59], [21, 21], [NULL, 45), (NULL, 82)}, {[29, ∞), [NULL, NULL], [45, ∞), (NULL, 98)}, {[29, ∞), (NULL, 21), [NULL, ∞), [NULL, ∞)}, {[29, ∞), [21, 21], [45, ∞), (NULL, 98)}, {[29, ∞), (21, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13406,34 +6643,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=15) OR (v1=15)) OR (v1 BETWEEN 14 AND 25 AND v4>55 AND v2<53 AND v3=95));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 14 (tinyint) AND 25 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 55 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 53 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 95 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[14, 15), (NULL, 53), [95, 95], (55, ∞)}, {[15, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[14, 15), (NULL, 53), [95, 95], (55, ∞)}, {[15, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13448,102 +6663,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<41 AND v4=9 AND v2>77 AND v3=41) OR (v1>62 AND v2>=48 AND v3=13 AND v4>61)) OR (v1 BETWEEN 33 AND 75)) OR (v1 BETWEEN 45 AND 65 AND v4 BETWEEN 4 AND 68));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 77 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 13 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 61 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v1:1 BETWEEN 33 (tinyint) AND 75 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 45 (tinyint) AND 65 (tinyint))\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 4 (tinyint) AND 68 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 33), (77, ∞), [41, 41], [9, 9]}, {[33, 75], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(75, ∞), [48, ∞), [13, 13], (61, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 33), (77, ∞), [41, 41], [9, 9]}, {[33, 75], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(75, ∞), [48, ∞), [13, 13], (61, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>20) OR (v1>=71 AND v4 BETWEEN 12 AND 20 AND v2<=30 AND v3 BETWEEN 14 AND 44)) AND (v1>97 AND v2=91 AND v3>=5) OR (v1>7 AND v2<34 AND v3<55 AND v4 BETWEEN 88 AND 97)) AND (v1 BETWEEN 2 AND 16 AND v2<>23 AND v3=75 AND v4>99);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 20 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 71 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 12 (tinyint) AND 20 (tinyint))\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 14 (tinyint) AND 44 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 97 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 91 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 5 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 7 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 34 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 55 (tinyint)\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 88 (tinyint) AND 97 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13568,50 +6703,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1=76) OR (v1>22 AND v3<49 AND v4=2)) OR (v1=85 AND v4>79)) OR (v1=10 AND v2=47 AND v3 BETWEEN 6 AND 21 AND v4>97));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 76 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 22 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 49 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 2 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 85 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 79 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 47 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 6 (tinyint) AND 21 (tinyint))\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 97 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[10, 10], [47, 47], [6, 21], (97, ∞)}, {(22, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[10, 10], [47, 47], [6, 21], (97, ∞)}, {(22, 76), [NULL, ∞), (NULL, 49), [2, 2]}, {[76, 76], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(76, ∞), [NULL, ∞), (NULL, 49), [2, 2]}, {[85, 85], [NULL, ∞), [NULL, ∞), (79, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13626,43 +6723,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>82 AND v4=74 AND v2=8 AND v3>=43) OR (v1=1 AND v2>=54 AND v3 BETWEEN 41 AND 91 AND v4>=0));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 82 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 74 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 1 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 41 (tinyint) AND 91 (tinyint))\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 0 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 82), [8, 8], [43, ∞), [74, 74]}, {[1, 1], [54, ∞), [41, 91], [0, ∞)}, {(82, ∞), [8, 8], [43, ∞), [74, 74]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 82), [8, 8], [43, ∞), [74, 74]}, {[1, 1], [54, ∞), [41, 91], [0, ∞)}, {(82, ∞), [8, 8], [43, ∞), [74, 74]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13687,75 +6753,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=10 AND v2 BETWEEN 29 AND 83 AND v3<30 AND v4=54) OR (v1=68 AND v2=9 AND v3<=31)) AND (v1=87 AND v2>=91) OR (v1<=3 AND v2<>65 AND v3<8 AND v4<54)) OR (v1<7 AND v2>=4 AND v3<=47));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 29 (tinyint) AND 83 (tinyint))\n" + - " │ │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ │ └─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 87 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 91 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 65 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 8 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 54 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 7 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 4 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 47 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 3], (NULL, 4), (NULL, 8), (NULL, 54)}, {(NULL, 7), [4, ∞), (NULL, 47], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 3], (NULL, 4), (NULL, 8), (NULL, 54)}, {(NULL, 7), [4, ∞), (NULL, 47], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13780,82 +6783,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>52) OR (v1<21 AND v2<61 AND v3=13)) OR (v1=89 AND v3>33));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 52 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 21 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 61 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 13 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 89 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 33 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 21), (NULL, 61), [13, 13], [NULL, ∞)}, {(52, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 21), (NULL, 61), [13, 13], [NULL, ∞)}, {(52, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<30 AND v4>11 AND v2<=11) OR (v1<>19 AND v2<>47 AND v3 BETWEEN 38 AND 77 AND v4>31)) OR (v1 BETWEEN 0 AND 27 AND v2 BETWEEN 33 AND 34)) OR (v1<32)) AND (v1<9 AND v3=54 AND v4<>31 AND v2<>95);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 38 (tinyint) AND 77 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 0 (tinyint) AND 27 (tinyint))\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 33 (tinyint) AND 34 (tinyint))\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 32 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 9), (NULL, 95), [54, 54], (NULL, 31)}, {(NULL, 9), (NULL, 95), [54, 54], (31, ∞)}, {(NULL, 9), (95, ∞), [54, 54], (NULL, 31)}, {(NULL, 9), (95, ∞), [54, 54], (31, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 9), (NULL, 95), [54, 54], (NULL, 31)}, {(NULL, 9), (NULL, 95), [54, 54], (31, ∞)}, {(NULL, 9), (95, ∞), [54, 54], (NULL, 31)}, {(NULL, 9), (95, ∞), [54, 54], (31, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -13870,134 +6813,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<>36) OR (v1<>70 AND v2 BETWEEN 23 AND 39)) OR (v1>51 AND v2>=57)) OR (v1<50 AND v2<=3 AND v3 BETWEEN 1 AND 74));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 70 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 23 (tinyint) AND 39 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 57 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 50 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 3 (tinyint)\n" + - " │ └─ (comp_index_t2.v3:3 BETWEEN 1 (tinyint) AND 74 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 36), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[36, 36], (NULL, 3], [1, 74], [NULL, ∞)}, {[36, 36], [23, 39], [NULL, ∞), [NULL, ∞)}, {(36, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 36), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[36, 36], (NULL, 3], [1, 74], [NULL, ∞)}, {[36, 36], [23, 39], [NULL, ∞), [NULL, ∞)}, {(36, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1>30) OR (v1>98 AND v4>43 AND v2<>80)) OR (v1 BETWEEN 2 AND 23 AND v2>=34)) OR (v1>=42));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 30 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 98 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 43 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 80 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 2 (tinyint) AND 23 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 34 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 42 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[2, 23], [34, ∞), [NULL, ∞), [NULL, ∞)}, {(30, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[2, 23], [34, ∞), [NULL, ∞), [NULL, ∞)}, {(30, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<68 AND v2<81 AND v3<34 AND v4<>33) OR (v1<=78 AND v4 BETWEEN 34 AND 99 AND v2>=79 AND v3>=9)) OR (v1=27 AND v4 BETWEEN 20 AND 41 AND v2<98 AND v3>=15));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 68 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 34 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 33 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 78 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 34 (tinyint) AND 99 (tinyint))\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 79 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 9 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 27 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 20 (tinyint) AND 41 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 98 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 15 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 27), (NULL, 81), (NULL, 34), (NULL, 33)}, {(NULL, 27), (NULL, 81), (NULL, 34), (33, ∞)}, {(NULL, 27), [79, 81), [34, ∞), [34, 99]}, {(NULL, 27), [81, ∞), [9, ∞), [34, 99]}, {[27, 27], (NULL, 79), [34, ∞), [20, 41]}, {[27, 27], (NULL, 81), (NULL, 15), (NULL, 33)}, {[27, 27], (NULL, 81), (NULL, 15), (33, ∞)}, {[27, 27], (NULL, 81), [15, 34), (NULL, ∞)}, {[27, 27], [79, 81), [34, ∞), [20, 99]}, {[27, 27], [81, 98), [9, 15), [34, 99]}, {[27, 27], [81, 98), [15, ∞), [20, 99]}, {[27, 27], [98, ∞), [9, ∞), [34, 99]}, {(27, 68), (NULL, 81), (NULL, 34), (NULL, 33)}, {(27, 68), (NULL, 81), (NULL, 34), (33, ∞)}, {(27, 68), [79, 81), [34, ∞), [34, 99]}, {(27, 68), [81, ∞), [9, ∞), [34, 99]}, {[68, 78], [79, ∞), [9, ∞), [34, 99]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 27), (NULL, 81), (NULL, 34), (NULL, 33)}, {(NULL, 27), (NULL, 81), (NULL, 34), (33, ∞)}, {(NULL, 27), [79, 81), [34, ∞), [34, 99]}, {(NULL, 27), [81, ∞), [9, ∞), [34, 99]}, {[27, 27], (NULL, 79), [34, ∞), [20, 41]}, {[27, 27], (NULL, 81), (NULL, 15), (NULL, 33)}, {[27, 27], (NULL, 81), (NULL, 15), (33, ∞)}, {[27, 27], (NULL, 81), [15, 34), (NULL, ∞)}, {[27, 27], [79, 81), [34, ∞), [20, 99]}, {[27, 27], [81, 98), [9, 15), [34, 99]}, {[27, 27], [81, 98), [15, ∞), [20, 99]}, {[27, 27], [98, ∞), [9, ∞), [34, 99]}, {(27, 68), (NULL, 81), (NULL, 34), (NULL, 33)}, {(27, 68), (NULL, 81), (NULL, 34), (33, ∞)}, {(27, 68), [79, 81), [34, ∞), [34, 99]}, {(27, 68), [81, ∞), [9, ∞), [34, 99]}, {[68, 78], [79, ∞), [9, ∞), [34, 99]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14052,108 +6893,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<=5 AND v2>=14 AND v3<=2) OR (v1<53 AND v4=99 AND v2=72)) OR (v1<>49 AND v2<>39 AND v3>=70 AND v4<>24)) OR (v1<79));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 14 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 2 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 49 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 70 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 24 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 79 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 79), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[79, ∞), (NULL, 39), [70, ∞), (NULL, 24)}, {[79, ∞), (NULL, 39), [70, ∞), (24, ∞)}, {[79, ∞), (39, ∞), [70, ∞), (NULL, 24)}, {[79, ∞), (39, ∞), [70, ∞), (24, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 79), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[79, ∞), (NULL, 39), [70, ∞), (NULL, 24)}, {[79, ∞), (NULL, 39), [70, ∞), (24, ∞)}, {[79, ∞), (39, ∞), [70, ∞), (NULL, 24)}, {[79, ∞), (39, ∞), [70, ∞), (24, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1<99 AND v2<=42) OR (v1=47 AND v4 BETWEEN 33 AND 63 AND v2>=10 AND v3<=57)) OR (v1>44)) OR (v1<>87 AND v2>42 AND v3<69));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 33 (tinyint) AND 63 (tinyint))\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 57 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 44 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 87 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 42 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 69 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 44], (NULL, 42], [NULL, ∞), [NULL, ∞)}, {(NULL, 44], (42, ∞), (NULL, 69), [NULL, ∞)}, {(44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 44], (NULL, 42], [NULL, ∞), [NULL, ∞)}, {(NULL, 44], (42, ∞), (NULL, 69), [NULL, ∞)}, {(44, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14168,94 +6923,22 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=15) OR (v1>=59 AND v2<18)) OR (v1 BETWEEN 23 AND 31 AND v3>50 AND v4 BETWEEN 15 AND 54));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 15 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 59 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 18 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 23 (tinyint) AND 31 (tinyint))\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 15 (tinyint) AND 54 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[15, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[15, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=50 AND v2<=84 AND v3 BETWEEN 22 AND 26) OR (v1<=18 AND v2<49 AND v3>19 AND v4 BETWEEN 61 AND 75)) AND (v1>48 AND v2>=56 AND v3=6) OR (v1<=88 AND v2>=76 AND v3<40 AND v4<=18));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 22 (tinyint) AND 26 (tinyint))\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 49 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 61 (tinyint) AND 75 (tinyint))\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 48 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 56 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 6 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 88 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 40 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 18 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 88], [76, ∞), (NULL, 40), (NULL, 18]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 88], [76, ∞), (NULL, 40), (NULL, 18]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14290,36 +6973,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>=10 AND v2<12 AND v3=54 AND v4>89) OR (v1=99 AND v4=37));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 12 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 54 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 89 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 99 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 37 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[10, 99), (NULL, 12), [54, 54], (89, ∞)}, {[99, 99], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(99, ∞), (NULL, 12), [54, 54], (89, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[10, ∞), (NULL, 12), [54, 54], (89, ∞)}, {[99, 99], [NULL, ∞), [NULL, ∞), [37, 37]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14334,36 +6993,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=62 AND v2<89) AND (v1<90 AND v2>=19) OR (v1<=1 AND v2>49));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 62 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 90 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 19 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 49 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 1], (49, ∞), [NULL, ∞), [NULL, ∞)}, {[62, 62], [19, 89), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 1], (49, ∞), [NULL, ∞), [NULL, ∞)}, {[62, 62], [19, 89), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14378,30 +7013,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 5 AND 69) OR (v1<52 AND v4<14 AND v2>=25 AND v3=63));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ (comp_index_t2.v1:1 BETWEEN 5 (tinyint) AND 69 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 14 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 25 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 63 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 5), [25, ∞), [63, 63], (NULL, 14)}, {[5, 69], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 5), [25, ∞), [63, 63], (NULL, 14)}, {[5, 69], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14426,104 +7043,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=19 AND v3<72 AND v4=23) OR (v1<=36 AND v2>99));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 72 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 99 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 19), (99, ∞), [NULL, ∞), [NULL, ∞)}, {[19, 19], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(19, 36], (99, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 36], (99, ∞), [NULL, ∞), [NULL, ∞)}, {[19, 19], [NULL, 99], (NULL, 72), [23, 23]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>43) OR (v1>=41 AND v4=32 AND v2<=66)) AND (v1>43 AND v2 BETWEEN 83 AND 97);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 41 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 32 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 66 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(43, ∞), [83, 97], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(43, ∞), [83, 97], [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=8 AND v4>=44) AND (v1=84 AND v2=41 AND v3 BETWEEN 5 AND 81) OR (v1<>31 AND v2<=96 AND v3<=20 AND v4<=14));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 8 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 44 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 41 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 5 (tinyint) AND 81 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 31 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 20 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 14 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 31), (NULL, 96], (NULL, 20], (NULL, 14]}, {(31, ∞), (NULL, 96], (NULL, 20], (NULL, 14]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 31), (NULL, 96], (NULL, 20], (NULL, 14]}, {(31, ∞), (NULL, 96], (NULL, 20], (NULL, 14]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14538,46 +7083,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<=11 AND v2>=41 AND v3=9) AND (v1<>41 AND v3<>69 AND v4<24) OR (v1>48 AND v4<79));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 11 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 41 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 69 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 24 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 48 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 79 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 11], [41, ∞), [9, 9], (NULL, 24)}, {(48, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 11], [41, ∞), [9, 9], (NULL, 24)}, {(48, ∞), [NULL, ∞), [NULL, ∞), (NULL, 79)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14592,40 +7103,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1 BETWEEN 32 AND 51 AND v4 BETWEEN 5 AND 14 AND v2=46 AND v3>=31) OR (v1>=32 AND v2<=26 AND v3>52 AND v4>55));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 32 (tinyint) AND 51 (tinyint))\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 5 (tinyint) AND 14 (tinyint))\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 46 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 31 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 32 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 26 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 52 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 55 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[32, 51], [46, 46], [31, ∞), [5, 14]}, {[32, ∞), (NULL, 26], (52, ∞), (55, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[32, 51], [46, 46], [31, ∞), [5, 14]}, {[32, ∞), (NULL, 26], (52, ∞), (55, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14640,138 +7123,32 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1=42 AND v4=47) OR (v1>=28)) AND (v1<>10) OR (v1 BETWEEN 20 AND 60 AND v2>96 AND v3<>28)) OR (v1=99 AND v2<=62 AND v3=30 AND v4 BETWEEN 92 AND 93));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 42 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ └─ 47 (tinyint)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 28 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 20 (tinyint) AND 60 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 96 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 28 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 62 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 30 (tinyint)\n" + - " │ └─ (comp_index_t2.v4:4 BETWEEN 92 (tinyint) AND 93 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[20, 28), (96, ∞), (NULL, 28), [NULL, ∞)}, {[20, 28), (96, ∞), (28, ∞), [NULL, ∞)}, {[28, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[20, 28), (96, ∞), (NULL, 28), [NULL, ∞)}, {[20, 28), (96, ∞), (28, ∞), [NULL, ∞)}, {[28, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=50 AND v3=4 AND v4=53 AND v2>=80) OR (v1<54 AND v4<=76 AND v2>48)) OR (v1>=38 AND v4<76 AND v2=56));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 50 (tinyint)\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 53 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 80 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 54 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 76 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 48 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 38 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 76 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 56 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 54), (48, ∞), [NULL, ∞), [NULL, ∞)}, {[54, ∞), [56, 56], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 54), (48, ∞), [NULL, ∞), (NULL, 76]}, {[54, ∞), [56, 56], [NULL, ∞), (NULL, 76)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=79 AND v2>24) OR (v1<76 AND v3<=59 AND v4<=36 AND v2=39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 79 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 24 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 76 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 59 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 36 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 76), [39, 39], (NULL, 59], (NULL, 36]}, {[79, 79], (24, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 76), [39, 39], (NULL, 59], (NULL, 36]}, {[79, 79], (24, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -14786,212 +7163,52 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=85 AND v2>37 AND v3<=57 AND v4 BETWEEN 12 AND 49) AND (v1>10) OR (v1>56)) OR (v1>=57));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 85 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 37 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 57 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 12 (tinyint) AND 49 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 10 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 56 (tinyint)\n" + - " │ └─ GreaterThanOrEqual\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 57 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(56, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(56, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((((v1<>89 AND v2>=75) OR (v1<=5)) OR (v1=5 AND v2<19 AND v3>=1)) OR (v1>=18 AND v2>=17 AND v3 BETWEEN 78 AND 83)) OR (v1>=11 AND v3<=9 AND v4>39));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ Or\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 89 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 75 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 17 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 78 (tinyint) AND 83 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 11 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 9 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 39 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 5], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(5, 11), [75, ∞), [NULL, ∞), [NULL, ∞)}, {[11, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 5], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(5, 89), [75, ∞), [NULL, ∞), [NULL, ∞)}, {[11, 89), [NULL, 75), (NULL, 9], (39, ∞)}, {[18, 89), [17, 75), [78, 83], [NULL, ∞)}, {[89, 89], [NULL, ∞), (NULL, 9], (39, ∞)}, {[89, 89], [17, ∞), [78, 83], [NULL, ∞)}, {(89, ∞), [NULL, 75), (NULL, 9], (39, ∞)}, {(89, ∞), [17, 75), [78, 83], [NULL, ∞)}, {(89, ∞), [75, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1 BETWEEN 36 AND 48 AND v4<97 AND v2>=99 AND v3=3) OR (v1<>84 AND v2=46 AND v3=4)) OR (v1>73 AND v2 BETWEEN 34 AND 39 AND v3 BETWEEN 34 AND 71 AND v4>=15)) OR (v1<>82));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 36 (tinyint) AND 48 (tinyint))\n" + - " │ │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ │ │ └─ 97 (tinyint)\n" + - " │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 99 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 3 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 84 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 46 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 4 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 73 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 34 (tinyint) AND 39 (tinyint))\n" + - " │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 34 (tinyint) AND 71 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 82 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 82), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[82, 82], [34, 39], [34, 71], [15, ∞)}, {[82, 82], [46, 46], [4, 4], [NULL, ∞)}, {(82, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 82), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[82, 82], [34, 39], [34, 71], [15, ∞)}, {[82, 82], [46, 46], [4, 4], [NULL, ∞)}, {(82, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (v1<=50 AND v3>=51 AND v4<>69) AND (v1>1 AND v3<24);`, - ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 51 (tinyint)\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 69 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 24 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(1, 50], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(∞, ∞), (∞, ∞), (∞, ∞), (∞, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>10 AND v2=72 AND v3<31) OR (v1<67 AND v3 BETWEEN 13 AND 70 AND v4>66 AND v2>39)) OR (v1<82)) AND (v1>=66);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 10 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ └─ 72 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 31 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 67 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 13 (tinyint) AND 70 (tinyint))\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 66 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 39 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v1:1\n" + - " │ └─ 82 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[66, 82), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[82, ∞), [72, 72], (NULL, 31), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[66, 82), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[82, ∞), [72, 72], (NULL, 31), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -15056,145 +7273,42 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1=85 AND v2<81 AND v3 BETWEEN 14 AND 61 AND v4<>99) OR (v1 BETWEEN 31 AND 86 AND v4<>43)) OR (v1 BETWEEN 15 AND 67)) AND (v1 BETWEEN 37 AND 55);`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ └─ 85 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ └─ 81 (tinyint)\n" + - " │ │ │ │ └─ (comp_index_t2.v3:3 BETWEEN 14 (tinyint) AND 61 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 99 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 31 (tinyint) AND 86 (tinyint))\n" + - " │ │ └─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 43 (tinyint)\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 15 (tinyint) AND 67 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[37, 55], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[37, 55], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1>=52 AND v4>=86) OR (v1>=86 AND v3=79 AND v4=9 AND v2 BETWEEN 2 AND 6)) OR (v1>98 AND v2<=44 AND v3<>53));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 52 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 86 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 86 (tinyint)\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 9 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v2:2 BETWEEN 2 (tinyint) AND 6 (tinyint))\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 98 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 44 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 53 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[52, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[52, 98], [NULL, ∞), [NULL, ∞), [86, ∞)}, {[86, 98], [2, 6], [79, 79], [9, 9]}, {(98, ∞), [NULL, NULL], [NULL, ∞), [86, ∞)}, {(98, ∞), (NULL, 44], [NULL, NULL], [86, ∞)}, {(98, ∞), (NULL, 44], (NULL, 53), [NULL, ∞)}, {(98, ∞), (NULL, 44], [53, 53], [86, ∞)}, {(98, ∞), (NULL, 44], (53, ∞), [NULL, ∞)}, {(98, ∞), (44, ∞), [NULL, ∞), [86, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>5 AND v4 BETWEEN 14 AND 43 AND v2>=62) OR (v1>=91 AND v2>=28 AND v3>=83 AND v4<>91));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 5 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v4:4 BETWEEN 14 (tinyint) AND 43 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 62 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 91 (tinyint)\n" + - " │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 28 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 83 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 91 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(5, ∞), [62, ∞), [NULL, ∞), [NULL, ∞)}, {[91, ∞), [28, 62), [83, ∞), (NULL, 91)}, {[91, ∞), [28, 62), [83, ∞), (91, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(5, 91), [62, ∞), [NULL, ∞), [14, 43]}, {[91, ∞), [28, ∞), [83, ∞), (NULL, 91)}, {[91, ∞), [28, ∞), [83, ∞), (91, ∞)}, {[91, ∞), [62, ∞), [NULL, 83), [14, 43]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1<>87) OR (v1>91 AND v2>23 AND v3<74));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 87 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 91 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 23 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 74 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 87), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(87, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 87), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(87, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -15209,68 +7323,12 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((((v1=76 AND v2>35 AND v3<=59 AND v4>25) OR (v1 BETWEEN 35 AND 82 AND v2 BETWEEN 8 AND 37 AND v3>18 AND v4<=70)) OR (v1<=95 AND v3=70 AND v4=11)) OR (v1 BETWEEN 15 AND 23 AND v2<>24 AND v3<=50 AND v4<>84));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ │ │ └─ 76 (tinyint)\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 35 (tinyint)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 25 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 35 (tinyint) AND 82 (tinyint))\n" + - " │ │ │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 8 (tinyint) AND 37 (tinyint))\n" + - " │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ └─ 18 (tinyint)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 70 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 95 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 70 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 11 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 15 (tinyint) AND 23 (tinyint))\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 24 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 50 (tinyint)\n" + - " │ └─ NOT\n" + - " │ └─ Eq\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 84 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 95], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 35), [NULL, ∞), [70, 70], [11, 11]}, {[15, 23], (NULL, 24), (NULL, 50], (NULL, 84)}, {[15, 23], (NULL, 24), (NULL, 50], (84, ∞)}, {[15, 23], (24, ∞), (NULL, 50], (NULL, 84)}, {[15, 23], (24, ∞), (NULL, 50], (84, ∞)}, {[35, 76), [8, 37], (18, ∞), (NULL, 70]}, {[35, 82], [NULL, 8), [70, 70], [11, 11]}, {[35, 82], (37, ∞), [70, 70], [11, 11]}, {[76, 76], [8, 35], (18, ∞), (NULL, 70]}, {[76, 76], (35, 37], (NULL, 18], (25, ∞)}, {[76, 76], (35, 37], (18, 59], (NULL, ∞)}, {[76, 76], (35, 37], (59, ∞), (NULL, 70]}, {[76, 76], (37, ∞), (NULL, 59], (25, ∞)}, {(76, 82], [8, 37], (18, ∞), (NULL, 70]}, {(82, 95], [NULL, ∞), [70, 70], [11, 11]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { @@ -15285,210 +7343,62 @@ var IndexPlanTests = []QueryPlanTest{ }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=79 AND v3<89 AND v4>=3) OR (v1<63 AND v2<66));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 79 (tinyint)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 89 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 3 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 63 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v2:2\n" + - " │ └─ 66 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 63), (NULL, 66), [NULL, ∞), [NULL, ∞)}, {[79, 79], [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 63), (NULL, 66), [NULL, ∞), [NULL, ∞)}, {[79, 79], [NULL, ∞), (NULL, 89), [3, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1<>66) OR (v1=33)) OR (v1<>39 AND v2>53 AND v3<73 AND v4<75));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 66 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 33 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 39 (tinyint)\n" + - " │ │ │ └─ GreaterThan\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 53 (tinyint)\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 73 (tinyint)\n" + - " │ └─ LessThan\n" + - " │ ├─ comp_index_t2.v4:4\n" + - " │ └─ 75 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 66), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[66, 66], (53, ∞), (NULL, 73), (NULL, 75)}, {(66, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 66), [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {[66, 66], (53, ∞), (NULL, 73), (NULL, 75)}, {(66, ∞), [NULL, ∞), [NULL, ∞), [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1=15) OR (v1>36 AND v3=13 AND v4<=98 AND v2 BETWEEN 70 AND 85));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Eq\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 15 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ └─ 13 (tinyint)\n" + - " │ │ └─ LessThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ └─ 98 (tinyint)\n" + - " │ └─ (comp_index_t2.v2:2 BETWEEN 70 (tinyint) AND 85 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[15, 15], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(36, ∞), [70, 85], [13, 13], (NULL, 98]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[15, 15], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(36, ∞), [70, 85], [13, 13], (NULL, 98]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 23 AND 45 AND v4<30) OR (v1>=36 AND v2<>6 AND v3 BETWEEN 30 AND 53)) OR (v1 BETWEEN 41 AND 95));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 23 (tinyint) AND 45 (tinyint))\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ └─ 30 (tinyint)\n" + - " │ │ └─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 36 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 6 (tinyint)\n" + - " │ │ └─ (comp_index_t2.v3:3 BETWEEN 30 (tinyint) AND 53 (tinyint))\n" + - " │ └─ (comp_index_t2.v1:1 BETWEEN 41 (tinyint) AND 95 (tinyint))\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[23, 95], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(95, ∞), (NULL, 6), [30, 53], [NULL, ∞)}, {(95, ∞), (6, ∞), [30, 53], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[23, 36), [NULL, ∞), [NULL, ∞), (NULL, 30)}, {[36, 41), [NULL, NULL], [NULL, ∞), (NULL, 30)}, {[36, 41), (NULL, 6), [NULL, 30), (NULL, 30)}, {[36, 41), (NULL, 6), [30, 53], [NULL, ∞)}, {[36, 41), (NULL, 6), (53, ∞), (NULL, 30)}, {[36, 41), [6, 6], [NULL, ∞), (NULL, 30)}, {[36, 41), (6, ∞), [NULL, 30), (NULL, 30)}, {[36, 41), (6, ∞), [30, 53], [NULL, ∞)}, {[36, 41), (6, ∞), (53, ∞), (NULL, 30)}, {[41, 95], [NULL, ∞), [NULL, ∞), [NULL, ∞)}, {(95, ∞), (NULL, 6), [30, 53], [NULL, ∞)}, {(95, ∞), (6, ∞), [30, 53], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE ((v1>6 AND v4<>9 AND v2<>77 AND v3>=81) OR (v1<>21 AND v2>=17 AND v3<=3));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ │ └─ 6 (tinyint)\n" + - " │ │ │ │ └─ NOT\n" + - " │ │ │ │ └─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 9 (tinyint)\n" + - " │ │ │ └─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ └─ 77 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ └─ 81 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ NOT\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ └─ 21 (tinyint)\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 17 (tinyint)\n" + - " │ └─ LessThanOrEqual\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 3 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{(NULL, 21), [17, ∞), (NULL, 3], [NULL, ∞)}, {(6, ∞), (NULL, 77), [81, ∞), (NULL, 9)}, {(6, ∞), (NULL, 77), [81, ∞), (9, ∞)}, {(6, ∞), (77, ∞), [81, ∞), (NULL, 9)}, {(6, ∞), (77, ∞), [81, ∞), (9, ∞)}, {(21, ∞), [17, ∞), (NULL, 3], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{(NULL, 21), [17, ∞), (NULL, 3], [NULL, ∞)}, {(6, ∞), (NULL, 77), [81, ∞), (NULL, 9)}, {(6, ∞), (NULL, 77), [81, ∞), (9, ∞)}, {(6, ∞), (77, ∞), [81, ∞), (NULL, 9)}, {(6, ∞), (77, ∞), [81, ∞), (9, ∞)}, {(21, ∞), [17, ∞), (NULL, 3], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { Query: `SELECT * FROM comp_index_t2 WHERE (((v1 BETWEEN 94 AND 99 AND v2>4 AND v3<94 AND v4<=59) OR (v1=19 AND v2 BETWEEN 47 AND 54)) AND (v1>=83) OR (v1 BETWEEN 50 AND 97 AND v2<12 AND v3>23));`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ AND\n" + - " │ │ ├─ Or\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ (comp_index_t2.v1:1 BETWEEN 94 (tinyint) AND 99 (tinyint))\n" + - " │ │ │ │ │ │ └─ GreaterThan\n" + - " │ │ │ │ │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ │ │ │ │ └─ 4 (tinyint)\n" + - " │ │ │ │ │ └─ LessThan\n" + - " │ │ │ │ │ ├─ comp_index_t2.v3:3\n" + - " │ │ │ │ │ └─ 94 (tinyint)\n" + - " │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ ├─ comp_index_t2.v4:4\n" + - " │ │ │ │ └─ 59 (tinyint)\n" + - " │ │ │ └─ AND\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ │ │ └─ 19 (tinyint)\n" + - " │ │ │ └─ (comp_index_t2.v2:2 BETWEEN 47 (tinyint) AND 54 (tinyint))\n" + - " │ │ └─ GreaterThanOrEqual\n" + - " │ │ ├─ comp_index_t2.v1:1\n" + - " │ │ └─ 83 (tinyint)\n" + - " │ └─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ (comp_index_t2.v1:1 BETWEEN 50 (tinyint) AND 97 (tinyint))\n" + - " │ │ └─ LessThan\n" + - " │ │ ├─ comp_index_t2.v2:2\n" + - " │ │ └─ 12 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ comp_index_t2.v3:3\n" + - " │ └─ 23 (tinyint)\n" + - " └─ IndexedTableAccess(comp_index_t2)\n" + - " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + - " ├─ static: [{[50, 97], (NULL, 12), (23, ∞), [NULL, ∞)}, {[94, 97], (4, 12), (NULL, 23], (NULL, 59]}, {[94, 97], [12, ∞), (NULL, 94), (NULL, 59]}, {(97, 99], (4, ∞), (NULL, 94), (NULL, 59]}]\n" + - " └─ Table\n" + - " ├─ name: comp_index_t2\n" + - " └─ columns: [pk v1 v2 v3 v4]\n" + + ExpectedPlan: "IndexedTableAccess(comp_index_t2)\n" + + " ├─ index: [comp_index_t2.v1,comp_index_t2.v2,comp_index_t2.v3,comp_index_t2.v4]\n" + + " ├─ static: [{[50, 97], (NULL, 12), (23, ∞), [NULL, ∞)}, {[94, 97], (4, 12), (NULL, 23], (NULL, 59]}, {[94, 97], [12, ∞), (NULL, 94), (NULL, 59]}, {(97, 99], (4, ∞), (NULL, 94), (NULL, 59]}]\n" + + " └─ Table\n" + + " ├─ name: comp_index_t2\n" + + " └─ columns: [pk v1 v2 v3 v4]\n" + "", }, { diff --git a/enginetest/queries/information_schema_queries.go b/enginetest/queries/information_schema_queries.go index 520bca2667..283038906f 100644 --- a/enginetest/queries/information_schema_queries.go +++ b/enginetest/queries/information_schema_queries.go @@ -1644,12 +1644,11 @@ var StatisticsQueries = []ScriptTest{ { Query: "SELECT * FROM information_schema.column_statistics", Expected: []sql.Row{ - {"mydb", "t", "i", stats.NewStatistic(3, 3, 0, 24, time.Now(), sql.NewStatQualifier("mydb", "t", "primary"), []string{"i"}, []sql.Type{types.Int64}, - []*stats.Bucket{ - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(1)}, nil, nil), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(2)}, nil, nil), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(3)}, nil, nil), - }), + {"mydb", "t", "i", stats.NewStatistic(3, 3, 0, 24, time.Now(), sql.NewStatQualifier("mydb", "t", "primary"), []string{"i"}, []sql.Type{types.Int64}, []*stats.Bucket{ + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(1)}, nil, nil), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(2)}, nil, nil), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(3)}, nil, nil), + }, sql.IndexClassDefault), }, }, }, @@ -1669,14 +1668,10 @@ var StatisticsQueries = []ScriptTest{ { Query: "SELECT * FROM information_schema.column_statistics", Expected: []sql.Row{ - {"mydb", "t", "i", stats.NewStatistic(40, 40, 1, 0, time.Now(), - sql.NewStatQualifier("mydb", "t", ""), - []string{"i"}, - []sql.Type{types.Int64}, - []*stats.Bucket{ - stats.NewHistogramBucket(20, 20, 0, 1, sql.Row{float64(50)}, nil, nil), - stats.NewHistogramBucket(20, 20, 0, 1, sql.Row{float64(80)}, nil, nil), - }), + {"mydb", "t", "i", stats.NewStatistic(40, 40, 1, 0, time.Now(), sql.NewStatQualifier("mydb", "t", "primary"), []string{"i"}, []sql.Type{types.Int64}, []*stats.Bucket{ + stats.NewHistogramBucket(20, 20, 0, 1, sql.Row{float64(50)}, nil, nil), + stats.NewHistogramBucket(20, 20, 0, 1, sql.Row{float64(80)}, nil, nil), + }, sql.IndexClassDefault), }, }, }, @@ -1701,25 +1696,17 @@ var StatisticsQueries = []ScriptTest{ { Query: "SELECT * FROM information_schema.column_statistics", Expected: []sql.Row{ - {"mydb", "t", "i", stats.NewStatistic(3, 3, 0, 48, time.Now(), - sql.NewStatQualifier("mydb", "t", "primary"), - []string{"i"}, - []sql.Type{types.Int64}, - []*stats.Bucket{ - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(1)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(2)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(3)}, nil, []sql.Row{}), - }), + {"mydb", "t", "i", stats.NewStatistic(3, 3, 0, 48, time.Now(), sql.NewStatQualifier("mydb", "t", "primary"), []string{"i"}, []sql.Type{types.Int64}, []*stats.Bucket{ + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(1)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(2)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(3)}, nil, []sql.Row{}), + }, sql.IndexClassDefault), }, - {"mydb", "t", "j", stats.NewStatistic(3, 3, 0, 48, time.Now(), - sql.NewStatQualifier("mydb", "t", "j"), - []string{"j"}, - []sql.Type{types.Int64}, - []*stats.Bucket{ - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(4)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(5)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(6)}, nil, []sql.Row{}), - }), + {"mydb", "t", "j", stats.NewStatistic(3, 3, 0, 48, time.Now(), sql.NewStatQualifier("mydb", "t", "j"), []string{"j"}, []sql.Type{types.Int64}, []*stats.Bucket{ + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(4)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(5)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{int64(6)}, nil, []sql.Row{}), + }, sql.IndexClassDefault), }, }, }, @@ -1736,16 +1723,12 @@ var StatisticsQueries = []ScriptTest{ { Query: "SELECT * FROM information_schema.column_statistics", Expected: []sql.Row{ - {"mydb", "t", "i", stats.NewStatistic(4, 4, 0, 32, time.Now(), - sql.NewStatQualifier("mydb", "t", "primary"), - []string{"i"}, - []sql.Type{types.Float64}, - []*stats.Bucket{ - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(1.25)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(7.5)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(10.5)}, nil, []sql.Row{}), - stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(45.25)}, nil, []sql.Row{}), - }), + {"mydb", "t", "i", stats.NewStatistic(4, 4, 0, 32, time.Now(), sql.NewStatQualifier("mydb", "t", "primary"), []string{"i"}, []sql.Type{types.Float64}, []*stats.Bucket{ + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(1.25)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(7.5)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(10.5)}, nil, []sql.Row{}), + stats.NewHistogramBucket(1, 1, 0, 1, sql.Row{float64(45.25)}, nil, []sql.Row{}), + }, sql.IndexClassDefault), }, }, }, diff --git a/enginetest/queries/integration_plans.go b/enginetest/queries/integration_plans.go index 9baa4973a2..979c8c535e 100644 --- a/enginetest/queries/integration_plans.go +++ b/enginetest/queries/integration_plans.go @@ -163,16 +163,13 @@ WHERE " │ │ ├─ name: HDDVB\n" + " │ │ └─ columns: [uj6xy]\n" + " │ │ as WGBRL]\n" + - " │ └─ Filter\n" + - " │ ├─ NOT\n" + - " │ │ └─ nd.ZH72S:7 IS NULL\n" + - " │ └─ TableAlias(nd)\n" + - " │ └─ IndexedTableAccess(E2I7U)\n" + - " │ ├─ index: [E2I7U.ZH72S]\n" + - " │ ├─ static: [{(NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: E2I7U\n" + - " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " │ └─ TableAlias(nd)\n" + + " │ └─ IndexedTableAccess(E2I7U)\n" + + " │ ├─ index: [E2I7U.ZH72S]\n" + + " │ ├─ static: [{(NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: E2I7U\n" + + " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + " └─ TableAlias(pbmrx)\n" + " └─ IndexedTableAccess(E2I7U)\n" + " ├─ index: [E2I7U.ZH72S]\n" + @@ -766,16 +763,13 @@ WHERE " │ │ ├─ name: FLQLP\n" + " │ │ └─ columns: [luevy]\n" + " │ │ as LEA4J]\n" + - " │ └─ Filter\n" + - " │ ├─ NOT\n" + - " │ │ └─ nd.ZH72S:7 IS NULL\n" + - " │ └─ TableAlias(nd)\n" + - " │ └─ IndexedTableAccess(E2I7U)\n" + - " │ ├─ index: [E2I7U.ZH72S]\n" + - " │ ├─ static: [{(NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: E2I7U\n" + - " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " │ └─ TableAlias(nd)\n" + + " │ └─ IndexedTableAccess(E2I7U)\n" + + " │ ├─ index: [E2I7U.ZH72S]\n" + + " │ ├─ static: [{(NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: E2I7U\n" + + " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + " └─ TableAlias(pbmrx)\n" + " └─ IndexedTableAccess(E2I7U)\n" + " ├─ index: [E2I7U.ZH72S]\n" + @@ -1080,10 +1074,10 @@ WHERE " │ │ │ ├─ right-key: TUPLE(scalarSubq0.NRURT:0)\n" + " │ │ │ └─ Project\n" + " │ │ │ ├─ columns: [scalarSubq0.NRURT:5]\n" + - " │ │ │ └─ Filter\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ scalarSubq0.NRURT:5 IS NULL\n" + - " │ │ │ └─ TableAlias(scalarSubq0)\n" + + " │ │ │ └─ TableAlias(scalarSubq0)\n" + + " │ │ │ └─ IndexedTableAccess(FLQLP)\n" + + " │ │ │ ├─ index: [FLQLP.NRURT]\n" + + " │ │ │ ├─ static: [{(NULL, ∞)}]\n" + " │ │ │ └─ Table\n" + " │ │ │ ├─ name: FLQLP\n" + " │ │ │ └─ columns: [id fz2r5 luevy m22qn ove3e nrurt oca7e xmm6q v5dpx s3q3y zrv3b fhcyt]\n" + @@ -1748,16 +1742,13 @@ WHERE " │ │ ├─ name: AMYXQ\n" + " │ │ └─ columns: [luevy]\n" + " │ │ as TJ66D]\n" + - " │ └─ Filter\n" + - " │ ├─ NOT\n" + - " │ │ └─ nd.ZH72S:7 IS NULL\n" + - " │ └─ TableAlias(nd)\n" + - " │ └─ IndexedTableAccess(E2I7U)\n" + - " │ ├─ index: [E2I7U.ZH72S]\n" + - " │ ├─ static: [{(NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: E2I7U\n" + - " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " │ └─ TableAlias(nd)\n" + + " │ └─ IndexedTableAccess(E2I7U)\n" + + " │ ├─ index: [E2I7U.ZH72S]\n" + + " │ ├─ static: [{(NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: E2I7U\n" + + " │ └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + " └─ TableAlias(pbmrx)\n" + " └─ IndexedTableAccess(E2I7U)\n" + " ├─ index: [E2I7U.ZH72S]\n" + @@ -1831,16 +1822,13 @@ WHERE " └─ HashLookup\n" + " ├─ left-key: TUPLE(ufc.ZH72S:2)\n" + " ├─ right-key: TUPLE(nd.ZH72S:7)\n" + - " └─ Filter\n" + - " ├─ NOT\n" + - " │ └─ nd.ZH72S:7 IS NULL\n" + - " └─ TableAlias(nd)\n" + - " └─ IndexedTableAccess(E2I7U)\n" + - " ├─ index: [E2I7U.ZH72S]\n" + - " ├─ static: [{(NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: E2I7U\n" + - " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " └─ TableAlias(nd)\n" + + " └─ IndexedTableAccess(E2I7U)\n" + + " ├─ index: [E2I7U.ZH72S]\n" + + " ├─ static: [{(NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: E2I7U\n" + + " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + "", }, { @@ -1907,16 +1895,13 @@ WHERE " └─ HashLookup\n" + " ├─ left-key: TUPLE(ufc.ZH72S:2)\n" + " ├─ right-key: TUPLE(nd.ZH72S:7)\n" + - " └─ Filter\n" + - " ├─ NOT\n" + - " │ └─ nd.ZH72S:7 IS NULL\n" + - " └─ TableAlias(nd)\n" + - " └─ IndexedTableAccess(E2I7U)\n" + - " ├─ index: [E2I7U.ZH72S]\n" + - " ├─ static: [{(NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: E2I7U\n" + - " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " └─ TableAlias(nd)\n" + + " └─ IndexedTableAccess(E2I7U)\n" + + " ├─ index: [E2I7U.ZH72S]\n" + + " ├─ static: [{(NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: E2I7U\n" + + " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + "", }, { @@ -2259,16 +2244,13 @@ WHERE " └─ HashLookup\n" + " ├─ left-key: TUPLE(umf.FGG57:2)\n" + " ├─ right-key: TUPLE(nd.FGG57:6)\n" + - " └─ Filter\n" + - " ├─ NOT\n" + - " │ └─ nd.FGG57:6 IS NULL\n" + - " └─ TableAlias(nd)\n" + - " └─ IndexedTableAccess(E2I7U)\n" + - " ├─ index: [E2I7U.FGG57]\n" + - " ├─ static: [{(NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: E2I7U\n" + - " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + + " └─ TableAlias(nd)\n" + + " └─ IndexedTableAccess(E2I7U)\n" + + " ├─ index: [E2I7U.FGG57]\n" + + " ├─ static: [{(NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: E2I7U\n" + + " └─ columns: [id dkcaj kng7t tw55n qrqxw ecxaj fgg57 zh72s fsk67 xqdyt tce7a iwv2h hpcms n5cc2 fhcyt etaq7 a75x7]\n" + "", }, { @@ -3398,7 +3380,7 @@ WHERE " └─ TableAlias(nt)\n" + " └─ IndexedTableAccess(F35MI)\n" + " ├─ index: [F35MI.DZLIM]\n" + - " ├─ static: [{(SUZTA, ∞)}, {(NULL, SUZTA)}]\n" + + " ├─ static: [{(NULL, SUZTA)}, {(SUZTA, ∞)}]\n" + " └─ Table\n" + " ├─ name: F35MI\n" + " └─ columns: [id dzlim f3yue]\n" + @@ -8927,8 +8909,8 @@ WHERE LUEVY IN ('1', '2', '3')`, " │ ├─ amyxq.LUEVY:2!null\n" + " │ └─ TUPLE(1 (longtext), 2 (longtext), 3 (longtext))\n" + " └─ IndexedTableAccess(AMYXQ)\n" + - " ├─ index: [AMYXQ.LUEVY]\n" + - " ├─ static: [{[1, 1]}, {[2, 2]}, {[3, 3]}]\n" + + " ├─ index: [AMYXQ.GXLUB,AMYXQ.LUEVY]\n" + + " ├─ static: [{[NULL, ∞), [1, 1]}, {[NULL, ∞), [2, 2]}, {[NULL, ∞), [3, 3]}]\n" + " └─ Table\n" + " ├─ name: AMYXQ\n" + " └─ columns: [id gxlub luevy xqdyt amyxq oztqf z35gy kkgn5]\n" + @@ -9061,10 +9043,8 @@ WHERE nd.FGG57 IS NOT NULL AND nd.KNG7T IS NULL`, " └─ columns: [id sshpj]\n" + " )\n" + " └─ Filter\n" + - " ├─ AND\n" + - " │ ├─ NOT\n" + - " │ │ └─ nd.FGG57:6 IS NULL\n" + - " │ └─ nd.KNG7T:2 IS NULL\n" + + " ├─ NOT\n" + + " │ └─ nd.FGG57:6 IS NULL\n" + " └─ TableAlias(nd)\n" + " └─ IndexedTableAccess(E2I7U)\n" + " ├─ index: [E2I7U.KNG7T]\n" + @@ -10473,15 +10453,12 @@ WHERE " │ │ │ │ │ └─ right: Subquery\n" + " │ │ │ │ │ ├─ cacheable: true\n" + " │ │ │ │ │ ├─ alias-string: select BTXC5 from TPXBU where BTXC5 is not null\n" + - " │ │ │ │ │ └─ Filter\n" + - " │ │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ │ └─ tpxbu.BTXC5:25 IS NULL\n" + - " │ │ │ │ │ └─ IndexedTableAccess(TPXBU)\n" + - " │ │ │ │ │ ├─ index: [TPXBU.BTXC5]\n" + - " │ │ │ │ │ ├─ static: [{(NULL, ∞)}]\n" + - " │ │ │ │ │ └─ Table\n" + - " │ │ │ │ │ ├─ name: TPXBU\n" + - " │ │ │ │ │ └─ columns: [btxc5]\n" + + " │ │ │ │ │ └─ IndexedTableAccess(TPXBU)\n" + + " │ │ │ │ │ ├─ index: [TPXBU.BTXC5]\n" + + " │ │ │ │ │ ├─ static: [{(NULL, ∞)}]\n" + + " │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ ├─ name: TPXBU\n" + + " │ │ │ │ │ └─ columns: [btxc5]\n" + " │ │ │ │ └─ NOT\n" + " │ │ │ │ └─ umf.SYPKF:8 IS NULL\n" + " │ │ │ └─ NOT\n" + @@ -10655,12 +10632,9 @@ INNER JOIN THNTS bs ON cla.id = bs.IXUXU`, " │ │ └─ Project\n" + " │ │ ├─ columns: [nd_for_id.id:84!null]\n" + " │ │ └─ Filter\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ nd_for_id.FGG57:85 IS NULL\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ nd_for_id.FGG57:85\n" + - " │ │ │ └─ umf.FGG57:2\n" + + " │ │ ├─ Eq\n" + + " │ │ │ ├─ nd_for_id.FGG57:85\n" + + " │ │ │ └─ umf.FGG57:2\n" + " │ │ └─ TableAlias(nd_for_id)\n" + " │ │ └─ IndexedTableAccess(E2I7U)\n" + " │ │ ├─ index: [E2I7U.FGG57]\n" + @@ -10676,14 +10650,12 @@ INNER JOIN THNTS bs ON cla.id = bs.IXUXU`, " │ │ ├─ alias-string: select id from TPXBU where BTXC5 is null\n" + " │ │ └─ Project\n" + " │ │ ├─ columns: [tpxbu.id:84!null]\n" + - " │ │ └─ Filter\n" + - " │ │ ├─ tpxbu.BTXC5:85 IS NULL\n" + - " │ │ └─ IndexedTableAccess(TPXBU)\n" + - " │ │ ├─ index: [TPXBU.BTXC5]\n" + - " │ │ ├─ static: [{[NULL, NULL]}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: TPXBU\n" + - " │ │ └─ columns: [id btxc5]\n" + + " │ │ └─ IndexedTableAccess(TPXBU)\n" + + " │ │ ├─ index: [TPXBU.BTXC5]\n" + + " │ │ ├─ static: [{[NULL, NULL]}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: TPXBU\n" + + " │ │ └─ columns: [id btxc5]\n" + " │ │ ELSE Subquery\n" + " │ │ ├─ cacheable: false\n" + " │ │ ├─ alias-string: select aac.id from TPXBU as aac where aac.BTXC5 = umf.SYPKF\n" + @@ -10750,12 +10722,9 @@ INNER JOIN THNTS bs ON cla.id = bs.IXUXU`, " │ │ └─ Project\n" + " │ │ ├─ columns: [nd_for_id.id:67!null]\n" + " │ │ └─ Filter\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ NOT\n" + - " │ │ │ │ └─ nd_for_id.FGG57:68 IS NULL\n" + - " │ │ │ └─ Eq\n" + - " │ │ │ ├─ nd_for_id.FGG57:68\n" + - " │ │ │ └─ umf.FGG57:6\n" + + " │ │ ├─ Eq\n" + + " │ │ │ ├─ nd_for_id.FGG57:68\n" + + " │ │ │ └─ umf.FGG57:6\n" + " │ │ └─ TableAlias(nd_for_id)\n" + " │ │ └─ IndexedTableAccess(E2I7U)\n" + " │ │ ├─ index: [E2I7U.FGG57]\n" + @@ -10771,14 +10740,12 @@ INNER JOIN THNTS bs ON cla.id = bs.IXUXU`, " │ │ ├─ alias-string: select id from TPXBU where BTXC5 is null\n" + " │ │ └─ Project\n" + " │ │ ├─ columns: [tpxbu.id:67!null]\n" + - " │ │ └─ Filter\n" + - " │ │ ├─ tpxbu.BTXC5:68 IS NULL\n" + - " │ │ └─ IndexedTableAccess(TPXBU)\n" + - " │ │ ├─ index: [TPXBU.BTXC5]\n" + - " │ │ ├─ static: [{[NULL, NULL]}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: TPXBU\n" + - " │ │ └─ columns: [id btxc5]\n" + + " │ │ └─ IndexedTableAccess(TPXBU)\n" + + " │ │ ├─ index: [TPXBU.BTXC5]\n" + + " │ │ ├─ static: [{[NULL, NULL]}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: TPXBU\n" + + " │ │ └─ columns: [id btxc5]\n" + " │ │ ELSE Subquery\n" + " │ │ ├─ cacheable: false\n" + " │ │ ├─ alias-string: select aac.id from TPXBU as aac where aac.BTXC5 = umf.SYPKF\n" + @@ -10858,35 +10825,32 @@ INNER JOIN THNTS bs ON cla.id = bs.IXUXU`, " │ │ │ ├─ AND\n" + " │ │ │ │ ├─ AND\n" + " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ HashIn\n" + - " │ │ │ │ │ │ │ ├─ nzkpm.id:0!null\n" + - " │ │ │ │ │ │ │ └─ TUPLE(1 (longtext), 2 (longtext), 3 (longtext))\n" + - " │ │ │ │ │ │ └─ NOT\n" + - " │ │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ │ ├─ nzkpm.ARN5P:7\n" + - " │ │ │ │ │ │ └─ N/A (longtext)\n" + - " │ │ │ │ │ └─ InSubquery\n" + - " │ │ │ │ │ ├─ left: nzkpm.T4IBQ:1\n" + - " │ │ │ │ │ └─ right: Subquery\n" + - " │ │ │ │ │ ├─ cacheable: true\n" + - " │ │ │ │ │ ├─ alias-string: select FTQLQ from YK2GW\n" + - " │ │ │ │ │ └─ Table\n" + - " │ │ │ │ │ ├─ name: YK2GW\n" + - " │ │ │ │ │ └─ columns: [ftqlq]\n" + - " │ │ │ │ └─ InSubquery\n" + - " │ │ │ │ ├─ left: nzkpm.FGG57:2\n" + - " │ │ │ │ └─ right: Subquery\n" + - " │ │ │ │ ├─ cacheable: true\n" + - " │ │ │ │ ├─ alias-string: select FGG57 from E2I7U where FGG57 is not null\n" + - " │ │ │ │ └─ Filter\n" + - " │ │ │ │ ├─ NOT\n" + - " │ │ │ │ │ └─ e2i7u.FGG57:25 IS NULL\n" + - " │ │ │ │ └─ IndexedTableAccess(E2I7U)\n" + - " │ │ │ │ ├─ index: [E2I7U.FGG57]\n" + - " │ │ │ │ ├─ static: [{(NULL, ∞)}]\n" + - " │ │ │ │ └─ Table\n" + - " │ │ │ │ ├─ name: E2I7U\n" + - " │ │ │ │ └─ columns: [fgg57]\n" + + " │ │ │ │ │ │ ├─ InSubquery\n" + + " │ │ │ │ │ │ │ ├─ left: nzkpm.T4IBQ:1\n" + + " │ │ │ │ │ │ │ └─ right: Subquery\n" + + " │ │ │ │ │ │ │ ├─ cacheable: true\n" + + " │ │ │ │ │ │ │ ├─ alias-string: select FTQLQ from YK2GW\n" + + " │ │ │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ │ │ ├─ name: YK2GW\n" + + " │ │ │ │ │ │ │ └─ columns: [ftqlq]\n" + + " │ │ │ │ │ │ └─ InSubquery\n" + + " │ │ │ │ │ │ ├─ left: nzkpm.FGG57:2\n" + + " │ │ │ │ │ │ └─ right: Subquery\n" + + " │ │ │ │ │ │ ├─ cacheable: true\n" + + " │ │ │ │ │ │ ├─ alias-string: select FGG57 from E2I7U where FGG57 is not null\n" + + " │ │ │ │ │ │ └─ IndexedTableAccess(E2I7U)\n" + + " │ │ │ │ │ │ ├─ index: [E2I7U.FGG57]\n" + + " │ │ │ │ │ │ ├─ static: [{(NULL, ∞)}]\n" + + " │ │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ │ ├─ name: E2I7U\n" + + " │ │ │ │ │ │ └─ columns: [fgg57]\n" + + " │ │ │ │ │ └─ HashIn\n" + + " │ │ │ │ │ ├─ nzkpm.id:0!null\n" + + " │ │ │ │ │ └─ TUPLE(1 (longtext), 2 (longtext), 3 (longtext))\n" + + " │ │ │ │ └─ NOT\n" + + " │ │ │ │ └─ Eq\n" + + " │ │ │ │ ├─ nzkpm.ARN5P:7\n" + + " │ │ │ │ └─ N/A (longtext)\n" + " │ │ │ └─ IndexedTableAccess(NZKPM)\n" + " │ │ │ ├─ index: [NZKPM.id]\n" + " │ │ │ ├─ static: [{[1, 1]}, {[2, 2]}, {[3, 3]}]\n" + diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index 8199609108..b2fd4dde52 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -38,6 +38,28 @@ type QueryTest struct { SkipPrepared bool } +type QueryPlanTest struct { + Query string + ExpectedPlan string + Skip bool +} + +// QueryPlanTODOs are queries where the query planner produces a correct (results) but suboptimal plan. +var QueryPlanTODOs = []QueryPlanTest{ + { + // TODO: this should use an index. Extra join condition should get moved out of the join clause into a filter + Query: `SELECT pk,i,f FROM one_pk RIGHT JOIN niltable ON pk=i and pk > 0 ORDER BY 2,3`, + ExpectedPlan: "Sort(niltable.i ASC, niltable.f ASC)\n" + + " └─ Project(one_pk.pk, niltable.i, niltable.f)\n" + + " └─ RightJoin((one_pk.pk = niltable.i) AND (one_pk.pk > 0))\n" + + " ├─ Projected table access on [pk]\n" + + " │ └─ Table(one_pk)\n" + + " └─ Projected table access on [i f]\n" + + " └─ Table(niltable)\n" + + "", + }, +} + var SpatialQueryTests = []QueryTest{ { Query: `SHOW CREATE TABLE point_table`, diff --git a/enginetest/queries/query_plans.go b/enginetest/queries/query_plans.go index 5f77de7b95..8318c2117d 100644 --- a/enginetest/queries/query_plans.go +++ b/enginetest/queries/query_plans.go @@ -16,13 +16,19 @@ package queries -type QueryPlanTest struct { - Query string - ExpectedPlan string - Skip bool -} - var PlanTests = []QueryPlanTest{ + { + Query: `select * from asset where name = 'val'`, + ExpectedPlan: "Filter\n" + + " ├─ Eq\n" + + " │ ├─ asset.name:3\n" + + " │ └─ val (longtext)\n" + + " └─ ProcessTable\n" + + " └─ Table\n" + + " ├─ name: asset\n" + + " └─ columns: [id orgid assetid name val]\n" + + "", + }, { Query: `select * from xy join uv on (x = u and u > 0) where u < 2`, ExpectedPlan: "Project\n" + @@ -113,16 +119,12 @@ From xy;`, { Query: `select * from MYTABLE where I = 2 and s = 'first row'`, ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ mytable.I:0!null\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ mytable.s:1!null\n" + - " │ └─ first row (longtext)\n" + + " ├─ Eq\n" + + " │ ├─ mytable.s:1!null\n" + + " │ └─ first row (longtext)\n" + " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.s,mytable.i]\n" + - " ├─ static: [{[first row, first row], [2, 2]}]\n" + + " ├─ index: [mytable.i]\n" + + " ├─ static: [{[2, 2]}]\n" + " └─ Table\n" + " ├─ name: mytable\n" + " └─ columns: [i s]\n" + @@ -466,8 +468,8 @@ where " │ │ │ └─ org1 (longtext)\n" + " │ │ └─ TableAlias(color)\n" + " │ │ └─ IndexedTableAccess(asset)\n" + - " │ │ ├─ index: [asset.orgId,asset.name,asset.val]\n" + - " │ │ ├─ static: [{[org1, org1], [color, color], [blue, blue]}]\n" + + " │ │ ├─ index: [asset.orgId,asset.name,asset.assetId]\n" + + " │ │ ├─ static: [{[org1, org1], [color, color], [NULL, ∞)}]\n" + " │ │ └─ Table\n" + " │ │ ├─ name: asset\n" + " │ │ └─ columns: [orgid assetid name val]\n" + @@ -514,17 +516,13 @@ where { Query: `select * from mytable alias where i = 1 and s = 'first row'`, ExpectedPlan: "Filter\n" + - " ├─ AND\n" + - " │ ├─ Eq\n" + - " │ │ ├─ alias.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ Eq\n" + - " │ ├─ alias.s:1!null\n" + - " │ └─ first row (longtext)\n" + + " ├─ Eq\n" + + " │ ├─ alias.s:1!null\n" + + " │ └─ first row (longtext)\n" + " └─ TableAlias(alias)\n" + " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.s,mytable.i]\n" + - " ├─ static: [{[first row, first row], [1, 1]}]\n" + + " ├─ index: [mytable.i]\n" + + " ├─ static: [{[1, 1]}]\n" + " └─ Table\n" + " ├─ name: mytable\n" + " └─ columns: [i s]\n" + @@ -605,9 +603,12 @@ where " │ │ │ ├─ scalarSubq0.sub_part:1!null\n" + " │ │ │ └─ crust (longtext)\n" + " │ │ └─ TableAlias(scalarSubq0)\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: parts\n" + - " │ │ └─ columns: [part sub_part quantity]\n" + + " │ │ └─ IndexedTableAccess(parts)\n" + + " │ │ ├─ index: [parts.part,parts.sub_part]\n" + + " │ │ ├─ static: [{[pie, pie], [crust, crust]}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: parts\n" + + " │ │ └─ columns: [part sub_part quantity]\n" + " │ └─ IndexedTableAccess(parts)\n" + " │ ├─ index: [parts.part,parts.sub_part]\n" + " │ ├─ keys: [scalarSubq0.part]\n" + @@ -972,7 +973,9 @@ Select * from ( " │ │ ├─ scalarSubq0.s2:0!null\n" + " │ │ └─ second (longtext)\n" + " │ └─ TableAlias(scalarSubq0)\n" + - " │ └─ ProcessTable\n" + + " │ └─ IndexedTableAccess(othertable)\n" + + " │ ├─ index: [othertable.s2]\n" + + " │ ├─ static: [{[second, second]}]\n" + " │ └─ Table\n" + " │ ├─ name: othertable\n" + " │ └─ columns: [s2 i2]\n" + @@ -1882,17 +1885,13 @@ Select * from ( " ├─ left-key: TUPLE()\n" + " ├─ right-key: TUPLE()\n" + " └─ Limit(1)\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ ab_1.a:0!null\n" + - " │ └─ 1 (tinyint)\n" + - " └─ TableAlias(ab_1)\n" + - " └─ IndexedTableAccess(ab)\n" + - " ├─ index: [ab.a]\n" + - " ├─ static: [{[1, 1]}]\n" + - " └─ Table\n" + - " ├─ name: ab\n" + - " └─ columns: [a b]\n" + + " └─ TableAlias(ab_1)\n" + + " └─ IndexedTableAccess(ab)\n" + + " ├─ index: [ab.a]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: ab\n" + + " └─ columns: [a b]\n" + "", }, { @@ -2630,17 +2629,13 @@ inner join pq on true ExpectedPlan: "Project\n" + " ├─ columns: [t1.i:1!null]\n" + " └─ LookupJoin\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t2.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + @@ -2689,8 +2684,8 @@ inner join pq on true " ├─ NOT\n" + " │ └─ one_pk_two_idx.v2:2 IS NULL\n" + " └─ IndexedTableAccess(one_pk_two_idx)\n" + - " ├─ index: [one_pk_two_idx.v1,one_pk_two_idx.v2]\n" + - " ├─ static: [{(NULL, 2), (NULL, ∞)}]\n" + + " ├─ index: [one_pk_two_idx.v1]\n" + + " ├─ static: [{(NULL, 2)}]\n" + " └─ Table\n" + " ├─ name: one_pk_two_idx\n" + " └─ columns: [pk v1 v2]\n" + @@ -2699,12 +2694,16 @@ inner join pq on true { Query: `SELECT * FROM one_pk_two_idx WHERE v1 IN (1, 2) AND v2 <= 2`, ExpectedPlan: "Filter\n" + - " ├─ HashIn\n" + - " │ ├─ one_pk_two_idx.v1:1\n" + - " │ └─ TUPLE(1 (tinyint), 2 (tinyint))\n" + + " ├─ AND\n" + + " │ ├─ HashIn\n" + + " │ │ ├─ one_pk_two_idx.v1:1\n" + + " │ │ └─ TUPLE(1 (tinyint), 2 (tinyint))\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ one_pk_two_idx.v2:2\n" + + " │ └─ 2 (tinyint)\n" + " └─ IndexedTableAccess(one_pk_two_idx)\n" + - " ├─ index: [one_pk_two_idx.v1,one_pk_two_idx.v2]\n" + - " ├─ static: [{[1, 1], (NULL, 2]}, {[2, 2], (NULL, 2]}]\n" + + " ├─ index: [one_pk_two_idx.v1]\n" + + " ├─ static: [{[1, 1]}, {[2, 2]}]\n" + " └─ Table\n" + " ├─ name: one_pk_two_idx\n" + " └─ columns: [pk v1 v2]\n" + @@ -2722,16 +2721,12 @@ inner join pq on true }, { Query: `SELECT * FROM one_pk_three_idx WHERE v1 > 2 AND v3 = 3`, - ExpectedPlan: "Filter\n" + - " ├─ Eq\n" + - " │ ├─ one_pk_three_idx.v3:3\n" + - " │ └─ 3 (tinyint)\n" + - " └─ IndexedTableAccess(one_pk_three_idx)\n" + - " ├─ index: [one_pk_three_idx.v1,one_pk_three_idx.v2,one_pk_three_idx.v3]\n" + - " ├─ static: [{(2, ∞), [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: one_pk_three_idx\n" + - " └─ columns: [pk v1 v2 v3]\n" + + ExpectedPlan: "IndexedTableAccess(one_pk_three_idx)\n" + + " ├─ index: [one_pk_three_idx.v1,one_pk_three_idx.v2,one_pk_three_idx.v3]\n" + + " ├─ static: [{(2, ∞), [NULL, ∞), [3, 3]}]\n" + + " └─ Table\n" + + " ├─ name: one_pk_three_idx\n" + + " └─ columns: [pk v1 v2 v3]\n" + "", }, { @@ -2783,17 +2778,13 @@ inner join pq on true " └─ Project\n" + " ├─ columns: [t1.i:1!null, hello (longtext)]\n" + " └─ LookupJoin\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t2.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + @@ -2815,17 +2806,13 @@ inner join pq on true " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + " │ └─ (t2.i:1!null + 1 (tinyint))\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t1.i:0!null\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ TableAlias(t1)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[2, 2]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t1)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[2, 2]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t2.i:0!null\n" + @@ -2844,17 +2831,13 @@ inner join pq on true ExpectedPlan: "Project\n" + " ├─ columns: [t1.i:1!null]\n" + " └─ LookupJoin\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t2.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + @@ -2873,17 +2856,13 @@ inner join pq on true ExpectedPlan: "Project\n" + " ├─ columns: [t1.i:1!null]\n" + " └─ LookupJoin\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t2.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + @@ -2902,17 +2881,13 @@ inner join pq on true ExpectedPlan: "Project\n" + " ├─ columns: [t1.i:1!null]\n" + " └─ LookupJoin\n" + - " ├─ Filter\n" + - " │ ├─ Eq\n" + - " │ │ ├─ t2.i:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + " └─ Filter\n" + " ├─ Eq\n" + " │ ├─ t1.i:0!null\n" + @@ -3215,17 +3190,13 @@ inner join pq on true " ├─ Eq\n" + " │ ├─ sub.i:2!null\n" + " │ └─ ot.i2:1!null\n" + - " ├─ Filter\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ ot.i2:1!null\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ TableAlias(ot)\n" + - " │ └─ IndexedTableAccess(othertable)\n" + - " │ ├─ index: [othertable.i2]\n" + - " │ ├─ static: [{(0, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: othertable\n" + - " │ └─ columns: [s2 i2]\n" + + " ├─ TableAlias(ot)\n" + + " │ └─ IndexedTableAccess(othertable)\n" + + " │ ├─ index: [othertable.i2]\n" + + " │ ├─ static: [{(0, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: othertable\n" + + " │ └─ columns: [s2 i2]\n" + " └─ SubqueryAlias\n" + " ├─ name: sub\n" + " ├─ outerVisibility: false\n" + @@ -3779,16 +3750,13 @@ inner join pq on true }, { Query: `SELECT a.* FROM mytable a WHERE a.s is not null`, - ExpectedPlan: "Filter\n" + - " ├─ NOT\n" + - " │ └─ a.s:1!null IS NULL\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.s]\n" + - " ├─ static: [{(NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + ExpectedPlan: "TableAlias(a)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.s]\n" + + " ├─ static: [{(NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [i s]\n" + "", }, { @@ -4756,7 +4724,13 @@ inner join pq on true " │ ├─ name: mytable\n" + " │ └─ columns: [s]\n" + " └─ Filter\n" + - " ├─ (a.i:0!null BETWEEN 10 (tinyint) AND 20 (tinyint))\n" + + " ├─ AND\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ a.i:0!null\n" + + " │ │ └─ 10 (tinyint)\n" + + " │ └─ LessThanOrEqual\n" + + " │ ├─ a.i:0!null\n" + + " │ └─ 20 (tinyint)\n" + " └─ TableAlias(a)\n" + " └─ IndexedTableAccess(mytable)\n" + " ├─ index: [mytable.i]\n" + @@ -7145,17 +7119,13 @@ inner join pq on true " └─ HashLookup\n" + " ├─ left-key: TUPLE()\n" + " ├─ right-key: TUPLE()\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ t1.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + - " └─ TableAlias(t1)\n" + - " └─ IndexedTableAccess(one_pk)\n" + - " ├─ index: [one_pk.pk]\n" + - " ├─ static: [{[1, 1]}]\n" + - " └─ Table\n" + - " ├─ name: one_pk\n" + - " └─ columns: [pk c1 c2 c3 c4 c5]\n" + + " └─ TableAlias(t1)\n" + + " └─ IndexedTableAccess(one_pk)\n" + + " ├─ index: [one_pk.pk]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: one_pk\n" + + " └─ columns: [pk c1 c2 c3 c4 c5]\n" + "", }, { @@ -7166,35 +7136,23 @@ inner join pq on true " └─ Project\n" + " ├─ columns: [t1.pk:7!null, t1.c1:8, t1.c2:9, t1.c3:10, t1.c4:11, t1.c5:12, t2.pk1:0!null, t2.pk2:1!null, t2.c1:2!null, t2.c2:3!null, t2.c3:4!null, t2.c4:5!null, t2.c5:6!null]\n" + " └─ CrossHashJoin\n" + - " ├─ Filter\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ t2.pk2:1!null\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ t2.pk1:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(two_pk)\n" + - " │ ├─ index: [two_pk.pk1,two_pk.pk2]\n" + - " │ ├─ static: [{[1, 1], [1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: two_pk\n" + - " │ └─ columns: [pk1 pk2 c1 c2 c3 c4 c5]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(two_pk)\n" + + " │ ├─ index: [two_pk.pk1,two_pk.pk2]\n" + + " │ ├─ static: [{[1, 1], [1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: two_pk\n" + + " │ └─ columns: [pk1 pk2 c1 c2 c3 c4 c5]\n" + " └─ HashLookup\n" + " ├─ left-key: TUPLE()\n" + " ├─ right-key: TUPLE()\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ t1.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + - " └─ TableAlias(t1)\n" + - " └─ IndexedTableAccess(one_pk)\n" + - " ├─ index: [one_pk.pk]\n" + - " ├─ static: [{[1, 1]}]\n" + - " └─ Table\n" + - " ├─ name: one_pk\n" + - " └─ columns: [pk c1 c2 c3 c4 c5]\n" + + " └─ TableAlias(t1)\n" + + " └─ IndexedTableAccess(one_pk)\n" + + " ├─ index: [one_pk.pk]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: one_pk\n" + + " └─ columns: [pk c1 c2 c3 c4 c5]\n" + "", }, { @@ -7321,17 +7279,13 @@ inner join pq on true " └─ HashLookup\n" + " ├─ left-key: TUPLE()\n" + " ├─ right-key: TUPLE()\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ t1.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + - " └─ TableAlias(t1)\n" + - " └─ IndexedTableAccess(one_pk)\n" + - " ├─ index: [one_pk.pk]\n" + - " ├─ static: [{[1, 1]}]\n" + - " └─ Table\n" + - " ├─ name: one_pk\n" + - " └─ columns: [pk c1 c2 c3 c4 c5]\n" + + " └─ TableAlias(t1)\n" + + " └─ IndexedTableAccess(one_pk)\n" + + " ├─ index: [one_pk.pk]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: one_pk\n" + + " └─ columns: [pk c1 c2 c3 c4 c5]\n" + "", }, { @@ -7350,7 +7304,9 @@ inner join pq on true " │ └─ Eq\n" + " │ ├─ othertable.s2:0!null\n" + " │ └─ second (longtext)\n" + - " └─ ProcessTable\n" + + " └─ IndexedTableAccess(othertable)\n" + + " ├─ index: [othertable.s2]\n" + + " ├─ static: [{(NULL, second)}, {(second, ∞)}]\n" + " └─ Table\n" + " ├─ name: othertable\n" + " └─ columns: [s2 i2]\n" + @@ -7393,18 +7349,12 @@ inner join pq on true " ├─ row_number() over ( order by othertable.s2 ASC)\n" + " ├─ othertable.i2:1!null\n" + " ├─ othertable.s2:0!null\n" + - " └─ Filter\n" + - " ├─ Or\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ othertable.i2:1!null\n" + - " │ │ └─ 2 (tinyint)\n" + - " │ └─ GreaterThan\n" + - " │ ├─ othertable.i2:1!null\n" + - " │ └─ 2 (tinyint)\n" + - " └─ ProcessTable\n" + - " └─ Table\n" + - " ├─ name: othertable\n" + - " └─ columns: [s2 i2]\n" + + " └─ IndexedTableAccess(othertable)\n" + + " ├─ index: [othertable.i2]\n" + + " ├─ static: [{(NULL, 2)}, {(2, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: othertable\n" + + " └─ columns: [s2 i2]\n" + "", }, { @@ -7910,17 +7860,13 @@ inner join pq on true " ├─ columns: [a.pk:1!null, c.v2:4]\n" + " └─ LeftOuterLookupJoin\n" + " ├─ CrossHashJoin\n" + - " │ ├─ Filter\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ b.pk:0!null\n" + - " │ │ │ └─ 0 (tinyint)\n" + - " │ │ └─ TableAlias(b)\n" + - " │ │ └─ IndexedTableAccess(one_pk_three_idx)\n" + - " │ │ ├─ index: [one_pk_three_idx.pk]\n" + - " │ │ ├─ static: [{[0, 0]}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: one_pk_three_idx\n" + - " │ │ └─ columns: [pk]\n" + + " │ ├─ TableAlias(b)\n" + + " │ │ └─ IndexedTableAccess(one_pk_three_idx)\n" + + " │ │ ├─ index: [one_pk_three_idx.pk]\n" + + " │ │ ├─ static: [{[0, 0]}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: one_pk_three_idx\n" + + " │ │ └─ columns: [pk]\n" + " │ └─ HashLookup\n" + " │ ├─ left-key: TUPLE()\n" + " │ ├─ right-key: TUPLE()\n" + @@ -8417,12 +8363,16 @@ inner join pq on true { Query: `SELECT * from one_pk_three_idx where pk < 1 and v1 = 1 and v2 = 1`, ExpectedPlan: "Filter\n" + - " ├─ LessThan\n" + - " │ ├─ one_pk_three_idx.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + + " ├─ AND\n" + + " │ ├─ Eq\n" + + " │ │ ├─ one_pk_three_idx.v1:1\n" + + " │ │ └─ 1 (tinyint)\n" + + " │ └─ Eq\n" + + " │ ├─ one_pk_three_idx.v2:2\n" + + " │ └─ 1 (tinyint)\n" + " └─ IndexedTableAccess(one_pk_three_idx)\n" + - " ├─ index: [one_pk_three_idx.v1,one_pk_three_idx.v2,one_pk_three_idx.v3]\n" + - " ├─ static: [{[1, 1], [1, 1], [NULL, ∞)}]\n" + + " ├─ index: [one_pk_three_idx.pk]\n" + + " ├─ static: [{(NULL, 1)}]\n" + " └─ Table\n" + " ├─ name: one_pk_three_idx\n" + " └─ columns: [pk v1 v2 v3]\n" + @@ -8431,12 +8381,16 @@ inner join pq on true { Query: `SELECT * from one_pk_three_idx where pk = 1 and v1 = 1 and v2 = 1`, ExpectedPlan: "Filter\n" + - " ├─ Eq\n" + - " │ ├─ one_pk_three_idx.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + + " ├─ AND\n" + + " │ ├─ Eq\n" + + " │ │ ├─ one_pk_three_idx.v1:1\n" + + " │ │ └─ 1 (tinyint)\n" + + " │ └─ Eq\n" + + " │ ├─ one_pk_three_idx.v2:2\n" + + " │ └─ 1 (tinyint)\n" + " └─ IndexedTableAccess(one_pk_three_idx)\n" + - " ├─ index: [one_pk_three_idx.v1,one_pk_three_idx.v2,one_pk_three_idx.v3]\n" + - " ├─ static: [{[1, 1], [1, 1], [NULL, ∞)}]\n" + + " ├─ index: [one_pk_three_idx.pk]\n" + + " ├─ static: [{[1, 1]}]\n" + " └─ Table\n" + " ├─ name: one_pk_three_idx\n" + " └─ columns: [pk v1 v2 v3]\n" + @@ -8620,35 +8574,23 @@ inner join pq on true " └─ Project\n" + " ├─ columns: [t1.pk:7!null, t1.c1:8, t1.c2:9, t1.c3:10, t1.c4:11, t1.c5:12, t2.pk1:0!null, t2.pk2:1!null, t2.c1:2!null, t2.c2:3!null, t2.c3:4!null, t2.c4:5!null, t2.c5:6!null]\n" + " └─ CrossHashJoin\n" + - " ├─ Filter\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ t2.pk2:1!null\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ t2.pk1:0!null\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ TableAlias(t2)\n" + - " │ └─ IndexedTableAccess(two_pk)\n" + - " │ ├─ index: [two_pk.pk1,two_pk.pk2]\n" + - " │ ├─ static: [{[1, 1], [1, 1]}]\n" + - " │ └─ Table\n" + - " │ ├─ name: two_pk\n" + - " │ └─ columns: [pk1 pk2 c1 c2 c3 c4 c5]\n" + + " ├─ TableAlias(t2)\n" + + " │ └─ IndexedTableAccess(two_pk)\n" + + " │ ├─ index: [two_pk.pk1,two_pk.pk2]\n" + + " │ ├─ static: [{[1, 1], [1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: two_pk\n" + + " │ └─ columns: [pk1 pk2 c1 c2 c3 c4 c5]\n" + " └─ HashLookup\n" + " ├─ left-key: TUPLE()\n" + " ├─ right-key: TUPLE()\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ t1.pk:0!null\n" + - " │ └─ 1 (tinyint)\n" + - " └─ TableAlias(t1)\n" + - " └─ IndexedTableAccess(one_pk)\n" + - " ├─ index: [one_pk.pk]\n" + - " ├─ static: [{[1, 1]}]\n" + - " └─ Table\n" + - " ├─ name: one_pk\n" + - " └─ columns: [pk c1 c2 c3 c4 c5]\n" + + " └─ TableAlias(t1)\n" + + " └─ IndexedTableAccess(one_pk)\n" + + " ├─ index: [one_pk.pk]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: one_pk\n" + + " └─ columns: [pk c1 c2 c3 c4 c5]\n" + "", }, { @@ -9761,10 +9703,9 @@ With c as ( " │ ├─ one_pk.pk:0!null\n" + " │ └─ 2 (tinyint)\n" + " └─ Limit(1)\n" + - " └─ Filter\n" + - " ├─ LessThan\n" + - " │ ├─ one_pk.pk:0!null\n" + - " │ └─ 2 (tinyint)\n" + + " └─ IndexedTableAccess(one_pk)\n" + + " ├─ index: [one_pk.pk]\n" + + " ├─ static: [{(NULL, 2)}]\n" + " └─ Table\n" + " ├─ name: one_pk\n" + " └─ columns: [pk]\n" + @@ -10206,23 +10147,13 @@ WHERE keyless.c0 IN ( }, { Query: `select * from xy_hasnull_idx where y < 1 or y > 1 or y is null order by y desc`, - ExpectedPlan: "Filter\n" + - " ├─ Or\n" + - " │ ├─ Or\n" + - " │ │ ├─ LessThan\n" + - " │ │ │ ├─ xy_hasnull_idx.y:1\n" + - " │ │ │ └─ 1 (tinyint)\n" + - " │ │ └─ GreaterThan\n" + - " │ │ ├─ xy_hasnull_idx.y:1\n" + - " │ │ └─ 1 (tinyint)\n" + - " │ └─ xy_hasnull_idx.y:1 IS NULL\n" + - " └─ IndexedTableAccess(xy_hasnull_idx)\n" + - " ├─ index: [xy_hasnull_idx.y]\n" + - " ├─ static: [{(1, ∞)}, {[NULL, 1)}]\n" + - " ├─ reverse: true\n" + - " └─ Table\n" + - " ├─ name: xy_hasnull_idx\n" + - " └─ columns: [x y]\n" + + ExpectedPlan: "IndexedTableAccess(xy_hasnull_idx)\n" + + " ├─ index: [xy_hasnull_idx.y]\n" + + " ├─ static: [{(1, ∞)}, {[NULL, 1)}]\n" + + " ├─ reverse: true\n" + + " └─ Table\n" + + " ├─ name: xy_hasnull_idx\n" + + " └─ columns: [x y]\n" + "", }, { @@ -10635,19 +10566,3 @@ order by i;`, "", }, } - -// QueryPlanTODOs are queries where the query planner produces a correct (results) but suboptimal plan. -var QueryPlanTODOs = []QueryPlanTest{ - { - // TODO: this should use an index. Extra join condition should get moved out of the join clause into a filter - Query: `SELECT pk,i,f FROM one_pk RIGHT JOIN niltable ON pk=i and pk > 0 ORDER BY 2,3`, - ExpectedPlan: "Sort(niltable.i ASC, niltable.f ASC)\n" + - " └─ Project(one_pk.pk, niltable.i, niltable.f)\n" + - " └─ RightJoin((one_pk.pk = niltable.i) AND (one_pk.pk > 0))\n" + - " ├─ Projected table access on [pk]\n" + - " │ └─ Table(one_pk)\n" + - " └─ Projected table access on [i f]\n" + - " └─ Table(niltable)\n" + - "", - }, -} diff --git a/enginetest/queries/script_queries.go b/enginetest/queries/script_queries.go index 7be8d47691..ffde4f6234 100644 --- a/enginetest/queries/script_queries.go +++ b/enginetest/queries/script_queries.go @@ -95,6 +95,9 @@ type ScriptTestAssertion struct { // Bindings are variable mappings only used for prepared tests Bindings map[string]*querypb.BindVariable + + // CheckIndexedAccess indicates whether we should verify the query plan uses an index + CheckIndexedAccess bool } // ScriptTests are a set of test scripts to run. diff --git a/enginetest/queries/tpcc_plans.go b/enginetest/queries/tpcc_plans.go index 90eec8f826..e6db0f2361 100644 --- a/enginetest/queries/tpcc_plans.go +++ b/enginetest/queries/tpcc_plans.go @@ -44,12 +44,16 @@ WHERE " │ └─ GroupBy\n" + " │ ├─ select: MAX(orders2.o_id:0!null)\n" + " │ ├─ group: \n" + - " │ └─ IndexedTableAccess(orders2)\n" + - " │ ├─ index: [orders2.o_w_id,orders2.o_d_id,orders2.o_c_id,orders2.o_id]\n" + - " │ ├─ static: [{[1, 1], [3, 3], [20001, 20001], [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: orders2\n" + - " │ └─ columns: [o_id o_d_id o_w_id o_c_id]\n" + + " │ └─ Filter\n" + + " │ ├─ Eq\n" + + " │ │ ├─ orders2.o_c_id:3\n" + + " │ │ └─ 20001 (smallint)\n" + + " │ └─ IndexedTableAccess(orders2)\n" + + " │ ├─ index: [orders2.o_w_id,orders2.o_d_id,orders2.o_id]\n" + + " │ ├─ static: [{[1, 1], [3, 3], [NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: orders2\n" + + " │ └─ columns: [o_id o_d_id o_w_id o_c_id]\n" + " └─ Filter\n" + " ├─ AND\n" + " │ ├─ AND\n" + @@ -126,20 +130,12 @@ from " └─ GroupBy\n" + " ├─ select: COUNTDISTINCT([orders2.o_id]), orders2.o_c_id:3, orders2.o_w_id:2!null, orders2.o_d_id:1!null, orders2.o_id:0!null\n" + " ├─ group: orders2.o_c_id:3, orders2.o_d_id:1!null, orders2.o_w_id:2!null\n" + - " └─ Filter\n" + - " ├─ AND\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ orders2.o_id:0!null\n" + - " │ │ └─ 2100 (smallint)\n" + - " │ └─ LessThan\n" + - " │ ├─ orders2.o_id:0!null\n" + - " │ └─ 11153 (smallint)\n" + - " └─ IndexedTableAccess(orders2)\n" + - " ├─ index: [orders2.o_w_id,orders2.o_d_id,orders2.o_id]\n" + - " ├─ static: [{[1, 1], [NULL, ∞), [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: orders2\n" + - " └─ columns: [o_id o_d_id o_w_id o_c_id o_entry_d o_carrier_id o_ol_cnt o_all_local]\n" + + " └─ IndexedTableAccess(orders2)\n" + + " ├─ index: [orders2.o_w_id,orders2.o_d_id,orders2.o_id]\n" + + " ├─ static: [{[1, 1], [NULL, ∞), (2100, 11153)}]\n" + + " └─ Table\n" + + " ├─ name: orders2\n" + + " └─ columns: [o_id o_d_id o_w_id o_c_id o_entry_d o_carrier_id o_ol_cnt o_all_local]\n" + "", }, } diff --git a/enginetest/queries/tpch_plans.go b/enginetest/queries/tpch_plans.go index 043a329793..29d91b7958 100644 --- a/enginetest/queries/tpch_plans.go +++ b/enginetest/queries/tpch_plans.go @@ -465,7 +465,13 @@ where " │ │ │ └─ LessThan\n" + " │ │ │ ├─ lineitem.l_shipdate:3!null\n" + " │ │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + - " │ │ └─ (lineitem.l_discount:2!null BETWEEN 0.05 (decimal(3,2)) AND 0.07 (decimal(3,2)))\n" + + " │ │ └─ AND\n" + + " │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ ├─ lineitem.l_discount:2!null\n" + + " │ │ │ └─ 0.05 (decimal(3,2))\n" + + " │ │ └─ LessThanOrEqual\n" + + " │ │ ├─ lineitem.l_discount:2!null\n" + + " │ │ └─ 0.07 (decimal(3,2))\n" + " │ └─ LessThan\n" + " │ ├─ lineitem.l_quantity:0!null\n" + " │ └─ 24 (tinyint)\n" + @@ -554,7 +560,13 @@ order by " │ │ ├─ LookupJoin\n" + " │ │ │ ├─ LookupJoin\n" + " │ │ │ │ ├─ Filter\n" + - " │ │ │ │ │ ├─ (lineitem.l_shipdate:4!null BETWEEN 1995-01-01 (longtext) AND 1996-12-31 (longtext))\n" + + " │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ │ │ ├─ lineitem.l_shipdate:4!null\n" + + " │ │ │ │ │ │ │ └─ 1995-01-01 (longtext)\n" + + " │ │ │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ │ │ ├─ lineitem.l_shipdate:4!null\n" + + " │ │ │ │ │ │ └─ 1996-12-31 (longtext)\n" + " │ │ │ │ │ └─ Table\n" + " │ │ │ │ │ ├─ name: lineitem\n" + " │ │ │ │ │ └─ columns: [l_orderkey l_suppkey l_extendedprice l_discount l_shipdate]\n" + @@ -690,7 +702,13 @@ order by " ├─ LookupJoin\n" + " │ ├─ LookupJoin\n" + " │ │ ├─ Filter\n" + - " │ │ │ ├─ (orders.o_orderdate:2!null BETWEEN 1995-01-01 (longtext) AND 1996-12-31 (longtext))\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ orders.o_orderdate:2!null\n" + + " │ │ │ │ │ └─ 1995-01-01 (longtext)\n" + + " │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ ├─ orders.o_orderdate:2!null\n" + + " │ │ │ │ └─ 1996-12-31 (longtext)\n" + " │ │ │ └─ Table\n" + " │ │ │ ├─ name: orders\n" + " │ │ │ └─ columns: [o_orderkey o_custkey o_orderdate]\n" + @@ -1606,7 +1624,13 @@ where " │ │ │ │ │ │ └─ LessThanOrEqual\n" + " │ │ │ │ │ │ ├─ lineitem.l_quantity:1!null\n" + " │ │ │ │ │ │ └─ 11 (bigint)\n" + - " │ │ │ │ │ └─ (part.p_size:8!null BETWEEN 1 (tinyint) AND 5 (tinyint))\n" + + " │ │ │ │ │ └─ AND\n" + + " │ │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ │ │ │ └─ 1 (tinyint)\n" + + " │ │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ │ │ └─ 5 (tinyint)\n" + " │ │ │ │ └─ IN\n" + " │ │ │ │ ├─ left: lineitem.l_shipmode:5!null\n" + " │ │ │ │ └─ right: TUPLE(AIR (longtext), AIR REG (longtext))\n" + @@ -1635,7 +1659,13 @@ where " │ │ │ │ │ └─ LessThanOrEqual\n" + " │ │ │ │ │ ├─ lineitem.l_quantity:1!null\n" + " │ │ │ │ │ └─ 20 (bigint)\n" + - " │ │ │ │ └─ (part.p_size:8!null BETWEEN 1 (tinyint) AND 10 (tinyint))\n" + + " │ │ │ │ └─ AND\n" + + " │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ │ │ └─ 1 (tinyint)\n" + + " │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ │ └─ 10 (tinyint)\n" + " │ │ │ └─ IN\n" + " │ │ │ ├─ left: lineitem.l_shipmode:5!null\n" + " │ │ │ └─ right: TUPLE(AIR (longtext), AIR REG (longtext))\n" + @@ -1664,7 +1694,13 @@ where " │ │ │ │ └─ LessThanOrEqual\n" + " │ │ │ │ ├─ lineitem.l_quantity:1!null\n" + " │ │ │ │ └─ 30 (bigint)\n" + - " │ │ │ └─ (part.p_size:8!null BETWEEN 1 (tinyint) AND 15 (tinyint))\n" + + " │ │ │ └─ AND\n" + + " │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ │ └─ 1 (tinyint)\n" + + " │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ ├─ part.p_size:8!null\n" + + " │ │ │ └─ 15 (tinyint)\n" + " │ │ └─ IN\n" + " │ │ ├─ left: lineitem.l_shipmode:5!null\n" + " │ │ └─ right: TUPLE(AIR (longtext), AIR REG (longtext))\n" + diff --git a/enginetest/query_engine.go b/enginetest/query_engine.go index 69fb589910..b906bd024e 100755 --- a/enginetest/query_engine.go +++ b/enginetest/query_engine.go @@ -24,10 +24,9 @@ import ( ) type QueryEngine interface { - PrepareQuery( - ctx *sql.Context, - query string, - ) (sql.Node, error) + PrepareQuery(*sql.Context, string) (sql.Node, error) + //BindQuery(*sql.Context, string) (sql.Node, error) + AnalyzeQuery(*sql.Context, string) (sql.Node, error) Query(ctx *sql.Context, query string) (sql.Schema, sql.RowIter, error) // TODO: get rid of this, should not be exposed to engine tests EngineAnalyzer() *analyzer.Analyzer diff --git a/enginetest/server_engine.go b/enginetest/server_engine.go index 5be277ce0a..6fe2a59fcf 100644 --- a/enginetest/server_engine.go +++ b/enginetest/server_engine.go @@ -104,6 +104,10 @@ func (s *ServerQueryEngine) NewConnection(ctx *sql.Context) error { return nil } +func (s *ServerQueryEngine) AnalyzeQuery(ctx *sql.Context, query string) (sql.Node, error) { + return s.engine.AnalyzeQuery(ctx, query) +} + func (s *ServerQueryEngine) PrepareQuery(ctx *sql.Context, query string) (sql.Node, error) { if s.conn == nil { err := s.NewConnection(ctx) diff --git a/memory/index.go b/memory/index.go index 6e15359700..1664606cdb 100644 --- a/memory/index.go +++ b/memory/index.go @@ -236,7 +236,7 @@ func (idx *Index) HandledFilters(filters []sql.Expression) []sql.Expression { return handled } for _, expr := range filters { - if expression.ContainsImpreciseComparison(expr) { + if !expression.PreciseComparison(expr) { continue } handled = append(handled, expr) diff --git a/memory/point_lookup_table.go b/memory/point_lookup_table.go index 28a95d6b29..b0fd476c8b 100644 --- a/memory/point_lookup_table.go +++ b/memory/point_lookup_table.go @@ -48,6 +48,10 @@ func (s PointLookupTable) Description() string { var _ sql.Partition = (*sequencePartition)(nil) +func (s PointLookupTable) PreciseMatch() bool { + return true +} + func (s PointLookupTable) GetIndexes(ctx *sql.Context) (indexes []sql.Index, err error) { return []sql.Index{ pointLookupIndex{&Index{ diff --git a/memory/sequence_table.go b/memory/sequence_table.go index e184d43108..362b0a2030 100644 --- a/memory/sequence_table.go +++ b/memory/sequence_table.go @@ -222,6 +222,10 @@ func (s IntSequenceTable) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable return s } +func (s IntSequenceTable) PreciseMatch() bool { + return true +} + func (s IntSequenceTable) GetIndexes(ctx *sql.Context) ([]sql.Index, error) { return []sql.Index{ &Index{ diff --git a/memory/stats.go b/memory/stats.go index 32f3aeb0f9..94a9ab08f2 100644 --- a/memory/stats.go +++ b/memory/stats.go @@ -148,7 +148,7 @@ func (s *StatsProv) estimateStats(ctx *sql.Context, table sql.Table, keys map[st return err } - s.colStats[key] = stats.NewStatistic(rowCount, rowCount, 0, dataLen, time.Now(), qual, cols, types, buckets) + s.colStats[key] = stats.NewStatistic(rowCount, rowCount, 0, dataLen, time.Now(), qual, cols, types, buckets, sql.IndexClassDefault) } return nil } diff --git a/memory/table.go b/memory/table.go index a377a8c16d..7873a61342 100644 --- a/memory/table.go +++ b/memory/table.go @@ -81,6 +81,7 @@ var _ sql.PrimaryKeyAlterableTable = (*Table)(nil) var _ sql.PrimaryKeyTable = (*Table)(nil) var _ fulltext.IndexAlterableTable = (*Table)(nil) var _ sql.IndexBuildingTable = (*Table)(nil) +var _ sql.Databaseable = (*Table)(nil) // NewTable creates a new Table with the given name and schema. Assigns the default collation, therefore if a different // collation is desired, please use NewTableWithCollation. @@ -213,6 +214,10 @@ func (t Table) Name() string { return t.name } +func (t Table) Database() string { + return t.dbName() +} + // Schema implements the sql.Table interface. func (t *Table) Schema() sql.Schema { if t.projectedSchema != nil { @@ -1597,6 +1602,10 @@ func (t *Table) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable { return &IndexedTable{Table: t, Lookup: lookup} } +func (t *Table) PreciseMatch() bool { + return true +} + // WithProjections implements sql.ProjectedTable func (t *Table) WithProjections(cols []string) sql.Table { nt := *t diff --git a/memory/table_editor.go b/memory/table_editor.go index a6cc15899b..206a5c5203 100644 --- a/memory/table_editor.go +++ b/memory/table_editor.go @@ -270,6 +270,10 @@ func (t *tableEditor) SetAutoIncrementValue(ctx *sql.Context, val uint64) error return nil } +func (t *tableEditor) PreciseMatch() bool { + return true +} + func (t *tableEditor) IndexedAccess(lookup sql.IndexLookup) sql.IndexedTable { // Before we return an indexed access for this table, we need to apply all the edits to the table // TODO: optimize this, should create some struct that encloses the tableEditor and filters based on the lookup diff --git a/sql/analyzer/analyzer.go b/sql/analyzer/analyzer.go index 8778a7b4a9..679aafbe39 100644 --- a/sql/analyzer/analyzer.go +++ b/sql/analyzer/analyzer.go @@ -487,6 +487,8 @@ func newInsertSourceSelector(sel RuleSelector) RuleSelector { // Analyze applies the transformation rules to the node given. In the case of an error, the last successfully // transformed node is returned along with the error. func (a *Analyzer) Analyze(ctx *sql.Context, n sql.Node, scope *plan.Scope) (sql.Node, error) { + //a.Verbose = true + //a.Debug = true n, _, err := a.analyzeWithSelector(ctx, n, scope, SelectAllBatches, DefaultRuleSelector) return n, err } diff --git a/sql/analyzer/costed_index_scan.go b/sql/analyzer/costed_index_scan.go index 0ab04cf7cc..9d40580c13 100644 --- a/sql/analyzer/costed_index_scan.go +++ b/sql/analyzer/costed_index_scan.go @@ -20,6 +20,11 @@ import ( "strings" "time" + "github.com/dolthub/go-mysql-server/sql/expression/function/spatial" + "github.com/dolthub/go-mysql-server/sql/fulltext" + "github.com/dolthub/go-mysql-server/sql/rowexec" + "github.com/dolthub/go-mysql-server/sql/types" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/plan" @@ -52,44 +57,70 @@ func costedIndexScans(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sco return n, transform.SameTree, nil } - rt, ok := filter.Child.(*plan.ResolvedTable) - if !ok { - return n, transform.SameTree, nil + var rt sql.TableNode + var aliasName string + switch n := filter.Child.(type) { + case *plan.ResolvedTable: + rt = n + case *plan.TableAlias: + rt, _ = n.Child.(sql.TableNode) + aliasName = n.Name() } - - statistics, err := a.Catalog.StatsProvider.GetTableStats(ctx, strings.ToLower(rt.Database().Name()), strings.ToLower(rt.Name())) - if err != nil { - return n, transform.SameTree, err + if rt == nil { + return n, transform.SameTree, nil } - var qualToStat map[sql.StatQualifier]sql.Statistic - if len(statistics) == 0 { - qualToStat, err = uniformDistStatistics(ctx, rt) - } else { - qualToStat = make(map[sql.StatQualifier]sql.Statistic) - for _, stat := range statistics { - if prev, ok := qualToStat[stat.Qualifier()]; !ok || ok && len(stat.Columns()) > len(prev.Columns()) { - qualToStat[stat.Qualifier()] = stat - } + var statistics []sql.Statistic + var err error + //statistics, err := a.Catalog.StatsProvider.GetTableStats(ctx, strings.ToLower(rt.Database().Name()), strings.ToLower(rt.Name())) + //if err != nil { + // return n, transform.SameTree, err + //} + + qualToStat := make(map[sql.StatQualifier]sql.Statistic) + for _, stat := range statistics { + if prev, ok := qualToStat[stat.Qualifier()]; !ok || ok && len(stat.Columns()) > len(prev.Columns()) { + qualToStat[stat.Qualifier()] = stat } } // flatten expression tree for costing - c := newIndexCoster() - root, leftover := c.flatten(filter.Expression, false) + c := newIndexCoster(rt.Name()) + root, leftover, imprecise := c.flatten(filter.Expression) + if root == nil { + return n, transform.SameTree, nil + } + + iat, ok := rt.UnderlyingTable().(sql.IndexAddressableTable) + if !ok { + return n, transform.SameTree, nil + } + indexes, err := iat.GetIndexes(ctx) + if err != nil { + return n, transform.SameTree, err + } // run each index through coster, save the cheapest - for _, stat := range qualToStat { + var dbName string + if dbTab, ok := rt.UnderlyingTable().(sql.Databaseable); ok { + dbName = strings.ToLower(dbTab.Database()) + } + tableName := strings.ToLower(rt.UnderlyingTable().Name()) + + for _, idx := range indexes { + qual := sql.NewStatQualifier(dbName, tableName, strings.ToLower(idx.ID())) + stat, ok := qualToStat[qual] + if !ok { + stat, err = uniformDistStatisticsForIndex(ctx, iat, idx) + } err := c.cost(root, stat) if err != nil { return nil, transform.SameTree, err } } - iat := rt.Table.(sql.IndexAddressableTable) - indexes, err := iat.GetIndexes(ctx) - if err != nil { - return n, transform.SameTree, err + if c.bestStat == nil || c.bestFilters.Empty() { + return n, transform.SameTree, nil } targetId := c.bestStat.Qualifier().Index() @@ -105,8 +136,10 @@ func costedIndexScans(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sco } // separate |include| and |leftover| filters - b := newIndexScanRangeBuilder(ctx, idx, c.bestFilters, c.idToExpr) - b.leftover = append(b.leftover, leftover) + b := newIndexScanRangeBuilder(ctx, idx, c.bestFilters, imprecise, c.idToExpr) + if leftover != nil { + b.leftover = append(b.leftover, leftover) + } ranges, err := b.buildRangeCollection(root) var emptyLookup bool @@ -117,28 +150,79 @@ func costedIndexScans(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sco if err != nil { return n, transform.SameTree, err } + allRange := true + for i, r := range ranges[0] { + _, uok := r.UpperBound.(sql.AboveAll) + _, lok := r.LowerBound.(sql.BelowNull) + allRange = allRange && uok && lok + if i == 0 && allRange { + // no prefix restriction + return n, transform.SameTree, nil + } + } + if allRange { + return n, transform.SameTree, nil + } + } + + if !idx.CanSupport(ranges...) { + return n, transform.SameTree, nil + } + + if idx.IsSpatial() && len(ranges) > 1 { + // spatials don't support disjunct ranges + return n, transform.SameTree, nil } // create ranges, lookup, ITA for best indexScan // TODO pass up FALSE filter information lookup := sql.NewIndexLookup(idx, ranges, false, emptyLookup, idx.IsSpatial(), false) - ita, err := plan.NewStaticIndexedAccessForTableNode(rt, lookup) - if err != nil { - return n, transform.SameTree, nil + var ret sql.Node + if idx.IsFullText() { + id, _ := c.bestFilters.Next(1) + ma := c.idToExpr[indexScanId(id)] + matchAgainst, ok := ma.(*expression.MatchAgainst) + if !ok { + return nil, transform.SameTree, fmt.Errorf("Full-Text index found in filter with unknown expression: %T", ma) + } + if matchAgainst.KeyCols.Type == fulltext.KeyType_None { + return n, transform.SameTree, nil + } + ret = plan.NewStaticIndexedAccessForFullTextTable(rt, lookup, &rowexec.FulltextFilterTable{ + MatchAgainst: matchAgainst, + Table: rt, + }) + } else { + ret, err = plan.NewStaticIndexedAccessForTableNode(rt, lookup) + if err != nil { + return n, transform.SameTree, nil + } } + if aliasName != "" { + ret = plan.NewTableAlias(aliasName, ret) + } + + if !iat.PreciseMatch() { + // cannot drop any filters + return plan.NewFilter(filter.Expression, ret), transform.NewTree, nil + } + if len(b.leftover) == 0 { + // pushed all filters into index + return ret, transform.NewTree, nil + } // excluded from tree + not included in index scan => filter above scan newFilter := expression.JoinAnd(b.leftover...) - - return plan.NewFilter(newFilter, ita), transform.NewTree, nil + return plan.NewFilter(newFilter, ret), transform.NewTree, nil }) } -func newIndexCoster() *indexCoster { +func newIndexCoster(underlyingName string) *indexCoster { return &indexCoster{ - i: 1, - idToExpr: make(map[indexScanId]sql.Expression), + i: 1, + idToExpr: make(map[indexScanId]sql.Expression), + underlyingName: underlyingName, } } @@ -150,8 +234,9 @@ type indexCoster struct { bestStat sql.Statistic // bestFilters is the set of conjunctions used to create bestStat bestFilters sql.FastIntSet - // invalid are expressions not considered for indexing - invalid []sql.Expression + // bestConstant are the constant best filters + bestConstant sql.FastIntSet + underlyingName string } // cost tries to build the lowest cardinality index scan for an expression @@ -159,7 +244,7 @@ type indexCoster struct { func (c *indexCoster) cost(f indexFilter, stat sql.Statistic) error { ordinals := ordinalsForStat(stat) - var newStat sql.Statistic + newStat := stat var filters sql.FastIntSet var err error var ok bool @@ -187,9 +272,6 @@ func (c *indexCoster) cost(f indexFilter, stat sql.Statistic) error { if ok { filters.Add(int(f.id)) } - case nil: - // todo support other filters - return nil default: panic("unreachable") } @@ -199,22 +281,138 @@ func (c *indexCoster) cost(f indexFilter, stat sql.Statistic) error { } func (c *indexCoster) updateBest(s sql.Statistic, filters sql.FastIntSet) { + if s == nil || filters.Len() == 0 { + return + } + + var update bool + defer func() { + if update { + c.bestStat = s + c.bestFilters = filters + } + }() + if c.bestStat == nil || s.RowCount() < c.bestStat.RowCount() { - c.bestStat = s - c.bestFilters = filters + update = true + return + } else if c.bestStat.FuncDeps().HasMax1Row() { + return + } else if s.RowCount() == c.bestStat.RowCount() { + // hand rules when stats don't exist or match exactly + cmp := s.FuncDeps() + best := c.bestStat.FuncDeps() + if cmp.HasMax1Row() { + update = true + return + } + + bestKey, bok := best.StrictKey() + cmpKey, cok := cmp.StrictKey() + if cok && !bok { + // prefer unique key + update = true + return + } else if bok && !cok { + // prefer unique key + return + } else if cok && bok { + // prefer shorter strict key + if cmpKey.Len() < bestKey.Len() { + update = true + return + } + } + + // the one below is sketchy, this is why we need costing + // prefer unique key even if non-unique has more constants + _, bestHasLax := best.LaxKey() + _, cmpHasLax := cmp.LaxKey() + if cmp.Constants().Len() > best.Constants().Len() { + if bestHasLax && !cmpHasLax { + // keep unique key + return + } + update = true + return + } else if cmp.Constants().Len() < best.Constants().Len() { + if cmpHasLax && !bestHasLax { + // keep unique key + update = true + } + return + } + + if filters.Len() > c.bestFilters.Len() { + update = true + return + } + + if s.ColSet().Len()-filters.Len() < c.bestStat.ColSet().Len()-c.bestFilters.Len() { + // prefer 1 range filter over 1 column index (1 - 1 = 0) + // vs. 1 range filter over 2 column index (2 - 1 = 1) + update = true + return + } + + { + // if no unique keys, prefer equality over ranges + bestConst, bestIsNull := c.getConstAndNullFilters(c.bestFilters) + cmpConst, cmpIsNull := c.getConstAndNullFilters(c.bestFilters) + if cmpConst.Len() > bestConst.Len() { + update = true + return + } + if cmpIsNull.Len() > bestIsNull.Len() { + update = true + return + } + } + + { + if strings.EqualFold(s.Qualifier().Index(), "primary") { + update = true + return + } else if strings.EqualFold(c.bestStat.Qualifier().Index(), "primary") { + return + } + if strings.Compare(s.Qualifier().Index(), c.bestStat.Qualifier().Index()) < 0 { + // if they are still equal, use index name to make deterministic + update = true + return + } + } } } +func (c *indexCoster) getConstAndNullFilters(filters sql.FastIntSet) (sql.FastIntSet, sql.FastIntSet) { + var isConst sql.FastIntSet + var isNull sql.FastIntSet + for i, hasNext := filters.Next(0); hasNext; i, hasNext = filters.Next(i + 1) { + e := c.idToExpr[indexScanId(i)] + switch e.(type) { + case *expression.Equals: + isConst.Add(i) + case *expression.IsNull: + isNull.Add(i) + case *expression.NullSafeEquals: + isConst.Add(i) + isNull.Add(i) + } + } + return isConst, isNull +} + // flatten converts a filter into a tree of indexFilter, a format designed // to make costing index scans easier. We return the root of the new tree // and a conjunction of filters that cannot be pushed into index scans. -func (c *indexCoster) flatten(e sql.Expression, invert bool) (indexFilter, sql.Expression) { +func (c *indexCoster) flatten(e sql.Expression) (indexFilter, sql.Expression, sql.FastIntSet) { switch e := e.(type) { case *expression.And: c.idToExpr[c.i] = e - newAnd := newIScanAnd(c.i) + newAnd := &iScanAnd{id: c.i} c.i++ - invalid := c.flattenAnd(e, newAnd) + invalid, imprecise := c.flattenAnd(e, newAnd) var leftovers []sql.Expression for i, hasMore := invalid.Next(1); hasMore; i, hasMore = invalid.Next(i + 1) { f, ok := c.idToExpr[indexScanId(i)] @@ -223,105 +421,127 @@ func (c *indexCoster) flatten(e sql.Expression, invert bool) (indexFilter, sql.E } leftovers = append(leftovers, f) } - return newAnd, expression.JoinAnd(leftovers...) + return newAnd, expression.JoinAnd(leftovers...), imprecise case *expression.Or: c.idToExpr[c.i] = e newOr := &iScanOr{id: c.i} c.i++ - valid := c.flattenOr(e, newOr) + valid, imp := c.flattenOr(e, newOr) if !valid { - return nil, e + return nil, e, sql.FastIntSet{} + } + var imprecise sql.FastIntSet + if imp { + imprecise.Add(int(newOr.id)) } - return newOr, nil + return newOr, nil, imprecise default: c.idToExpr[c.i] = e - leaf, ok := newLeaf(c.i, e) + leaf, ok := newLeaf(c.i, e, c.underlyingName) c.i++ if !ok { - return nil, e + return nil, e, sql.FastIntSet{} } - return leaf, nil + var imprecise sql.FastIntSet + if !expression.PreciseComparison(e) { + imprecise.Add(int(leaf.id)) + } + return leaf, nil, imprecise } } -func (c *indexCoster) flattenAnd(e *expression.And, and *iScanAnd) sql.FastIntSet { +// flattenAnd return two bitsets to indicate invalid index filter ids, and imprecise filter ids +func (c *indexCoster) flattenAnd(e *expression.And, and *iScanAnd) (sql.FastIntSet, sql.FastIntSet) { var invalid sql.FastIntSet + var imprecise sql.FastIntSet for _, e := range e.Children() { switch e := e.(type) { case *expression.And: c.idToExpr[c.i] = e c.i++ - inv := c.flattenAnd(e, and) + inv, imp := c.flattenAnd(e, and) invalid = invalid.Union(inv) + imprecise = invalid.Union(imp) case *expression.Or: c.idToExpr[c.i] = e newOr := &iScanOr{id: c.i} c.i++ - ok := c.flattenOr(e, newOr) - if !ok { + valid, imp := c.flattenOr(e, newOr) + if !valid { // this or is invalid invalid.Add(int(newOr.Id())) } else { and.orChildren = append(and.orChildren, newOr) + if imp { + imprecise.Add(int(newOr.id)) + } } default: c.idToExpr[c.i] = e - leaf, ok := newLeaf(c.i, e) + leaf, ok := newLeaf(c.i, e, c.underlyingName) if !ok { invalid.Add(int(c.i)) } else { and.newLeaf(leaf) + if !expression.PreciseComparison(e) { + imprecise.Add(int(leaf.id)) + } } // keep a ref to the invalid |e| c.i++ } } - return invalid + return invalid, imprecise } -func (c *indexCoster) flattenOr(e *expression.Or, or *iScanOr) bool { +func (c *indexCoster) flattenOr(e *expression.Or, or *iScanOr) (bool, bool) { + var imprecise bool for _, e := range e.Children() { switch e := e.(type) { case *expression.And: c.idToExpr[c.i] = e newAnd := &iScanAnd{id: c.i} c.i++ - inv := c.flattenAnd(e, newAnd) + inv, imp := c.flattenAnd(e, newAnd) if !inv.Empty() { - return false + return false, false } or.children = append(or.children, newAnd) + imprecise = imprecise || !imp.Empty() case *expression.Or: c.idToExpr[c.i] = e c.i++ - ok := c.flattenOr(e, or) + ok, imp := c.flattenOr(e, or) if !ok { - return false + return false, false } + imprecise = imprecise || imp default: c.idToExpr[c.i] = e - leaf, ok := newLeaf(c.i, e) + leaf, ok := newLeaf(c.i, e, c.underlyingName) if !ok { - return false + return false, false } else { c.i++ - newAnd := &iScanAnd{id: c.i, leafChildren: make(map[string][]*iScanLeaf)} - newAnd.newLeaf(leaf) - or.children = append(or.children, newAnd) + or.children = append(or.children, leaf) + if !expression.PreciseComparison(e) { + imprecise = true + } } } } - return true + return true, imprecise } -func newIndexScanRangeBuilder(ctx *sql.Context, idx sql.Index, include sql.FastIntSet, idToExpr map[indexScanId]sql.Expression) *indexScanRangeBuilder { +func newIndexScanRangeBuilder(ctx *sql.Context, idx sql.Index, include, imprecise sql.FastIntSet, idToExpr map[indexScanId]sql.Expression) *indexScanRangeBuilder { return &indexScanRangeBuilder{ - ctx: ctx, - idx: idx, - include: include, - idToExpr: idToExpr, + ctx: ctx, + idx: idx, + include: include, + imprecise: imprecise, + idToExpr: idToExpr, } } @@ -329,10 +549,12 @@ type indexScanRangeBuilder struct { ctx *sql.Context idx sql.Index include sql.FastIntSet + imprecise sql.FastIntSet idToExpr map[indexScanId]sql.Expression conjIb *sql.IndexBuilder allRanges sql.RangeCollection leftover []sql.Expression + tableName string } // buildRangeCollection converts our representation of the best index scan @@ -348,12 +570,7 @@ func (b *indexScanRangeBuilder) buildRangeCollection(f indexFilter) (sql.RangeCo case *iScanOr: ranges, err = b.rangeBuildOr(f, inScan) case *iScanLeaf: - bb := sql.NewIndexBuilder(b.idx) - b.rangeBuildLeaf(bb, f, inScan) - if _, err := bb.Build(b.ctx); err != nil { - return nil, err - } - ranges = bb.Ranges(b.ctx) + ranges, err = b.rangeBuildLeaf(f, inScan) default: return nil, fmt.Errorf("unknown indexFilter type: %T", f) } @@ -391,7 +608,32 @@ func (b *indexScanRangeBuilder) rangeBuildAnd(f *iScanAnd, inScan bool) (sql.Ran partBuilder := sql.NewIndexBuilder(b.idx) for _, leaf := range f.leaves() { - b.rangeBuildLeaf(partBuilder, leaf, inScan) + switch leaf.Op() { + case indexScanOpSpatialEq: + ranges, err := b.rangeBuildSpatialLeaf(leaf, inScan) + if err != nil { + return nil, err + } + if ranges != nil { + ret, err = ret.Intersect(partBuilder.Ranges(b.ctx)) + if err != nil { + return nil, err + } + } + case indexScanOpFulltextEq: + ranges, err := b.rangeBuildFulltextLeaf(leaf, inScan) + if err != nil { + return nil, err + } + if ranges != nil { + ret, err = ret.Intersect(partBuilder.Ranges(b.ctx)) + if err != nil { + return nil, err + } + } + default: + b.rangeBuildDefaultLeaf(partBuilder, leaf, inScan) + } } if _, err := partBuilder.Build(b.ctx); err != nil { @@ -416,10 +658,22 @@ func (b *indexScanRangeBuilder) rangeBuildOr(f *iScanOr, inScan bool) (sql.Range return nil, nil } + // imprecise filters cannot be removed + b.markImprecise(f) + //todo union the or ranges var ret sql.RangeCollection for _, c := range f.children { - ranges, err := b.rangeBuildAnd(c, inScan) + var ranges sql.RangeCollection + var err error + switch c := c.(type) { + case *iScanAnd: + ranges, err = b.rangeBuildAnd(c, inScan) + case *iScanLeaf: + ranges, err = b.rangeBuildLeaf(c, inScan) + default: + return nil, fmt.Errorf("invalid *iScanOr child: %T", c) + } if err != nil { return nil, err } @@ -428,32 +682,91 @@ func (b *indexScanRangeBuilder) rangeBuildOr(f *iScanOr, inScan bool) (sql.Range return ret, nil } -func (b *indexScanRangeBuilder) rangeBuildLeaf(bb *sql.IndexBuilder, f *iScanLeaf, inScan bool) { +func (b *indexScanRangeBuilder) rangeBuildSpatialLeaf(f *iScanLeaf, inScan bool) (sql.RangeCollection, error) { + inScan = !b.markLeftover(f, inScan) + if inScan { + // always mark leftover + b.leftover = append(b.leftover, b.idToExpr[f.Id()]) + } else { + return nil, nil + } + + g, ok := f.litValue.(types.GeometryValue) + if !ok { + return nil, sql.ErrInvalidGISData.New() + } + minX, minY, maxX, maxY := g.BBox() + lower := types.Point{X: minX, Y: minY} + upper := types.Point{X: maxX, Y: maxY} + + return sql.RangeCollection{{{ + LowerBound: sql.Below{Key: lower}, + UpperBound: sql.Above{Key: upper}, + Typ: f.gf.Type(), + }}}, nil +} + +func (b *indexScanRangeBuilder) rangeBuildFulltextLeaf(f *iScanLeaf, inScan bool) (sql.RangeCollection, error) { + // fulltext leaf doesn't use ranges + inScan = !b.markLeftover(f, inScan) + if inScan { + // always mark leftover + b.leftover = append(b.leftover, b.idToExpr[f.Id()]) + } else { + return nil, nil + } + return sql.RangeCollection{{sql.EmptyRangeColumnExpr(f.gf.Type())}}, nil +} + +func (b *indexScanRangeBuilder) rangeBuildLeaf(f *iScanLeaf, inScan bool) (sql.RangeCollection, error) { + switch f.Op() { + case indexScanOpSpatialEq: + return b.rangeBuildSpatialLeaf(f, inScan) + case indexScanOpFulltextEq: + return b.rangeBuildFulltextLeaf(f, inScan) + default: + bb := sql.NewIndexBuilder(b.idx) + b.rangeBuildDefaultLeaf(bb, f, inScan) + if _, err := bb.Build(b.ctx); err != nil { + return nil, err + } + return bb.Ranges(b.ctx), nil + } +} + +func (b *indexScanRangeBuilder) rangeBuildDefaultLeaf(bb *sql.IndexBuilder, f *iScanLeaf, inScan bool) { inScan = !b.markLeftover(f, inScan) if !inScan { return } + b.markImprecise(f) + + name := f.normString() switch f.Op() { case indexScanOpEq: - bb.Equals(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.Equals(b.ctx, name, f.litValue) + case indexScanOpNotEq: + bb.NotEquals(b.ctx, name, f.litValue) + case indexScanOpInSet: + bb.Equals(b.ctx, name, f.setValues...) case indexScanOpGt: - bb.GreaterThan(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.GreaterThan(b.ctx, name, f.litValue) case indexScanOpGte: - bb.GreaterOrEqual(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.GreaterOrEqual(b.ctx, name, f.litValue) case indexScanOpLt: - bb.LessThan(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.LessThan(b.ctx, name, f.litValue) case indexScanOpLte: - bb.LessOrEqual(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.LessOrEqual(b.ctx, name, f.litValue) case indexScanOpIsNotNull: - bb.IsNotNull(b.ctx, strings.ToLower(f.gf.Name())) + bb.IsNotNull(b.ctx, name) case indexScanOpIsNull: - bb.IsNull(b.ctx, strings.ToLower(f.gf.Name())) + bb.IsNull(b.ctx, name) case indexScanOpNullSafeEq: - if f.value == nil { - bb.IsNull(b.ctx, strings.ToLower(f.gf.Name())) + if f.litValue == nil { + bb.IsNull(b.ctx, name) } else { - bb.Equals(b.ctx, strings.ToLower(f.gf.Name()), f.value) + bb.Equals(b.ctx, name, f.litValue) } default: panic(fmt.Sprintf("unknown indexScanOp: %d", f.Op())) @@ -471,6 +784,12 @@ func (b *indexScanRangeBuilder) markLeftover(f indexFilter, inScan bool) bool { return false } +func (b *indexScanRangeBuilder) markImprecise(f indexFilter) { + if b.imprecise.Contains(int(f.Id())) { + b.leftover = append(b.leftover, b.idToExpr[f.Id()]) + } +} + // indexFilter decomposes filter conjunction into a format // amenable for checking index prefix alignment type indexFilter interface { @@ -479,10 +798,20 @@ type indexFilter interface { } type iScanLeaf struct { - op indexScanOp - id indexScanId - gf *expression.GetField - value interface{} + op indexScanOp + id indexScanId + gf *expression.GetField + underlying string + litValue interface{} + setValues []interface{} + fulltextIndex string +} + +func (l *iScanLeaf) normString() string { + if l.underlying != "" { + return fmt.Sprintf("%s.%s", strings.ToLower(l.underlying), strings.ToLower(l.gf.Name())) + } + return strings.ToLower(l.gf.String()) } func (l *iScanLeaf) Id() indexScanId { @@ -495,7 +824,7 @@ func (l *iScanLeaf) Op() indexScanOp { type iScanOr struct { id indexScanId - children []*iScanAnd + children []indexFilter } func (o *iScanOr) Id() indexScanId { @@ -606,8 +935,14 @@ func formatIndexFilterRec(b *strings.Builder, nesting int, f indexFilter) { switch f.Op() { case indexScanOpIsNull, indexScanOpIsNotNull: fmt.Fprintf(b, "(%d: %s %s)", f.Id(), f.gf, f.Op()) + case indexScanOpInSet: + var valStrs []string + for _, v := range f.setValues { + valStrs = append(valStrs, fmt.Sprintf("%v", v)) + } + fmt.Fprintf(b, "(%d: %s %s (%s))", f.Id(), f.gf, f.Op(), strings.Join(valStrs, ", ")) default: - fmt.Fprintf(b, "(%d: %s %s %v)", f.Id(), f.gf, f.Op(), f.value) + fmt.Fprintf(b, "(%d: %s %s %v)", f.Id(), f.gf, f.Op(), f.litValue) } default: @@ -620,7 +955,7 @@ type indexScanId uint16 func ordinalsForStat(stat sql.Statistic) map[string]int { ret := make(map[string]int) for i, c := range stat.Columns() { - ret[c] = i + ret[strings.ToLower(c)] = i } return ret } @@ -670,31 +1005,64 @@ func (c *indexCoster) costIndexScanOr(filter *iScanOr, s sql.Statistic, ordinals // if one of the children is invalid, we balk and return false // otherwise we union the buckets between the children ret := s + for _, child := range filter.children { - childStat, ids, err := c.costIndexScanAnd(child, s, ordinals) - if err != nil { - return nil, false, err - } - if ids.Len() != 1 || !ids.Contains(int(child.Id())) { - // scan option missed some filters - return nil, false, nil + switch child := child.(type) { + case *iScanAnd: + childStat, ids, err := c.costIndexScanAnd(child, s, ordinals) + if err != nil { + return nil, false, err + } + if ids.Len() != 1 || !ids.Contains(int(child.Id())) { + // scan option missed some filters + return nil, false, nil + } + ret = stats.Union(s, childStat) + + case *iScanLeaf: + var ok bool + childStat, ok, err := c.costIndexScanLeaf(child, s, ordinals) + if err != nil { + return nil, false, err + } + if !ok { + return nil, false, nil + } + ret = stats.Union(s, childStat) + + default: + return nil, false, fmt.Errorf("invalid *iScanOr child: %T", child) } - ret = stats.Union(s, childStat) } return ret, true, nil } func (c *indexCoster) costIndexScanLeaf(filter *iScanLeaf, s sql.Statistic, ordinals map[string]int) (sql.Statistic, bool, error) { - _, ok := ordinals[filter.gf.Name()] + ord, ok := ordinals[strings.ToLower(filter.gf.Name())] if !ok { return nil, false, nil } - ret := s + switch filter.op { + case indexScanOpSpatialEq: + return c.costSpatial(filter, s, ord) + case indexScanOpFulltextEq: + return c.costFulltext(filter, s, ord) + default: + conj := newConjCollector(s, ordinals) + conj.add(filter) + return conj.stat, true, nil + } - conj := newConjCollector(ret, ordinals) - conj.add(filter) - return conj.stat, conj.applied.Len() == 1, nil +} + +func (c *indexCoster) costSpatial(filter *iScanLeaf, s sql.Statistic, ordinal int) (sql.Statistic, bool, error) { + return s, s.IndexClass() == sql.IndexClassSpatial && ordinal == 0 && filter.litValue != nil, nil +} + +func (c *indexCoster) costFulltext(filter *iScanLeaf, s sql.Statistic, ordinal int) (sql.Statistic, bool, error) { + // check that the filter's index matches the fulltext index + return s, s.IndexClass() == sql.IndexClassFulltext && s.Qualifier().Index() == filter.fulltextIndex, nil } type indexScanOp uint8 @@ -704,6 +1072,8 @@ type indexScanOp uint8 const ( indexScanOpEq indexScanOp = iota // = indexScanOpNullSafeEq // <=> + indexScanOpInSet // = + indexScanOpNotEq // != indexScanOpGt // > indexScanOpGte // >= indexScanOpLt // < @@ -712,9 +1082,27 @@ const ( indexScanOpOr // || indexScanOpIsNull // IS NULL indexScanOpIsNotNull // IS NOT NULL + indexScanOpSpatialEq // SpatialEq + indexScanOpFulltextEq // FulltextEq ) -func newLeaf(id indexScanId, e sql.Expression) (*iScanLeaf, bool) { +// swap returns the identity op for swapping a comparison's LHS and RHS +func (o indexScanOp) swap() indexScanOp { + switch o { + case indexScanOpGt: + return indexScanOpLt + case indexScanOpGte: + return indexScanOpLte + case indexScanOpLt: + return indexScanOpGt + case indexScanOpLte: + return indexScanOpGte + default: + return o + } +} + +func newLeaf(id indexScanId, e sql.Expression, underlying string) (*iScanLeaf, bool) { var op indexScanOp var left sql.Expression var right sql.Expression @@ -727,6 +1115,14 @@ func newLeaf(id indexScanId, e sql.Expression) (*iScanLeaf, bool) { op = indexScanOpEq right = e.Right() left = e.Left() + case *expression.InTuple: + op = indexScanOpInSet + right = e.Right() + left = e.Left() + case *expression.HashInTuple: + op = indexScanOpInSet + right = e.Right() + left = e.Left() case *expression.LessThan: left = e.Left() right = e.Right() @@ -746,20 +1142,33 @@ func newLeaf(id indexScanId, e sql.Expression) (*iScanLeaf, bool) { case *expression.IsNull: left = e.Child op = indexScanOpIsNull - // todo not null case *expression.Not: - isNull, ok := e.Child.(*expression.IsNull) - if !ok { + switch e := e.Child.(type) { + case *expression.IsNull: + left = e.Child + op = indexScanOpIsNotNull + case *expression.Equals: + left = e.Left() + right = e.Right() + op = indexScanOpNotEq + default: return nil, false } - left = isNull.Child - op = indexScanOpIsNotNull + case *spatial.Intersects, *spatial.Within, *spatial.STEquals: + op = indexScanOpSpatialEq + children := e.Children() + left = children[0] + right = children[1] + case *expression.MatchAgainst: + op = indexScanOpFulltextEq + return &iScanLeaf{id: id, op: op, gf: e.Columns[0].(*expression.GetField), underlying: underlying, fulltextIndex: e.GetIndex().ID()}, true default: return nil, false } if _, ok := left.(*expression.GetField); !ok { left, right = right, left + op = op.swap() } gf, ok := left.(*expression.GetField) @@ -768,66 +1177,112 @@ func newLeaf(id indexScanId, e sql.Expression) (*iScanLeaf, bool) { } if op == indexScanOpIsNull || op == indexScanOpIsNotNull { - return &iScanLeaf{id: id, gf: gf, op: op}, true + return &iScanLeaf{id: id, gf: gf, op: op, underlying: underlying}, true } if !isEvaluable(right) { return nil, false } + if op == indexScanOpInSet { + tup := right.(expression.Tuple) + var litSet []interface{} + for _, lit := range tup { + value, err := lit.Eval(nil, nil) + if err != nil { + return nil, false + } + litSet = append(litSet, value) + } + return &iScanLeaf{id: id, gf: gf, op: op, setValues: litSet, underlying: underlying}, true + } + value, err := right.Eval(nil, nil) if err != nil { return nil, false } - return &iScanLeaf{id: id, gf: gf, op: op, value: value}, true + return &iScanLeaf{id: id, gf: gf, op: op, litValue: value, underlying: underlying}, true } -const dummyBucketCnt = 10 const dummyNotUniqueDistinct = .90 const dummyNotUniqueNull = .03 -func uniformDistStatistics(ctx *sql.Context, rt *plan.ResolvedTable) (map[sql.StatQualifier]sql.Statistic, error) { - iat := rt.Table.(sql.IndexAddressableTable) - indexes, err := iat.GetIndexes(ctx) - if err != nil { - return nil, err - } - - if len(indexes) == 0 { - return nil, nil - } - +func uniformDistStatisticsForIndex(ctx *sql.Context, iat sql.IndexAddressableTable, idx sql.Index) (sql.Statistic, error) { var rowCount uint64 var avgSize uint64 - if st, ok := rt.Table.(sql.StatisticsTable); ok { - rowCount, _, err = st.RowCount(ctx) + if st, ok := iat.(sql.StatisticsTable); ok { + rowCount, _, err := st.RowCount(ctx) if err != nil { return nil, err } - dataSize, err := st.DataLength(ctx) - if err != nil { - return nil, err + if rowCount > 0 { + dataSize, err := st.DataLength(ctx) + if err != nil { + return nil, err + } + avgSize = dataSize / rowCount } - avgSize = dataSize / rowCount } - ret := make(map[sql.StatQualifier]sql.Statistic) + var dbName string + if dbTable, ok := iat.(sql.Databaseable); ok { + dbName = strings.ToLower(dbTable.Database()) + } + tableName := strings.ToLower(iat.Name()) + + var sch sql.Schema + if pkt, ok := iat.(sql.PrimaryKeyTable); ok { + sch = pkt.PrimaryKeySchema().Schema + } else { + sch = iat.Schema() + } + + return newUniformDistStatistic(dbName, tableName, sch, idx, rowCount, avgSize) +} - dbName := strings.ToLower(rt.Database().Name()) - tableName := strings.ToLower(rt.Name()) +func indexFds(tableName string, sch sql.Schema, idx sql.Index) (*sql.FuncDepSet, sql.ColSet, error) { + var idxCols sql.ColSet + pref := fmt.Sprintf("%s.", tableName) + for _, col := range idx.ColumnExpressionTypes() { + colName := strings.TrimPrefix(strings.ToLower(col.Expression), pref) + i := sch.IndexOfColName(colName) + if i < 0 { + return nil, idxCols, fmt.Errorf("column not found on table during stats building: %s", colName) + } + idxCols.Add(sql.ColumnId(i + 1)) + } - for _, idx := range indexes { - idxName := strings.ToLower(idx.ID()) - qual := sql.NewStatQualifier(dbName, tableName, idxName) - newStat := newUniformDistStatistic(strings.ToLower(rt.Database().Name()), strings.ToLower(rt.Name()), idx, rowCount, avgSize) - ret[qual] = newStat + var all sql.ColSet + var notNull sql.ColSet + for i, col := range sch { + all.Add(sql.ColumnId(i + 1)) + if !col.Nullable { + notNull.Add(sql.ColumnId(i + 1)) + } } - return ret, nil + + strict := true + for i, hasNext := idxCols.Next(1); hasNext; i, hasNext = idxCols.Next(i + 1) { + if !notNull.Contains(i) { + strict = false + } + } + + var strictKeys []sql.ColSet + var laxKeys []sql.ColSet + if !idx.IsUnique() { + // not an FD + } else if strict { + strictKeys = append(strictKeys, idxCols) + } else { + laxKeys = append(laxKeys, idxCols) + } + return sql.NewTablescanFDs(all, strictKeys, laxKeys, notNull), idxCols, nil } -func newUniformDistStatistic(dbName, tableName string, idx sql.Index, rowCount, avgSize uint64) sql.Statistic { +func newUniformDistStatistic(dbName, tableName string, sch sql.Schema, idx sql.Index, rowCount, avgSize uint64) (sql.Statistic, error) { tablePrefix := fmt.Sprintf("%s.", tableName) distinctCount := rowCount @@ -839,13 +1294,31 @@ func newUniformDistStatistic(dbName, tableName string, idx sql.Index, rowCount, var cols []string var types []sql.Type - for _, exp := range idx.ColumnExpressionTypes() { - cols = append(cols, strings.TrimPrefix(exp.Expression, tablePrefix)) - types = append(types, exp.Type) + for _, e := range idx.ColumnExpressionTypes() { + cols = append(cols, strings.TrimPrefix(strings.ToLower(e.Expression), tablePrefix)) + types = append(types, e.Type) + } + + var class sql.IndexClass + switch { + case idx.IsSpatial(): + class = sql.IndexClassSpatial + case idx.IsFullText(): + class = sql.IndexClassFulltext + default: + class = sql.IndexClassDefault } qual := sql.NewStatQualifier(dbName, tableName, strings.ToLower(idx.ID())) - return stats.NewStatistic(rowCount, distinctCount, nullCount, avgSize, time.Now(), qual, cols, types, nil) + stat := stats.NewStatistic(rowCount, distinctCount, nullCount, avgSize, time.Now(), qual, cols, types, nil, class) + + fds, idxCols, err := indexFds(tableName, sch, idx) + if err != nil { + return nil, err + } + stat.SetFuncDeps(fds) + stat.SetColSet(idxCols) + return stat, nil } func newConjCollector(s sql.Statistic, ordinals map[string]int) *conjCollector { @@ -862,8 +1335,8 @@ func newConjCollector(s sql.Statistic, ordinals map[string]int) *conjCollector { type conjCollector struct { stat sql.Statistic ordinals map[string]int - missingPrefix sql.ColumnId - constant sql.ColSet + missingPrefix int + constant sql.FastIntSet eqVals []interface{} nullable []bool applied sql.FastIntSet @@ -874,17 +1347,20 @@ func (c *conjCollector) add(f *iScanLeaf) { c.applied.Add(int(f.Id())) switch f.Op() { case indexScanOpNullSafeEq: - c.addEq(f.gf.Name(), f.value, true) + c.addEq(f.gf.Name(), f.litValue, true) case indexScanOpEq: - c.addEq(f.gf.Name(), f.value, false) + c.addEq(f.gf.Name(), f.litValue, false) + case indexScanOpInSet: + // TODO cost UNION of equals + c.addEq(f.gf.Name(), f.setValues[0], false) default: - c.addIneq(f.Op(), f.gf.Name(), f.value) + c.addIneq(f.Op(), f.gf.Name(), f.litValue) } } func (c *conjCollector) addEq(col string, val interface{}, nullSafe bool) { // make constant - ord := sql.ColumnId(c.ordinals[col]) + ord := c.ordinals[col] if c.constant.Contains(ord) { if c.eqVals[ord] != val { // FALSE filter @@ -901,7 +1377,7 @@ func (c *conjCollector) addEq(col string, val interface{}, nullSafe bool) { if ord == c.missingPrefix { // we are interested in the cases where the index prefix // key is extended - if int(ord) == len(c.eqVals)-1 { + if ord == len(c.eqVals)-1 { // full prefix c.missingPrefix++ } else { @@ -938,6 +1414,8 @@ func (c *conjCollector) cmpFirstCol(op indexScanOp, val interface{}) { return } switch op { + case indexScanOpNotEq: + // todo notEq case indexScanOpGt: c.stat = stats.PrefixGt(c.stat, val) case indexScanOpGte: diff --git a/sql/analyzer/costed_index_scan_test.go b/sql/analyzer/costed_index_scan_test.go index 74058e67c7..e71f5143d1 100644 --- a/sql/analyzer/costed_index_scan_test.go +++ b/sql/analyzer/costed_index_scan_test.go @@ -16,16 +16,17 @@ package analyzer import ( "fmt" - "github.com/dolthub/go-mysql-server/memory" - "github.com/dolthub/go-mysql-server/sql/types" - "github.com/stretchr/testify/assert" "strings" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/dolthub/go-mysql-server/memory" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/expression" + "github.com/dolthub/go-mysql-server/sql/transform" + "github.com/dolthub/go-mysql-server/sql/types" ) func TestExprFlatten(t *testing.T) { @@ -67,10 +68,8 @@ func TestExprFlatten(t *testing.T) { (3: xy.x = 1) (4: xy.y = 2) (5: or - (7: and - (6: xy.y > 0)) - (8: and - (7: xy.y < 7))))`, + (6: xy.y > 0) + (7: xy.y < 7)))`, }, { name: "ors with and", @@ -86,10 +85,8 @@ func TestExprFlatten(t *testing.T) { ), exp: ` (1: or - (4: and - (3: xy.x = 1)) - (5: and - (4: xy.y = 2)) + (3: xy.x = 1) + (4: xy.y = 2) (5: and (6: xy.y > 0) (7: xy.y < 7)))`, @@ -190,8 +187,8 @@ Or for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - c := newIndexCoster() - root, leftover := c.flatten(tt.in, false) + c := newIndexCoster("xyz") + root, leftover, _ := c.flatten(tt.in) costTree := formatIndexFilter(root) require.Equal(t, strings.TrimSpace(tt.exp), strings.TrimSpace(costTree), costTree) if leftover != nil { @@ -208,9 +205,9 @@ var rangeType = types.Uint8 func TestRangeBuilder(t *testing.T) { ctx := sql.NewEmptyContext() - x := expression.NewGetField(0, rangeType, "x", true) - y := expression.NewGetField(1, rangeType, "y", true) - z := expression.NewGetField(2, rangeType, "z", true) + x := expression.NewGetFieldWithTable(0, rangeType, "mydb", "xyz", "x", true) + y := expression.NewGetFieldWithTable(1, rangeType, "mydb", "xyz", "y", true) + z := expression.NewGetFieldWithTable(2, rangeType, "mydb", "xyz", "z", true) tests := []struct { filter sql.Expression @@ -513,11 +510,16 @@ func TestRangeBuilder(t *testing.T) { TableName: testTable, } + var sch = make(sql.Schema, 3) + for i, e := range []*expression.GetField{x, y, z} { + sch[i] = transform.ExpressionToColumn(e, testTable) + } + for _, tt := range tests { t.Run(fmt.Sprintf("Expr: %s\nRange: %s", tt.filter.String(), tt.exp.DebugString()), func(t *testing.T) { - c := newIndexCoster() - root, _ := c.flatten(tt.filter, false) + c := newIndexCoster(testTable) + root, _, _ := c.flatten(tt.filter) var idx sql.Index switch len(tt.exp[0]) { @@ -527,8 +529,10 @@ func TestRangeBuilder(t *testing.T) { idx = idx_3 } - stat := newUniformDistStatistic("mydb", "xyz", idx, 10, 10) - err := c.cost(root, stat) + stat, err := newUniformDistStatistic("mydb", testTable, sch, idx, 10, 10) + require.NoError(t, err) + + err = c.cost(root, stat) require.NoError(t, err) include := c.bestFilters @@ -537,7 +541,7 @@ func TestRangeBuilder(t *testing.T) { require.Equal(t, include.Len(), 1) require.True(t, include.Contains(1)) - b := newIndexScanRangeBuilder(ctx, idx, include, c.idToExpr) + b := newIndexScanRangeBuilder(ctx, idx, include, sql.FastIntSet{}, c.idToExpr) cmpRanges, err := b.buildRangeCollection(root) require.NoError(t, err) require.Equal(t, 0, len(b.leftover)) @@ -561,8 +565,8 @@ func TestRangeBuilder(t *testing.T) { func TestRangeBuilderInclude(t *testing.T) { - x := expression.NewGetField(0, rangeType, "x", true) - y := expression.NewGetField(1, rangeType, "y", true) + x := expression.NewGetFieldWithTable(0, rangeType, "mydb", "xyz", "x", true) + y := expression.NewGetFieldWithTable(1, rangeType, "mydb", "xyz", "y", true) tests := []struct { name string @@ -606,7 +610,7 @@ func TestRangeBuilderInclude(t *testing.T) { } const testDb = "mydb" - const testTable = "test" + const testTable = "xyz" dummy1 := &memory.Index{ Name: "dummy1", Exprs: []sql.Expression{x, y}, @@ -620,9 +624,9 @@ func TestRangeBuilderInclude(t *testing.T) { //t.Skip("todo add tests and implement") // TODO make index - c := newIndexCoster() - root, _ := c.flatten(tt.in, false) - b := newIndexScanRangeBuilder(ctx, dummy1, tt.include, c.idToExpr) + c := newIndexCoster("xyz") + root, _, _ := c.flatten(tt.in) + b := newIndexScanRangeBuilder(ctx, dummy1, tt.include, sql.FastIntSet{}, c.idToExpr) cmpRanges, err := b.buildRangeCollection(root) require.NoError(t, err) cmpRanges, err = sql.SortRanges(cmpRanges...) diff --git a/sql/analyzer/indexscanop_string.go b/sql/analyzer/indexscanop_string.go index eadc713804..af186c7263 100644 --- a/sql/analyzer/indexscanop_string.go +++ b/sql/analyzer/indexscanop_string.go @@ -10,19 +10,21 @@ func _() { var x [1]struct{} _ = x[indexScanOpEq-0] _ = x[indexScanOpNullSafeEq-1] - _ = x[indexScanOpGt-2] - _ = x[indexScanOpGte-3] - _ = x[indexScanOpLt-4] - _ = x[indexScanOpLte-5] - _ = x[indexScanOpAnd-6] - _ = x[indexScanOpOr-7] - _ = x[indexScanOpIsNull-8] - _ = x[indexScanOpIsNotNull-9] + _ = x[indexScanOpInSet-2] + _ = x[indexScanOpNotEq-3] + _ = x[indexScanOpGt-4] + _ = x[indexScanOpGte-5] + _ = x[indexScanOpLt-6] + _ = x[indexScanOpLte-7] + _ = x[indexScanOpAnd-8] + _ = x[indexScanOpOr-9] + _ = x[indexScanOpIsNull-10] + _ = x[indexScanOpIsNotNull-11] } -const _indexScanOp_name = "=<=>>>=<<=&&||IS NULLIS NOT NULL" +const _indexScanOp_name = "=<=>=!=>>=<<=&&||IS NULLIS NOT NULL" -var _indexScanOp_index = [...]uint8{0, 1, 4, 5, 7, 8, 10, 12, 14, 21, 32} +var _indexScanOp_index = [...]uint8{0, 1, 4, 5, 7, 8, 10, 11, 13, 15, 17, 24, 35} func (i indexScanOp) String() string { if i >= indexScanOp(len(_indexScanOp_index)-1) { diff --git a/sql/analyzer/match_against.go b/sql/analyzer/match_against.go deleted file mode 100644 index ab5e394de2..0000000000 --- a/sql/analyzer/match_against.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2023 Dolthub, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package analyzer - -import ( - "fmt" - - "github.com/dolthub/go-mysql-server/sql/fulltext" - - "github.com/dolthub/go-mysql-server/sql" - "github.com/dolthub/go-mysql-server/sql/expression" - "github.com/dolthub/go-mysql-server/sql/plan" - "github.com/dolthub/go-mysql-server/sql/transform" -) - -// matchAgainst handles the MATCH ... AGAINST ... expression, which will contain all of the information needed to -// perform relevancy calculations using the indexes. -func matchAgainst(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, sel RuleSelector) (sql.Node, transform.TreeIdentity, error) { - span, ctx := ctx.Span("match_against") - defer span.End() - - return transform.NodeExprs(n, func(expr sql.Expression) (sql.Expression, transform.TreeIdentity, error) { - matchAgainstExpr, ok := expr.(*expression.MatchAgainst) - if !ok { - return expr, transform.SameTree, nil - } - return processMatchAgainst(ctx, matchAgainstExpr, getResolvedTable(n)) - }) -} - -// processMatchAgainst returns a new MatchAgainst expression that has had all of its tables filled in. This essentially -// grabs the appropriate index (if it hasn't already been grabbed), and then loads the appropriate tables that are -// referenced by the index. The returned expression contains everything needed to calculate relevancy. -// -// A fully resolved MatchAgainst expression is also used by the index filter, since we only need to load the tables once. -// All steps after this one can assume that the expression has been fully resolved and is valid. -// TODO: this won't work with a virtual column -func processMatchAgainst(ctx *sql.Context, matchAgainstExpr *expression.MatchAgainst, tbl *plan.ResolvedTable) (*expression.MatchAgainst, transform.TreeIdentity, error) { - // Grab the table - if tbl == nil { - return nil, transform.NewTree, fmt.Errorf("cannot use MATCH ... AGAINST ... as no table was found") - } - innerTbl := tbl.UnderlyingTable() - indexedTbl, ok := innerTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("cannot use MATCH ... AGAINST ... on a table that does not declare indexes") - } - if _, ok = indexedTbl.(sql.StatisticsTable); !ok { - return nil, transform.NewTree, fmt.Errorf("cannot use MATCH ... AGAINST ... on a table that does not implement sql.StatisticsTable") - } - - // Verify the indexes that have been set - ftIndex := matchAgainstExpr.GetIndex() - if ftIndex == nil { - indexes, err := indexedTbl.GetIndexes(ctx) - if err != nil { - return nil, transform.NewTree, err - } - ftIndex = assignMatchAgainstIndex(ctx, matchAgainstExpr, &indexAnalyzer{ - indexesByTable: map[string][]sql.Index{indexedTbl.Name(): indexes}, - }) - if ftIndex == nil { - return nil, transform.NewTree, sql.ErrNoFullTextIndexFound.New(indexedTbl.Name()) - } - } - - // Grab the pseudo-index table names - tableNames, err := ftIndex.FullTextTableNames(ctx) - if err != nil { - return nil, transform.NewTree, err - } - // Get the config table - configTbl, ok, err := tbl.SqlDatabase.GetTableInsensitive(ctx, tableNames.Config) - if err != nil { - return nil, transform.NewTree, err - } - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` is linked to table `%s` which could not be found", - ftIndex.ID(), indexedTbl.Name(), tableNames.Config) - } - indexedConfigTbl, ok := configTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` requires table `%s` to implement sql.IndexAddressableTable", - ftIndex.ID(), indexedTbl.Name(), tableNames.Config) - } - // Get the position table - positionTbl, ok, err := tbl.SqlDatabase.GetTableInsensitive(ctx, tableNames.Position) - if err != nil { - return nil, transform.NewTree, err - } - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` is linked to table `%s` which could not be found", - ftIndex.ID(), indexedTbl.Name(), tableNames.Position) - } - indexedPositionTbl, ok := positionTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` requires table `%s` to implement sql.IndexAddressableTable", - ftIndex.ID(), indexedTbl.Name(), tableNames.Position) - } - // Get the document count table - docCountTbl, ok, err := tbl.SqlDatabase.GetTableInsensitive(ctx, tableNames.DocCount) - if err != nil { - return nil, transform.NewTree, err - } - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` is linked to table `%s` which could not be found", - ftIndex.ID(), indexedTbl.Name(), tableNames.DocCount) - } - indexedDocCountTbl, ok := docCountTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` requires table `%s` to implement sql.IndexAddressableTable", - ftIndex.ID(), indexedTbl.Name(), tableNames.DocCount) - } - // Get the document count table - globalCountTbl, ok, err := tbl.SqlDatabase.GetTableInsensitive(ctx, tableNames.GlobalCount) - if err != nil { - return nil, transform.NewTree, err - } - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` is linked to table `%s` which could not be found", - ftIndex.ID(), indexedTbl.Name(), tableNames.GlobalCount) - } - indexedGlobalCountTbl, ok := globalCountTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` requires table `%s` to implement sql.IndexAddressableTable", - ftIndex.ID(), indexedTbl.Name(), tableNames.GlobalCount) - } - // Get the row count table - rowCountTbl, ok, err := tbl.SqlDatabase.GetTableInsensitive(ctx, tableNames.RowCount) - if err != nil { - return nil, transform.NewTree, err - } - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` is linked to table `%s` which could not be found", - ftIndex.ID(), indexedTbl.Name(), tableNames.RowCount) - } - indexedRowCountTbl, ok := rowCountTbl.(sql.IndexAddressableTable) - if !ok { - return nil, transform.NewTree, fmt.Errorf("Full-Text index `%s` on table `%s` requires table `%s` to implement sql.IndexAddressableTable", - ftIndex.ID(), indexedTbl.Name(), tableNames.RowCount) - } - - // Get the key columns - keyCols, err := ftIndex.FullTextKeyColumns(ctx) - if err != nil { - return nil, transform.NewTree, err - } - return matchAgainstExpr.WithInfo(indexedTbl, indexedConfigTbl, indexedPositionTbl, indexedDocCountTbl, indexedGlobalCountTbl, indexedRowCountTbl, keyCols), transform.NewTree, nil -} - -func assignMatchAgainstIndex(ctx *sql.Context, e *expression.MatchAgainst, ia *indexAnalyzer) fulltext.Index { - if ftIndex := e.GetIndex(); ftIndex != nil { - return ftIndex - } - getFields := e.ColumnsAsGetFields() - if len(getFields) == 0 { - return nil - } - ftIndexes := ia.MatchingIndexes(ctx, getFields[0].TableID(), e.Columns...) - for _, idx := range ftIndexes { - // Full-Text does not support partial matches, so we filter for the exact match - if idx.IsFullText() && len(getFields) == len(idx.Expressions()) { - // Ensure that it implements the interface - if ftIndex, ok := idx.(fulltext.Index); ok { - e.SetIndex(ftIndex) - return ftIndex - } - } - } - return nil -} diff --git a/sql/analyzer/optimization_rules.go b/sql/analyzer/optimization_rules.go index f42dbf103b..54097a0ac7 100644 --- a/sql/analyzer/optimization_rules.go +++ b/sql/analyzer/optimization_rules.go @@ -205,6 +205,11 @@ func simplifyFilters(ctx *sql.Context, a *Analyzer, node sql.Node, scope *plan.S return e, transform.SameTree, err } return e.WithQuery(newQ), transform.NewTree, nil + case *expression.Between: + return expression.NewAnd( + expression.NewGreaterThanOrEqual(e.Val, e.Lower), + expression.NewLessThanOrEqual(e.Val, e.Upper), + ), transform.NewTree, nil case *expression.Or: if isTrue(e.Left) { return e.Left, transform.NewTree, nil diff --git a/sql/analyzer/rules.go b/sql/analyzer/rules.go index c5a8671910..85fbe484c9 100644 --- a/sql/analyzer/rules.go +++ b/sql/analyzer/rules.go @@ -64,7 +64,7 @@ var OnceAfterDefault = []Rule{ {stripTableNameInDefaultsId, stripTableNamesFromColumnDefaults}, {pushFiltersId, pushFilters}, {optimizeJoinsId, optimizeJoins}, - {generateIndexScansId, generateIndexScans}, + {generateIndexScansId, costedIndexScans}, {finalizeSubqueriesId, finalizeSubqueries}, {applyIndexesFromOuterScopeId, applyIndexesFromOuterScope}, {replaceAggId, replaceAgg}, diff --git a/sql/col_set.go b/sql/col_set.go index 086792d757..610a172cdf 100644 --- a/sql/col_set.go +++ b/sql/col_set.go @@ -19,6 +19,10 @@ func NewColSet(vals ...ColumnId) ColSet { return ret } +func NewColSetFromIntSet(set FastIntSet) ColSet { + return ColSet{set: set} +} + // We offset the ColumnIDs in the underlying FastIntSet by 1, so that the // internal set fast-path can be used for ColumnIDs in the range [1, 64] instead // of [0, 63]. ColumnId 0 is reserved as an unknown ColumnId, and a ColSet diff --git a/sql/expression/comparison.go b/sql/expression/comparison.go index 08bb988eab..f159ddb22a 100644 --- a/sql/expression/comparison.go +++ b/sql/expression/comparison.go @@ -38,10 +38,10 @@ type Comparer interface { // ErrNilOperand ir returned if some or both of the comparison's operands is nil. var ErrNilOperand = errors.NewKind("nil operand found in comparison") -// ContainsImpreciseComparison searches an expression tree for comparison +// PreciseComparison searches an expression tree for comparison // expressions that require a conversion or type promotion. // This utility helps determine if filter predicates can be pushed down. -func ContainsImpreciseComparison(e sql.Expression) bool { +func PreciseComparison(e sql.Expression) bool { var imprecise bool sql.Inspect(e, func(expr sql.Expression) bool { if cmp, ok := expr.(Comparer); ok { @@ -60,7 +60,7 @@ func ContainsImpreciseComparison(e sql.Expression) bool { } return true }) - return imprecise + return !imprecise } type comparison struct { diff --git a/sql/fulltext/multi_editor.go b/sql/fulltext/multi_editor.go index 1b03f8cf41..33e33e5370 100644 --- a/sql/fulltext/multi_editor.go +++ b/sql/fulltext/multi_editor.go @@ -126,6 +126,10 @@ func (editor MultiTableEditor) IndexedAccess(lookup sql.IndexLookup) sql.Indexed return editor.primary.(sql.ForeignKeyEditor).IndexedAccess(lookup) } +func (editor MultiTableEditor) PreciseMatch() bool { + return true +} + // GetIndexes implements the interface ForeignKeyEditor. func (editor MultiTableEditor) GetIndexes(ctx *sql.Context) ([]sql.Index, error) { return editor.primary.(sql.ForeignKeyEditor).GetIndexes(ctx) diff --git a/sql/func_deps.go b/sql/func_deps.go index 45fb9c853c..bf97ae2581 100644 --- a/sql/func_deps.go +++ b/sql/func_deps.go @@ -167,6 +167,10 @@ func (f *FuncDepSet) All() ColSet { return f.all } +func (f *FuncDepSet) Empty() bool { + return f.all.Empty() +} + func (f *FuncDepSet) NotNull() ColSet { return f.notNull } diff --git a/sql/memo/rel_props_test.go b/sql/memo/rel_props_test.go index da65c36402..a8d2c2dbfb 100644 --- a/sql/memo/rel_props_test.go +++ b/sql/memo/rel_props_test.go @@ -154,6 +154,10 @@ func (t *dummyTable) IndexedAccess(sql.IndexLookup) sql.IndexedTable { panic("implement me") } +func (t *dummyTable) PreciseMatch() bool { + return true +} + func (t *dummyTable) GetIndexes(*sql.Context) ([]sql.Index, error) { var exprs []string for _, i := range t.schema.PkOrdinals { diff --git a/sql/plan/histogram.go b/sql/plan/histogram.go index baaa646fb6..b1cf7f2ecc 100644 --- a/sql/plan/histogram.go +++ b/sql/plan/histogram.go @@ -10,13 +10,14 @@ import ( "github.com/dolthub/go-mysql-server/sql" ) -func NewUpdateHistogram(db, table string, cols []string, stats *stats.Statistic) *UpdateHistogram { - return &UpdateHistogram{db: db, cols: cols, table: table, stats: stats} +func NewUpdateHistogram(db, table, index string, cols []string, stats *stats.Statistic) *UpdateHistogram { + return &UpdateHistogram{db: db, cols: cols, index: index, table: table, stats: stats} } type UpdateHistogram struct { db string table string + index string cols []string stats *stats.Statistic prov sql.StatsProvider @@ -32,6 +33,10 @@ func (u *UpdateHistogram) Table() string { return u.table } +func (u *UpdateHistogram) Index() string { + return u.index +} + func (u *UpdateHistogram) Cols() []string { return u.cols } diff --git a/sql/planbuilder/analyze.go b/sql/planbuilder/analyze.go index ad2c1d87a0..63f911d0f8 100644 --- a/sql/planbuilder/analyze.go +++ b/sql/planbuilder/analyze.go @@ -142,9 +142,14 @@ func (b *Builder) buildAnalyzeUpdate(inScope *scope, n *ast.Analyze, dbName, tab err := fmt.Errorf("no statistics found for update") b.handleErr(err) } - statistic.SetQualifier(sql.NewStatQualifier(dbName, tableName, "")) + var indexName string + if statistic.Qual.Index() == "" { + indexName = "primary" + } + statistic.SetQualifier(sql.NewStatQualifier(dbName, tableName, indexName)) statistic.SetColumns(columns) statistic.SetTypes(types) - outScope.node = plan.NewUpdateHistogram(dbName, tableName, columns, statistic).WithProvider(b.cat) + // TODO make sure index has the given columns + outScope.node = plan.NewUpdateHistogram(dbName, tableName, indexName, columns, statistic).WithProvider(b.cat) return outScope } diff --git a/sql/planbuilder/parse_test.go b/sql/planbuilder/parse_test.go index 001bf96d1f..cb97bb71c2 100644 --- a/sql/planbuilder/parse_test.go +++ b/sql/planbuilder/parse_test.go @@ -86,7 +86,7 @@ Project { Query: "analyze table xy update histogram on (x, y) using data '{\"row_count\": 40, \"distinct_count\": 40, \"null_count\": 1, \"columns\": [\"x\", \"y\"], \"histogram\": [{\"row_count\": 20, \"upper_bound\": [50.0]}, {\"row_count\": 20, \"upper_bound\": [80.0]}]}'", ExpectedPlan: ` -update histogram xy.(x,y) using {"statistic":{"avg_size":0,"buckets":[],"columns":["x","y"],"created_at":"0001-01-01T00:00:00Z","distinct_count":40,"null_count":40,"qualifier":"mydb.xy","row_count":40,"types:":["bigint","bigint"]}}`, +update histogram xy.(x,y) using {"statistic":{"avg_size":0,"buckets":[],"columns":["x","y"],"created_at":"0001-01-01T00:00:00Z","distinct_count":40,"null_count":40,"qualifier":"mydb.xy.primary","row_count":40,"types:":["bigint","bigint"]}}`, }, { Query: "SELECT b.y as s1, a.y as s2, first_value(a.z) over (partition by a.y) from xy a join xy b on a.y = b.y", diff --git a/sql/planbuilder/scalar.go b/sql/planbuilder/scalar.go index 0259913ae0..f0e9628740 100644 --- a/sql/planbuilder/scalar.go +++ b/sql/planbuilder/scalar.go @@ -953,6 +953,8 @@ func (b *Builder) buildMatchAgainst(inScope *scope, v *ast.MatchExpr) *expressio } matchAgainst := expression.NewMatchAgainst(genericCols, matchExpr, searchModifier) + matchAgainst.SetIndex(ftIndex) + return matchAgainst.WithInfo(indexedTbl, idxTables[0], idxTables[1], idxTables[2], idxTables[3], idxTables[4], keyCols) } diff --git a/sql/rowexec/ddl_iters.go b/sql/rowexec/ddl_iters.go index d21f6e5f8d..399e77b1e6 100644 --- a/sql/rowexec/ddl_iters.go +++ b/sql/rowexec/ddl_iters.go @@ -1176,6 +1176,13 @@ func (d *dropPkIter) rewriteTable(ctx *sql.Context, rwt sql.RewritableTable) err return err } + hasFullText := hasFullText(ctx, d.pkAlterable) + if hasFullText { + if err = rebuildFullText(ctx, d.pkAlterable.Name(), d.db); err != nil { + return err + } + } + return nil } diff --git a/sql/statistics.go b/sql/statistics.go index 52a6da1bcf..74ebac35c5 100644 --- a/sql/statistics.go +++ b/sql/statistics.go @@ -49,6 +49,14 @@ type StatsProvider interface { DataLength(ctx *Context, db, table string) (uint64, error) } +type IndexClass uint8 + +const ( + IndexClassDefault = iota + IndexClassSpatial + IndexClassFulltext +) + // Statistic is the top-level interface for accessing cardinality and // costing estimates for an index prefix. type Statistic interface { @@ -62,6 +70,11 @@ type Statistic interface { Types() []Type Qualifier() StatQualifier Histogram() Histogram + IndexClass() IndexClass + FuncDeps() *FuncDepSet + SetFuncDeps(*FuncDepSet) + ColSet() ColSet + SetColSet(ColSet) } func NewQualifierFromString(q string) (StatQualifier, error) { diff --git a/sql/stats/statistic.go b/sql/stats/statistic.go index 41d770cc30..8f5f7007c9 100644 --- a/sql/stats/statistic.go +++ b/sql/stats/statistic.go @@ -29,7 +29,7 @@ import ( "github.com/dolthub/go-mysql-server/sql/types" ) -func NewStatistic(rowCount, distinctCount, nullCount, avgSize uint64, createdAt time.Time, qualifier sql.StatQualifier, columns []string, types []sql.Type, histogram []*Bucket) *Statistic { +func NewStatistic(rowCount, distinctCount, nullCount, avgSize uint64, createdAt time.Time, qualifier sql.StatQualifier, columns []string, types []sql.Type, histogram []*Bucket, class sql.IndexClass) *Statistic { return &Statistic{ RowCnt: rowCount, DistinctCnt: distinctCount, @@ -40,6 +40,7 @@ func NewStatistic(rowCount, distinctCount, nullCount, avgSize uint64, createdAt Cols: columns, Typs: types, Hist: histogram, + IdxClass: uint8(class), } } @@ -53,6 +54,28 @@ type Statistic struct { Cols []string `json:"columns"` Typs []sql.Type `json:"types"` Hist []*Bucket `json:"buckets"` + IdxClass uint8 `json:"index_class"` + fds *sql.FuncDepSet `json:"-"` + colSet sql.ColSet `json:"-"` +} + +var _ sql.JSONWrapper = (*Statistic)(nil) +var _ sql.Statistic = (*Statistic)(nil) + +func (s *Statistic) FuncDeps() *sql.FuncDepSet { + return s.fds +} + +func (s *Statistic) SetFuncDeps(fds *sql.FuncDepSet) { + s.fds = fds +} + +func (s *Statistic) ColSet() sql.ColSet { + return s.colSet +} + +func (s *Statistic) SetColSet(cols sql.ColSet) { + s.colSet = cols } func (s *Statistic) SetTypes(t []sql.Type) { @@ -107,8 +130,9 @@ func (s *Statistic) Histogram() sql.Histogram { return buckets } -var _ sql.JSONWrapper = (*Statistic)(nil) -var _ sql.Statistic = (*Statistic)(nil) +func (s *Statistic) IndexClass() sql.IndexClass { + return sql.IndexClass(s.IdxClass) +} func (s *Statistic) ToInterface() interface{} { typs := make([]string, len(s.Typs)) diff --git a/sql/stats/union.go b/sql/stats/union.go index 3550789965..8d30a727e6 100644 --- a/sql/stats/union.go +++ b/sql/stats/union.go @@ -1,63 +1,91 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package stats import "github.com/dolthub/go-mysql-server/sql" func Union(s1, s2 sql.Statistic) sql.Statistic { - return nil + return s1 } func Intersect(s1, s2 sql.Statistic) sql.Statistic { - return nil + return s1 } func PrefixKey(s1 sql.Statistic, key []interface{}, nullable []bool) sql.Statistic { - return nil + idxCols := s1.ColSet() + var constant sql.ColSet + var notNull sql.ColSet + var i sql.ColumnId + for _, null := range nullable[:len(key)] { + i, _ = idxCols.Next(i + 1) + constant.Add(i) + if !null { + notNull.Add(i) + } + } + + old := s1.FuncDeps() + new := sql.NewFilterFDs(old, old.NotNull().Union(notNull), old.Constants().Union(constant), nil) + s1.SetFuncDeps(new) + return s1 } func PrefixLt(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func PrefixGt(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func PrefixLte(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func PrefixGte(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func PrefixIsNull(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func PrefixIsNotNull(s1 sql.Statistic, val interface{}) sql.Statistic { - return nil + return s1 } func McvIndexGt(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } func McvIndexLt(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } func McvIndexGte(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } func McvIndexLte(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } func McvIndexIsNull(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } func McvIndexIsNotNull(s sql.Statistic, i int, val interface{}) sql.Statistic { - return nil + return s } diff --git a/sql/tables.go b/sql/tables.go index 7948260cd0..1e31352a0b 100644 --- a/sql/tables.go +++ b/sql/tables.go @@ -107,6 +107,8 @@ type IndexAddressable interface { IndexedAccess(lookup IndexLookup) IndexedTable // GetIndexes returns an array of this table's Indexes GetIndexes(ctx *Context) ([]Index, error) + // PreciseMatch returns whether an indexed access can substitute for filters + PreciseMatch() bool } // IndexAddressableTable is a table that can be accessed through an index From 3d38753891c2f65a7dd89afb3dd9c47f4e8d95d8 Mon Sep 17 00:00:00 2001 From: Max Hoffman Date: Mon, 6 Nov 2023 08:03:38 -0800 Subject: [PATCH 04/11] Fix interface --- enginetest/query_engine.go | 1 - 1 file changed, 1 deletion(-) diff --git a/enginetest/query_engine.go b/enginetest/query_engine.go index b906bd024e..510846fbff 100755 --- a/enginetest/query_engine.go +++ b/enginetest/query_engine.go @@ -25,7 +25,6 @@ import ( type QueryEngine interface { PrepareQuery(*sql.Context, string) (sql.Node, error) - //BindQuery(*sql.Context, string) (sql.Node, error) AnalyzeQuery(*sql.Context, string) (sql.Node, error) Query(ctx *sql.Context, query string) (sql.Schema, sql.RowIter, error) // TODO: get rid of this, should not be exposed to engine tests From 6ea71790a5a13f05b40e80816bd773cf53b20c3a Mon Sep 17 00:00:00 2001 From: max-hoffman Date: Mon, 6 Nov 2023 16:05:06 +0000 Subject: [PATCH 05/11] [ga-format-pr] Run ./format_repo.sh to fix formatting --- enginetest/enginetests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index 0450d8d9bb..be538dc7df 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -3637,7 +3637,7 @@ func TestForeignKeys(t *testing.T, harness Harness) { TestScript(t, harness, script) } } - + func TestFulltextIndexes(t *testing.T, harness Harness) { harness.Setup(setup.MydbData) for _, script := range queries.FulltextTests { From 99ca3db84320d135ef7a938c07d62b50b59af8cb Mon Sep 17 00:00:00 2001 From: Maximilian Hoffman Date: Tue, 7 Nov 2023 09:47:26 -0800 Subject: [PATCH 06/11] ReferenceChecker interface (#2132) --- sql/plan/foreign_key_editor.go | 23 +++++++++++++++-------- sql/tables.go | 8 ++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/sql/plan/foreign_key_editor.go b/sql/plan/foreign_key_editor.go index 0b2518411b..9dc45f27e0 100644 --- a/sql/plan/foreign_key_editor.go +++ b/sql/plan/foreign_key_editor.go @@ -121,7 +121,7 @@ func (fkEditor *ForeignKeyEditor) OnUpdateRestrict(ctx *sql.Context, refActionDa return nil } - rowIter, err := refActionData.RowMapper.GetIter(ctx, old) + rowIter, err := refActionData.RowMapper.GetIter(ctx, old, false) if err != nil { return err } @@ -144,7 +144,7 @@ func (fkEditor *ForeignKeyEditor) OnUpdateCascade(ctx *sql.Context, refActionDat return nil } - rowIter, err := refActionData.RowMapper.GetIter(ctx, old) + rowIter, err := refActionData.RowMapper.GetIter(ctx, old, false) if err != nil { return err } @@ -182,7 +182,7 @@ func (fkEditor *ForeignKeyEditor) OnUpdateSetNull(ctx *sql.Context, refActionDat return nil } - rowIter, err := refActionData.RowMapper.GetIter(ctx, old) + rowIter, err := refActionData.RowMapper.GetIter(ctx, old, false) if err != nil { return err } @@ -243,7 +243,7 @@ func (fkEditor *ForeignKeyEditor) Delete(ctx *sql.Context, row sql.Row, depth in // OnDeleteRestrict handles the ON DELETE RESTRICT referential action. func (fkEditor *ForeignKeyEditor) OnDeleteRestrict(ctx *sql.Context, refActionData ForeignKeyRefActionData, row sql.Row) error { - rowIter, err := refActionData.RowMapper.GetIter(ctx, row) + rowIter, err := refActionData.RowMapper.GetIter(ctx, row, false) if err != nil { return err } @@ -260,7 +260,7 @@ func (fkEditor *ForeignKeyEditor) OnDeleteRestrict(ctx *sql.Context, refActionDa // OnDeleteCascade handles the ON DELETE CASCADE referential action. func (fkEditor *ForeignKeyEditor) OnDeleteCascade(ctx *sql.Context, refActionData ForeignKeyRefActionData, row sql.Row, depth int) error { - rowIter, err := refActionData.RowMapper.GetIter(ctx, row) + rowIter, err := refActionData.RowMapper.GetIter(ctx, row, false) if err != nil { return err } @@ -289,7 +289,7 @@ func (fkEditor *ForeignKeyEditor) OnDeleteCascade(ctx *sql.Context, refActionDat // OnDeleteSetNull handles the ON DELETE SET NULL referential action. func (fkEditor *ForeignKeyEditor) OnDeleteSetNull(ctx *sql.Context, refActionData ForeignKeyRefActionData, row sql.Row, depth int) error { - rowIter, err := refActionData.RowMapper.GetIter(ctx, row) + rowIter, err := refActionData.RowMapper.GetIter(ctx, row, false) if err != nil { return err } @@ -377,7 +377,7 @@ func (reference *ForeignKeyReferenceHandler) CheckReference(ctx *sql.Context, ro } } - rowIter, err := reference.RowMapper.GetIter(ctx, row) + rowIter, err := reference.RowMapper.GetIter(ctx, row, true) if err != nil { return err } @@ -458,7 +458,7 @@ func (mapper *ForeignKeyRowMapper) IsInitialized() bool { } // GetIter returns a row iterator for all rows that match the given source row. -func (mapper *ForeignKeyRowMapper) GetIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { +func (mapper *ForeignKeyRowMapper) GetIter(ctx *sql.Context, row sql.Row, refCheck bool) (sql.RowIter, error) { rang := make(sql.Range, len(mapper.IndexPositions)+len(mapper.AppendTypes)) for rangPosition, rowPos := range mapper.IndexPositions { rowVal := row[rowPos] @@ -480,6 +480,13 @@ func (mapper *ForeignKeyRowMapper) GetIter(ctx *sql.Context, row sql.Row) (sql.R editorData := mapper.Updater.IndexedAccess(lookup) + if rc, ok := editorData.(sql.ReferenceChecker); refCheck && ok { + err := rc.SetReferenceCheck() + if err != nil { + return nil, err + } + } + partIter, err := editorData.LookupPartitions(ctx, lookup) if err != nil { return nil, err diff --git a/sql/tables.go b/sql/tables.go index 7948260cd0..8e5d2b74de 100644 --- a/sql/tables.go +++ b/sql/tables.go @@ -179,6 +179,14 @@ type ForeignKeyEditor interface { IndexAddressable } +// ReferenceChecker is usually an IndexAddressableTable that does key +// lookups for existence checks. Indicating that the engine is performing +// a reference check lets the integrator avoid expensive deserialization +// steps. +type ReferenceChecker interface { + SetReferenceCheck() error +} + // CheckTable is a table that declares check constraints. type CheckTable interface { Table From cf4306a55804548c1ba8e00a3a560f7d24e07a14 Mon Sep 17 00:00:00 2001 From: Maximilian Hoffman Date: Tue, 7 Nov 2023 09:52:44 -0800 Subject: [PATCH 07/11] Add query plans for index/join sysbench queries (#2133) --- enginetest/plangen/cmd/plangen/main.go | 4 + enginetest/plangen/testdata/spec.yaml | 4 +- enginetest/queries/queries.go | 22 ++++ enginetest/queries/query_plans.go | 22 ---- enginetest/queries/sysbench_plans.go | 106 ++++++++++++++++++++ enginetest/scriptgen/cmd/scriptgen/main.go | 2 + enginetest/scriptgen/setup/helper.go | 1 + enginetest/scriptgen/setup/main.go | 2 - enginetest/scriptgen/setup/scripts/sysbench | 49 +++++++++ enginetest/scriptgen/setup/setup_data.sg.go | 7 ++ 10 files changed, 194 insertions(+), 25 deletions(-) create mode 100644 enginetest/queries/sysbench_plans.go create mode 100644 enginetest/scriptgen/setup/scripts/sysbench diff --git a/enginetest/plangen/cmd/plangen/main.go b/enginetest/plangen/cmd/plangen/main.go index 585ec09501..95308a6baf 100644 --- a/enginetest/plangen/cmd/plangen/main.go +++ b/enginetest/plangen/cmd/plangen/main.go @@ -216,6 +216,8 @@ func specSetup(name string) [][]setup.SetupScript { return setup.TpccPlanSetup case "GeneratedColumnPlanTests": return setup.GeneratedColumnSetup + case "SysbenchPlanTests": + return setup.SysbenchSetup default: exit(fmt.Errorf("setup not found for plan suite: %s", name)) return nil @@ -240,6 +242,8 @@ func specQueries(name string) []queries.QueryPlanTest { return queries.IntegrationPlanTests case "GeneratedColumnPlanTests": return queries.GeneratedColumnPlanTests + case "SysbenchPlanTests": + return queries.SysbenchPlanTests default: exit(fmt.Errorf("queries not found for plan suite: %s", name)) return nil diff --git a/enginetest/plangen/testdata/spec.yaml b/enginetest/plangen/testdata/spec.yaml index e5c5253c9b..98c5d88660 100644 --- a/enginetest/plangen/testdata/spec.yaml +++ b/enginetest/plangen/testdata/spec.yaml @@ -14,4 +14,6 @@ plans: - name: ImdbPlanTests path: enginetest/queries/imdb_plans.go - name: GeneratedColumnPlanTests - path: enginetest/queries/generated_column_plans.go \ No newline at end of file + path: enginetest/queries/generated_column_plans.go + - name: SysbenchPlanTests + path: enginetest/queries/sysbench_plans.go \ No newline at end of file diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index 9cff15c5b8..9b7b27a0c1 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -38,6 +38,28 @@ type QueryTest struct { SkipPrepared bool } +type QueryPlanTest struct { + Query string + ExpectedPlan string + Skip bool +} + +// QueryPlanTODOs are queries where the query planner produces a correct (results) but suboptimal plan. +var QueryPlanTODOs = []QueryPlanTest{ + { + // TODO: this should use an index. Extra join condition should get moved out of the join clause into a filter + Query: `SELECT pk,i,f FROM one_pk RIGHT JOIN niltable ON pk=i and pk > 0 ORDER BY 2,3`, + ExpectedPlan: "Sort(niltable.i ASC, niltable.f ASC)\n" + + " └─ Project(one_pk.pk, niltable.i, niltable.f)\n" + + " └─ RightJoin((one_pk.pk = niltable.i) AND (one_pk.pk > 0))\n" + + " ├─ Projected table access on [pk]\n" + + " │ └─ Table(one_pk)\n" + + " └─ Projected table access on [i f]\n" + + " └─ Table(niltable)\n" + + "", + }, +} + var SpatialQueryTests = []QueryTest{ { Query: `SHOW CREATE TABLE point_table`, diff --git a/enginetest/queries/query_plans.go b/enginetest/queries/query_plans.go index 5f77de7b95..90de76f965 100644 --- a/enginetest/queries/query_plans.go +++ b/enginetest/queries/query_plans.go @@ -16,12 +16,6 @@ package queries -type QueryPlanTest struct { - Query string - ExpectedPlan string - Skip bool -} - var PlanTests = []QueryPlanTest{ { Query: `select * from xy join uv on (x = u and u > 0) where u < 2`, @@ -10635,19 +10629,3 @@ order by i;`, "", }, } - -// QueryPlanTODOs are queries where the query planner produces a correct (results) but suboptimal plan. -var QueryPlanTODOs = []QueryPlanTest{ - { - // TODO: this should use an index. Extra join condition should get moved out of the join clause into a filter - Query: `SELECT pk,i,f FROM one_pk RIGHT JOIN niltable ON pk=i and pk > 0 ORDER BY 2,3`, - ExpectedPlan: "Sort(niltable.i ASC, niltable.f ASC)\n" + - " └─ Project(one_pk.pk, niltable.i, niltable.f)\n" + - " └─ RightJoin((one_pk.pk = niltable.i) AND (one_pk.pk > 0))\n" + - " ├─ Projected table access on [pk]\n" + - " │ └─ Table(one_pk)\n" + - " └─ Projected table access on [i f]\n" + - " └─ Table(niltable)\n" + - "", - }, -} diff --git a/enginetest/queries/sysbench_plans.go b/enginetest/queries/sysbench_plans.go new file mode 100644 index 0000000000..e139d09752 --- /dev/null +++ b/enginetest/queries/sysbench_plans.go @@ -0,0 +1,106 @@ +// Code generated by plangen. + +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package queries + +var SysbenchPlanTests = []QueryPlanTest{ + { + Query: `select a.id, a.small_int_col from sbtest1 a, sbtest1 b where a.id = b.id limit 500`, + ExpectedPlan: "Limit(500)\n" + + " └─ Project\n" + + " ├─ columns: [a.id:1!null, a.small_int_col:2!null]\n" + + " └─ MergeJoin\n" + + " ├─ cmp: Eq\n" + + " │ ├─ b.id:0!null\n" + + " │ └─ a.id:1!null\n" + + " ├─ TableAlias(b)\n" + + " │ └─ IndexedTableAccess(sbtest1)\n" + + " │ ├─ index: [sbtest1.id]\n" + + " │ ├─ static: [{[NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: sbtest1\n" + + " │ └─ columns: [id]\n" + + " └─ TableAlias(a)\n" + + " └─ IndexedTableAccess(sbtest1)\n" + + " ├─ index: [sbtest1.id]\n" + + " ├─ static: [{[NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: sbtest1\n" + + " └─ columns: [id small_int_col]\n" + + "", + }, + { + Query: `select a.id, a.small_int_col, b.id, b.int_col from sbtest1 a, sbtest2 b where a.id = b.int_col limit 500`, + ExpectedPlan: "Limit(500)\n" + + " └─ Project\n" + + " ├─ columns: [a.id:2!null, a.small_int_col:3!null, b.id:0!null, b.int_col:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ TableAlias(b)\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: sbtest2\n" + + " │ └─ columns: [id int_col]\n" + + " └─ TableAlias(a)\n" + + " └─ IndexedTableAccess(sbtest1)\n" + + " ├─ index: [sbtest1.id]\n" + + " ├─ keys: [b.int_col]\n" + + " └─ Table\n" + + " ├─ name: sbtest1\n" + + " └─ columns: [id small_int_col]\n" + + "", + }, + { + Query: `SELECT year_col, count(year_col), max(big_int_col), avg(small_int_col) FROM sbtest1 WHERE big_int_col > 0 GROUP BY set_col ORDER BY year_col`, + ExpectedPlan: "Project\n" + + " ├─ columns: [sbtest1.year_col:3!null, count(sbtest1.year_col):1!null as count(year_col), max(sbtest1.big_int_col):2!null as max(big_int_col), avg(sbtest1.small_int_col):0 as avg(small_int_col)]\n" + + " └─ Sort(sbtest1.year_col:3!null ASC nullsFirst)\n" + + " └─ GroupBy\n" + + " ├─ select: AVG(sbtest1.small_int_col:0!null), COUNT(sbtest1.year_col:3!null), MAX(sbtest1.big_int_col:1!null), sbtest1.year_col:3!null\n" + + " ├─ group: sbtest1.set_col:2!null\n" + + " └─ IndexedTableAccess(sbtest1)\n" + + " ├─ index: [sbtest1.big_int_col]\n" + + " ├─ static: [{(0, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: sbtest1\n" + + " └─ columns: [small_int_col big_int_col set_col year_col]\n" + + "", + }, + { + Query: `SELECT count(id) FROM sbtest1 WHERE big_int_col > 0`, + ExpectedPlan: "Project\n" + + " ├─ columns: [count(sbtest1.id):0!null as count(id)]\n" + + " └─ GroupBy\n" + + " ├─ select: COUNT(sbtest1.id:0!null)\n" + + " ├─ group: \n" + + " └─ IndexedTableAccess(sbtest1)\n" + + " ├─ index: [sbtest1.big_int_col]\n" + + " ├─ static: [{(0, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: sbtest1\n" + + " └─ columns: [id big_int_col]\n" + + "", + }, + { + Query: `SELECT * FROM sbtest1 WHERE big_int_col > 0`, + ExpectedPlan: "IndexedTableAccess(sbtest1)\n" + + " ├─ index: [sbtest1.big_int_col]\n" + + " ├─ static: [{(0, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: sbtest1\n" + + " └─ columns: [id tiny_int_col unsigned_tiny_int_col small_int_col unsigned_small_int_col medium_int_col unsigned_medium_int_col int_col unsigned_int_col big_int_col unsigned_big_int_col decimal_col float_col double_col bit_col char_col var_char_col enum_col set_col date_col time_col datetime_col timestamp_col year_col]\n" + + "", + }, +} diff --git a/enginetest/scriptgen/cmd/scriptgen/main.go b/enginetest/scriptgen/cmd/scriptgen/main.go index 965652d461..6c8944691c 100644 --- a/enginetest/scriptgen/cmd/scriptgen/main.go +++ b/enginetest/scriptgen/cmd/scriptgen/main.go @@ -30,6 +30,8 @@ import ( "github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup" ) +//go:generate go run ./main.go -out ../../setup/setup_data.sg.go -pkg setup setup ../../setup/scripts + var ( errInvalidArgCount = errors.New("invalid number of arguments") errUnrecognizedCommand = errors.New("unrecognized command") diff --git a/enginetest/scriptgen/setup/helper.go b/enginetest/scriptgen/setup/helper.go index d9296ea7f5..3253ffc06b 100644 --- a/enginetest/scriptgen/setup/helper.go +++ b/enginetest/scriptgen/setup/helper.go @@ -25,6 +25,7 @@ var ( GraphSetup = [][]SetupScript{MydbData, Graph_tablesData} ReservedSetup = [][]SetupScript{MydbData, Reserved_keywordsData} GeneratedColumnSetup = [][]SetupScript{MydbData, Generated_column_tablesData} + SysbenchSetup = [][]SetupScript{MydbData, SysbenchData} Mytable = [][]SetupScript{MydbData, MytableData} ChecksSetup = [][]SetupScript{MydbData, Check_constraintData} NullsSetup = [][]SetupScript{MydbData, Null_rangesData} diff --git a/enginetest/scriptgen/setup/main.go b/enginetest/scriptgen/setup/main.go index 518932dced..8416412503 100644 --- a/enginetest/scriptgen/setup/main.go +++ b/enginetest/scriptgen/setup/main.go @@ -25,8 +25,6 @@ import ( ast "github.com/dolthub/vitess/go/vt/sqlparser" ) -//go:generate go run ../cmd/scriptgen/main.go -out setup_data.sg.go -pkg setup setup scripts - type setupSource interface { Next() (bool, error) Close() error diff --git a/enginetest/scriptgen/setup/scripts/sysbench b/enginetest/scriptgen/setup/scripts/sysbench new file mode 100644 index 0000000000..11312eed9b --- /dev/null +++ b/enginetest/scriptgen/setup/scripts/sysbench @@ -0,0 +1,49 @@ +exec + CREATE TABLE `sbtest1` ( + `id` int NOT NULL, + `tiny_int_col` tinyint NOT NULL, + `unsigned_tiny_int_col` tinyint unsigned NOT NULL, + `small_int_col` smallint NOT NULL, + `unsigned_small_int_col` smallint unsigned NOT NULL, + `medium_int_col` mediumint NOT NULL, + `unsigned_medium_int_col` mediumint unsigned NOT NULL, + `int_col` int NOT NULL, + `unsigned_int_col` int unsigned NOT NULL, + `big_int_col` bigint NOT NULL, + `unsigned_big_int_col` bigint unsigned NOT NULL, + `decimal_col` decimal(10,0) NOT NULL, + `float_col` float NOT NULL, + `double_col` double NOT NULL, + `bit_col` bit(1) NOT NULL, + `char_col` char(1) NOT NULL, + `var_char_col` varchar(64) NOT NULL, + `enum_col` enum('val0','val1','val2') NOT NULL, + `set_col` set('val0','val1','val2') NOT NULL, + `date_col` date NOT NULL, + `time_col` time(6) NOT NULL, + `datetime_col` datetime NOT NULL, + `timestamp_col` timestamp NOT NULL, + `year_col` year NOT NULL, + PRIMARY KEY (`id`), + KEY `big_int_col` (`big_int_col`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin +--- + +exec +CREATE TABLE `sbtest2` ( + `id` int NOT NULL, + `int_col` int NOT NULL, + `unsigned_int_col` int unsigned NOT NULL, + `char_col` char(1) NOT NULL, + `var_char_col` varchar(64) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin +---- + +exec +analyze table sbtest1 update histogram on id using data '{\"row_count\": 10000}'; +---- + +exec +analyze table sbtest2 update histogram on id using data '{\"row_count\": 10000}'; +---- \ No newline at end of file diff --git a/enginetest/scriptgen/setup/setup_data.sg.go b/enginetest/scriptgen/setup/setup_data.sg.go index 75eaedd71d..e5706ab25c 100755 --- a/enginetest/scriptgen/setup/setup_data.sg.go +++ b/enginetest/scriptgen/setup/setup_data.sg.go @@ -3064,6 +3064,13 @@ var StringandtableData = []SetupScript{{ (6, null, '2');`, }} +var SysbenchData = []SetupScript{{ + "CREATE TABLE `sbtest1` ( `id` int NOT NULL, `tiny_int_col` tinyint NOT NULL, `unsigned_tiny_int_col` tinyint unsigned NOT NULL, `small_int_col` smallint NOT NULL, `unsigned_small_int_col` smallint unsigned NOT NULL, `medium_int_col` mediumint NOT NULL, `unsigned_medium_int_col` mediumint unsigned NOT NULL, `int_col` int NOT NULL, `unsigned_int_col` int unsigned NOT NULL, `big_int_col` bigint NOT NULL, `unsigned_big_int_col` bigint unsigned NOT NULL, `decimal_col` decimal(10,0) NOT NULL, `float_col` float NOT NULL, `double_col` double NOT NULL, `bit_col` bit(1) NOT NULL, `char_col` char(1) NOT NULL, `var_char_col` varchar(64) NOT NULL, `enum_col` enum('val0','val1','val2') NOT NULL, `set_col` set('val0','val1','val2') NOT NULL, `date_col` date NOT NULL, `time_col` time(6) NOT NULL, `datetime_col` datetime NOT NULL, `timestamp_col` timestamp NOT NULL, `year_col` year NOT NULL, PRIMARY KEY (`id`), KEY `big_int_col` (`big_int_col`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin ---", + "CREATE TABLE `sbtest2` ( `id` int NOT NULL, `int_col` int NOT NULL, `unsigned_int_col` int unsigned NOT NULL, `char_col` char(1) NOT NULL, `var_char_col` varchar(64) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin", + `analyze table sbtest1 update histogram on id using data '{\"row_count\": 10000}';`, + `analyze table sbtest2 update histogram on id using data '{\"row_count\": 10000}';`, +}} + var TabletestData = []SetupScript{{ `create table tabletest ( i int primary key, From 36cd28d68616a0d0b87d3968375d20315b7d4d8a Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Tue, 7 Nov 2023 09:53:36 -0800 Subject: [PATCH 08/11] [ga-bump-dep] Bump dependency in GMS by JCOR11599 (#2129) Co-authored-by: JCOR11599 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 761ec8d449..334690b764 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20231024170615-f475795064f6 + github.com/dolthub/vitess v0.0.0-20231106195946-51b76945ad0c github.com/go-kit/kit v0.10.0 github.com/go-sql-driver/mysql v1.7.1 github.com/gocraft/dbr/v2 v2.7.2 diff --git a/go.sum b/go.sum index 0572ccdd46..6ab0916c79 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,8 @@ github.com/dolthub/vitess v0.0.0-20231020183313-ef26be7c2600 h1:y28nGSuLzR48fSNS github.com/dolthub/vitess v0.0.0-20231020183313-ef26be7c2600/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= github.com/dolthub/vitess v0.0.0-20231024170615-f475795064f6 h1:2fGQYxszmACz2xtuyRVblnwvusIefQK9AloUKGIdcCI= github.com/dolthub/vitess v0.0.0-20231024170615-f475795064f6/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= +github.com/dolthub/vitess v0.0.0-20231106195946-51b76945ad0c h1:dZ95h8OHK/L4nLUU9Je7qKrUQ4Uyj2pfR7IK6qJphWU= +github.com/dolthub/vitess v0.0.0-20231106195946-51b76945ad0c/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From 1513b8c429d29234ed120d75a122340ca076d72f Mon Sep 17 00:00:00 2001 From: Maximilian Hoffman Date: Tue, 7 Nov 2023 10:09:42 -0800 Subject: [PATCH 09/11] More TPC-C tests, fix the slow HASH_JOIN (#2130) * Add more TPCC plans, fix the slow one * fixup plans * fix build * tweak sysbench plan * update plans --- enginetest/join_planning_tests.go | 9 +- enginetest/queries/integration_plans.go | 26 +- enginetest/queries/query_plans.go | 584 +++++++++++------------- enginetest/queries/tpcc_plans.go | 423 +++++++++++++++++ enginetest/queries/tpch_plans.go | 548 +++++++++++----------- sql/memo/coster.go | 2 +- 6 files changed, 962 insertions(+), 630 deletions(-) diff --git a/enginetest/join_planning_tests.go b/enginetest/join_planning_tests.go index c30210d29a..27c27ec702 100644 --- a/enginetest/join_planning_tests.go +++ b/enginetest/join_planning_tests.go @@ -445,12 +445,7 @@ order by 1;`, }, { q: "select * from xy where x in (select u from uv join ab on u = a and a = 2) order by 1;", - types: []plan.JoinType{plan.JoinTypeHash, plan.JoinTypeMerge}, - exp: []sql.Row{{2, 1}}, - }, - { - q: "select * from xy where x = (select u from uv join ab on u = a and a = 2) order by 1;", - types: []plan.JoinType{plan.JoinTypeLookup, plan.JoinTypeMerge}, + types: []plan.JoinType{plan.JoinTypeHash, plan.JoinTypeLookup}, exp: []sql.Row{{2, 1}}, }, { @@ -759,7 +754,7 @@ where u in (select * from rec);`, tests: []JoinPlanTest{ { q: "select * from xy where x in (select u from uv join ab on u = a and a = 2) order by 1;", - types: []plan.JoinType{plan.JoinTypeHash, plan.JoinTypeMerge}, + types: []plan.JoinType{plan.JoinTypeHash, plan.JoinTypeLookup}, exp: []sql.Row{{2, 1}}, }, { diff --git a/enginetest/queries/integration_plans.go b/enginetest/queries/integration_plans.go index 9baa4973a2..efcc27d064 100644 --- a/enginetest/queries/integration_plans.go +++ b/enginetest/queries/integration_plans.go @@ -8834,7 +8834,7 @@ INNER JOIN E2I7U nd INNER JOIN XOAOP pa ON QNRBH.CH3FR = pa.id`, ExpectedPlan: "Project\n" + - " ├─ columns: [pa.DZLIM:3!null as ECUWU, nd.TW55N:5!null]\n" + + " ├─ columns: [pa.DZLIM:5!null as ECUWU, nd.TW55N:3!null]\n" + " └─ LookupJoin\n" + " ├─ LookupJoin\n" + " │ ├─ TableAlias(qnrbh)\n" + @@ -8842,20 +8842,20 @@ INNER JOIN XOAOP pa " │ │ └─ Table\n" + " │ │ ├─ name: JJGQT\n" + " │ │ └─ columns: [ch3fr luevy]\n" + - " │ └─ TableAlias(pa)\n" + - " │ └─ IndexedTableAccess(XOAOP)\n" + - " │ ├─ index: [XOAOP.id]\n" + - " │ ├─ keys: [qnrbh.CH3FR]\n" + + " │ └─ TableAlias(nd)\n" + + " │ └─ IndexedTableAccess(E2I7U)\n" + + " │ ├─ index: [E2I7U.id]\n" + + " │ ├─ keys: [qnrbh.LUEVY]\n" + " │ └─ Table\n" + - " │ ├─ name: XOAOP\n" + - " │ └─ columns: [id dzlim]\n" + - " └─ TableAlias(nd)\n" + - " └─ IndexedTableAccess(E2I7U)\n" + - " ├─ index: [E2I7U.id]\n" + - " ├─ keys: [qnrbh.LUEVY]\n" + + " │ ├─ name: E2I7U\n" + + " │ └─ columns: [id tw55n]\n" + + " └─ TableAlias(pa)\n" + + " └─ IndexedTableAccess(XOAOP)\n" + + " ├─ index: [XOAOP.id]\n" + + " ├─ keys: [qnrbh.CH3FR]\n" + " └─ Table\n" + - " ├─ name: E2I7U\n" + - " └─ columns: [id tw55n]\n" + + " ├─ name: XOAOP\n" + + " └─ columns: [id dzlim]\n" + "", }, { diff --git a/enginetest/queries/query_plans.go b/enginetest/queries/query_plans.go index 90de76f965..c246e0412a 100644 --- a/enginetest/queries/query_plans.go +++ b/enginetest/queries/query_plans.go @@ -336,29 +336,27 @@ WHERE " └─ GroupBy\n" + " ├─ select: COUNTDISTINCT([stock1.s_i_id])\n" + " ├─ group: \n" + - " └─ HashJoin\n" + - " ├─ Eq\n" + - " │ ├─ stock1.s_i_id:4!null\n" + - " │ └─ order_line1.ol_i_id:3\n" + + " └─ LookupJoin\n" + " ├─ IndexedTableAccess(order_line1)\n" + " │ ├─ index: [order_line1.ol_w_id,order_line1.ol_d_id,order_line1.ol_o_id,order_line1.ol_number]\n" + " │ ├─ static: [{[5, 5], [2, 2], [2981, 3001), [NULL, ∞)}]\n" + " │ └─ Table\n" + " │ ├─ name: order_line1\n" + " │ └─ columns: [ol_o_id ol_d_id ol_w_id ol_i_id]\n" + - " └─ HashLookup\n" + - " ├─ left-key: TUPLE(order_line1.ol_i_id:3)\n" + - " ├─ right-key: TUPLE(stock1.s_i_id:0!null)\n" + - " └─ Filter\n" + - " ├─ LessThan\n" + - " │ ├─ stock1.s_quantity:2\n" + - " │ └─ 15 (tinyint)\n" + - " └─ IndexedTableAccess(stock1)\n" + - " ├─ index: [stock1.s_w_id,stock1.s_i_id]\n" + - " ├─ static: [{[5, 5], [NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: stock1\n" + - " └─ columns: [s_i_id s_w_id s_quantity]\n" + + " └─ Filter\n" + + " ├─ AND\n" + + " │ ├─ Eq\n" + + " │ │ ├─ stock1.s_w_id:1!null\n" + + " │ │ └─ 5 (tinyint)\n" + + " │ └─ LessThan\n" + + " │ ├─ stock1.s_quantity:2\n" + + " │ └─ 15 (tinyint)\n" + + " └─ IndexedTableAccess(stock1)\n" + + " ├─ index: [stock1.s_w_id,stock1.s_i_id]\n" + + " ├─ keys: [5 order_line1.ol_i_id]\n" + + " └─ Table\n" + + " ├─ name: stock1\n" + + " └─ columns: [s_i_id s_w_id s_quantity]\n" + "", }, { @@ -1698,36 +1696,28 @@ Select * from ( { Query: `select * from mytable t1 natural join mytable t2 join othertable t3 on t2.i = t3.i2;`, ExpectedPlan: "Project\n" + - " ├─ columns: [t1.i:2!null, t1.s:3!null, t3.s2:0!null, t3.i2:1!null]\n" + + " ├─ columns: [t1.i:2!null, t1.s:3!null, t3.s2:4!null, t3.i2:5!null]\n" + " └─ LookupJoin\n" + - " ├─ Eq\n" + - " │ ├─ t2.i:4!null\n" + - " │ └─ t3.i2:1!null\n" + - " ├─ MergeJoin\n" + - " │ ├─ cmp: Eq\n" + - " │ │ ├─ t3.i2:1!null\n" + - " │ │ └─ t1.i:2!null\n" + - " │ ├─ TableAlias(t3)\n" + - " │ │ └─ IndexedTableAccess(othertable)\n" + - " │ │ ├─ index: [othertable.i2]\n" + - " │ │ ├─ static: [{[NULL, ∞)}]\n" + + " ├─ LookupJoin\n" + + " │ ├─ TableAlias(t2)\n" + + " │ │ └─ ProcessTable\n" + " │ │ └─ Table\n" + - " │ │ ├─ name: othertable\n" + - " │ │ └─ columns: [s2 i2]\n" + + " │ │ ├─ name: mytable\n" + + " │ │ └─ columns: [i s]\n" + " │ └─ TableAlias(t1)\n" + " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + + " │ ├─ index: [mytable.s,mytable.i]\n" + + " │ ├─ keys: [t2.s t2.i]\n" + " │ └─ Table\n" + " │ ├─ name: mytable\n" + " │ └─ columns: [i s]\n" + - " └─ TableAlias(t2)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.s,mytable.i]\n" + - " ├─ keys: [t1.s t1.i]\n" + + " └─ TableAlias(t3)\n" + + " └─ IndexedTableAccess(othertable)\n" + + " ├─ index: [othertable.i2]\n" + + " ├─ keys: [t2.i]\n" + " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ name: othertable\n" + + " └─ columns: [s2 i2]\n" + "", }, { @@ -2740,27 +2730,20 @@ inner join pq on true " ├─ columns: [row_number() over ( order by mytable.i desc):0!null, mytable.i:1!null, mytable.i:1!null as i2]\n" + " └─ Window\n" + " ├─ row_number() over ( order by mytable.i DESC)\n" + - " ├─ mytable.i:1!null\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ othertable.i2:0!null\n" + - " │ └─ mytable.i:1!null\n" + - " ├─ IndexedTableAccess(othertable)\n" + - " │ ├─ index: [othertable.i2]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + + " ├─ mytable.i:0!null\n" + + " └─ LookupJoin\n" + + " ├─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[2, 2]}]\n" + " │ └─ Table\n" + - " │ ├─ name: othertable\n" + - " │ └─ columns: [i2]\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ mytable.i:0!null\n" + - " │ └─ 2 (tinyint)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[2, 2]}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i]\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i]\n" + + " └─ IndexedTableAccess(othertable)\n" + + " ├─ index: [othertable.i2]\n" + + " ├─ keys: [mytable.i]\n" + + " └─ Table\n" + + " ├─ name: othertable\n" + + " └─ columns: [i2]\n" + "", }, { @@ -3227,10 +3210,7 @@ inner join pq on true " ├─ cacheable: true\n" + " └─ Project\n" + " ├─ columns: [mytable.i:2!null, othertable.i2:1!null, othertable.s2:0!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ othertable.i2:1!null\n" + - " │ └─ mytable.i:2!null\n" + + " └─ LookupJoin\n" + " ├─ Filter\n" + " │ ├─ NOT\n" + " │ │ └─ Eq\n" + @@ -3238,15 +3218,12 @@ inner join pq on true " │ │ │ ├─ type: signed\n" + " │ │ │ └─ othertable.s2:0!null\n" + " │ │ └─ 0 (tinyint)\n" + - " │ └─ IndexedTableAccess(othertable)\n" + - " │ ├─ index: [othertable.i2]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: othertable\n" + - " │ └─ columns: [s2 i2]\n" + + " │ └─ Table\n" + + " │ ├─ name: othertable\n" + + " │ └─ columns: [s2 i2]\n" + " └─ IndexedTableAccess(mytable)\n" + " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + + " ├─ keys: [othertable.i2]\n" + " └─ Table\n" + " ├─ name: mytable\n" + " └─ columns: [i]\n" + @@ -3788,28 +3765,25 @@ inner join pq on true { Query: `SELECT a.* FROM mytable a inner join mytable b on (a.i = b.s) WHERE a.s is not null`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.s:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.s,mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [s]\n" + - " └─ Filter\n" + - " ├─ NOT\n" + - " │ └─ a.s:1!null IS NULL\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ NOT\n" + + " │ │ └─ a.s:1!null IS NULL\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.s]\n" + + " │ ├─ static: [{(NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.s]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [s]\n" + "", }, { @@ -3842,58 +3816,52 @@ inner join pq on true { Query: `SELECT a.* FROM mytable a inner join mytable b on (a.i = b.s) WHERE a.s not in ('1', '2', '3', '4')`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.s:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.s,mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [s]\n" + - " └─ Filter\n" + - " ├─ NOT\n" + - " │ └─ HashIn\n" + - " │ ├─ a.s:1!null\n" + - " │ └─ TUPLE(1 (longtext), 2 (longtext), 3 (longtext), 4 (longtext))\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ NOT\n" + + " │ │ └─ HashIn\n" + + " │ │ ├─ a.s:1!null\n" + + " │ │ └─ TUPLE(1 (longtext), 2 (longtext), 3 (longtext), 4 (longtext))\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.s]\n" + + " │ ├─ static: [{(1, 2)}, {(2, 3)}, {(3, 4)}, {(4, ∞)}, {(NULL, 1)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.s]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [s]\n" + "", }, { Query: `SELECT a.* FROM mytable a inner join mytable b on (a.i = b.s) WHERE a.i in (1, 2, 3, 4)`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.s:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.s,mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [s]\n" + - " └─ Filter\n" + - " ├─ HashIn\n" + - " │ ├─ a.i:0!null\n" + - " │ └─ TUPLE(1 (tinyint), 2 (tinyint), 3 (tinyint), 4 (tinyint))\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ HashIn\n" + + " │ │ ├─ a.i:0!null\n" + + " │ │ └─ TUPLE(1 (tinyint), 2 (tinyint), 3 (tinyint), 4 (tinyint))\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[1, 1]}, {[2, 2]}, {[3, 3]}, {[4, 4]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.s]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [s]\n" + "", }, { @@ -4303,52 +4271,55 @@ inner join pq on true { Query: `SELECT a.* FROM mytable a, mytable b, mytable c, mytable d where a.i = b.i AND b.i = c.i AND c.i = d.i AND c.i = 2`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " ├─ columns: [a.i:1!null, a.s:2!null]\n" + " └─ LookupJoin\n" + " ├─ AND\n" + " │ ├─ Eq\n" + - " │ │ ├─ b.i:4!null\n" + - " │ │ └─ c.i:2!null\n" + + " │ │ ├─ c.i:4!null\n" + + " │ │ └─ d.i:3!null\n" + " │ └─ Eq\n" + - " │ ├─ b.i:4!null\n" + - " │ └─ d.i:3!null\n" + + " │ ├─ a.i:1!null\n" + + " │ └─ c.i:4!null\n" + " ├─ LookupJoin\n" + + " │ ├─ Eq\n" + + " │ │ ├─ b.i:0!null\n" + + " │ │ └─ d.i:3!null\n" + " │ ├─ MergeJoin\n" + " │ │ ├─ cmp: Eq\n" + - " │ │ │ ├─ a.i:0!null\n" + - " │ │ │ └─ c.i:2!null\n" + - " │ │ ├─ TableAlias(a)\n" + + " │ │ │ ├─ b.i:0!null\n" + + " │ │ │ └─ a.i:1!null\n" + + " │ │ ├─ TableAlias(b)\n" + " │ │ │ └─ IndexedTableAccess(mytable)\n" + " │ │ │ ├─ index: [mytable.i]\n" + " │ │ │ ├─ static: [{[NULL, ∞)}]\n" + " │ │ │ └─ Table\n" + " │ │ │ ├─ name: mytable\n" + - " │ │ │ └─ columns: [i s]\n" + - " │ │ └─ Filter\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ c.i:0!null\n" + - " │ │ │ └─ 2 (tinyint)\n" + - " │ │ └─ TableAlias(c)\n" + - " │ │ └─ IndexedTableAccess(mytable)\n" + - " │ │ ├─ index: [mytable.i]\n" + - " │ │ ├─ static: [{[2, 2]}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: mytable\n" + - " │ │ └─ columns: [i]\n" + + " │ │ │ └─ columns: [i]\n" + + " │ │ └─ TableAlias(a)\n" + + " │ │ └─ IndexedTableAccess(mytable)\n" + + " │ │ ├─ index: [mytable.i]\n" + + " │ │ ├─ static: [{[NULL, ∞)}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: mytable\n" + + " │ │ └─ columns: [i s]\n" + " │ └─ TableAlias(d)\n" + " │ └─ IndexedTableAccess(mytable)\n" + " │ ├─ index: [mytable.i]\n" + - " │ ├─ keys: [c.i]\n" + + " │ ├─ keys: [a.i]\n" + " │ └─ Table\n" + " │ ├─ name: mytable\n" + " │ └─ columns: [i]\n" + - " └─ TableAlias(b)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ keys: [a.i]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i]\n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ c.i:0!null\n" + + " │ └─ 2 (tinyint)\n" + + " └─ TableAlias(c)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.i]\n" + + " ├─ keys: [b.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [i]\n" + "", }, { @@ -4593,52 +4564,55 @@ inner join pq on true { Query: `SELECT a.* FROM mytable a CROSS JOIN mytable b CROSS JOIN mytable c CROSS JOIN mytable d where a.i = b.i AND b.i = c.i AND c.i = d.i AND c.i = 2`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " ├─ columns: [a.i:1!null, a.s:2!null]\n" + " └─ LookupJoin\n" + " ├─ AND\n" + " │ ├─ Eq\n" + - " │ │ ├─ b.i:4!null\n" + - " │ │ └─ c.i:2!null\n" + + " │ │ ├─ c.i:4!null\n" + + " │ │ └─ d.i:3!null\n" + " │ └─ Eq\n" + - " │ ├─ b.i:4!null\n" + - " │ └─ d.i:3!null\n" + + " │ ├─ a.i:1!null\n" + + " │ └─ c.i:4!null\n" + " ├─ LookupJoin\n" + + " │ ├─ Eq\n" + + " │ │ ├─ b.i:0!null\n" + + " │ │ └─ d.i:3!null\n" + " │ ├─ MergeJoin\n" + " │ │ ├─ cmp: Eq\n" + - " │ │ │ ├─ a.i:0!null\n" + - " │ │ │ └─ c.i:2!null\n" + - " │ │ ├─ TableAlias(a)\n" + + " │ │ │ ├─ b.i:0!null\n" + + " │ │ │ └─ a.i:1!null\n" + + " │ │ ├─ TableAlias(b)\n" + " │ │ │ └─ IndexedTableAccess(mytable)\n" + " │ │ │ ├─ index: [mytable.i]\n" + " │ │ │ ├─ static: [{[NULL, ∞)}]\n" + " │ │ │ └─ Table\n" + " │ │ │ ├─ name: mytable\n" + - " │ │ │ └─ columns: [i s]\n" + - " │ │ └─ Filter\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ c.i:0!null\n" + - " │ │ │ └─ 2 (tinyint)\n" + - " │ │ └─ TableAlias(c)\n" + - " │ │ └─ IndexedTableAccess(mytable)\n" + - " │ │ ├─ index: [mytable.i]\n" + - " │ │ ├─ static: [{[2, 2]}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: mytable\n" + - " │ │ └─ columns: [i]\n" + + " │ │ │ └─ columns: [i]\n" + + " │ │ └─ TableAlias(a)\n" + + " │ │ └─ IndexedTableAccess(mytable)\n" + + " │ │ ├─ index: [mytable.i]\n" + + " │ │ ├─ static: [{[NULL, ∞)}]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: mytable\n" + + " │ │ └─ columns: [i s]\n" + " │ └─ TableAlias(d)\n" + " │ └─ IndexedTableAccess(mytable)\n" + " │ ├─ index: [mytable.i]\n" + - " │ ├─ keys: [c.i]\n" + + " │ ├─ keys: [a.i]\n" + " │ └─ Table\n" + " │ ├─ name: mytable\n" + " │ └─ columns: [i]\n" + - " └─ TableAlias(b)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ keys: [a.i]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i]\n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ c.i:0!null\n" + + " │ └─ 2 (tinyint)\n" + + " └─ TableAlias(c)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.i]\n" + + " ├─ keys: [b.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [i]\n" + "", }, { @@ -4737,27 +4711,24 @@ inner join pq on true { Query: `SELECT a.* FROM mytable a inner join mytable b on (a.i = b.s) WHERE a.i BETWEEN 10 AND 20`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.s:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.s,mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [s]\n" + - " └─ Filter\n" + - " ├─ (a.i:0!null BETWEEN 10 (tinyint) AND 20 (tinyint))\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ (a.i:0!null BETWEEN 10 (tinyint) AND 20 (tinyint))\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{[10, 20]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.s]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [s]\n" + "", }, { @@ -5005,52 +4976,42 @@ inner join pq on true }, { Query: `SELECT * FROM mytable mt INNER JOIN othertable ot ON mt.i = ot.i2 AND mt.i > 2`, - ExpectedPlan: "Project\n" + - " ├─ columns: [mt.i:2!null, mt.s:3!null, ot.s2:0!null, ot.i2:1!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ ot.i2:1!null\n" + - " │ └─ mt.i:2!null\n" + - " ├─ TableAlias(ot)\n" + - " │ └─ IndexedTableAccess(othertable)\n" + - " │ ├─ index: [othertable.i2]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: othertable\n" + - " │ └─ columns: [s2 i2]\n" + - " └─ Filter\n" + - " ├─ GreaterThan\n" + - " │ ├─ mt.i:0!null\n" + - " │ └─ 2 (tinyint)\n" + - " └─ TableAlias(mt)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + ExpectedPlan: "LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ GreaterThan\n" + + " │ │ ├─ mt.i:0!null\n" + + " │ │ └─ 2 (tinyint)\n" + + " │ └─ TableAlias(mt)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{(2, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(ot)\n" + + " └─ IndexedTableAccess(othertable)\n" + + " ├─ index: [othertable.i2]\n" + + " ├─ keys: [mt.i]\n" + + " └─ Table\n" + + " ├─ name: othertable\n" + + " └─ columns: [s2 i2]\n" + "", }, { Query: `SELECT /*+ JOIN_ORDER(mt, o) */ * FROM mytable mt INNER JOIN one_pk o ON mt.i = o.pk AND mt.s = o.c2`, - ExpectedPlan: "MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ mt.i:0!null\n" + - " │ └─ o.pk:2!null\n" + - " ├─ sel: Eq\n" + + ExpectedPlan: "LookupJoin\n" + + " ├─ Eq\n" + " │ ├─ mt.s:1!null\n" + " │ └─ o.c2:4\n" + " ├─ TableAlias(mt)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + + " │ └─ ProcessTable\n" + " │ └─ Table\n" + " │ ├─ name: mytable\n" + " │ └─ columns: [i s]\n" + " └─ TableAlias(o)\n" + " └─ IndexedTableAccess(one_pk)\n" + " ├─ index: [one_pk.pk]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + + " ├─ keys: [mt.i]\n" + " └─ Table\n" + " ├─ name: one_pk\n" + " └─ columns: [pk c1 c2 c3 c4 c5]\n" + @@ -8355,57 +8316,49 @@ inner join pq on true { Query: `select a.* from mytable a join mytable b on a.i = b.i and a.i > 2`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.i:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + - " └─ Filter\n" + - " ├─ GreaterThan\n" + - " │ ├─ a.i:0!null\n" + - " │ └─ 2 (tinyint)\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ GreaterThan\n" + + " │ │ ├─ a.i:0!null\n" + + " │ │ └─ 2 (tinyint)\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ IndexedTableAccess(mytable)\n" + + " │ ├─ index: [mytable.i]\n" + + " │ ├─ static: [{(2, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.i]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [i]\n" + "", }, { Query: `select a.* from mytable a join mytable b on a.i = b.i and now() >= coalesce(NULL, NULL, now())`, ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:1!null, a.s:2!null]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.i:0!null\n" + - " │ └─ a.i:1!null\n" + - " ├─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(mytable)\n" + - " │ ├─ index: [mytable.i]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: mytable\n" + - " │ └─ columns: [i]\n" + - " └─ Filter\n" + - " ├─ GreaterThanOrEqual\n" + - " │ ├─ NOW()\n" + - " │ └─ coalesce(NULL (null),NULL (null),NOW())\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + - " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ columns: [a.i:0!null, a.s:1!null]\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ GreaterThanOrEqual\n" + + " │ │ ├─ NOW()\n" + + " │ │ └─ coalesce(NULL (null),NULL (null),NOW())\n" + + " │ └─ TableAlias(a)\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(mytable)\n" + + " ├─ index: [mytable.i]\n" + + " ├─ keys: [a.i]\n" + + " └─ Table\n" + + " ├─ name: mytable\n" + + " └─ columns: [i]\n" + "", }, { @@ -8475,31 +8428,24 @@ inner join pq on true }, { Query: `select * from mytable a join niltable b on a.i = b.i and b != 0`, - ExpectedPlan: "Project\n" + - " ├─ columns: [a.i:4!null, a.s:5!null, b.i:0!null, b.i2:1, b.b:2, b.f:3]\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ b.i:0!null\n" + - " │ └─ a.i:4!null\n" + - " ├─ Filter\n" + - " │ ├─ NOT\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ b.b:2\n" + - " │ │ └─ 0 (tinyint)\n" + - " │ └─ TableAlias(b)\n" + - " │ └─ IndexedTableAccess(niltable)\n" + - " │ ├─ index: [niltable.i]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: niltable\n" + - " │ └─ columns: [i i2 b f]\n" + - " └─ TableAlias(a)\n" + - " └─ IndexedTableAccess(mytable)\n" + - " ├─ index: [mytable.i]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + + ExpectedPlan: "LookupJoin\n" + + " ├─ TableAlias(a)\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: mytable\n" + + " │ └─ columns: [i s]\n" + + " └─ Filter\n" + + " ├─ NOT\n" + + " │ └─ Eq\n" + + " │ ├─ b.b:2\n" + + " │ └─ 0 (tinyint)\n" + + " └─ TableAlias(b)\n" + + " └─ IndexedTableAccess(niltable)\n" + + " ├─ index: [niltable.i]\n" + + " ├─ keys: [a.i]\n" + " └─ Table\n" + - " ├─ name: mytable\n" + - " └─ columns: [i s]\n" + + " ├─ name: niltable\n" + + " └─ columns: [i i2 b f]\n" + "", }, { diff --git a/enginetest/queries/tpcc_plans.go b/enginetest/queries/tpcc_plans.go index 90eec8f826..ee9b27f58d 100644 --- a/enginetest/queries/tpcc_plans.go +++ b/enginetest/queries/tpcc_plans.go @@ -19,6 +19,429 @@ package queries var TpccPlanTests = []QueryPlanTest{ { Query: ` +-- cycle 1a +SELECT c_discount, c_last, c_credit, w_tax FROM customer2, warehouse2 WHERE w_id = 1 AND c_w_id = w_id AND c_d_id = 9 AND c_id = 2151`, + ExpectedPlan: "Project\n" + + " ├─ columns: [customer2.c_discount:7, customer2.c_last:5, customer2.c_credit:6, warehouse2.w_tax:1]\n" + + " └─ LookupJoin\n" + + " ├─ IndexedTableAccess(warehouse2)\n" + + " │ ├─ index: [warehouse2.w_id]\n" + + " │ ├─ static: [{[1, 1]}]\n" + + " │ └─ Table\n" + + " │ ├─ name: warehouse2\n" + + " │ └─ columns: [w_id w_tax]\n" + + " └─ Filter\n" + + " ├─ AND\n" + + " │ ├─ Eq\n" + + " │ │ ├─ customer2.c_d_id:1!null\n" + + " │ │ └─ 9 (tinyint)\n" + + " │ └─ Eq\n" + + " │ ├─ customer2.c_id:0!null\n" + + " │ └─ 2151 (smallint)\n" + + " └─ IndexedTableAccess(customer2)\n" + + " ├─ index: [customer2.c_w_id,customer2.c_d_id,customer2.c_id]\n" + + " ├─ keys: [warehouse2.w_id 9 2151]\n" + + " └─ Table\n" + + " ├─ name: customer2\n" + + " └─ columns: [c_id c_d_id c_w_id c_last c_credit c_discount]\n" + + "", + }, + { + Query: `SELECT d_next_o_id, d_tax FROM district2 WHERE d_w_id = 1 AND d_id = 9 FOR UPDATE`, + ExpectedPlan: "Project\n" + + " ├─ columns: [district2.d_next_o_id:3, district2.d_tax:2]\n" + + " └─ IndexedTableAccess(district2)\n" + + " ├─ index: [district2.d_w_id,district2.d_id]\n" + + " ├─ static: [{[1, 1], [9, 9]}]\n" + + " └─ Table\n" + + " ├─ name: district2\n" + + " └─ columns: [d_id d_w_id d_tax d_next_o_id]\n" + + "", + }, + { + Query: `UPDATE district2 SET d_next_o_id = 3002 WHERE d_id = 9 AND d_w_id= 1`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET district2.d_next_o_id:10 = 3002 (smallint))\n" + + " └─ IndexedTableAccess(district2)\n" + + " ├─ index: [district2.d_w_id,district2.d_id]\n" + + " ├─ static: [{[1, 1], [9, 9]}]\n" + + " └─ Table\n" + + " ├─ name: district2\n" + + " └─ columns: [d_id d_w_id d_name d_street_1 d_street_2 d_city d_state d_zip d_tax d_ytd d_next_o_id]\n" + + "", + }, + { + Query: `INSERT INTO orders2 (o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_ol_cnt, o_all_local) VALUES (3001,9,1,2151,NOW(),12,1)`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Insert(o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_ol_cnt, o_all_local)\n" + + " ├─ InsertDestination\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: orders2\n" + + " │ └─ columns: [o_id o_d_id o_w_id o_c_id o_entry_d o_carrier_id o_ol_cnt o_all_local]\n" + + " └─ Project\n" + + " ├─ columns: [o_id:0!null, o_d_id:1!null, o_w_id:2!null, o_c_id:3, o_entry_d:4, , o_ol_cnt:5, o_all_local:6]\n" + + " └─ Values([3001 (smallint),9 (tinyint),1 (tinyint),2151 (smallint),NOW(),12 (tinyint),1 (tinyint)])\n" + + "", + }, + { + Query: `INSERT INTO new_orders2 (no_o_id, no_d_id, no_w_id) VALUES (3001,9,1)`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Insert(no_o_id, no_d_id, no_w_id)\n" + + " ├─ InsertDestination\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: new_orders2\n" + + " │ └─ columns: [no_o_id no_d_id no_w_id]\n" + + " └─ Project\n" + + " ├─ columns: [no_o_id:0!null, no_d_id:1!null, no_w_id:2!null]\n" + + " └─ Values([3001 (smallint),9 (tinyint),1 (tinyint)])\n" + + "", + }, + { + Query: `SELECT i_price, i_name, i_data FROM item2 WHERE i_id = 2532`, + ExpectedPlan: "Project\n" + + " ├─ columns: [item2.i_price:2, item2.i_name:1, item2.i_data:3]\n" + + " └─ IndexedTableAccess(item2)\n" + + " ├─ index: [item2.i_id]\n" + + " ├─ static: [{[2532, 2532]}]\n" + + " └─ Table\n" + + " ├─ name: item2\n" + + " └─ columns: [i_id i_name i_price i_data]\n" + + "", + }, + { + Query: `SELECT s_quantity, s_data, s_dist_09 s_dist FROM stock2 WHERE s_i_id = 2532 AND s_w_id= 1 FOR UPDATE`, + ExpectedPlan: "Project\n" + + " ├─ columns: [stock2.s_quantity:2, stock2.s_data:4, stock2.s_dist_09:3 as s_dist]\n" + + " └─ IndexedTableAccess(stock2)\n" + + " ├─ index: [stock2.s_w_id,stock2.s_i_id]\n" + + " ├─ static: [{[1, 1], [2532, 2532]}]\n" + + " └─ Table\n" + + " ├─ name: stock2\n" + + " └─ columns: [s_i_id s_w_id s_quantity s_dist_09 s_data]\n" + + "", + }, + { + Query: `UPDATE stock2 SET s_quantity = 39 WHERE s_i_id = 2532 AND s_w_id= 1`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET stock2.s_quantity:2 = 39 (tinyint))\n" + + " └─ IndexedTableAccess(stock2)\n" + + " ├─ index: [stock2.s_w_id,stock2.s_i_id]\n" + + " ├─ static: [{[1, 1], [2532, 2532]}]\n" + + " └─ Table\n" + + " ├─ name: stock2\n" + + " └─ columns: [s_i_id s_w_id s_quantity s_dist_01 s_dist_02 s_dist_03 s_dist_04 s_dist_05 s_dist_06 s_dist_07 s_dist_08 s_dist_09 s_dist_10 s_ytd s_order_cnt s_remote_cnt s_data]\n" + + "", + }, + { + Query: `INSERT INTO order_line2 (ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info) VALUES ( +3001,9,1,1,2532,1,5,301,'kkkkkkkkkkkkkkkkkkkkkkkk')`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Insert(ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info)\n" + + " ├─ InsertDestination\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: order_line2\n" + + " │ └─ columns: [ol_o_id ol_d_id ol_w_id ol_number ol_i_id ol_supply_w_id ol_delivery_d ol_quantity ol_amount ol_dist_info]\n" + + " └─ Project\n" + + " ├─ columns: [ol_o_id:0!null, ol_d_id:1!null, ol_w_id:2!null, ol_number:3!null, ol_i_id:4, ol_supply_w_id:5, , ol_quantity:6, ol_amount:7, ol_dist_info:8]\n" + + " └─ Values([3001 (smallint),9 (tinyint),1 (tinyint),1 (tinyint),2532 (smallint),1 (tinyint),5 (tinyint),301 (smallint),kkkkkkkkkkkkkkkkkkkkkkkk (longtext)])\n" + + "", + }, + { + Query: ` +-- cycle 1b +SELECT i_price, i_name, i_data FROM item2 WHERE i_id = 2532`, + ExpectedPlan: "Project\n" + + " ├─ columns: [item2.i_price:2, item2.i_name:1, item2.i_data:3]\n" + + " └─ IndexedTableAccess(item2)\n" + + " ├─ index: [item2.i_id]\n" + + " ├─ static: [{[2532, 2532]}]\n" + + " └─ Table\n" + + " ├─ name: item2\n" + + " └─ columns: [i_id i_name i_price i_data]\n" + + "", + }, + { + Query: `SELECT s_quantity, s_data, s_dist_09 s_dist FROM stock2 WHERE s_i_id = 2532 AND s_w_id= 1 FOR UPDATE`, + ExpectedPlan: "Project\n" + + " ├─ columns: [stock2.s_quantity:2, stock2.s_data:4, stock2.s_dist_09:3 as s_dist]\n" + + " └─ IndexedTableAccess(stock2)\n" + + " ├─ index: [stock2.s_w_id,stock2.s_i_id]\n" + + " ├─ static: [{[1, 1], [2532, 2532]}]\n" + + " └─ Table\n" + + " ├─ name: stock2\n" + + " └─ columns: [s_i_id s_w_id s_quantity s_dist_09 s_data]\n" + + "", + }, + { + Query: `UPDATE stock2 SET s_quantity = 5 WHERE s_i_id = 64568 AND s_w_id= 1`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET stock2.s_quantity:2 = 5 (tinyint))\n" + + " └─ IndexedTableAccess(stock2)\n" + + " ├─ index: [stock2.s_w_id,stock2.s_i_id]\n" + + " ├─ static: [{[1, 1], [64568, 64568]}]\n" + + " └─ Table\n" + + " ├─ name: stock2\n" + + " └─ columns: [s_i_id s_w_id s_quantity s_dist_01 s_dist_02 s_dist_03 s_dist_04 s_dist_05 s_dist_06 s_dist_07 s_dist_08 s_dist_09 s_dist_10 s_ytd s_order_cnt s_remote_cnt s_data]\n" + + "", + }, + { + Query: `INSERT INTO order_line2 (ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info) VALUES ( +3001,9,1,11,64568,1,7,298,'oooooooooooooooooooooooo')`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Insert(ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info)\n" + + " ├─ InsertDestination\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: order_line2\n" + + " │ └─ columns: [ol_o_id ol_d_id ol_w_id ol_number ol_i_id ol_supply_w_id ol_delivery_d ol_quantity ol_amount ol_dist_info]\n" + + " └─ Project\n" + + " ├─ columns: [ol_o_id:0!null, ol_d_id:1!null, ol_w_id:2!null, ol_number:3!null, ol_i_id:4, ol_supply_w_id:5, , ol_quantity:6, ol_amount:7, ol_dist_info:8]\n" + + " └─ Values([3001 (smallint),9 (tinyint),1 (tinyint),11 (tinyint),64568 (smallint unsigned),1 (tinyint),7 (tinyint),298 (smallint),oooooooooooooooooooooooo (longtext)])\n" + + "", + }, + { + Query: ` +-- cycle 2 +UPDATE warehouse1 SET w_ytd = w_ytd + 1767 WHERE w_id = 1`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET warehouse1.w_ytd:8 = (warehouse1.w_ytd:8 + 1767 (smallint)))\n" + + " └─ IndexedTableAccess(warehouse1)\n" + + " ├─ index: [warehouse1.w_id]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: warehouse1\n" + + " └─ columns: [w_id w_name w_street_1 w_street_2 w_city w_state w_zip w_tax w_ytd]\n" + + "", + }, + { + Query: `SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name FROM warehouse1 WHERE w_id = 1`, + ExpectedPlan: "Project\n" + + " ├─ columns: [warehouse1.w_street_1:2, warehouse1.w_street_2:3, warehouse1.w_city:4, warehouse1.w_state:5, warehouse1.w_zip:6, warehouse1.w_name:1]\n" + + " └─ IndexedTableAccess(warehouse1)\n" + + " ├─ index: [warehouse1.w_id]\n" + + " ├─ static: [{[1, 1]}]\n" + + " └─ Table\n" + + " ├─ name: warehouse1\n" + + " └─ columns: [w_id w_name w_street_1 w_street_2 w_city w_state w_zip]\n" + + "", + }, + { + Query: `UPDATE district1 SET d_ytd = d_ytd + 1767 WHERE d_w_id = 1 AND d_id= 8`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET district1.d_ytd:9 = (district1.d_ytd:9 + 1767 (smallint)))\n" + + " └─ IndexedTableAccess(district1)\n" + + " ├─ index: [district1.d_w_id,district1.d_id]\n" + + " ├─ static: [{[1, 1], [8, 8]}]\n" + + " └─ Table\n" + + " ├─ name: district1\n" + + " └─ columns: [d_id d_w_id d_name d_street_1 d_street_2 d_city d_state d_zip d_tax d_ytd d_next_o_id]\n" + + "", + }, + { + Query: `SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name FROM district1 WHERE d_w_id = 1 AND d_id = 8`, + ExpectedPlan: "Project\n" + + " ├─ columns: [district1.d_street_1:3, district1.d_street_2:4, district1.d_city:5, district1.d_state:6, district1.d_zip:7, district1.d_name:2]\n" + + " └─ IndexedTableAccess(district1)\n" + + " ├─ index: [district1.d_w_id,district1.d_id]\n" + + " ├─ static: [{[1, 1], [8, 8]}]\n" + + " └─ Table\n" + + " ├─ name: district1\n" + + " └─ columns: [d_id d_w_id d_name d_street_1 d_street_2 d_city d_state d_zip]\n" + + "", + }, + { + Query: `SELECT count(c_id) namecnt FROM customer1 WHERE c_w_id = 1 AND c_d_id= 5 AND c_last='ESEEINGABLE'`, + ExpectedPlan: "Project\n" + + " ├─ columns: [count(customer1.c_id):0!null as namecnt]\n" + + " └─ GroupBy\n" + + " ├─ select: COUNT(customer1.c_id:0!null)\n" + + " ├─ group: \n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ customer1.c_last:3\n" + + " │ └─ ESEEINGABLE (longtext)\n" + + " └─ IndexedTableAccess(customer1)\n" + + " ├─ index: [customer1.c_w_id,customer1.c_d_id,customer1.c_last,customer1.c_first]\n" + + " ├─ static: [{[1, 1], [5, 5], [ESEEINGABLE, ESEEINGABLE], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: customer1\n" + + " └─ columns: [c_id c_d_id c_w_id c_last]\n" + + "", + }, + { + Query: `SELECT c_id FROM customer1 WHERE c_w_id = 1 AND c_d_id= 5 AND c_last='ESEEINGABLE' ORDER BY c_first`, + ExpectedPlan: "Project\n" + + " ├─ columns: [customer1.c_id:0!null]\n" + + " └─ Sort(customer1.c_first:3 ASC nullsFirst)\n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ customer1.c_last:5\n" + + " │ └─ ESEEINGABLE (longtext)\n" + + " └─ IndexedTableAccess(customer1)\n" + + " ├─ index: [customer1.c_w_id,customer1.c_d_id,customer1.c_last,customer1.c_first]\n" + + " ├─ static: [{[1, 1], [5, 5], [ESEEINGABLE, ESEEINGABLE], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: customer1\n" + + " └─ columns: [c_id c_d_id c_w_id c_first c_middle c_last c_street_1 c_street_2 c_city c_state c_zip c_phone c_since c_credit c_credit_lim c_discount c_balance c_ytd_payment c_payment_cnt c_delivery_cnt c_data]\n" + + "", + }, + { + Query: `SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_credit, c_credit_lim, c_discount, c_balance, c_ytd_payment, c_since FROM customer1 WHERE c_w_id = 1 AND c_d_id= 5 AND c_id=1838 FOR UPDATE`, + ExpectedPlan: "Project\n" + + " ├─ columns: [customer1.c_first:3, customer1.c_middle:4, customer1.c_last:5, customer1.c_street_1:6, customer1.c_street_2:7, customer1.c_city:8, customer1.c_state:9, customer1.c_zip:10, customer1.c_phone:11, customer1.c_credit:13, customer1.c_credit_lim:14, customer1.c_discount:15, customer1.c_balance:16, customer1.c_ytd_payment:17, customer1.c_since:12]\n" + + " └─ IndexedTableAccess(customer1)\n" + + " ├─ index: [customer1.c_w_id,customer1.c_d_id,customer1.c_id]\n" + + " ├─ static: [{[1, 1], [5, 5], [1838, 1838]}]\n" + + " └─ Table\n" + + " ├─ name: customer1\n" + + " └─ columns: [c_id c_d_id c_w_id c_first c_middle c_last c_street_1 c_street_2 c_city c_state c_zip c_phone c_since c_credit c_credit_lim c_discount c_balance c_ytd_payment]\n" + + "", + }, + { + Query: `UPDATE customer1 SET c_balance=-1777.000000, c_ytd_payment=1777.000000 WHERE c_w_id = 1 AND c_d_id=5 AND c_id=1838`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Update\n" + + " └─ UpdateSource(SET customer1.c_balance:16 = -1777.000000,SET customer1.c_ytd_payment:17 = 1777 (decimal(10,6)))\n" + + " └─ IndexedTableAccess(customer1)\n" + + " ├─ index: [customer1.c_w_id,customer1.c_d_id,customer1.c_id]\n" + + " ├─ static: [{[1, 1], [5, 5], [1838, 1838]}]\n" + + " └─ Table\n" + + " ├─ name: customer1\n" + + " └─ columns: [c_id c_d_id c_w_id c_first c_middle c_last c_street_1 c_street_2 c_city c_state c_zip c_phone c_since c_credit c_credit_lim c_discount c_balance c_ytd_payment c_payment_cnt c_delivery_cnt c_data]\n" + + "", + }, + { + Query: `INSERT INTO history1 (h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data) VALUES (5,1,1838,8,1,NOW(),1767,'name-rqojn name-dnvgs ')`, + ExpectedPlan: "RowUpdateAccumulator\n" + + " └─ Insert(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data)\n" + + " ├─ InsertDestination\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: history1\n" + + " │ └─ columns: [h_c_id h_c_d_id h_c_w_id h_d_id h_w_id h_date h_amount h_data]\n" + + " └─ Project\n" + + " ├─ columns: [h_c_id:2, h_c_d_id:0, h_c_w_id:1, h_d_id:3, h_w_id:4, h_date:5, h_amount:6, h_data:7]\n" + + " └─ Values([5 (tinyint),1 (tinyint),1838 (smallint),8 (tinyint),1 (tinyint),NOW(),1767 (smallint),name-rqojn name-dnvgs (longtext)])\n" + + "", + }, + { + Query: ` +-- cycle 3 +SELECT count(c_id) namecnt FROM customer3 WHERE c_w_id = 1 AND c_d_id= 1 AND c_last='PRIESEPRES'`, + ExpectedPlan: "Project\n" + + " ├─ columns: [count(customer3.c_id):0!null as namecnt]\n" + + " └─ GroupBy\n" + + " ├─ select: COUNT(customer3.c_id:0!null)\n" + + " ├─ group: \n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ customer3.c_last:3\n" + + " │ └─ PRIESEPRES (longtext)\n" + + " └─ IndexedTableAccess(customer3)\n" + + " ├─ index: [customer3.c_w_id,customer3.c_d_id,customer3.c_last,customer3.c_first]\n" + + " ├─ static: [{[1, 1], [1, 1], [PRIESEPRES, PRIESEPRES], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: customer3\n" + + " └─ columns: [c_id c_d_id c_w_id c_last]\n" + + "", + }, + { + Query: `SELECT c_balance, c_first, c_middle, c_id FROM customer2 WHERE c_w_id = 1 AND c_d_id= 1 AND c_last='PRIESEPRES' ORDER BY c_first`, + ExpectedPlan: "Project\n" + + " ├─ columns: [customer2.c_balance:16, customer2.c_first:3, customer2.c_middle:4, customer2.c_id:0!null]\n" + + " └─ Sort(customer2.c_first:3 ASC nullsFirst)\n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ customer2.c_last:5\n" + + " │ └─ PRIESEPRES (longtext)\n" + + " └─ IndexedTableAccess(customer2)\n" + + " ├─ index: [customer2.c_w_id,customer2.c_d_id,customer2.c_last,customer2.c_first]\n" + + " ├─ static: [{[1, 1], [1, 1], [PRIESEPRES, PRIESEPRES], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: customer2\n" + + " └─ columns: [c_id c_d_id c_w_id c_first c_middle c_last c_street_1 c_street_2 c_city c_state c_zip c_phone c_since c_credit c_credit_lim c_discount c_balance c_ytd_payment c_payment_cnt c_delivery_cnt c_data]\n" + + "", + }, + { + Query: `SELECT o_id, o_carrier_id, o_entry_d FROM orders2 WHERE o_w_id = 1 AND o_d_id = 1 AND o_c_id = 355 ORDER BY o_id DESC`, + ExpectedPlan: "Project\n" + + " ├─ columns: [orders2.o_id:0!null, orders2.o_carrier_id:5, orders2.o_entry_d:4]\n" + + " └─ Sort(orders2.o_id:0!null DESC nullsFirst)\n" + + " └─ IndexedTableAccess(orders2)\n" + + " ├─ index: [orders2.o_w_id,orders2.o_d_id,orders2.o_c_id,orders2.o_id]\n" + + " ├─ static: [{[1, 1], [1, 1], [355, 355], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: orders2\n" + + " └─ columns: [o_id o_d_id o_w_id o_c_id o_entry_d o_carrier_id o_ol_cnt o_all_local]\n" + + "", + }, + { + Query: `SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d FROM order_line2 WHERE ol_w_id = 1 AND ol_d_id = 1 AND ol_o_id = 1`, + ExpectedPlan: "Project\n" + + " ├─ columns: [order_line2.ol_i_id:3, order_line2.ol_supply_w_id:4, order_line2.ol_quantity:6, order_line2.ol_amount:7, order_line2.ol_delivery_d:5]\n" + + " └─ IndexedTableAccess(order_line2)\n" + + " ├─ index: [order_line2.ol_w_id,order_line2.ol_d_id,order_line2.ol_o_id,order_line2.ol_number]\n" + + " ├─ static: [{[1, 1], [1, 1], [1, 1], [NULL, ∞)}]\n" + + " └─ Table\n" + + " ├─ name: order_line2\n" + + " └─ columns: [ol_o_id ol_d_id ol_w_id ol_i_id ol_supply_w_id ol_delivery_d ol_quantity ol_amount]\n" + + "", + }, + { + Query: ` +-- cycle 4 +SELECT d_next_o_id FROM district3 WHERE d_id = 5 AND d_w_id= 1`, + ExpectedPlan: "Project\n" + + " ├─ columns: [district3.d_next_o_id:2]\n" + + " └─ IndexedTableAccess(district3)\n" + + " ├─ index: [district3.d_w_id,district3.d_id]\n" + + " ├─ static: [{[1, 1], [5, 5]}]\n" + + " └─ Table\n" + + " ├─ name: district3\n" + + " └─ columns: [d_id d_w_id d_next_o_id]\n" + + "", + }, + { + Query: `SELECT COUNT(DISTINCT (s_i_id)) FROM order_line3, stock3 WHERE ol_w_id = 1 AND ol_d_id = 5 AND ol_o_id < 3003 AND ol_o_id >= 2983 AND s_w_id= 1 AND s_i_id=ol_i_id AND s_quantity < 18`, + ExpectedPlan: "Project\n" + + " ├─ columns: [countdistinct([stock3.s_i_id]):0!null as COUNT(DISTINCT (s_i_id))]\n" + + " └─ GroupBy\n" + + " ├─ select: COUNTDISTINCT([stock3.s_i_id])\n" + + " ├─ group: \n" + + " └─ LookupJoin\n" + + " ├─ IndexedTableAccess(order_line3)\n" + + " │ ├─ index: [order_line3.ol_w_id,order_line3.ol_d_id,order_line3.ol_o_id,order_line3.ol_number]\n" + + " │ ├─ static: [{[1, 1], [5, 5], [2983, 3003), [NULL, ∞)}]\n" + + " │ └─ Table\n" + + " │ ├─ name: order_line3\n" + + " │ └─ columns: [ol_o_id ol_d_id ol_w_id ol_i_id]\n" + + " └─ Filter\n" + + " ├─ AND\n" + + " │ ├─ Eq\n" + + " │ │ ├─ stock3.s_w_id:1!null\n" + + " │ │ └─ 1 (tinyint)\n" + + " │ └─ LessThan\n" + + " │ ├─ stock3.s_quantity:2\n" + + " │ └─ 18 (tinyint)\n" + + " └─ IndexedTableAccess(stock3)\n" + + " ├─ index: [stock3.s_w_id,stock3.s_i_id]\n" + + " ├─ keys: [1 order_line3.ol_i_id]\n" + + " └─ Table\n" + + " ├─ name: stock3\n" + + " └─ columns: [s_i_id s_w_id s_quantity]\n" + + "", + }, + { + Query: ` +-- other SELECT o_id, o_entry_d, COALESCE(o_carrier_id,0) FROM orders2 WHERE diff --git a/enginetest/queries/tpch_plans.go b/enginetest/queries/tpch_plans.go index 043a329793..9afd91e612 100644 --- a/enginetest/queries/tpch_plans.go +++ b/enginetest/queries/tpch_plans.go @@ -232,43 +232,38 @@ order by " ├─ group: lineitem.l_orderkey:0!null, orders.o_orderdate:6!null, orders.o_shippriority:7!null\n" + " └─ HashJoin\n" + " ├─ Eq\n" + - " │ ├─ customer.c_custkey:8!null\n" + - " │ └─ orders.o_custkey:5!null\n" + - " ├─ MergeJoin\n" + - " │ ├─ cmp: Eq\n" + - " │ │ ├─ lineitem.l_orderkey:0!null\n" + - " │ │ └─ orders.o_orderkey:4!null\n" + - " │ ├─ Filter\n" + - " │ │ ├─ GreaterThan\n" + - " │ │ │ ├─ lineitem.l_shipdate:3!null\n" + - " │ │ │ └─ 1995-03-15 (longtext)\n" + - " │ │ └─ IndexedTableAccess(lineitem)\n" + - " │ │ ├─ index: [lineitem.L_ORDERKEY,lineitem.L_LINENUMBER]\n" + - " │ │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: lineitem\n" + - " │ │ └─ columns: [l_orderkey l_extendedprice l_discount l_shipdate]\n" + - " │ └─ Filter\n" + - " │ ├─ LessThan\n" + - " │ │ ├─ orders.o_orderdate:2!null\n" + - " │ │ └─ 1995-03-15 (longtext)\n" + - " │ └─ IndexedTableAccess(orders)\n" + - " │ ├─ index: [orders.O_ORDERKEY]\n" + - " │ ├─ static: [{[NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: orders\n" + - " │ └─ columns: [o_orderkey o_custkey o_orderdate o_shippriority]\n" + + " │ ├─ lineitem.l_orderkey:0!null\n" + + " │ └─ orders.o_orderkey:4!null\n" + + " ├─ Filter\n" + + " │ ├─ GreaterThan\n" + + " │ │ ├─ lineitem.l_shipdate:3!null\n" + + " │ │ └─ 1995-03-15 (longtext)\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: lineitem\n" + + " │ └─ columns: [l_orderkey l_extendedprice l_discount l_shipdate]\n" + " └─ HashLookup\n" + - " ├─ left-key: TUPLE(orders.o_custkey:5!null)\n" + - " ├─ right-key: TUPLE(customer.c_custkey:0!null)\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ customer.c_mktsegment:1!null\n" + - " │ └─ BUILDING (longtext)\n" + - " └─ ProcessTable\n" + - " └─ Table\n" + - " ├─ name: customer\n" + - " └─ columns: [c_custkey c_mktsegment]\n" + + " ├─ left-key: TUPLE(lineitem.l_orderkey:0!null)\n" + + " ├─ right-key: TUPLE(orders.o_orderkey:0!null)\n" + + " └─ LookupJoin\n" + + " ├─ Filter\n" + + " │ ├─ LessThan\n" + + " │ │ ├─ orders.o_orderdate:2!null\n" + + " │ │ └─ 1995-03-15 (longtext)\n" + + " │ └─ ProcessTable\n" + + " │ └─ Table\n" + + " │ ├─ name: orders\n" + + " │ └─ columns: [o_orderkey o_custkey o_orderdate o_shippriority]\n" + + " └─ Filter\n" + + " ├─ Eq\n" + + " │ ├─ customer.c_mktsegment:1!null\n" + + " │ └─ BUILDING (longtext)\n" + + " └─ IndexedTableAccess(customer)\n" + + " ├─ index: [customer.C_CUSTKEY]\n" + + " ├─ keys: [orders.o_custkey]\n" + + " └─ Table\n" + + " ├─ name: customer\n" + + " └─ columns: [c_custkey c_mktsegment]\n" + "", }, { @@ -371,71 +366,66 @@ order by " └─ Project\n" + " ├─ columns: [sum((lineitem.l_extendedprice * (1 - lineitem.l_discount))):0!null, nation.n_name:1!null, sum((lineitem.l_extendedprice * (1 - lineitem.l_discount))):0!null as revenue]\n" + " └─ GroupBy\n" + - " ├─ select: SUM((lineitem.l_extendedprice:2!null * (1 (tinyint) - lineitem.l_discount:3!null))), nation.n_name:12!null\n" + - " ├─ group: nation.n_name:12!null\n" + - " └─ HashJoin\n" + + " ├─ select: SUM((lineitem.l_extendedprice:2!null * (1 (tinyint) - lineitem.l_discount:3!null))), nation.n_name:10!null\n" + + " ├─ group: nation.n_name:10!null\n" + + " └─ LookupJoin\n" + " ├─ AND\n" + - " │ ├─ AND\n" + - " │ │ ├─ Eq\n" + - " │ │ │ ├─ lineitem.l_orderkey:0!null\n" + - " │ │ │ └─ orders.o_orderkey:6!null\n" + - " │ │ └─ Eq\n" + - " │ │ ├─ customer.c_nationkey:10!null\n" + - " │ │ └─ supplier.s_nationkey:5!null\n" + + " │ ├─ Eq\n" + + " │ │ ├─ customer.c_nationkey:15!null\n" + + " │ │ └─ supplier.s_nationkey:5!null\n" + " │ └─ Eq\n" + - " │ ├─ supplier.s_nationkey:5!null\n" + - " │ └─ nation.n_nationkey:11!null\n" + + " │ ├─ customer.c_nationkey:15!null\n" + + " │ └─ nation.n_nationkey:9!null\n" + " ├─ LookupJoin\n" + - " │ ├─ ProcessTable\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: lineitem\n" + - " │ │ └─ columns: [l_orderkey l_suppkey l_extendedprice l_discount]\n" + - " │ └─ IndexedTableAccess(supplier)\n" + - " │ ├─ index: [supplier.S_SUPPKEY]\n" + - " │ ├─ keys: [lineitem.l_suppkey]\n" + - " │ └─ Table\n" + - " │ ├─ name: supplier\n" + - " │ └─ columns: [s_suppkey s_nationkey]\n" + - " └─ HashLookup\n" + - " ├─ left-key: TUPLE(lineitem.l_orderkey:0!null, supplier.s_nationkey:5!null, supplier.s_nationkey:5!null)\n" + - " ├─ right-key: TUPLE(orders.o_orderkey:0!null, customer.c_nationkey:4!null, nation.n_nationkey:5!null)\n" + - " └─ LookupJoin\n" + - " ├─ LookupJoin\n" + - " │ ├─ LookupJoin\n" + - " │ │ ├─ Filter\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ ├─ orders.o_orderdate:2!null\n" + - " │ │ │ │ │ └─ 1994-01-01 (longtext)\n" + - " │ │ │ │ └─ LessThan\n" + - " │ │ │ │ ├─ orders.o_orderdate:2!null\n" + - " │ │ │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + - " │ │ │ └─ ProcessTable\n" + - " │ │ │ └─ Table\n" + - " │ │ │ ├─ name: orders\n" + - " │ │ │ └─ columns: [o_orderkey o_custkey o_orderdate]\n" + - " │ │ └─ IndexedTableAccess(customer)\n" + - " │ │ ├─ index: [customer.C_CUSTKEY]\n" + - " │ │ ├─ keys: [orders.o_custkey]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: customer\n" + - " │ │ └─ columns: [c_custkey c_nationkey]\n" + - " │ └─ IndexedTableAccess(nation)\n" + - " │ ├─ index: [nation.N_NATIONKEY]\n" + - " │ ├─ keys: [customer.c_nationkey]\n" + - " │ └─ Table\n" + - " │ ├─ name: nation\n" + - " │ └─ columns: [n_nationkey n_name n_regionkey]\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ region.r_name:1!null\n" + - " │ └─ ASIA (longtext)\n" + - " └─ IndexedTableAccess(region)\n" + - " ├─ index: [region.R_REGIONKEY]\n" + - " ├─ keys: [nation.n_regionkey]\n" + - " └─ Table\n" + - " ├─ name: region\n" + - " └─ columns: [r_regionkey r_name]\n" + + " │ ├─ LookupJoin\n" + + " │ │ ├─ LookupJoin\n" + + " │ │ │ ├─ LookupJoin\n" + + " │ │ │ │ ├─ ProcessTable\n" + + " │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ ├─ name: lineitem\n" + + " │ │ │ │ │ └─ columns: [l_orderkey l_suppkey l_extendedprice l_discount]\n" + + " │ │ │ │ └─ IndexedTableAccess(supplier)\n" + + " │ │ │ │ ├─ index: [supplier.S_SUPPKEY]\n" + + " │ │ │ │ ├─ keys: [lineitem.l_suppkey]\n" + + " │ │ │ │ └─ Table\n" + + " │ │ │ │ ├─ name: supplier\n" + + " │ │ │ │ └─ columns: [s_suppkey s_nationkey]\n" + + " │ │ │ └─ Filter\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ orders.o_orderdate:2!null\n" + + " │ │ │ │ │ └─ 1994-01-01 (longtext)\n" + + " │ │ │ │ └─ LessThan\n" + + " │ │ │ │ ├─ orders.o_orderdate:2!null\n" + + " │ │ │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + + " │ │ │ └─ IndexedTableAccess(orders)\n" + + " │ │ │ ├─ index: [orders.O_ORDERKEY]\n" + + " │ │ │ ├─ keys: [lineitem.l_orderkey]\n" + + " │ │ │ └─ Table\n" + + " │ │ │ ├─ name: orders\n" + + " │ │ │ └─ columns: [o_orderkey o_custkey o_orderdate]\n" + + " │ │ └─ IndexedTableAccess(nation)\n" + + " │ │ ├─ index: [nation.N_NATIONKEY]\n" + + " │ │ ├─ keys: [supplier.s_nationkey]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: nation\n" + + " │ │ └─ columns: [n_nationkey n_name n_regionkey]\n" + + " │ └─ Filter\n" + + " │ ├─ Eq\n" + + " │ │ ├─ region.r_name:1!null\n" + + " │ │ └─ ASIA (longtext)\n" + + " │ └─ IndexedTableAccess(region)\n" + + " │ ├─ index: [region.R_REGIONKEY]\n" + + " │ ├─ keys: [nation.n_regionkey]\n" + + " │ └─ Table\n" + + " │ ├─ name: region\n" + + " │ └─ columns: [r_regionkey r_name]\n" + + " └─ IndexedTableAccess(customer)\n" + + " ├─ index: [customer.C_CUSTKEY]\n" + + " ├─ keys: [orders.o_custkey]\n" + + " └─ Table\n" + + " ├─ name: customer\n" + + " └─ columns: [c_custkey c_nationkey]\n" + "", }, { @@ -558,24 +548,24 @@ order by " │ │ │ │ │ └─ Table\n" + " │ │ │ │ │ ├─ name: lineitem\n" + " │ │ │ │ │ └─ columns: [l_orderkey l_suppkey l_extendedprice l_discount l_shipdate]\n" + - " │ │ │ │ └─ IndexedTableAccess(supplier)\n" + - " │ │ │ │ ├─ index: [supplier.S_SUPPKEY]\n" + - " │ │ │ │ ├─ keys: [lineitem.l_suppkey]\n" + + " │ │ │ │ └─ IndexedTableAccess(orders)\n" + + " │ │ │ │ ├─ index: [orders.O_ORDERKEY]\n" + + " │ │ │ │ ├─ keys: [lineitem.l_orderkey]\n" + " │ │ │ │ └─ Table\n" + - " │ │ │ │ ├─ name: supplier\n" + - " │ │ │ │ └─ columns: [s_suppkey s_nationkey]\n" + - " │ │ │ └─ IndexedTableAccess(orders)\n" + - " │ │ │ ├─ index: [orders.O_ORDERKEY]\n" + - " │ │ │ ├─ keys: [lineitem.l_orderkey]\n" + + " │ │ │ │ ├─ name: orders\n" + + " │ │ │ │ └─ columns: [o_orderkey o_custkey]\n" + + " │ │ │ └─ IndexedTableAccess(customer)\n" + + " │ │ │ ├─ index: [customer.C_CUSTKEY]\n" + + " │ │ │ ├─ keys: [orders.o_custkey]\n" + " │ │ │ └─ Table\n" + - " │ │ │ ├─ name: orders\n" + - " │ │ │ └─ columns: [o_orderkey o_custkey]\n" + - " │ │ └─ IndexedTableAccess(customer)\n" + - " │ │ ├─ index: [customer.C_CUSTKEY]\n" + - " │ │ ├─ keys: [orders.o_custkey]\n" + + " │ │ │ ├─ name: customer\n" + + " │ │ │ └─ columns: [c_custkey c_nationkey]\n" + + " │ │ └─ IndexedTableAccess(supplier)\n" + + " │ │ ├─ index: [supplier.S_SUPPKEY]\n" + + " │ │ ├─ keys: [lineitem.l_suppkey]\n" + " │ │ └─ Table\n" + - " │ │ ├─ name: customer\n" + - " │ │ └─ columns: [c_custkey c_nationkey]\n" + + " │ │ ├─ name: supplier\n" + + " │ │ └─ columns: [s_suppkey s_nationkey]\n" + " │ └─ TableAlias(n2)\n" + " │ └─ IndexedTableAccess(nation)\n" + " │ ├─ index: [nation.N_NATIONKEY]\n" + @@ -649,74 +639,71 @@ order by " ├─ isLateral: false\n" + " ├─ cacheable: true\n" + " └─ Project\n" + - " ├─ columns: [extract('YEAR' from orders.o_orderdate) as o_year, (lineitem.l_extendedprice:3!null * (1 (tinyint) - lineitem.l_discount:4!null)) as volume, n2.n_name:10!null as nation]\n" + - " └─ HashJoin\n" + - " ├─ Eq\n" + - " │ ├─ lineitem.l_orderkey:0!null\n" + - " │ └─ orders.o_orderkey:11!null\n" + + " ├─ columns: [extract('YEAR' from orders.o_orderdate) as o_year, (lineitem.l_extendedprice:3!null * (1 (tinyint) - lineitem.l_discount:4!null)) as volume, n2.n_name:19!null as nation]\n" + + " └─ LookupJoin\n" + " ├─ LookupJoin\n" + " │ ├─ LookupJoin\n" + " │ │ ├─ LookupJoin\n" + - " │ │ │ ├─ Table\n" + - " │ │ │ │ ├─ name: lineitem\n" + - " │ │ │ │ └─ columns: [l_orderkey l_partkey l_suppkey l_extendedprice l_discount]\n" + - " │ │ │ └─ Filter\n" + - " │ │ │ ├─ Eq\n" + - " │ │ │ │ ├─ part.p_type:1!null\n" + - " │ │ │ │ └─ ECONOMY ANODIZED STEEL (longtext)\n" + - " │ │ │ └─ IndexedTableAccess(part)\n" + - " │ │ │ ├─ index: [part.P_PARTKEY]\n" + - " │ │ │ ├─ keys: [lineitem.l_partkey]\n" + + " │ │ │ ├─ LookupJoin\n" + + " │ │ │ │ ├─ LookupJoin\n" + + " │ │ │ │ │ ├─ LookupJoin\n" + + " │ │ │ │ │ │ ├─ Table\n" + + " │ │ │ │ │ │ │ ├─ name: lineitem\n" + + " │ │ │ │ │ │ │ └─ columns: [l_orderkey l_partkey l_suppkey l_extendedprice l_discount]\n" + + " │ │ │ │ │ │ └─ Filter\n" + + " │ │ │ │ │ │ ├─ Eq\n" + + " │ │ │ │ │ │ │ ├─ part.p_type:1!null\n" + + " │ │ │ │ │ │ │ └─ ECONOMY ANODIZED STEEL (longtext)\n" + + " │ │ │ │ │ │ └─ IndexedTableAccess(part)\n" + + " │ │ │ │ │ │ ├─ index: [part.P_PARTKEY]\n" + + " │ │ │ │ │ │ ├─ keys: [lineitem.l_partkey]\n" + + " │ │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ │ ├─ name: part\n" + + " │ │ │ │ │ │ └─ columns: [p_partkey p_type]\n" + + " │ │ │ │ │ └─ Filter\n" + + " │ │ │ │ │ ├─ (orders.o_orderdate:2!null BETWEEN 1995-01-01 (longtext) AND 1996-12-31 (longtext))\n" + + " │ │ │ │ │ └─ IndexedTableAccess(orders)\n" + + " │ │ │ │ │ ├─ index: [orders.O_ORDERKEY]\n" + + " │ │ │ │ │ ├─ keys: [lineitem.l_orderkey]\n" + + " │ │ │ │ │ └─ Table\n" + + " │ │ │ │ │ ├─ name: orders\n" + + " │ │ │ │ │ └─ columns: [o_orderkey o_custkey o_orderdate]\n" + + " │ │ │ │ └─ IndexedTableAccess(customer)\n" + + " │ │ │ │ ├─ index: [customer.C_CUSTKEY]\n" + + " │ │ │ │ ├─ keys: [orders.o_custkey]\n" + + " │ │ │ │ └─ Table\n" + + " │ │ │ │ ├─ name: customer\n" + + " │ │ │ │ └─ columns: [c_custkey c_nationkey]\n" + + " │ │ │ └─ TableAlias(n1)\n" + + " │ │ │ └─ IndexedTableAccess(nation)\n" + + " │ │ │ ├─ index: [nation.N_NATIONKEY]\n" + + " │ │ │ ├─ keys: [customer.c_nationkey]\n" + " │ │ │ └─ Table\n" + - " │ │ │ ├─ name: part\n" + - " │ │ │ └─ columns: [p_partkey p_type]\n" + + " │ │ │ ├─ name: nation\n" + + " │ │ │ └─ columns: [n_nationkey n_regionkey]\n" + " │ │ └─ IndexedTableAccess(supplier)\n" + " │ │ ├─ index: [supplier.S_SUPPKEY]\n" + " │ │ ├─ keys: [lineitem.l_suppkey]\n" + " │ │ └─ Table\n" + " │ │ ├─ name: supplier\n" + " │ │ └─ columns: [s_suppkey s_nationkey]\n" + - " │ └─ TableAlias(n2)\n" + - " │ └─ IndexedTableAccess(nation)\n" + - " │ ├─ index: [nation.N_NATIONKEY]\n" + - " │ ├─ keys: [supplier.s_nationkey]\n" + + " │ └─ Filter\n" + + " │ ├─ Eq\n" + + " │ │ ├─ region.r_name:1!null\n" + + " │ │ └─ AMERICA (longtext)\n" + + " │ └─ IndexedTableAccess(region)\n" + + " │ ├─ index: [region.R_REGIONKEY]\n" + + " │ ├─ keys: [n1.n_regionkey]\n" + " │ └─ Table\n" + - " │ ├─ name: nation\n" + - " │ └─ columns: [n_nationkey n_name]\n" + - " └─ HashLookup\n" + - " ├─ left-key: TUPLE(lineitem.l_orderkey:0!null)\n" + - " ├─ right-key: TUPLE(orders.o_orderkey:0!null)\n" + - " └─ LookupJoin\n" + - " ├─ LookupJoin\n" + - " │ ├─ LookupJoin\n" + - " │ │ ├─ Filter\n" + - " │ │ │ ├─ (orders.o_orderdate:2!null BETWEEN 1995-01-01 (longtext) AND 1996-12-31 (longtext))\n" + - " │ │ │ └─ Table\n" + - " │ │ │ ├─ name: orders\n" + - " │ │ │ └─ columns: [o_orderkey o_custkey o_orderdate]\n" + - " │ │ └─ IndexedTableAccess(customer)\n" + - " │ │ ├─ index: [customer.C_CUSTKEY]\n" + - " │ │ ├─ keys: [orders.o_custkey]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: customer\n" + - " │ │ └─ columns: [c_custkey c_nationkey]\n" + - " │ └─ TableAlias(n1)\n" + - " │ └─ IndexedTableAccess(nation)\n" + - " │ ├─ index: [nation.N_NATIONKEY]\n" + - " │ ├─ keys: [customer.c_nationkey]\n" + - " │ └─ Table\n" + - " │ ├─ name: nation\n" + - " │ └─ columns: [n_nationkey n_regionkey]\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ region.r_name:1!null\n" + - " │ └─ AMERICA (longtext)\n" + - " └─ IndexedTableAccess(region)\n" + - " ├─ index: [region.R_REGIONKEY]\n" + - " ├─ keys: [n1.n_regionkey]\n" + - " └─ Table\n" + - " ├─ name: region\n" + - " └─ columns: [r_regionkey r_name]\n" + + " │ ├─ name: region\n" + + " │ └─ columns: [r_regionkey r_name]\n" + + " └─ TableAlias(n2)\n" + + " └─ IndexedTableAccess(nation)\n" + + " ├─ index: [nation.N_NATIONKEY]\n" + + " ├─ keys: [supplier.s_nationkey]\n" + + " └─ Table\n" + + " ├─ name: nation\n" + + " └─ columns: [n_nationkey n_name]\n" + "", }, { @@ -1045,10 +1032,7 @@ order by " │ └─ 2-HIGH (longtext)\n" + " │ THEN 1 (tinyint) ELSE 0 (tinyint) END), lineitem.l_shipmode:4!null\n" + " ├─ group: lineitem.l_shipmode:4!null\n" + - " └─ MergeJoin\n" + - " ├─ cmp: Eq\n" + - " │ ├─ lineitem.l_orderkey:0!null\n" + - " │ └─ orders.o_orderkey:5!null\n" + + " └─ LookupJoin\n" + " ├─ Filter\n" + " │ ├─ AND\n" + " │ │ ├─ AND\n" + @@ -1069,15 +1053,13 @@ order by " │ │ └─ LessThan\n" + " │ │ ├─ lineitem.l_receiptdate:3!null\n" + " │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + - " │ └─ IndexedTableAccess(lineitem)\n" + - " │ ├─ index: [lineitem.L_ORDERKEY,lineitem.L_LINENUMBER]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + + " │ └─ ProcessTable\n" + " │ └─ Table\n" + " │ ├─ name: lineitem\n" + " │ └─ columns: [l_orderkey l_shipdate l_commitdate l_receiptdate l_shipmode]\n" + " └─ IndexedTableAccess(orders)\n" + " ├─ index: [orders.O_ORDERKEY]\n" + - " ├─ static: [{[NULL, ∞)}]\n" + + " ├─ keys: [lineitem.l_orderkey]\n" + " └─ Table\n" + " ├─ name: orders\n" + " └─ columns: [o_orderkey o_orderpriority]\n" + @@ -1741,119 +1723,105 @@ order by " ├─ columns: [supplier.s_name:1!null, supplier.s_address:2!null]\n" + " └─ Sort(supplier.s_name:1!null ASC nullsFirst)\n" + " └─ Project\n" + - " ├─ columns: [supplier.S_SUPPKEY:4!null, supplier.S_NAME:5!null, supplier.S_ADDRESS:6!null, supplier.S_NATIONKEY:7!null, supplier.S_PHONE:8!null, supplier.S_ACCTBAL:9!null, supplier.S_COMMENT:10!null, nation.N_NATIONKEY:0!null, nation.N_NAME:1!null, nation.N_REGIONKEY:2!null, nation.N_COMMENT:3]\n" + - " └─ Project\n" + - " ├─ columns: [nation.n_nationkey:8!null, nation.n_name:9!null, nation.N_REGIONKEY:10!null, nation.N_COMMENT:11, supplier.s_suppkey:1!null, supplier.S_NAME:2!null, supplier.S_ADDRESS:3!null, supplier.s_nationkey:4!null, supplier.S_PHONE:5!null, supplier.S_ACCTBAL:6!null, supplier.S_COMMENT:7!null]\n" + - " └─ HashJoin\n" + + " ├─ columns: [supplier.S_SUPPKEY:0!null, supplier.S_NAME:1!null, supplier.S_ADDRESS:2!null, supplier.S_NATIONKEY:3!null, supplier.S_PHONE:4!null, supplier.S_ACCTBAL:5!null, supplier.S_COMMENT:6!null, nation.N_NATIONKEY:7!null, nation.N_NAME:8!null, nation.N_REGIONKEY:9!null, nation.N_COMMENT:10]\n" + + " └─ LookupJoin\n" + + " ├─ Project\n" + + " │ ├─ columns: [supplier.s_suppkey:1!null, supplier.S_NAME:2!null, supplier.S_ADDRESS:3!null, supplier.s_nationkey:4!null, supplier.S_PHONE:5!null, supplier.S_ACCTBAL:6!null, supplier.S_COMMENT:7!null]\n" + + " │ └─ LookupJoin\n" + + " │ ├─ Distinct\n" + + " │ │ └─ Project\n" + + " │ │ ├─ columns: [scalarSubq0.ps_suppkey:1!null]\n" + + " │ │ └─ Filter\n" + + " │ │ ├─ GreaterThan\n" + + " │ │ │ ├─ scalarSubq0.ps_availqty:2!null\n" + + " │ │ │ └─ Subquery\n" + + " │ │ │ ├─ cacheable: false\n" + + " │ │ │ ├─ alias-string: select 0.5 * sum(l_quantity) from lineitem where l_partkey = ps_partkey and l_suppkey = ps_suppkey and l_shipdate >= '1994-01-01' and l_shipdate < '1994-01-01' + interval '1' year\n" + + " │ │ │ └─ Project\n" + + " │ │ │ ├─ columns: [(0.5 (decimal(2,1)) * sum(lineitem.l_quantity):5!null) as 0.5 * sum(l_quantity)]\n" + + " │ │ │ └─ GroupBy\n" + + " │ │ │ ├─ select: SUM(lineitem.l_quantity:7!null)\n" + + " │ │ │ ├─ group: \n" + + " │ │ │ └─ Filter\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ ├─ Eq\n" + + " │ │ │ │ │ │ │ ├─ lineitem.l_partkey:5!null\n" + + " │ │ │ │ │ │ │ └─ partsupp.ps_partkey:0!null\n" + + " │ │ │ │ │ │ └─ Eq\n" + + " │ │ │ │ │ │ ├─ lineitem.l_suppkey:6!null\n" + + " │ │ │ │ │ │ └─ partsupp.ps_suppkey:1!null\n" + + " │ │ │ │ │ └─ GreaterThanOrEqual\n" + + " │ │ │ │ │ ├─ lineitem.l_shipdate:8!null\n" + + " │ │ │ │ │ └─ 1994-01-01 (longtext)\n" + + " │ │ │ │ └─ LessThan\n" + + " │ │ │ │ ├─ lineitem.l_shipdate:8!null\n" + + " │ │ │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + + " │ │ │ └─ Table\n" + + " │ │ │ ├─ name: lineitem\n" + + " │ │ │ └─ columns: [l_partkey l_suppkey l_quantity l_shipdate]\n" + + " │ │ └─ SemiLookupJoin\n" + + " │ │ ├─ TableAlias(scalarSubq0)\n" + + " │ │ │ └─ ProcessTable\n" + + " │ │ │ └─ Table\n" + + " │ │ │ ├─ name: partsupp\n" + + " │ │ │ └─ columns: [ps_partkey ps_suppkey ps_availqty ps_supplycost ps_comment]\n" + + " │ │ └─ Filter\n" + + " │ │ ├─ AND\n" + + " │ │ │ ├─ AND\n" + + " │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ │ │ ├─ AND\n" + + " │ │ │ │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + + " │ │ │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ │ │ │ │ │ └─ forest (longtext)\n" + + " │ │ │ │ │ │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ │ │ │ │ └─ forestÿ (longtext)\n" + + " │ │ │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + + " │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ │ │ │ └─ forest (longtext)\n" + + " │ │ │ │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ │ │ └─ forestÿ (longtext)\n" + + " │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + + " │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ │ └─ forest (longtext)\n" + + " │ │ │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ │ └─ forestÿ (longtext)\n" + + " │ │ │ │ └─ GreaterThanOrEqual\n" + + " │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ │ └─ forest (longtext)\n" + + " │ │ │ └─ LessThanOrEqual\n" + + " │ │ │ ├─ scalarSubq1.p_name:1!null\n" + + " │ │ │ └─ forestÿ (longtext)\n" + + " │ │ └─ TableAlias(scalarSubq1)\n" + + " │ │ └─ IndexedTableAccess(part)\n" + + " │ │ ├─ index: [part.P_PARTKEY]\n" + + " │ │ ├─ keys: [scalarSubq0.ps_partkey]\n" + + " │ │ └─ Table\n" + + " │ │ ├─ name: part\n" + + " │ │ └─ columns: [p_partkey p_name p_mfgr p_brand p_type p_size p_container p_retailprice p_comment]\n" + + " │ └─ IndexedTableAccess(supplier)\n" + + " │ ├─ index: [supplier.S_SUPPKEY]\n" + + " │ ├─ keys: [scalarSubq0.ps_suppkey]\n" + + " │ └─ Table\n" + + " │ ├─ name: supplier\n" + + " │ └─ columns: [s_suppkey s_name s_address s_nationkey s_phone s_acctbal s_comment]\n" + + " └─ Filter\n" + " ├─ Eq\n" + - " │ ├─ supplier.s_suppkey:1!null\n" + - " │ └─ scalarSubq0.ps_suppkey:0!null\n" + - " ├─ Distinct\n" + - " │ └─ Project\n" + - " │ ├─ columns: [scalarSubq0.ps_suppkey:1!null]\n" + - " │ └─ Filter\n" + - " │ ├─ GreaterThan\n" + - " │ │ ├─ scalarSubq0.ps_availqty:2!null\n" + - " │ │ └─ Subquery\n" + - " │ │ ├─ cacheable: false\n" + - " │ │ ├─ alias-string: select 0.5 * sum(l_quantity) from lineitem where l_partkey = ps_partkey and l_suppkey = ps_suppkey and l_shipdate >= '1994-01-01' and l_shipdate < '1994-01-01' + interval '1' year\n" + - " │ │ └─ Project\n" + - " │ │ ├─ columns: [(0.5 (decimal(2,1)) * sum(lineitem.l_quantity):5!null) as 0.5 * sum(l_quantity)]\n" + - " │ │ └─ GroupBy\n" + - " │ │ ├─ select: SUM(lineitem.l_quantity:7!null)\n" + - " │ │ ├─ group: \n" + - " │ │ └─ Filter\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ Eq\n" + - " │ │ │ │ │ │ ├─ lineitem.l_partkey:5!null\n" + - " │ │ │ │ │ │ └─ partsupp.ps_partkey:0!null\n" + - " │ │ │ │ │ └─ Eq\n" + - " │ │ │ │ │ ├─ lineitem.l_suppkey:6!null\n" + - " │ │ │ │ │ └─ partsupp.ps_suppkey:1!null\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ lineitem.l_shipdate:8!null\n" + - " │ │ │ │ └─ 1994-01-01 (longtext)\n" + - " │ │ │ └─ LessThan\n" + - " │ │ │ ├─ lineitem.l_shipdate:8!null\n" + - " │ │ │ └─ 1995-01-01 00:00:00 +0000 UTC (datetime(6))\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: lineitem\n" + - " │ │ └─ columns: [l_partkey l_suppkey l_quantity l_shipdate]\n" + - " │ └─ Project\n" + - " │ ├─ columns: [scalarSubq0.ps_partkey:1!null, scalarSubq0.ps_suppkey:2!null, scalarSubq0.ps_availqty:3!null, scalarSubq0.PS_SUPPLYCOST:4!null, scalarSubq0.PS_COMMENT:5!null]\n" + - " │ └─ MergeJoin\n" + - " │ ├─ cmp: Eq\n" + - " │ │ ├─ scalarSubq1.p_partkey:0!null\n" + - " │ │ └─ scalarSubq0.ps_partkey:1!null\n" + - " │ ├─ Distinct\n" + - " │ │ └─ Project\n" + - " │ │ ├─ columns: [scalarSubq1.p_partkey:0!null]\n" + - " │ │ └─ Filter\n" + - " │ │ ├─ AND\n" + - " │ │ │ ├─ AND\n" + - " │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ │ │ ├─ AND\n" + - " │ │ │ │ │ │ │ │ │ ├─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ │ │ │ │ │ └─ forest (longtext)\n" + - " │ │ │ │ │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ │ │ │ │ └─ forestÿ (longtext)\n" + - " │ │ │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ │ │ │ └─ forest (longtext)\n" + - " │ │ │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ │ │ └─ forestÿ (longtext)\n" + - " │ │ │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ │ └─ forest (longtext)\n" + - " │ │ │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ │ └─ forestÿ (longtext)\n" + - " │ │ │ │ └─ GreaterThanOrEqual\n" + - " │ │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ │ └─ forest (longtext)\n" + - " │ │ │ └─ LessThanOrEqual\n" + - " │ │ │ ├─ scalarSubq1.p_name:1!null\n" + - " │ │ │ └─ forestÿ (longtext)\n" + - " │ │ └─ TableAlias(scalarSubq1)\n" + - " │ │ └─ IndexedTableAccess(part)\n" + - " │ │ ├─ index: [part.P_PARTKEY]\n" + - " │ │ ├─ static: [{[NULL, ∞)}]\n" + - " │ │ └─ Table\n" + - " │ │ ├─ name: part\n" + - " │ │ └─ columns: [p_partkey p_name p_mfgr p_brand p_type p_size p_container p_retailprice p_comment]\n" + - " │ └─ TableAlias(scalarSubq0)\n" + - " │ └─ IndexedTableAccess(partsupp)\n" + - " │ ├─ index: [partsupp.PS_PARTKEY,partsupp.PS_SUPPKEY]\n" + - " │ ├─ static: [{[NULL, ∞), [NULL, ∞)}]\n" + - " │ └─ Table\n" + - " │ ├─ name: partsupp\n" + - " │ └─ columns: [ps_partkey ps_suppkey ps_availqty ps_supplycost ps_comment]\n" + - " └─ HashLookup\n" + - " ├─ left-key: TUPLE(scalarSubq0.ps_suppkey:0!null)\n" + - " ├─ right-key: TUPLE(supplier.s_suppkey:0!null)\n" + - " └─ LookupJoin\n" + - " ├─ ProcessTable\n" + - " │ └─ Table\n" + - " │ ├─ name: supplier\n" + - " │ └─ columns: [s_suppkey s_name s_address s_nationkey s_phone s_acctbal s_comment]\n" + - " └─ Filter\n" + - " ├─ Eq\n" + - " │ ├─ nation.n_name:1!null\n" + - " │ └─ CANADA (longtext)\n" + - " └─ IndexedTableAccess(nation)\n" + - " ├─ index: [nation.N_NATIONKEY]\n" + - " ├─ keys: [supplier.s_nationkey]\n" + - " └─ Table\n" + - " ├─ name: nation\n" + - " └─ columns: [n_nationkey n_name n_regionkey n_comment]\n" + + " │ ├─ nation.n_name:1!null\n" + + " │ └─ CANADA (longtext)\n" + + " └─ IndexedTableAccess(nation)\n" + + " ├─ index: [nation.N_NATIONKEY]\n" + + " ├─ keys: [supplier.s_nationkey]\n" + + " └─ Table\n" + + " ├─ name: nation\n" + + " └─ columns: [n_nationkey n_name n_regionkey n_comment]\n" + "", }, { diff --git a/sql/memo/coster.go b/sql/memo/coster.go index 1fd91242f1..a213b1b053 100644 --- a/sql/memo/coster.go +++ b/sql/memo/coster.go @@ -26,7 +26,7 @@ const ( // reference https://github.com/postgres/postgres/blob/master/src/include/optimizer/cost.h cpuCostFactor = 0.01 seqIOCostFactor = 1 - randIOCostFactor = 2 + randIOCostFactor = 1.3 memCostFactor = 2 concatCostFactor = 0.75 degeneratePenalty = 2.0 From 48af7c32637dacdef68b078f669b21128deed4b4 Mon Sep 17 00:00:00 2001 From: jennifersp <44716627+jennifersp@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:29:07 -0800 Subject: [PATCH 10/11] [no-release-notes] add server engine test to ci (#2123) --- .github/workflows/server-test.yml | 33 +++++++++++++++ enginetest/engine_only_test.go | 43 +++++++++---------- enginetest/enginetests.go | 63 ++++++++++------------------ enginetest/memory_engine_test.go | 58 +++++++++++++++++++------ enginetest/memory_harness.go | 13 +++++- enginetest/queries/queries.go | 2 +- enginetest/queries/script_queries.go | 2 +- enginetest/server_engine.go | 40 +++++++++++++++++- 8 files changed, 175 insertions(+), 79 deletions(-) create mode 100644 .github/workflows/server-test.yml diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml new file mode 100644 index 0000000000..b6e3dfbba8 --- /dev/null +++ b/.github/workflows/server-test.yml @@ -0,0 +1,33 @@ +name: Test Server Engine +on: [pull_request] + +concurrency: + group: server-engine-test-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + matrix: + go-version: [1.20.x] + platform: [ubuntu-latest] + runs-on: ${{ matrix.platform }} + steps: + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v3 + - name: Test using Server Engine + if: ${{ matrix.platform == 'ubuntu-latest' }} + run: go test ./... + env: + CI_TEST: "true" + SERVER_ENGINE_TEST: "true" + - name: Test using Server Engine + if: ${{ matrix.platform == 'ubuntu-latest' }} + run: go test -race ./... + env: + CI_TEST: "true" + SERVER_ENGINE_TEST: "true" diff --git a/enginetest/engine_only_test.go b/enginetest/engine_only_test.go index 6b4167f76c..58b6889b60 100644 --- a/enginetest/engine_only_test.go +++ b/enginetest/engine_only_test.go @@ -79,7 +79,12 @@ func TestWarnings(t *testing.T) { } func TestClearWarnings(t *testing.T) { - enginetest.TestClearWarnings(t, enginetest.NewDefaultMemoryHarness()) + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + // TODO: needs more investigation on this test + t.Skip("depends on Warnings() method call on context") + } + enginetest.TestClearWarnings(t, harness) } func TestUse(t *testing.T) { @@ -91,7 +96,11 @@ func TestNoDatabaseSelected(t *testing.T) { } func TestTracing(t *testing.T) { - enginetest.TestTracing(t, enginetest.NewDefaultMemoryHarness()) + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") + } + enginetest.TestTracing(t, harness) } func TestCurrentTimestamp(t *testing.T) { @@ -158,13 +167,13 @@ func newMockSpan(ctx context.Context) (context.Context, *mockSpan) { func TestRootSpanFinish(t *testing.T) { harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") + } e, err := harness.NewEngine(t) if err != nil { panic(err) } - if enginetest.IsServerEngine(e) { - t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") - } sqlCtx := harness.NewContext() ctx, fakeSpan := newMockSpan(sqlCtx) sql.WithRootSpan(fakeSpan)(sqlCtx) @@ -633,7 +642,7 @@ func TestShowCharset(t *testing.T) { func TestTableFunctions(t *testing.T) { // TODO different error messages - harness := enginetest.NewMemoryHarness("", 1, testNumPartitions, true, nil) + harness := enginetest.NewDefaultMemoryHarness() harness.Setup(setup.MydbData) databaseProvider := harness.NewDatabaseProvider() @@ -688,9 +697,6 @@ func TestTriggerViewWarning(t *testing.T) { harness.Setup(setup.MydbData, setup.MytableData) e, err := harness.NewEngine(t) assert.NoError(t, err) - if enginetest.IsServerEngine(e) { - t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") - } prov := e.EngineAnalyzer().Catalog.DbProvider.(*memory.DbProvider) db, err := prov.Database(nil, "mydb") @@ -704,23 +710,18 @@ func TestTriggerViewWarning(t *testing.T) { assert.NoError(t, err) ctx := harness.NewContext() + enginetest.CreateNewConnectionForServerEngine(ctx, e) - mytableIns := queries.QueryTest{ - Query: "insert into mytable values (4, 'fourth row')", - Expected: []sql.Row{{types.NewOkResult(1)}}, - } - enginetest.TestQueryWithContext(t, ctx, e, harness, mytableIns.Query, mytableIns.Expected, nil, nil) - require.Equal(t, uint16(1), ctx.Session.WarningCount()) - - myViewIns := queries.QueryErrorTest{ - Query: "insert into myview values (5, 'fifth row')", - ExpectedErrStr: "expected insert destination to be resolved or unresolved table", - } - enginetest.AssertErr(t, e, harness, myViewIns.Query, nil, myViewIns.ExpectedErrStr) + enginetest.TestQueryWithContext(t, ctx, e, harness, "insert into mytable values (4, 'fourth row')", []sql.Row{{types.NewOkResult(1)}}, nil, nil) + 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) + enginetest.AssertErrWithCtx(t, e, harness, ctx, "insert into myview values (5, 'fifth row')", nil, "expected insert destination to be resolved or unresolved table") } func TestCollationCoercion(t *testing.T) { harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("TODO: need further investigation") + } harness.Setup(setup.MydbData) engine, err := harness.NewEngine(t) require.NoError(t, err) diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index 8da3a4f2a4..e1b8400184 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -73,15 +73,6 @@ func TestQueries(t *testing.T, harness Harness) { TestQuery2(t, harness, e, tt.Query, tt.Expected, tt.ExpectedColumns, nil) } } - - t.Run("date parse tests", func(t *testing.T) { - harness.Setup(setup.MydbData) - for _, tt := range queries.DateParseQueries { - t.Run(tt.Query, func(t *testing.T) { - TestQueryWithEngine(t, harness, e, tt) - }) - } - }) } // TestStatistics tests the statistics from ANALYZE TABLE @@ -684,7 +675,9 @@ func TestReadOnly(t *testing.T, harness Harness, testStoredProcedures bool) { engine := mustNewEngine(t, harness) e, ok := engine.(*sqle.Engine) - require.True(t, ok, "Need a *sqle.Engine for TestReadOnly") + if !ok { + t.Skip("Need a *sqle.Engine for TestReadOnly") + } e.ReadOnly.Store(true) defer e.Close() @@ -1017,8 +1010,7 @@ func TestTruncate(t *testing.T, harness Harness) { RunQuery(t, e, harness, "CREATE TABLE t2parent (pk BIGINT PRIMARY KEY, v1 BIGINT, INDEX (v1))") RunQuery(t, e, harness, "CREATE TABLE t2child (pk BIGINT PRIMARY KEY, v1 BIGINT, "+ "FOREIGN KEY (v1) REFERENCES t2parent (v1))") - _, _, err := e.Query(ctx, "TRUNCATE t2parent") - require.True(t, sql.ErrTruncateReferencedFromForeignKey.Is(err)) + AssertErrWithCtx(t, e, harness, ctx, "TRUNCATE t2parent", sql.ErrTruncateReferencedFromForeignKey) }) t.Run("ON DELETE Triggers", func(t *testing.T) { @@ -1428,9 +1420,6 @@ func TestUserPrivileges(t *testing.T, harness ClientHarness) { t.Run(script.Name, func(t *testing.T) { engine := mustNewEngine(t, harness) defer engine.Close() - if IsServerEngine(engine) { - t.Skip("TestUserPrivileges test depend on Context to switch the user to run test queries") - } ctx := NewContext(harness) ctx.NewCtxWithClient(sql.Client{ @@ -1496,9 +1485,6 @@ func TestUserPrivileges(t *testing.T, harness ClientHarness) { t.Run(strings.Join(script.Queries, "\n > "), func(t *testing.T) { engine := mustNewEngine(t, harness) defer engine.Close() - if IsServerEngine(engine) { - t.Skip("TestUserPrivileges test depend on Context to switch the user to run test queries") - } engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount() engine.EngineAnalyzer().Catalog.MySQLDb.SetPersister(&mysql_db.NoopPersister{}) @@ -1601,11 +1587,10 @@ func TestUserAuthentication(t *testing.T, h Harness) { } e := mustNewEngine(t, clientHarness) - if IsServerEngine(e) { - t.Skip("TestUserPrivileges test depend on Context to switch the user to run test queries") - } engine, ok := e.(*sqle.Engine) - require.True(t, ok, "Need a *sqle.Engine for TestUserAuthentication") + if !ok { + t.Skip("Need a *sqle.Engine for TestUserAuthentication") + } defer engine.Close() engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount() @@ -1718,8 +1703,8 @@ func TestShowTriggers(t *testing.T, harness Harness) { harness.Setup(setup.MydbData) e := mustNewEngine(t, harness) - // Pick a date - date := time.Unix(0, 0).UTC() + // Pick a valid date + date := time.Unix(1257894000, 0).UTC() // Set up Harness to contain triggers; created at a specific time var ctx *sql.Context @@ -3832,6 +3817,7 @@ func TestClearWarnings(t *testing.T, harness Harness) { harness.Setup(setup.Mytable...) e := mustNewEngine(t, harness) defer e.Close() + ctx := NewContext(harness) err := CreateNewConnectionForServerEngine(ctx, e) require.NoError(err) @@ -3934,7 +3920,9 @@ func TestConcurrentTransactions(t *testing.T, harness Harness) { engine := mustNewEngine(t, harness) e, ok := engine.(*sqle.Engine) - require.True(ok, "Need a *sqle.Engine for TestConcurrentTransactions") + if !ok { + t.Skip("Need a *sqle.Engine for TestConcurrentTransactions") + } defer e.Close() pl := e.ProcessList @@ -4109,8 +4097,6 @@ func TestSessionSelectLimit(t *testing.T, harness Harness) { defer e.Close() ctx := NewContext(harness) if IsServerEngine(e) { - err := CreateNewConnectionForServerEngine(ctx, e) - require.NoError(t, err, nil) RunQueryWithContext(t, e, harness, ctx, "SET @@sql_select_limit = 2") } else { err := ctx.Session.SetSessionVariable(ctx, "sql_select_limit", int64(2)) @@ -4128,11 +4114,8 @@ func TestTracing(t *testing.T, harness Harness) { harness.Setup(setup.MydbData, setup.MytableData) e := mustNewEngine(t, harness) defer e.Close() - if IsServerEngine(e) { - t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") - } - ctx := NewContext(harness) + ctx := NewContext(harness) tracer := new(test.MemTracer) sql.WithTracer(tracer)(ctx) @@ -4300,9 +4283,8 @@ func TestColumnDefaults(t *testing.T, harness Harness) { // Some tests can't currently be run with as a script because they do additional checks t.Run("DATETIME/TIMESTAMP NOW/CURRENT_TIMESTAMP current_timestamp", func(t *testing.T) { - // TODO: fix result formatting for server engine tests if IsServerEngine(e) { - t.Skip() + t.Skip("TODO: fix result formatting for server engine tests") } // ctx = NewContext(harness) // e.Query(ctx, "set @@session.time_zone='SYSTEM';") @@ -4327,9 +4309,8 @@ func TestColumnDefaults(t *testing.T, harness Harness) { // TODO: zero timestamps work slightly differently than they do in MySQL, where the zero time is "0000-00-00 00:00:00" // We use "0000-01-01 00:00:00" t.Run("DATETIME/TIMESTAMP NOW/CURRENT_TIMESTAMP literals", func(t *testing.T) { - // TODO: fix result formatting for server engine tests if IsServerEngine(e) { - t.Skip() + t.Skip("TODO: fix result formatting for server engine tests") } TestQueryWithContext(t, ctx, e, harness, "CREATE TABLE t10zero(pk BIGINT PRIMARY KEY, v1 DATETIME DEFAULT '2020-01-01 01:02:03', v2 DATETIME DEFAULT 0,"+ "v3 TIMESTAMP DEFAULT '2020-01-01 01:02:03', v4 TIMESTAMP DEFAULT 0)", []sql.Row{{types.NewOkResult(0)}}, nil, nil) @@ -4404,9 +4385,6 @@ func TestPersist(t *testing.T, harness Harness, newPersistableSess func(ctx *sql harness.Setup(setup.MydbData, setup.MytableData) e := mustNewEngine(t, harness) defer e.Close() - if IsServerEngine(e) { - t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") - } for _, tt := range q { t.Run(tt.Name, func(t *testing.T) { @@ -4731,6 +4709,7 @@ func TestCharsetCollationEngine(t *testing.T, harness Harness) { t.Run(script.Name, func(t *testing.T) { engine := mustNewEngine(t, harness) defer engine.Close() + ctx := harness.NewContext() ctx.SetCurrentDatabase("mydb") @@ -4797,7 +4776,9 @@ func testCharsetCollationWire(t *testing.T, h Harness, sessionBuilder server.Ses engine, ok := e.(*sqle.Engine) // TODO: do we? - require.True(t, ok, "Need a *sqle.Engine for testCharsetCollationWire") + if !ok { + t.Skip("Need a *sqle.Engine for testCharsetCollationWire") + } defer engine.Close() engine.EngineAnalyzer().Catalog.MySQLDb.AddRootAccount() @@ -4873,7 +4854,9 @@ func TestTypesOverWire(t *testing.T, harness ClientHarness, sessionBuilder serve engine, ok := e.(*sqle.Engine) // TODO: do we? - require.True(t, ok, "Need a *sqle.Engine for TestTypesOverWire") + if !ok { + t.Skip("Need a *sqle.Engine for TestTypesOverWire") + } defer engine.Close() ctx := NewContextWithClient(harness, sql.Client{ diff --git a/enginetest/memory_engine_test.go b/enginetest/memory_engine_test.go index 538ff51cbe..cc194b2074 100644 --- a/enginetest/memory_engine_test.go +++ b/enginetest/memory_engine_test.go @@ -88,48 +88,52 @@ func TestQueries(t *testing.T) { // TestQueriesPreparedSimple runs the canonical test queries against a single threaded index enabled harness. func TestQueriesPreparedSimple(t *testing.T) { - enginetest.TestQueriesPrepared(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("issue: https://github.com/dolthub/dolt/issues/6904 and https://github.com/dolthub/dolt/issues/6901") + } + enginetest.TestQueriesPrepared(t, harness) } // TestQueriesSimple runs the canonical test queries against a single threaded index enabled harness. func TestQueriesSimple(t *testing.T) { - harness := enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil) + harness := enginetest.NewDefaultMemoryHarness() enginetest.TestQueries(t, harness) } // TestJoinQueries runs the canonical test queries against a single threaded index enabled harness. func TestJoinQueries(t *testing.T) { - enginetest.TestJoinQueries(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestJoinQueries(t, enginetest.NewDefaultMemoryHarness()) } func TestLateralJoin(t *testing.T) { - enginetest.TestLateralJoinQueries(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestLateralJoinQueries(t, enginetest.NewDefaultMemoryHarness()) } // TestJoinPlanning runs join-specific tests for merge func TestJoinPlanning(t *testing.T) { - enginetest.TestJoinPlanning(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestJoinPlanning(t, enginetest.NewDefaultMemoryHarness()) } // TestJoinOps runs join-specific tests for merge func TestJoinOps(t *testing.T) { - enginetest.TestJoinOps(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestJoinOps(t, enginetest.NewDefaultMemoryHarness()) } // TestJSONTableQueries runs the canonical test queries against a single threaded index enabled harness. func TestJSONTableQueries(t *testing.T) { - enginetest.TestJSONTableQueries(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestJSONTableQueries(t, enginetest.NewDefaultMemoryHarness()) } // TestJSONTableScripts runs the canonical test queries against a single threaded index enabled harness. func TestJSONTableScripts(t *testing.T) { - enginetest.TestJSONTableScripts(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestJSONTableScripts(t, enginetest.NewDefaultMemoryHarness()) } // TestBrokenJSONTableScripts runs the canonical test queries against a single threaded index enabled harness. func TestBrokenJSONTableScripts(t *testing.T) { t.Skip("incorrect errors and unsupported json_table functionality") - enginetest.TestBrokenJSONTableScripts(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil)) + enginetest.TestBrokenJSONTableScripts(t, enginetest.NewDefaultMemoryHarness()) } // Convenience test for debugging a single query. Unskip and set to the desired query. @@ -258,7 +262,7 @@ func TestUnbuildableIndex(t *testing.T) { } for _, test := range scripts { - harness := enginetest.NewMemoryHarness("", 1, testNumPartitions, true, nil) + harness := enginetest.NewDefaultMemoryHarness() enginetest.TestScript(t, harness, test) } } @@ -301,6 +305,10 @@ func TestAnsiQuotesSqlMode(t *testing.T) { } func TestAnsiQuotesSqlModePrepared(t *testing.T) { + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("prepared test depend on context for current sql_mode information, but it does not get updated when using ServerEngine") + } enginetest.TestAnsiQuotesSqlModePrepared(t, enginetest.NewDefaultMemoryHarness()) } @@ -570,11 +578,19 @@ func TestSpatialIndexPlans(t *testing.T) { } func TestUserPrivileges(t *testing.T) { - enginetest.TestUserPrivileges(t, enginetest.NewMemoryHarness("default", 1, testNumPartitions, true, mergableIndexDriver)) + harness := enginetest.NewMemoryHarness("default", 1, testNumPartitions, true, mergableIndexDriver) + if harness.IsUsingServer() { + t.Skip("TestUserPrivileges test depend on Context to switch the user to run test queries") + } + enginetest.TestUserPrivileges(t, harness) } func TestUserAuthentication(t *testing.T) { - enginetest.TestUserAuthentication(t, enginetest.NewMemoryHarness("default", 1, testNumPartitions, true, mergableIndexDriver)) + harness := enginetest.NewMemoryHarness("default", 1, testNumPartitions, true, mergableIndexDriver) + if harness.IsUsingServer() { + t.Skip("TestUserPrivileges test depend on Context to switch the user to run test queries") + } + enginetest.TestUserAuthentication(t, harness) } func TestPrivilegePersistence(t *testing.T) { @@ -753,6 +769,10 @@ func TestAlterTable(t *testing.T) { } func TestDateParse(t *testing.T) { + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("issue: https://github.com/dolthub/dolt/issues/6901") + } enginetest.TestDateParse(t, enginetest.NewDefaultMemoryHarness()) } @@ -793,6 +813,9 @@ func TestIndexPrefix(t *testing.T) { func TestPersist(t *testing.T) { harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("this test depends on Context, which ServerEngine does not depend on or update the current context") + } newSess := func(_ *sql.Context) sql.PersistableSession { ctx := harness.NewSession() persistedGlobals := memory.GlobalsMap{} @@ -809,6 +832,9 @@ func TestValidateSession(t *testing.T) { } harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + t.Skip("It depends on ValidateSession() method call on context") + } newSess := func(ctx *sql.Context) sql.PersistableSession { memSession := ctx.Session.(*memory.Session) memSession.SetValidationCallback(incrementValidateCb) @@ -830,7 +856,13 @@ func TestPreparedStatements(t *testing.T) { } func TestCharsetCollationEngine(t *testing.T) { - enginetest.TestCharsetCollationEngine(t, enginetest.NewDefaultMemoryHarness()) + harness := enginetest.NewDefaultMemoryHarness() + if harness.IsUsingServer() { + // Note: charset introducer needs to be handled with the SQLVal when preparing + // e.g. what we do currently for `_utf16'hi'` is `_utf16 :v1` with v1 = "hi", instead of `:v1` with v1 = "_utf16'hi'". + t.Skip("way we prepare the queries with injectBindVarsAndPrepare() method does not work for ServerEngine test") + } + enginetest.TestCharsetCollationEngine(t, harness) } func TestCharsetCollationWire(t *testing.T) { diff --git a/enginetest/memory_harness.go b/enginetest/memory_harness.go index 253c8d9ab1..9f5c07280c 100644 --- a/enginetest/memory_harness.go +++ b/enginetest/memory_harness.go @@ -17,6 +17,7 @@ package enginetest import ( "context" "fmt" + "os" "strings" "sync" "testing" @@ -70,6 +71,11 @@ func NewMemoryHarness(name string, parallelism int, numTablePartitions int, useN externalProcedureRegistry.Register(esp) } + var useServer bool + if _, ok := os.LookupEnv("SERVER_ENGINE_TEST"); ok { + useServer = true + } + return &MemoryHarness{ name: name, numTablePartitions: numTablePartitions, @@ -79,6 +85,7 @@ func NewMemoryHarness(name string, parallelism int, numTablePartitions int, useN skippedQueries: make(map[string]struct{}), externalProcedureRegistry: externalProcedureRegistry, mu: &sync.Mutex{}, + server: useServer, } } @@ -87,7 +94,7 @@ func NewDefaultMemoryHarness() *MemoryHarness { } func NewReadOnlyMemoryHarness() *MemoryHarness { - h := NewMemoryHarness("default", 1, testNumPartitions, true, nil) + h := NewDefaultMemoryHarness() h.readonly = true return h } @@ -143,6 +150,10 @@ func (m *MemoryHarness) UseServer() { m.server = true } +func (m *MemoryHarness) IsUsingServer() bool { + return m.server +} + type SkippingMemoryHarness struct { MemoryHarness } diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index 9b7b27a0c1..ff85a74089 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -10369,7 +10369,7 @@ var IndexPrefixQueries = []ScriptTest{ Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `b` blob,\n PRIMARY KEY (`i`),\n KEY `b` (`b`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}}, }, { - Query: "insert into t values (998, X'4242');;", + Query: "insert into t values (998, X'4242');", Expected: []sql.Row{{types.NewOkResult(1)}}, }, { diff --git a/enginetest/queries/script_queries.go b/enginetest/queries/script_queries.go index d130f9dce6..4a7cb80b94 100644 --- a/enginetest/queries/script_queries.go +++ b/enginetest/queries/script_queries.go @@ -561,7 +561,7 @@ var ScriptTests = []ScriptTest{ }, }, { - Name: "trigger with signal and user var", + Name: "alter table out of range value error of column type change", SetUpScript: []string{ "create table t (i int primary key, i2 int, key(i2));", "insert into t values (0,-1)", diff --git a/enginetest/server_engine.go b/enginetest/server_engine.go index f2bf7435b4..2b93129446 100644 --- a/enginetest/server_engine.go +++ b/enginetest/server_engine.go @@ -27,6 +27,7 @@ import ( "github.com/dolthub/vitess/go/vt/proto/query" "github.com/dolthub/vitess/go/vt/sqlparser" + "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql" sqle "github.com/dolthub/go-mysql-server" @@ -132,6 +133,9 @@ func (s *ServerQueryEngine) Query(ctx *sql.Context, query string) (sql.Schema, s // For example, `USE db` does not change the db in the ctx. return s.QueryWithBindings(ctx, query, nil, nil) } + if _, ok := cannotBePrepared[query]; ok { + return s.QueryWithBindings(ctx, query, nil, nil) + } return s.QueryWithBindings(ctx, q, nil, bindVars) } @@ -159,7 +163,15 @@ func (s *ServerQueryEngine) QueryWithBindings(ctx *sql.Context, query string, pa if strings.HasSuffix(err.Error(), "empty statement") { return nil, sql.RowsToRowIter(), nil } - return nil, nil, err + // Note: we cannot access sql_mode when using ServerEngine + // to use ParseWithOptions() method. Replacing double quotes + // because the 'ANSI' mode is not on by default and will not + // be set on the context after SET @@sql_mode = 'ANSI' query. + ansiQuery := strings.Replace(query, "\"", "`", -1) + parsed, err = sqlparser.Parse(ansiQuery) + if err != nil { + return nil, nil, err + } } } @@ -200,10 +212,20 @@ func (s *ServerQueryEngine) QueryWithBindings(ctx *sql.Context, query string, pa // trimMySQLErrCodePrefix temporarily removes the error code part of the error message returned from the server. // This allows us to assert the error message strings in the enginetest. func trimMySQLErrCodePrefix(err error) error { - r := strings.Split(err.Error(), "(HY000): ") + errMsg := err.Error() + r := strings.Split(errMsg, "(HY000): ") if len(r) == 2 { return errors.New(r[1]) } + if e, ok := err.(*mysql.MySQLError); ok { + // Note: the error msg can be fixed to match with MySQLError at https://github.com/dolthub/vitess/blob/main/go/mysql/sql_error.go#L62 + return errors.New(fmt.Sprintf("%s (errno %v) (sqlstate %s)", e.Message, e.Number, e.SQLState)) + } + if strings.HasPrefix(errMsg, "sql: expected") && strings.Contains(errMsg, "arguments, got") { + // TODO: needs better error message for non matching number of binding argument + // for Dolt, this error is caught on the first binding variable + err = sql.ErrUnboundPreparedStatementVariable.New("v1") + } return err } @@ -640,3 +662,17 @@ func enableUserAccounts(ctx *sql.Context, engine *sqle.Engine) error { return nil } + +// We skip preparing these queries using injectBindVarsAndPrepare() method. They fail because +// injectBindVarsAndPrepare() method causes the non-string sql values to become string values. +// Other queries simply cause incorrect type result, which is not checked for ServerEngine test for now. +// TODO: remove this map when we fix this issue. +var cannotBePrepared = map[string]bool{ + "with recursive t (n) as (select (1) from dual union all select n + 1 from t where n < 10002) select sum(n) from t": true, + //"DELETE FROM mytable WHERE i = ?": true, + "REPLACE INTO `GzaKtwgIya` VALUES ('58567047399981325523662211357420045483361289734772861386428.89028','bvo5~Tt8%kMW2nm2!8HghaeulI6!pMadE+j-J2LeU1O1*-#@Lm8Ibh00bTYiA*H1Q8P1_kQq 24Rrd4@HeF%#7#C#U7%mqOMrQ0%!HVrGV1li.XyYa:7#3V^DtAMDTQ9 cY=07T4|DStrwy4.MAQxOG#1d#fcq+7675$y0e96-2@8-WlQ^p|%E!a^TV!Yj2_eqZZys1z:883l5I%zAT:i56K^T!cx#us $60Tb#gH$1#$P.709E#VrH9FbQ5QZK2hZUH!qUa4Xl8*I*0fT~oAha$8jU5AoWs+Uv!~:14Yq%pLXpP9RlZ:Gd1g|*$Qa.9*^K~YlYWVaxwY~_g6zOMpU$YijT+!_*m3=||cMNn#uN0!!OyCg~GTQlJ11+#@Ohqc7b#2|Jp2Aei56GOmq^I=7cQ=sQh~V.D^HzwK5~4E$QzFXfWNVN5J_w2b4dkR~bB~7F%=@R@9qE~e:-_RnoJcOLfBS@0:*hTIP$5ui|5Ea-l+qU4nx98X6rV2bLBxn8am@p~:xLF#T^_9kJVN76q^18=i *FJo.v-xA2GP==^C^Jz3yBF0OY4bIxC59Y#6G=$w:xh71kMxBcYJKf3+$Ci_uWx0P*AfFNne0_1E0Lwv#3J8vm:. 8Wo~F3VT:@w.t@w .JZz$bok9Tls7RGo=~4 Y$~iELr$s@53YuTPM8oqu!x*1%GswpJR=0K#qs00nW-1MqEUc:0wZv#X4qY^pzVDb:!:!yDhjhh+KIT%2%w@+t8c!f~o!%EnwBIr_OyzL6e1$-R8n0nWPU.toODd*|fW3H$9ZLc9!dMS:QfjI0M$nK 8aGvUVP@9kS~W#Y=Q%=37$@pAUkDTXkJo~-DRvCG6phPp*Xji@9|AEODHi+-6p%X4YM5Y3WasPHcZQ8QgTwi9 N=2RQD_MtVU~0J~3SAx*HrMlKvCPTswZq#q_96ny_A@7g!E2jyaxWFJD:C233onBdchW$WdAc.LZdZHYDR^uwZb9B9p-q.BkD1I',608583,'-7.276514330627342e-28','FN3O_E:$ 5S40T7^Vu1g!Ktn^N|4RE!9GnZiW5dG:%SJb5|SNuuI.d2^qnMY.Xn*_fRfk Eo7OhqY8OZ~pA0^ !2P.uN~r@pZ2!A0+4b*%nxO.tm%S6=$CZ9+c1zu-p $b:7:fOkC%@E3951st@2Q93~8hj:ZGeJ6S@nw-TAG+^lad37aB#xN*rD^9TO0|hleA#.Nh28S2PB72L*TxD0$|XE3S5eVVmbI*pkzE~lPecopX1fUyFj#LC+%~pjmab7^ Kdd4B%8I!ohOCQV.oiw++N|#W2=D4:_sK0@~kTTeNA8_+FMKRwro.M0| LdKHf-McKm0Z-R9+H%!9r l6%7UEB50yNH-ld%eW8!f=LKgZLc*TuTP2DA_o0izvzZokNp3ShR+PA7Fk* 1RcSt5KXe+8tLc+WGP','3RvfN2N.Q1tIffE965#2r=u_-4!u:9w!F1p7+mSsO8ckio|ib 1t@~GtgUkJX',1858932,'DJMaQcI=vS-Jk2L#^2N8qZcRpMJ2Ga!30A+@I!+35d-9bwVEVi5-~i.a%!KdoF5h','1.0354401044541863e+255');": true, + "INSERT INTO `GzaKtwgIya` VALUES ('91198031969464085142628031466155813748261645250257051732159.65596','96Lu=focmodq4otVAUN6TD-F$@k^4443higo=KH!1WBDH9|vpEGdO* 1uF6yWjT4:7G|altXnWSv+d:c8Km8vL!b%-nuB8mAxO9E|a5N5#v@z!ij5ifeIEoZGXrhBJl.m*Rx-@%g~t:y$3Pp3Q7Bd3y$=YG%6yibqXWO9$SS+g=*6QzdSCzuR~@v!:.ATye0A@y~DG=uq!PaZd6wN7.2S Aq868-RN3RM61V#N+Qywqo=%iYV*554@h6GPKZ| pmNwQw=PywuyBhr*MHAOXV+u9_-#imKI-wT4gEcA1~lGg1cfL2IvhkwOXRhrjAx-8+R3#4!Ai J6SYP|YUuuGalJ_N8k_8K^~h!JyiH$0JbGQ4AOxO3-eW=BaopOd8FF1.cfFMK!tXR ^I15g:npOuZZO$Vq3yQ4bl4s$E9:t2^.4f.:I4_@u9_UI1ApBthJZNiv~o#*uhs9K@ufZ1YPJQY-pMj$v-lQ2#%=Uu!iEAO3%vQ^5YITKcWRk~$kd1H#F675r@P5#M%*F_xP3Js7$YuEC4YuQjZ A74tMw:KwQ8dR:k_ Sa85G~42-K3%:jk5G9csC@iW3nY|@-:_dg~5@J!FWF5F+nyBgz4fDpdkdk9^:_.t$A3W-C@^Ax.~o|Rq96_i%HeG*7jBjOGhY-e1k@aD@WW.@GmpGAI|T-84gZFG3BU9@#9lpL|U2YCEA.BEA%sxDZ Kw:n+d$Y!SZw0Iml$Bdtyr:02Np=DZpiI%$N9*U=%Jq#$P5BI60WOTK+UynVx9Dd**5q8y9^v+I|PPa#_2XheV5YQU.ONdQQNJxsiRaEl!*=xv4bTWj1wBH#_-eM3T',490529,'-8.419238802182018e+25','|WD!NpWJOfN+_Au 1y!|XF8l38#%%R5%$TRUEaFt%4ywKQ8 O1LD-3qRDrnHAXboH~0uivbo87f+V%=q9~Mvz1EIxsU!whSmPqtb9r*11346R_@L+H#@@Z9H-Dc6j%.D0o##m@B9o7jO#~N81ACI|f#J3z4dho:jc54Xws$8r%cxuov^1$w_58Fv2*.8qbAW$TF153A:8wwj4YIhkd#^Q7 |g7I0iQG0p+yE64rk!Pu!SA-z=ELtLNOCJBk_4!lV$izn%sB6JwM+uq~ 49I7','v|eUA_h2@%t~bn26ci8Ngjm@Lk*G=l2MhxhceV2V|ka#c',8150267,'nX-=1Q$3riw_jlukGuHmjodT_Y_SM$xRbEt$%$%hlIUF1+GpRp~U6JvRX^: k@n#','7.956726808353253e+267');": true, + `INSERT INTO test VALUES (0, 1), ("b", "y"), ("b,c", "z,z"), ("a,c,b", 10);`: true, + "insert into t values (998, X'4242');": true, + `select """""foo""""";`: true, +} From 853f9cf01f2e5555a66bd974eaa26db15bc46053 Mon Sep 17 00:00:00 2001 From: Max Hoffman Date: Tue, 7 Nov 2023 15:07:31 -0800 Subject: [PATCH 11/11] skip index check on server tests --- enginetest/evaluation.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/enginetest/evaluation.go b/enginetest/evaluation.go index 5232acc68d..902e68f523 100644 --- a/enginetest/evaluation.go +++ b/enginetest/evaluation.go @@ -354,10 +354,11 @@ func TestQueryWithIndexCheck(t *testing.T, ctx *sql.Context, e QueryEngine, harn require.NoError(err) } - node, err := e.AnalyzeQuery(ctx, q) - require.NoError(err, "Unexpected error for query %s: %s", q, err) - - require.True(CheckIndexedAccess(node), "expected plan to have index, but found: %s", sql.DebugString(node)) + if _, ok := e.(*ServerQueryEngine); !ok { + node, err := e.AnalyzeQuery(ctx, q) + require.NoError(err, "Unexpected error for query %s: %s", q, err) + require.True(CheckIndexedAccess(node), "expected plan to have index, but found: %s", sql.DebugString(node)) + } sch, iter, err := e.QueryWithBindings(ctx, q, nil, bindings) require.NoError(err, "Unexpected error for query %s: %s", q, err)