mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-21 11:29:51 -05:00
Merge pull request #4785 from dolthub/james/inline-string-index
use prefix indexes for inline string columns
This commit is contained in:
@@ -58,7 +58,7 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.1.3
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/creasty/defaults v1.6.0
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115164917-f8c6c16520ab
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115231632-9a7e526cf95d
|
||||
github.com/google/flatbuffers v2.0.6+incompatible
|
||||
github.com/kch42/buzhash v0.0.0-20160816060738-9bdec3dec7c6
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
|
||||
@@ -180,8 +180,8 @@ github.com/dolthub/flatbuffers v1.13.0-dh.1 h1:OWJdaPep22N52O/0xsUevxJ6Qfw1M2txC
|
||||
github.com/dolthub/flatbuffers v1.13.0-dh.1/go.mod h1:CorYGaDmXjHz1Z7i50PYXG1Ricn31GcA2wNOTFIQAKE=
|
||||
github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U=
|
||||
github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0=
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115164917-f8c6c16520ab h1:xBvGPqRiDoi+jLAuCmLGN1qj7DeC9fJ7/ATz8bKq/J4=
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115164917-f8c6c16520ab/go.mod h1:KtpU4Sf7J+SIat/nxoA733QTn3tdL34NtoGxEBFcTsA=
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115231632-9a7e526cf95d h1:C/eCuecwWpC1Za860FRULxRsl+jyCoeeasfQkm0m//E=
|
||||
github.com/dolthub/go-mysql-server v0.14.1-0.20221115231632-9a7e526cf95d/go.mod h1:KtpU4Sf7J+SIat/nxoA733QTn3tdL34NtoGxEBFcTsA=
|
||||
github.com/dolthub/ishell v0.0.0-20220112232610-14e753f0f371 h1:oyPHJlzumKta1vnOQqUnfdz+pk3EmnHS3Nd0cCT0I2g=
|
||||
github.com/dolthub/ishell v0.0.0-20220112232610-14e753f0f371/go.mod h1:dhGBqcCEfK5kuFmeO5+WOx3hqc1k3M29c1oS/R7N4ms=
|
||||
github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474 h1:xTrR+l5l+1Lfq0NvhiEsctylXinUMFhhsqaEcl414p8=
|
||||
|
||||
@@ -8166,448 +8166,152 @@ var DoltCommitTests = []queries.ScriptTest{
|
||||
|
||||
var DoltIndexPrefixScripts = []queries.ScriptTest{
|
||||
{
|
||||
Name: "varchar primary key prefix",
|
||||
Name: "inline secondary indexes with collation",
|
||||
SetUpScript: []string{
|
||||
"create table t (v varchar(100))",
|
||||
"create table t (i int primary key, v1 varchar(10), v2 varchar(10), unique index (v1(3),v2(5))) collate utf8mb4_0900_ai_ci",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (v(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (v varchar(100), primary key (v(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "varchar keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, v varchar(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (v(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `v` varchar(10),\n PRIMARY KEY (`i`),\n UNIQUE KEY `v` (`v`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `v1` varchar(10) COLLATE utf8mb4_0900_ai_ci,\n `v2` varchar(10) COLLATE utf8mb4_0900_ai_ci,\n PRIMARY KEY (`i`),\n UNIQUE KEY `v1v2` (`v1`(3),`v2`(5))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
Query: "insert into t values (0, 'a', 'a'), (1, 'ab','ab'), (2, 'abc', 'abc'), (3, 'abcde', 'abcde')",
|
||||
Expected: []sql.Row{{sql.NewOkResult(4)}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (99, 'ABC', 'ABCDE')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'bb'), (2, 'cc')",
|
||||
Expected: []sql.Row{{sql.NewOkResult(3)}},
|
||||
Query: "insert into t values (99, 'ABC123', 'ABCDE123')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v = 'a'",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v = 'aa'",
|
||||
Query: "select * from t where v1 = 'A'",
|
||||
Expected: []sql.Row{
|
||||
{0, "aa"},
|
||||
{0, "a", "a"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (i int primary key, v varchar(100), index (v(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
Query: "explain select * from t where v1 = 'A'",
|
||||
Expected: []sql.Row{
|
||||
{"Filter(t.v1 = 'A')"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" ├─ filters: [{[A, A], [NULL, ∞)}]"},
|
||||
{" └─ columns: [i v1 v2]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v1 = 'ABC'",
|
||||
Expected: []sql.Row{
|
||||
{2, "abc", "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "explain select * from t where v1 = 'ABC'",
|
||||
Expected: []sql.Row{
|
||||
{"Filter(t.v1 = 'ABC')"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" ├─ filters: [{[ABC, ABC], [NULL, ∞)}]"},
|
||||
{" └─ columns: [i v1 v2]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v1 = 'ABCD'",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
{
|
||||
Query: "explain select * from t where v1 = 'ABCD'",
|
||||
Expected: []sql.Row{
|
||||
{"Filter(t.v1 = 'ABCD')"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" ├─ filters: [{[ABCD, ABCD], [NULL, ∞)}]"},
|
||||
{" └─ columns: [i v1 v2]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v1 > 'A' and v1 < 'ABCDE'",
|
||||
Expected: []sql.Row{
|
||||
{1, "ab", "ab"},
|
||||
{2, "abc", "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "explain select * from t where v1 > 'A' and v1 < 'ABCDE'",
|
||||
Expected: []sql.Row{
|
||||
{"Filter((t.v1 > 'A') AND (t.v1 < 'ABCDE'))"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" ├─ filters: [{(A, ABCDE), [NULL, ∞)}]"},
|
||||
{" └─ columns: [i v1 v2]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "select * from t where v1 > 'A' and v2 < 'ABCDE'",
|
||||
Expected: []sql.Row{
|
||||
{1, "ab", "ab"},
|
||||
{2, "abc", "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "explain select * from t where v1 > 'A' and v2 < 'ABCDE'",
|
||||
Expected: []sql.Row{
|
||||
{"Filter((t.v1 > 'A') AND (t.v2 < 'ABCDE'))"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" ├─ filters: [{(A, ∞), (NULL, ABCDE)}]"},
|
||||
{" └─ columns: [i v1 v2]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "update t set v1 = concat(v1, 'Z') where v1 >= 'A'",
|
||||
Expected: []sql.Row{
|
||||
{sql.OkResult{RowsAffected: 4, InsertID: 0, Info: plan.UpdateInfo{Matched: 4, Updated: 4}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "explain update t set v1 = concat(v1, 'Z') where v1 >= 'A'",
|
||||
Expected: []sql.Row{
|
||||
{"Update"},
|
||||
{" └─ UpdateSource(SET t.v1 = concat(t.v1, 'Z'))"},
|
||||
{" └─ Filter(t.v1 >= 'A')"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" └─ filters: [{[A, ∞), [NULL, ∞)}]"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "select * from t",
|
||||
Expected: []sql.Row{
|
||||
{0, "aZ", "a"},
|
||||
{1, "abZ", "ab"},
|
||||
{2, "abcZ", "abc"},
|
||||
{3, "abcdeZ", "abcde"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "delete from t where v1 >= 'A'",
|
||||
Expected: []sql.Row{
|
||||
{sql.OkResult{RowsAffected: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: "show create table v_tbl",
|
||||
Expected: []sql.Row{{"v_tbl", "CREATE TABLE `v_tbl` (\n `i` int NOT NULL,\n `v` varchar(100),\n PRIMARY KEY (`i`),\n KEY `v` (`v`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
Query: "explain delete from t where v1 >= 'A'",
|
||||
Expected: []sql.Row{
|
||||
{"Delete"},
|
||||
{" └─ Filter(t.v1 >= 'A')"},
|
||||
{" └─ IndexedTableAccess(t)"},
|
||||
{" ├─ index: [t.v1,t.v2]"},
|
||||
{" └─ filters: [{[A, ∞), [NULL, ∞)}]"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "varchar keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (v varchar(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (v(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `v` varchar(10),\n UNIQUE KEY `v` (`v`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (v varchar(100), index (v(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table v_tbl",
|
||||
Expected: []sql.Row{{"v_tbl", "CREATE TABLE `v_tbl` (\n `v` varchar(100),\n KEY `v` (`v`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "char primary key prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (c char(100))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (c(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table c_tbl (c char(100), primary key (c(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "char keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, c char(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (c(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `c` char(10),\n PRIMARY KEY (`i`),\n UNIQUE KEY `c` (`c`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table c_tbl (i int primary key, c varchar(100), index (c(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table c_tbl",
|
||||
Expected: []sql.Row{{"c_tbl", "CREATE TABLE `c_tbl` (\n `i` int NOT NULL,\n `c` varchar(100),\n PRIMARY KEY (`i`),\n KEY `c` (`c`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "char keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (c char(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (c(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `c` char(10),\n UNIQUE KEY `c` (`c`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table c_tbl (c char(100), index (c(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table c_tbl",
|
||||
Expected: []sql.Row{{"c_tbl", "CREATE TABLE `c_tbl` (\n `c` char(100),\n KEY `c` (`c`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "varbinary primary key prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (v varbinary(100))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (v(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (v varbinary(100), primary key (v(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "varbinary keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, v varbinary(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (v(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `v` varbinary(10),\n PRIMARY KEY (`i`),\n UNIQUE KEY `v` (`v`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (i int primary key, v varbinary(100), index (v(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table v_tbl",
|
||||
Expected: []sql.Row{{"v_tbl", "CREATE TABLE `v_tbl` (\n `i` int NOT NULL,\n `v` varbinary(100),\n PRIMARY KEY (`i`),\n KEY `v` (`v`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "varbinary keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (v varbinary(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (v(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `v` varbinary(10),\n UNIQUE KEY `v` (`v`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table v_tbl (v varbinary(100), index (v(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table v_tbl",
|
||||
Expected: []sql.Row{{"v_tbl", "CREATE TABLE `v_tbl` (\n `v` varbinary(100),\n KEY `v` (`v`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "binary primary key prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (b binary(100))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (b(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (b binary(100), primary key (b(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "binary keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, b binary(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (b(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `b` binary(10),\n PRIMARY KEY (`i`),\n UNIQUE KEY `b` (`b`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (i int primary key, b binary(100), index (b(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table b_tbl",
|
||||
Expected: []sql.Row{{"b_tbl", "CREATE TABLE `b_tbl` (\n `i` int NOT NULL,\n `b` binary(100),\n PRIMARY KEY (`i`),\n KEY `b` (`b`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "binary keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (b binary(10))",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (b(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `b` binary(10),\n UNIQUE KEY `b` (`b`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (b binary(100), index (b(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table b_tbl",
|
||||
Expected: []sql.Row{{"b_tbl", "CREATE TABLE `b_tbl` (\n `b` binary(100),\n KEY `b` (`b`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "blob primary key prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (b blob)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (b(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (b blob, primary key (b(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "blob keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, b blob)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (b(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `b` blob,\n PRIMARY KEY (`i`),\n UNIQUE KEY `b` (`b`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (i int primary key, b blob, index (b(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table b_tbl",
|
||||
Expected: []sql.Row{{"b_tbl", "CREATE TABLE `b_tbl` (\n `i` int NOT NULL,\n `b` blob,\n PRIMARY KEY (`i`),\n KEY `b` (`b`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "blob keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (b blob)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (b(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `b` blob,\n UNIQUE KEY `b` (`b`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (b blob, index (b(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table b_tbl",
|
||||
Expected: []sql.Row{{"b_tbl", "CREATE TABLE `b_tbl` (\n `b` blob,\n KEY `b` (`b`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "text primary key prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (t text)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add primary key (t(10))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
{
|
||||
Query: "create table b_tbl (t text, primary key (t(10)))",
|
||||
ExpectedErr: sql.ErrUnsupportedIndexPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "text keyed secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (i int primary key, t text)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (t(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `i` int NOT NULL,\n `t` text,\n PRIMARY KEY (`i`),\n UNIQUE KEY `t` (`t`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values (0, 'aa'), (1, 'ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table t_tbl (i int primary key, t text, index (t(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t_tbl",
|
||||
Expected: []sql.Row{{"t_tbl", "CREATE TABLE `t_tbl` (\n `i` int NOT NULL,\n `t` text,\n PRIMARY KEY (`i`),\n KEY `t` (`t`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "text keyless secondary index prefix",
|
||||
SetUpScript: []string{
|
||||
"create table t (t text)",
|
||||
},
|
||||
Assertions: []queries.ScriptTestAssertion{
|
||||
{
|
||||
Query: "alter table t add unique index (t(1))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t",
|
||||
Expected: []sql.Row{{"t", "CREATE TABLE `t` (\n `t` text,\n UNIQUE KEY `t` (`t`(1))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
},
|
||||
{
|
||||
Query: "insert into t values ('aa'), ('ab')",
|
||||
ExpectedErr: sql.ErrUniqueKeyViolation,
|
||||
},
|
||||
{
|
||||
Query: "create table t_tbl (t text, index (t(10)))",
|
||||
Expected: []sql.Row{{sql.NewOkResult(0)}},
|
||||
},
|
||||
{
|
||||
Query: "show create table t_tbl",
|
||||
Expected: []sql.Row{{"t_tbl", "CREATE TABLE `t_tbl` (\n `t` text,\n KEY `t` (`t`(10))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
|
||||
Query: "select * from t",
|
||||
Expected: []sql.Row{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -395,8 +395,18 @@ var _ DoltIndex = (*doltIndex)(nil)
|
||||
|
||||
// CanSupport implements sql.Index
|
||||
func (di *doltIndex) CanSupport(...sql.Range) bool {
|
||||
// TODO (james): don't use and prefix indexes if there's a prefix on a text/blob column
|
||||
if len(di.prefixLengths) > 0 {
|
||||
return false
|
||||
hasTextBlob := false
|
||||
colColl := di.indexSch.GetAllCols()
|
||||
colColl.Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
|
||||
if sql.IsTextBlob(col.TypeInfo.ToSqlType()) {
|
||||
hasTextBlob = true
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return !hasTextBlob
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -634,6 +644,11 @@ func (di *doltIndex) HandledFilters(filters []sql.Expression) []sql.Expression {
|
||||
return nil
|
||||
}
|
||||
|
||||
// filters on indexes with prefix lengths are not completely handled
|
||||
if len(di.prefixLengths) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var handled []sql.Expression
|
||||
for _, f := range filters {
|
||||
if expression.ContainsImpreciseComparison(f) {
|
||||
@@ -776,6 +791,30 @@ func pruneEmptyRanges(sqlRanges []sql.Range) (pruned []sql.Range, err error) {
|
||||
return pruned, nil
|
||||
}
|
||||
|
||||
// trimRangeCutValue will trim the key value retrieved, depending on its type and prefix length
|
||||
// TODO: this is just the trimKeyPart in the SecondaryIndexWriters, maybe find a different place
|
||||
func (di *doltIndex) trimRangeCutValue(to int, keyPart interface{}) interface{} {
|
||||
var prefixLength uint16
|
||||
if len(di.prefixLengths) > to {
|
||||
prefixLength = di.prefixLengths[to]
|
||||
}
|
||||
if prefixLength != 0 {
|
||||
switch kp := keyPart.(type) {
|
||||
case string:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
case []uint8:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
}
|
||||
}
|
||||
return keyPart
|
||||
}
|
||||
|
||||
func (di *doltIndex) prollyRangesFromSqlRanges(ctx context.Context, ns tree.NodeStore, ranges []sql.Range, tb *val.TupleBuilder) ([]prolly.Range, error) {
|
||||
ranges, err := pruneEmptyRanges(ranges)
|
||||
if err != nil {
|
||||
@@ -788,19 +827,20 @@ func (di *doltIndex) prollyRangesFromSqlRanges(ctx context.Context, ns tree.Node
|
||||
fields := make([]prolly.RangeField, len(rng))
|
||||
for j, expr := range rng {
|
||||
if rangeCutIsBinding(expr.LowerBound) {
|
||||
bound := expr.LowerBound.TypeAsLowerBound()
|
||||
fields[j].Lo = prolly.Bound{
|
||||
Binding: true,
|
||||
Inclusive: bound == sql.Closed,
|
||||
}
|
||||
// accumulate bound values in |tb|
|
||||
v, err := getRangeCutValue(expr.LowerBound, rng[j].Typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = PutField(ctx, ns, tb, j, v); err != nil {
|
||||
nv := di.trimRangeCutValue(j, v)
|
||||
if err = PutField(ctx, ns, tb, j, nv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bound := expr.LowerBound.TypeAsLowerBound()
|
||||
fields[j].Lo = prolly.Bound{
|
||||
Binding: true,
|
||||
Inclusive: bound == sql.Closed,
|
||||
}
|
||||
} else {
|
||||
fields[j].Lo = prolly.Bound{}
|
||||
}
|
||||
@@ -814,18 +854,19 @@ func (di *doltIndex) prollyRangesFromSqlRanges(ctx context.Context, ns tree.Node
|
||||
for i, expr := range rng {
|
||||
if rangeCutIsBinding(expr.UpperBound) {
|
||||
bound := expr.UpperBound.TypeAsUpperBound()
|
||||
fields[i].Hi = prolly.Bound{
|
||||
Binding: true,
|
||||
Inclusive: bound == sql.Closed,
|
||||
}
|
||||
// accumulate bound values in |tb|
|
||||
v, err := getRangeCutValue(expr.UpperBound, rng[i].Typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = PutField(ctx, ns, tb, i, v); err != nil {
|
||||
nv := di.trimRangeCutValue(i, v)
|
||||
if err = PutField(ctx, ns, tb, i, nv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields[i].Hi = prolly.Bound{
|
||||
Binding: true,
|
||||
Inclusive: bound == sql.Closed || nv != v, // TODO (james): this might panic for []byte
|
||||
}
|
||||
} else {
|
||||
fields[i].Hi = prolly.Bound{}
|
||||
}
|
||||
|
||||
@@ -293,8 +293,14 @@ func (m prollySecondaryIndexWriter) trimKeyPart(to int, keyPart interface{}) int
|
||||
if prefixLength != 0 {
|
||||
switch kp := keyPart.(type) {
|
||||
case string:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
case []uint8:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +218,14 @@ func (writer prollyKeylessSecondaryWriter) trimKeyPart(to int, keyPart interface
|
||||
if prefixLength != 0 {
|
||||
switch kp := keyPart.(type) {
|
||||
case string:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
case []uint8:
|
||||
if prefixLength > uint16(len(kp)) {
|
||||
prefixLength = uint16(len(kp))
|
||||
}
|
||||
keyPart = kp[:prefixLength]
|
||||
}
|
||||
}
|
||||
@@ -304,7 +310,8 @@ func (writer prollyKeylessSecondaryWriter) Delete(ctx context.Context, sqlRow sq
|
||||
|
||||
for to := range writer.keyMap {
|
||||
from := writer.keyMap.MapOrdinal(to)
|
||||
if err := index.PutField(ctx, writer.mut.NodeStore(), writer.keyBld, to, sqlRow[from]); err != nil {
|
||||
keyPart := writer.trimKeyPart(to, sqlRow[from])
|
||||
if err := index.PutField(ctx, writer.mut.NodeStore(), writer.keyBld, to, keyPart); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user