Merge pull request #4785 from dolthub/james/inline-string-index

use prefix indexes for inline string columns
This commit is contained in:
James Cor
2022-11-15 17:02:41 -08:00
committed by GitHub
6 changed files with 196 additions and 438 deletions
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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{},
},
},
},
+53 -12
View File
@@ -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
}
}