diff --git a/enginetest/queries/index_query_plans.go b/enginetest/queries/index_query_plans.go index be3f5bb77e..a66342617f 100644 --- a/enginetest/queries/index_query_plans.go +++ b/enginetest/queries/index_query_plans.go @@ -16288,115 +16288,140 @@ var IndexPlanTests = []QueryPlanTest{ "", }, { - Query: `select * from comp_vector_index_t0 order by vec_distance('[50,50]', v2) limit 5`, + Query: `select * from comp_vector_index_t0 order by vec_distance('[50,50]', json_column) limit 5`, ExpectedPlan: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " ├─ colSet: (1-3)\n" + + " ├─ index: [comp_vector_index_t0.json_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.json_column) LIMIT 5 (bigint)\n" + + " ├─ colSet: (1-4)\n" + " ├─ tableId: 1\n" + " └─ Table\n" + " ├─ name: comp_vector_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", ExpectedEstimates: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " └─ columns: [pk v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.json_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.json_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", ExpectedAnalysis: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " └─ columns: [pk v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.json_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.json_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", }, { - Query: `select * from comp_vector_index_t0 order by vec_distance(v2, '[50,50]') limit 5`, + Query: `select * from comp_vector_index_t0 order by vec_distance('[50,50]', vector_column) limit 5`, ExpectedPlan: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " ├─ colSet: (1-3)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " ├─ colSet: (1-4)\n" + " ├─ tableId: 1\n" + " └─ Table\n" + " ├─ name: comp_vector_index_t0\n" + - " └─ columns: [pk v1 v2]\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", ExpectedEstimates: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " └─ columns: [pk v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", ExpectedAnalysis: "Limit(5)\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " └─ columns: [pk v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + "", }, { - Query: `select pk+1 from comp_vector_index_t0 order by vec_distance('[50,50]', v2) limit 5`, + Query: `select * from comp_vector_index_t0 order by vec_distance(vector_column, '[50,50]') limit 5`, + ExpectedPlan: "Limit(5)\n" + + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " ├─ colSet: (1-4)\n" + + " ├─ tableId: 1\n" + + " └─ Table\n" + + " ├─ name: comp_vector_index_t0\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + + "", + ExpectedEstimates: "Limit(5)\n" + + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + + "", + ExpectedAnalysis: "Limit(5)\n" + + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " └─ columns: [pk v1 json_column vector_column]\n" + + "", + }, + { + Query: `select pk+1 from comp_vector_index_t0 order by vec_distance('[50,50]', vector_column) limit 5`, ExpectedPlan: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.pk:0!null + 1 (tinyint))->pk+1:0]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " ├─ colSet: (1-3)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " ├─ colSet: (1-4)\n" + " ├─ tableId: 1\n" + " └─ Table\n" + " ├─ name: comp_vector_index_t0\n" + - " └─ columns: [pk v2]\n" + + " └─ columns: [pk vector_column]\n" + "", ExpectedEstimates: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.pk + 1) as pk+1]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " └─ columns: [pk v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk vector_column]\n" + "", ExpectedAnalysis: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.pk + 1) as pk+1]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.v2) LIMIT 5 (bigint)\n" + - " └─ columns: [pk v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED('[50,50]', comp_vector_index_t0.vector_column) LIMIT 5 (bigint)\n" + + " └─ columns: [pk vector_column]\n" + "", }, { - Query: `select v1+1 from comp_vector_index_t0 order by vec_distance(v2, '[50,50]') limit 5`, + Query: `select v1+1 from comp_vector_index_t0 order by vec_distance(vector_column, '[50,50]') limit 5`, ExpectedPlan: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.v1:0 + 1 (tinyint))->v1+1:0]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " ├─ colSet: (1-3)\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " ├─ colSet: (1-4)\n" + " ├─ tableId: 1\n" + " └─ Table\n" + " ├─ name: comp_vector_index_t0\n" + - " └─ columns: [v1 v2]\n" + + " └─ columns: [v1 vector_column]\n" + "", ExpectedEstimates: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.v1 + 1) as v1+1]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " └─ columns: [v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " └─ columns: [v1 vector_column]\n" + "", ExpectedAnalysis: "Limit(5)\n" + " └─ Project\n" + " ├─ columns: [(comp_vector_index_t0.v1 + 1) as v1+1]\n" + " └─ IndexedTableAccess(comp_vector_index_t0)\n" + - " ├─ index: [comp_vector_index_t0.v2]\n" + - " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.v2, '[50,50]') LIMIT 5 (bigint)\n" + - " └─ columns: [v1 v2]\n" + + " ├─ index: [comp_vector_index_t0.vector_column]\n" + + " ├─ order: VEC_DISTANCE_L2_SQUARED(comp_vector_index_t0.vector_column, '[50,50]') LIMIT 5 (bigint)\n" + + " └─ columns: [v1 vector_column]\n" + "", }, { diff --git a/enginetest/queries/vector_index_queries.go b/enginetest/queries/vector_index_queries.go index c7b7254ac4..bfa1ea3fa8 100644 --- a/enginetest/queries/vector_index_queries.go +++ b/enginetest/queries/vector_index_queries.go @@ -23,7 +23,7 @@ var VectorIndexQueries = []ScriptTest{ { Name: "basic JSON vector index", SetUpScript: []string{ - "create table vectors (id int primary key, v json);", + "create table vectors (id int primary key, v json not null);", `insert into vectors values (1, '[4.0,3.0]'), (2, '[0.0,0.0]'), (3, '[-1.0,1.0]'), (4, '[0.0,-2.0]');`, `create vector index v_idx on vectors(v);`, `set @query_vec = '[0.0,0.0]';`, @@ -32,7 +32,7 @@ var VectorIndexQueries = []ScriptTest{ { Query: "show create table vectors", Expected: []sql.Row{ - {"vectors", "CREATE TABLE `vectors` (\n `id` int NOT NULL,\n `v` json,\n PRIMARY KEY (`id`),\n VECTOR KEY `v_idx` (`v`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}, + {"vectors", "CREATE TABLE `vectors` (\n `id` int NOT NULL,\n `v` json NOT NULL,\n PRIMARY KEY (`id`),\n VECTOR KEY `v_idx` (`v`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}, }, }, { @@ -119,7 +119,7 @@ var VectorIndexQueries = []ScriptTest{ { Name: "basic VECTOR vector index", SetUpScript: []string{ - "create table vectors (id int primary key, v vector(2));", + "create table vectors (id int primary key, v vector(2) not null);", `insert into vectors values (1, STRING_TO_VECTOR('[4.0,3.0]')), (2, STRING_TO_VECTOR('[0.0,0.0]')), (3, STRING_TO_VECTOR('[-1.0,1.0]')), (4, STRING_TO_VECTOR('[0.0,-2.0]'));`, `create vector index v_idx on vectors(v);`, `set @query_vec = '[0.0,0.0]';`, @@ -128,7 +128,7 @@ var VectorIndexQueries = []ScriptTest{ { Query: "show create table vectors", Expected: []sql.Row{ - {"vectors", "CREATE TABLE `vectors` (\n `id` int NOT NULL,\n `v` VECTOR(2),\n PRIMARY KEY (`id`),\n VECTOR KEY `v_idx` (`v`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}, + {"vectors", "CREATE TABLE `vectors` (\n `id` int NOT NULL,\n `v` VECTOR(2) NOT NULL,\n PRIMARY KEY (`id`),\n VECTOR KEY `v_idx` (`v`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}, }, }, { @@ -233,4 +233,20 @@ var VectorIndexQueries = []ScriptTest{ }, }, }, + { + Name: "vector index on nullable column errors", + SetUpScript: []string{ + "create table vectors_nullable (id int primary key, v vector(2) null);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: `create vector index v_idx on vectors_nullable(v);`, + ExpectedErr: sql.ErrNullableVectorIdx, + }, + { + Query: `create table bad_vector_idx (id int primary key, v vector(2), vector index (v));`, + ExpectedErr: sql.ErrNullableVectorIdx, + }, + }, + }, } diff --git a/enginetest/scriptgen/setup/scripts/comp_index_tables b/enginetest/scriptgen/setup/scripts/comp_index_tables index 067d50cf8d..07b7b548c5 100644 --- a/enginetest/scriptgen/setup/scripts/comp_index_tables +++ b/enginetest/scriptgen/setup/scripts/comp_index_tables @@ -98,11 +98,11 @@ create table pref_index_t4 (i int primary key, v1 varchar(10), v2 varchar(10), u ---- exec -CREATE TABLE comp_vector_index_t0 (pk BIGINT PRIMARY KEY, v1 BIGINT, v2 JSON); +CREATE TABLE comp_vector_index_t0 (pk BIGINT PRIMARY KEY, v1 BIGINT, json_column JSON NOT NULL, vector_column VECTOR(2) NOT NULL GENERATED ALWAYS AS (STRING_TO_VECTOR(json_column)) STORED); ---- exec -INSERT INTO comp_vector_index_t0 VALUES (0,0,"[3,16]"),(1,2,"[65,9]"),(2,3,"[38,37]"),(3,3,"[99,99]"),(4,5,"[17,42]"),(5,6,"[6,76]"),(6,6,"[81,33]"), +INSERT INTO comp_vector_index_t0 (pk, v1, json_column) VALUES (0,0,"[3,16]"),(1,2,"[65,9]"),(2,3,"[38,37]"),(3,3,"[99,99]"),(4,5,"[17,42]"),(5,6,"[6,76]"),(6,6,"[81,33]"), (7,7,"[33,51]"),(8,7,"[37,42]"),(9,8,"[9,21]"),(10,8,"[37,90]"),(11,9,"[39,20]"),(12,9,"[71,82]"),(13,10,"[16,21]"),(14,10,"[32,46]"),(15,10,"[47,36]"), (16,12,"[44,84]"),(17,12,"[66,40]"),(18,13,"[47,30]"),(19,13,"[56,41]"),(20,14,"[38,24]"),(21,14,"[91,1]"),(22,15,"[2,69]"),(23,16,"[40,36]"), (24,20,"[29,93]"),(25,21,"[9,89]"),(26,21,"[42,76]"),(27,23,"[13,53]"),(28,23,"[28,68]"),(29,23,"[28,90]"),(30,23,"[30,44]"),(31,24,"[20,8]"), @@ -118,7 +118,11 @@ INSERT INTO comp_vector_index_t0 VALUES (0,0,"[3,16]"),(1,2,"[65,9]"),(2,3,"[38, ---- exec -create VECTOR INDEX v_idx on comp_vector_index_t0 (v2) +create VECTOR INDEX v_idx_json on comp_vector_index_t0 (json_column) +---- + +exec +create VECTOR INDEX v_idx_vec on comp_vector_index_t0 (vector_column) ---- exec diff --git a/enginetest/scriptgen/setup/setup_data.sg.go b/enginetest/scriptgen/setup/setup_data.sg.go index 4c8f54eb8a..d40b01bb8c 100755 --- a/enginetest/scriptgen/setup/setup_data.sg.go +++ b/enginetest/scriptgen/setup/setup_data.sg.go @@ -103,8 +103,8 @@ var Comp_index_tablesData = []SetupScript{{ `create table pref_index_t1 (i int primary key, v1 text, v2 text, unique index (v1(3),v2(5)));`, `create table pref_index_t3 (v1 varchar(10), v2 varchar(10), unique index (v1(3),v2(5)));`, `create table pref_index_t4 (i int primary key, v1 varchar(10), v2 varchar(10), unique index (v1(3),v2(5)));`, - `CREATE TABLE comp_vector_index_t0 (pk BIGINT PRIMARY KEY, v1 BIGINT, v2 JSON);`, - `INSERT INTO comp_vector_index_t0 VALUES (0,0,"[3,16]"),(1,2,"[65,9]"),(2,3,"[38,37]"),(3,3,"[99,99]"),(4,5,"[17,42]"),(5,6,"[6,76]"),(6,6,"[81,33]"), + `CREATE TABLE comp_vector_index_t0 (pk BIGINT PRIMARY KEY, v1 BIGINT, json_column JSON NOT NULL, vector_column VECTOR(2) NOT NULL GENERATED ALWAYS AS (STRING_TO_VECTOR(json_column)) STORED);`, + `INSERT INTO comp_vector_index_t0 (pk, v1, json_column) VALUES (0,0,"[3,16]"),(1,2,"[65,9]"),(2,3,"[38,37]"),(3,3,"[99,99]"),(4,5,"[17,42]"),(5,6,"[6,76]"),(6,6,"[81,33]"), (7,7,"[33,51]"),(8,7,"[37,42]"),(9,8,"[9,21]"),(10,8,"[37,90]"),(11,9,"[39,20]"),(12,9,"[71,82]"),(13,10,"[16,21]"),(14,10,"[32,46]"),(15,10,"[47,36]"), (16,12,"[44,84]"),(17,12,"[66,40]"),(18,13,"[47,30]"),(19,13,"[56,41]"),(20,14,"[38,24]"),(21,14,"[91,1]"),(22,15,"[2,69]"),(23,16,"[40,36]"), (24,20,"[29,93]"),(25,21,"[9,89]"),(26,21,"[42,76]"),(27,23,"[13,53]"),(28,23,"[28,68]"),(29,23,"[28,90]"),(30,23,"[30,44]"),(31,24,"[20,8]"), @@ -117,7 +117,8 @@ var Comp_index_tablesData = []SetupScript{{ (80,75,"[91,35]"),(81,76,"[40,52]"),(82,76,"[44,87]"),(83,81,"[32,4]"),(84,82,"[11,6]"),(85,82,"[46,32]"),(86,84,"[40,8]"),(87,84,"[93,37]"), (88,85,"[53,50]"),(89,86,"[63,79]"),(90,87,"[22,34]"),(91,87,"[57,62]"),(92,88,"[88,42]"),(93,90,"[30,67]"),(94,91,"[15,15]"),(95,93,"[7,26]"), (96,94,"[92,38]"),(97,95,"[89,66]"),(98,97,"[63,19]"),(99,98,"[31,21]"),(100,98,"[42,22]")`, - `create VECTOR INDEX v_idx on comp_vector_index_t0 (v2)`, + `create VECTOR INDEX v_idx_json on comp_vector_index_t0 (json_column)`, + `create VECTOR INDEX v_idx_vec on comp_vector_index_t0 (vector_column)`, `create table three_pk ( pk1 tinyint, pk2 tinyint, diff --git a/sql/analyzer/validate_create_table.go b/sql/analyzer/validate_create_table.go index 61d5153434..13b0530466 100644 --- a/sql/analyzer/validate_create_table.go +++ b/sql/analyzer/validate_create_table.go @@ -15,6 +15,7 @@ package analyzer import ( + "fmt" "strings" "github.com/dolthub/go-mysql-server/sql" @@ -888,6 +889,16 @@ func validateIndex(ctx *sql.Context, colMap map[string]*sql.Column, idxDef *sql. } } + if idxDef.IsVector() { + if len(idxDef.Columns) != 1 { + return fmt.Errorf("a vector index must have exactly one column") + } + schCol, _ := colMap[strings.ToLower(idxDef.Columns[0].Name)] + if schCol.Nullable { + return sql.ErrNullableVectorIdx.New() + } + } + if idxDef.IsSpatial() { if len(idxDef.Columns) != 1 { return sql.ErrTooManyKeyParts.New(1) diff --git a/sql/errors.go b/sql/errors.go index 0be1672f38..f147d7e851 100644 --- a/sql/errors.go +++ b/sql/errors.go @@ -651,6 +651,9 @@ var ( // ErrNullableSpatialIdx is thrown when creating a SPATIAL index with a nullable column ErrNullableSpatialIdx = errors.NewKind("All parts of a SPATIAL index must be NOT NULL") + // ErrNullableVectorIdx is thrown when creating a VECTOR index with a nullable column + ErrNullableVectorIdx = errors.NewKind("All parts of a VECTOR index must be NOT NULL") + // ErrBadSpatialIdxCol is thrown when attempting to define a SPATIAL index over a non-geometry column ErrBadSpatialIdxCol = errors.NewKind("a SPATIAL index may only contain a geometrical type column") diff --git a/sql/rowexec/ddl_iters.go b/sql/rowexec/ddl_iters.go index 777adbe9bf..7a66c07c4a 100644 --- a/sql/rowexec/ddl_iters.go +++ b/sql/rowexec/ddl_iters.go @@ -2163,6 +2163,9 @@ func (b *BaseBuilder) executeAlterIndex(ctx *sql.Context, n *plan.AlterIndex) er if !types.IsVectorConvertable(tblCol.Type) { return sql.ErrVectorInvalidColumnType.New() } + if tblCol.Nullable { + return sql.ErrNullableVectorIdx.New() + } break } }