mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-09 18:24:20 +01:00
Merge 'names shall not be shared between tables,indexs,vtabs,views' from Pavan Nambi
closes #3675 Closes #3681
This commit is contained in:
@@ -2247,7 +2247,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(users_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(users_table))
|
||||
.expect("Test setup: failed to add users table");
|
||||
|
||||
// Add products table for join tests
|
||||
let products_table = BTreeTable {
|
||||
@@ -2301,7 +2303,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(products_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(products_table))
|
||||
.expect("Test setup: failed to add products table");
|
||||
|
||||
// Add orders table for join tests
|
||||
let orders_table = BTreeTable {
|
||||
@@ -2367,7 +2371,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(orders_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(orders_table))
|
||||
.expect("Test setup: failed to add orders table");
|
||||
|
||||
// Add customers table with id and name for testing column ambiguity
|
||||
let customers_table = BTreeTable {
|
||||
@@ -2406,7 +2412,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(customers_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(customers_table))
|
||||
.expect("Test setup: failed to add customers table");
|
||||
|
||||
// Add purchases table (junction table for three-way join)
|
||||
let purchases_table = BTreeTable {
|
||||
@@ -2469,7 +2477,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(purchases_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(purchases_table))
|
||||
.expect("Test setup: failed to add purchases table");
|
||||
|
||||
// Add vendors table with id, name, and price (ambiguous columns with customers)
|
||||
let vendors_table = BTreeTable {
|
||||
@@ -2520,7 +2530,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(vendors_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(vendors_table))
|
||||
.expect("Test setup: failed to add vendors table");
|
||||
|
||||
let sales_table = BTreeTable {
|
||||
name: "sales".to_string(),
|
||||
@@ -2558,7 +2570,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(sales_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(sales_table))
|
||||
.expect("Test setup: failed to add sales table");
|
||||
|
||||
schema
|
||||
}};
|
||||
|
||||
@@ -1565,10 +1565,22 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
};
|
||||
|
||||
schema.add_btree_table(Arc::new(customers_table));
|
||||
schema.add_btree_table(Arc::new(orders_table));
|
||||
schema.add_btree_table(Arc::new(products_table));
|
||||
schema.add_btree_table(Arc::new(logs_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(customers_table))
|
||||
.expect("Test setup: failed to add customers table");
|
||||
|
||||
schema
|
||||
.add_btree_table(Arc::new(orders_table))
|
||||
.expect("Test setup: failed to add orders table");
|
||||
|
||||
schema
|
||||
.add_btree_table(Arc::new(products_table))
|
||||
.expect("Test setup: failed to add products table");
|
||||
|
||||
schema
|
||||
.add_btree_table(Arc::new(logs_table))
|
||||
.expect("Test setup: failed to add logs table");
|
||||
|
||||
schema
|
||||
}
|
||||
|
||||
|
||||
@@ -289,9 +289,11 @@ impl Schema {
|
||||
}
|
||||
|
||||
/// Add a regular (non-materialized) view
|
||||
pub fn add_view(&mut self, view: View) {
|
||||
pub fn add_view(&mut self, view: View) -> Result<()> {
|
||||
self.check_object_name_conflict(&view.name)?;
|
||||
let name = normalize_ident(&view.name);
|
||||
self.views.insert(name, Arc::new(view));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a regular view by name
|
||||
@@ -300,14 +302,18 @@ impl Schema {
|
||||
self.views.get(&name).cloned()
|
||||
}
|
||||
|
||||
pub fn add_btree_table(&mut self, table: Arc<BTreeTable>) {
|
||||
pub fn add_btree_table(&mut self, table: Arc<BTreeTable>) -> Result<()> {
|
||||
self.check_object_name_conflict(&table.name)?;
|
||||
let name = normalize_ident(&table.name);
|
||||
self.tables.insert(name, Table::BTree(table).into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_virtual_table(&mut self, table: Arc<VirtualTable>) {
|
||||
pub fn add_virtual_table(&mut self, table: Arc<VirtualTable>) -> Result<()> {
|
||||
self.check_object_name_conflict(&table.name)?;
|
||||
let name = normalize_ident(&table.name);
|
||||
self.tables.insert(name, Table::Virtual(table).into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_table(&self, name: &str) -> Option<Arc<Table>> {
|
||||
@@ -340,7 +346,8 @@ impl Schema {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_index(&mut self, index: Arc<Index>) {
|
||||
pub fn add_index(&mut self, index: Arc<Index>) -> Result<()> {
|
||||
self.check_object_name_conflict(&index.name)?;
|
||||
let table_name = normalize_ident(&index.table_name);
|
||||
// We must add the new index to the front of the deque, because SQLite stores index definitions as a linked list
|
||||
// where the newest parsed index entry is at the head of list. If we would add it to the back of a regular Vec for example,
|
||||
@@ -350,7 +357,8 @@ impl Schema {
|
||||
self.indexes
|
||||
.entry(table_name)
|
||||
.or_default()
|
||||
.push_front(index.clone())
|
||||
.push_front(index.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_indices(&self, table_name: &str) -> impl Iterator<Item = &Arc<Index>> {
|
||||
@@ -507,7 +515,7 @@ impl Schema {
|
||||
unparsed_sql_from_index.root_page,
|
||||
table.as_ref(),
|
||||
)?;
|
||||
self.add_index(Arc::new(index));
|
||||
self.add_index(Arc::new(index))?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +557,7 @@ impl Schema {
|
||||
table.as_ref(),
|
||||
automatic_indexes.pop().unwrap(),
|
||||
1,
|
||||
)?));
|
||||
)?))?;
|
||||
} else {
|
||||
// Add single column unique index
|
||||
if let Some(autoidx) = automatic_indexes.pop() {
|
||||
@@ -557,7 +565,7 @@ impl Schema {
|
||||
table.as_ref(),
|
||||
autoidx,
|
||||
vec![(pos_in_table, unique_set.columns.first().unwrap().1)],
|
||||
)?));
|
||||
)?))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,7 +583,7 @@ impl Schema {
|
||||
table.as_ref(),
|
||||
automatic_indexes.pop().unwrap(),
|
||||
unique_set.columns.len(),
|
||||
)?));
|
||||
)?))?;
|
||||
} else {
|
||||
// Add composite unique index
|
||||
let mut column_indices_and_sort_orders =
|
||||
@@ -593,7 +601,7 @@ impl Schema {
|
||||
table.as_ref(),
|
||||
automatic_indexes.pop().unwrap(),
|
||||
column_indices_and_sort_orders,
|
||||
)?));
|
||||
)?))?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,7 +709,7 @@ impl Schema {
|
||||
syms,
|
||||
)?
|
||||
};
|
||||
self.add_virtual_table(vtab);
|
||||
self.add_virtual_table(vtab)?;
|
||||
} else {
|
||||
let table = BTreeTable::from_sql(sql, root_page)?;
|
||||
|
||||
@@ -735,7 +743,7 @@ impl Schema {
|
||||
}
|
||||
}
|
||||
|
||||
self.add_btree_table(Arc::new(table));
|
||||
self.add_btree_table(Arc::new(table))?;
|
||||
}
|
||||
}
|
||||
"index" => {
|
||||
@@ -834,7 +842,7 @@ impl Schema {
|
||||
// Create regular view
|
||||
let view =
|
||||
View::new(name.to_string(), sql.to_string(), select, final_columns);
|
||||
self.add_view(view);
|
||||
self.add_view(view)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -1105,6 +1113,32 @@ impl Schema {
|
||||
.and_then(|t| t.btree())
|
||||
.is_some_and(|t| !t.foreign_keys.is_empty())
|
||||
}
|
||||
|
||||
fn check_object_name_conflict(&self, name: &str) -> Result<()> {
|
||||
let normalized_name = normalize_ident(name);
|
||||
|
||||
if self.tables.contains_key(&normalized_name) {
|
||||
return Err(crate::LimboError::ParseError(
|
||||
["table \"", name, "\" already exists"].concat().to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if self.views.contains_key(&normalized_name) {
|
||||
return Err(crate::LimboError::ParseError(
|
||||
["view \"", name, "\" already exists"].concat().to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
for index_list in self.indexes.values() {
|
||||
if index_list.iter().any(|i| i.name.eq_ignore_ascii_case(name)) {
|
||||
return Err(crate::LimboError::ParseError(
|
||||
["index \"", name, "\" already exists"].concat().to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Schema {
|
||||
|
||||
@@ -2445,7 +2445,9 @@ mod tests {
|
||||
has_autoincrement: false,
|
||||
unique_sets: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(users_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(users_table))
|
||||
.expect("Test setup: failed to add users table");
|
||||
|
||||
// Create orders table
|
||||
let orders_table = BTreeTable {
|
||||
@@ -2508,7 +2510,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(orders_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(orders_table))
|
||||
.expect("Test setup: failed to add orders table");
|
||||
|
||||
// Create products table
|
||||
let products_table = BTreeTable {
|
||||
@@ -2571,7 +2575,9 @@ mod tests {
|
||||
unique_sets: vec![],
|
||||
foreign_keys: vec![],
|
||||
};
|
||||
schema.add_btree_table(Arc::new(products_table));
|
||||
schema
|
||||
.add_btree_table(Arc::new(products_table))
|
||||
.expect("Test setup: failed to add products table");
|
||||
|
||||
schema
|
||||
}
|
||||
|
||||
@@ -66,3 +66,38 @@ do_execsql_test_in_memory_any_error create_table_duplicate_column_names_case_ins
|
||||
do_execsql_test_in_memory_any_error create_table_duplicate_column_names_quoted {
|
||||
CREATE TABLE t("a", a);
|
||||
}
|
||||
|
||||
# https://github.com/tursodatabase/turso/issues/3675
|
||||
do_execsql_test_in_memory_any_error create_table_view_collision-1 {
|
||||
CREATE VIEW v_same AS SELECT 1;
|
||||
CREATE TABLE v_same(x INT);
|
||||
}
|
||||
|
||||
do_execsql_test_in_memory_any_error create_view_table_collision-1 {
|
||||
CREATE TABLE t_same(x INT);
|
||||
CREATE VIEW t_same AS SELECT 1;
|
||||
}
|
||||
|
||||
do_execsql_test_in_memory_any_error create_index_view_collision-1 {
|
||||
CREATE VIEW i_same AS SELECT 1;
|
||||
CREATE TABLE t1(x);
|
||||
CREATE INDEX i_same ON t1(x);
|
||||
}
|
||||
|
||||
do_execsql_test_in_memory_any_error create_index_table_collision-1 {
|
||||
CREATE TABLE i_same(x INT);
|
||||
CREATE TABLE t2(y);
|
||||
CREATE INDEX i_same ON t2(y);
|
||||
}
|
||||
|
||||
do_execsql_test_in_memory_any_error create_table_index_collision-1 {
|
||||
CREATE TABLE t3(z);
|
||||
CREATE INDEX ix_same ON t3(z);
|
||||
CREATE TABLE ix_same(x INT);
|
||||
}
|
||||
|
||||
do_execsql_test_in_memory_any_error create_view_index_collision-1 {
|
||||
CREATE TABLE t4(w);
|
||||
CREATE INDEX ix_same ON t4(w);
|
||||
CREATE VIEW ix_same AS SELECT 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user