uqa_sql/schema/indexes/
vectors.rs1use crate::{
9 ast::{ColumnType, CreateIndex},
10 SQLError,
11};
12pub trait VectorIndexCatalog {
13 fn resolve_table_name(&self, name: &str) -> Result<Option<String>, SQLError>;
14 fn column_type(&self, table: &str, column: &str) -> Result<Option<ColumnType>, SQLError>;
15 fn vector_index_names(&self, table: &str, column: &str) -> Result<Vec<String>, SQLError>;
16}
17pub struct VectorIndexTarget<'a> {
18 pub table: String,
19 pub fields: Vec<(&'a str, u32)>,
20}
21pub fn resolve_vector_index_target<'a>(
22 catalog: &dyn VectorIndexCatalog,
23 statement: &'a CreateIndex,
24 access_method: &str,
25) -> Result<VectorIndexTarget<'a>, SQLError> {
26 let target = resolve_vector_index_columns(catalog, statement, access_method)?;
27 for (column, _) in &target.fields {
28 let existing = catalog.vector_index_names(&target.table, column)?;
29 if !existing.is_empty() {
30 return Err(SQLError::Unsupported(format!(
31 "CREATE INDEX USING {access_method}: `{}`.`{column}` already has physical vector index `{}`",
32 target.table, existing.join("`, `")
33 )));
34 }
35 }
36 Ok(target)
37}
38
39pub fn resolve_vector_index_columns<'a>(
41 catalog: &dyn VectorIndexCatalog,
42 statement: &'a CreateIndex,
43 access_method: &str,
44) -> Result<VectorIndexTarget<'a>, SQLError> {
45 let table = catalog
46 .resolve_table_name(&statement.table)?
47 .ok_or_else(|| {
48 SQLError::Unsupported(format!(
49 "CREATE INDEX USING {access_method}: relation `{}` does not exist",
50 statement.table
51 ))
52 })?;
53 let mut fields = Vec::with_capacity(statement.columns.len());
54 for key in &statement.columns {
55 let column = super::keys::require_column_key(key, access_method)?;
56 let dimensions = match catalog.column_type(&table, column)? {
57 Some(ColumnType::Vector(dim) | ColumnType::Tensor(dim)) => dim,
58 Some(other) => {
59 return Err(SQLError::Unsupported(format!(
60 "CREATE INDEX USING {access_method} requires VECTOR or TENSOR column `{column}`, got {other:?}"
61 )));
62 }
63 None => {
64 return Err(SQLError::Unsupported(format!(
65 "CREATE INDEX USING {access_method}: column `{table}`.`{column}` does not exist"
66 )));
67 }
68 };
69 fields.push((column, dimensions));
70 }
71 Ok(VectorIndexTarget { table, fields })
72}