fix schema sql-gen internal logic to use as_ident() helper

This commit is contained in:
Nikita Sivukhin
2025-09-26 12:58:24 +04:00
parent 27c9506059
commit f82dd8dffd
5 changed files with 38 additions and 32 deletions

View File

@@ -3475,6 +3475,7 @@ pub fn bind_and_rewrite_expr<'a>(
}
}
Expr::Qualified(tbl, id) => {
tracing::debug!("bind_and_rewrite_expr({:?}, {:?})", tbl, id);
let normalized_table_name = normalize_ident(tbl.as_str());
let matching_tbl = referenced_tables
.find_table_and_internal_id_by_identifier(&normalized_table_name);
@@ -3504,6 +3505,7 @@ pub fn bind_and_rewrite_expr<'a>(
column: col_idx,
is_rowid_alias: col.is_rowid_alias,
};
tracing::debug!("rewritten to column");
referenced_tables.mark_column_used(tbl_id, col_idx);
return Ok(WalkControl::Continue);
}
@@ -4147,7 +4149,7 @@ fn determine_column_alias(
) -> Option<String> {
// First check for explicit alias
if let Some(As::As(name)) = explicit_alias {
return Some(name.to_string());
return Some(name.as_str().to_string());
}
// For ROWID expressions, use "rowid" as the alias

View File

@@ -21,15 +21,15 @@ use crate::{
insn::{IdxInsertFlags, Insn, RegisterOrLiteral},
},
};
use turso_parser::ast::{Expr, SortOrder, SortedColumn};
use turso_parser::ast::{Expr, Name, SortOrder, SortedColumn};
use super::schema::{emit_schema_entry, SchemaEntryType, SQLITE_TABLEID};
#[allow(clippy::too_many_arguments)]
pub fn translate_create_index(
unique_if_not_exists: (bool, bool),
idx_name: &str,
tbl_name: &str,
idx_name: &Name,
tbl_name: &Name,
columns: &[SortedColumn],
schema: &Schema,
syms: &SymbolTable,
@@ -37,6 +37,11 @@ pub fn translate_create_index(
connection: &Arc<crate::Connection>,
where_clause: Option<Box<Expr>>,
) -> crate::Result<ProgramBuilder> {
let original_idx_name = idx_name;
let original_tbl_name = tbl_name;
let idx_name = normalize_ident(idx_name.as_str());
let tbl_name = normalize_ident(tbl_name.as_str());
if tbl_name.eq_ignore_ascii_case("sqlite_sequence") {
crate::bail_parse_error!("table sqlite_sequence may not be indexed");
}
@@ -45,10 +50,6 @@ pub fn translate_create_index(
"CREATE INDEX is disabled by default. Run with `--experimental-indexes` to enable this feature."
);
}
let original_idx_name = idx_name;
let original_tbl_name = tbl_name;
let idx_name = normalize_ident(idx_name);
let tbl_name = normalize_ident(tbl_name);
if RESERVED_TABLE_PREFIXES
.iter()
.any(|prefix| idx_name.starts_with(prefix))
@@ -173,8 +174,8 @@ pub fn translate_create_index(
db: 0,
});
let sql = create_idx_stmt_to_sql(
original_tbl_name,
original_idx_name,
&original_tbl_name.as_ident(),
&original_idx_name.as_ident(),
unique_if_not_exists,
original_columns,
&idx.where_clause.clone(),
@@ -392,10 +393,10 @@ fn create_idx_stmt_to_sql(
sql.push_str(", ");
}
let col_ident = match col.expr.as_ref() {
Expr::Id(name) | Expr::Name(name) => name.as_str(),
Expr::Id(name) | Expr::Name(name) => name.as_ident(),
_ => unreachable!("expressions in CREATE INDEX should have been rejected earlier"),
};
sql.push_str(col_ident);
sql.push_str(&col_ident);
if col.order.unwrap_or(SortOrder::Asc) == SortOrder::Desc {
sql.push_str(" DESC");
}

View File

@@ -165,8 +165,8 @@ pub fn translate_inner(
where_clause,
} => translate_create_index(
(unique, if_not_exists),
idx_name.name.as_str(),
tbl_name.as_str(),
&idx_name.name,
&tbl_name,
&columns,
schema,
syms,
@@ -197,7 +197,7 @@ pub fn translate_inner(
..
} => view::translate_create_view(
schema,
view_name.name.as_str(),
&view_name.name,
&select,
&columns,
connection.clone(),
@@ -208,7 +208,7 @@ pub fn translate_inner(
view_name, select, ..
} => view::translate_create_materialized_view(
schema,
view_name.name.as_str(),
&view_name.name,
&select,
connection.clone(),
syms,

View File

@@ -463,15 +463,15 @@ fn create_vtable_body_to_str(vtab: &ast::CreateVirtualTable, module: Arc<VTabImp
};
format!(
"CREATE VIRTUAL TABLE {} {} USING {}{}\n /*{}{}*/",
vtab.tbl_name.name.as_str(),
vtab.tbl_name.name.as_ident(),
if_not_exists,
vtab.module_name.as_str(),
vtab.module_name.as_ident(),
if args.is_empty() {
String::new()
} else {
format!("({args})")
},
vtab.tbl_name.name.as_str(),
vtab.tbl_name.name.as_ident(),
vtab_args
)
}

View File

@@ -11,7 +11,7 @@ use turso_parser::ast;
pub fn translate_create_materialized_view(
schema: &Schema,
view_name: &str,
view_name: &ast::Name,
select_stmt: &ast::Select,
connection: Arc<Connection>,
syms: &SymbolTable,
@@ -25,7 +25,7 @@ pub fn translate_create_materialized_view(
));
}
let normalized_view_name = normalize_ident(view_name);
let normalized_view_name = normalize_ident(view_name.as_str());
// Check if view already exists
if schema
@@ -46,7 +46,7 @@ pub fn translate_create_materialized_view(
let view_columns = view_column_schema.flat_columns();
// Reconstruct the SQL string for storage
let sql = create_materialized_view_to_str(view_name, select_stmt);
let sql = create_materialized_view_to_str(&view_name.as_ident(), select_stmt);
// Create a btree for storing the materialized view state
// This btree will hold the materialized rows (row_id -> values)
@@ -145,14 +145,16 @@ pub fn translate_create_materialized_view(
// Add the DBSP state table to sqlite_master (required for materialized views)
// Include the version number in the table name
use crate::incremental::compiler::DBSP_CIRCUIT_VERSION;
let dbsp_table_name =
format!("{DBSP_TABLE_PREFIX}{DBSP_CIRCUIT_VERSION}_{normalized_view_name}");
let dbsp_table_name = ast::Name::exact(format!(
"{DBSP_TABLE_PREFIX}{DBSP_CIRCUIT_VERSION}_{normalized_view_name}"
));
let dbsp_table_ident = dbsp_table_name.as_ident();
// The element_id column uses SQLite's dynamic typing system to store different value types:
// - For hash-based operators (joins, filters): stores INTEGER hash values or rowids
// - For future MIN/MAX operators: stores the actual values being compared (INTEGER, REAL, TEXT, BLOB)
// SQLite's type affinity and sorting rules ensure correct ordering within each operator's data
let dbsp_sql = format!(
"CREATE TABLE {dbsp_table_name} (\
"CREATE TABLE {dbsp_table_ident} (\
operator_id INTEGER NOT NULL, \
zset_id BLOB NOT NULL, \
element_id BLOB NOT NULL, \
@@ -168,8 +170,8 @@ pub fn translate_create_materialized_view(
sqlite_schema_cursor_id,
None, // cdc_table_cursor_id
SchemaEntryType::Table,
&dbsp_table_name,
&dbsp_table_name,
dbsp_table_name.as_str(),
dbsp_table_name.as_str(),
dbsp_state_root_reg, // Root for DBSP state table
Some(dbsp_sql),
)?;
@@ -186,7 +188,8 @@ pub fn translate_create_materialized_view(
// Register the index in sqlite_schema
let dbsp_index_name = format!(
"{}{}_1",
PRIMARY_KEY_AUTOMATIC_INDEX_NAME_PREFIX, &dbsp_table_name
PRIMARY_KEY_AUTOMATIC_INDEX_NAME_PREFIX,
&dbsp_table_name.as_str()
);
emit_schema_entry(
&mut program,
@@ -195,7 +198,7 @@ pub fn translate_create_materialized_view(
None, // cdc_table_cursor_id
SchemaEntryType::Index,
&dbsp_index_name,
&dbsp_table_name,
dbsp_table_name.as_str(),
dbsp_index_root_reg,
None, // Automatic indexes don't store SQL
)?;
@@ -231,14 +234,14 @@ fn create_materialized_view_to_str(view_name: &str, select_stmt: &ast::Select) -
pub fn translate_create_view(
schema: &Schema,
view_name: &str,
view_name: &ast::Name,
select_stmt: &ast::Select,
_columns: &[ast::IndexedColumn],
_connection: Arc<Connection>,
syms: &SymbolTable,
mut program: ProgramBuilder,
) -> Result<ProgramBuilder> {
let normalized_view_name = normalize_ident(view_name);
let normalized_view_name = normalize_ident(view_name.as_str());
// Check if view already exists
if schema.get_view(&normalized_view_name).is_some()
@@ -252,7 +255,7 @@ pub fn translate_create_view(
}
// Reconstruct the SQL string
let sql = create_view_to_str(view_name, select_stmt);
let sql = create_view_to_str(&view_name.as_ident(), select_stmt);
// Open cursor to sqlite_schema table
let table = schema.get_btree_table(SQLITE_TABLEID).unwrap();