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 table = catalog
27 .resolve_table_name(&statement.table)?
28 .ok_or_else(|| {
29 SQLError::Unsupported(format!(
30 "CREATE INDEX USING {access_method}: relation `{}` does not exist",
31 statement.table
32 ))
33 })?;
34 let mut fields = Vec::with_capacity(statement.columns.len());
35 for key in &statement.columns {
36 let column = super::keys::require_column_key(key, access_method)?;
37 let dimensions = match catalog.column_type(&table, column)? {
38 Some(ColumnType::Vector(dim) | ColumnType::Tensor(dim)) => dim,
39 Some(other) => {
40 return Err(SQLError::Unsupported(format!(
41 "CREATE INDEX USING {access_method} requires VECTOR or TENSOR column `{column}`, got {other:?}"
42 )));
43 }
44 None => {
45 return Err(SQLError::Unsupported(format!(
46 "CREATE INDEX USING {access_method}: column `{table}`.`{column}` does not exist"
47 )));
48 }
49 };
50 let existing = catalog.vector_index_names(&table, column)?;
51 if !existing.is_empty() {
52 return Err(SQLError::Unsupported(format!(
53 "CREATE INDEX USING {access_method}: `{table}`.`{column}` already has physical vector index `{}`",
54 existing.join("`, `")
55 )));
56 }
57 fields.push((column, dimensions));
58 }
59 Ok(VectorIndexTarget { table, fields })
60}