Merge 'Fix get_column_name() when a column name doesn't exist' from meteorgan

we would encounter a panic in `display.rs` when a column name does not
exist.
```
turso> select * from (select 1);

thread 'main' panicked at core/translate/display.rs:252:50:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
after this PR:
```
turso> select * from (select 1);
2025-07-25T15:52:24.241294Z DEBUG ThreadId(01) run_cmd:translate:optimize_plan: turso_core::translate::optimizer: 51: plan_sql="SELECT subquery_0.0 FROM (SELECT 1 FROM) AS subquery_0"
2025-07-25T15:52:24.242036Z DEBUG ThreadId(01) step:begin_read_tx:begin_read_tx: turso_core::storage::wal: 552: begin_read_tx(min_frame=1, max_frame=0, lock=0, max_frame_in_wal=0)
2025-07-25T15:52:24.242349Z DEBUG ThreadId(01) step:commit_txn:end_read_tx:end_read_tx: turso_core::storage::wal: 566: end_read_tx(lock=0)
┌───┐
│ . │
├───┤
│ 1 │
└───┘
```

Closes #2269
This commit is contained in:
Pekka Enberg
2025-07-25 21:38:09 +03:00
5 changed files with 22 additions and 17 deletions

View File

@@ -1,6 +1,5 @@
use core::fmt;
use std::fmt::{Display, Formatter};
use turso_sqlite3_parser::{
ast::{
self,
@@ -237,19 +236,17 @@ pub struct PlanContext<'a>(pub &'a [&'a TableReferences]);
// Definitely not perfect yet
impl ToSqlContext for PlanContext<'_> {
fn get_column_name(&self, table_id: TableInternalId, col_idx: usize) -> &str {
fn get_column_name(&self, table_id: TableInternalId, col_idx: usize) -> String {
let table = self
.0
.iter()
.map(|table_ref| table_ref.find_table_by_internal_id(table_id))
.reduce(|accum, curr| match (accum, curr) {
(Some(table), _) | (_, Some(table)) => Some(table),
_ => None,
})
.unwrap()
.find_map(|table_ref| table_ref.find_table_by_internal_id(table_id))
.unwrap();
let cols = table.columns();
cols.get(col_idx).unwrap().name.as_ref().unwrap()
match cols.get(col_idx).unwrap().name.as_ref() {
None => format!("{col_idx}"),
Some(n) => n.to_string(),
}
}
fn get_table_name(&self, id: TableInternalId) -> &str {

View File

@@ -119,7 +119,7 @@ impl ToSqlContext for EmptyContext {
&self,
_table_id: turso_sqlite3_parser::ast::TableInternalId,
_col_idx: usize,
) -> &str {
) -> String {
unreachable!()
}

View File

@@ -89,8 +89,8 @@ impl<T: fmt::Write> TokenStream for WriteTokenStream<'_, T> {
struct BlankContext;
impl ToSqlContext for BlankContext {
fn get_column_name(&self, _table_id: crate::ast::TableInternalId, _col_idx: usize) -> &str {
""
fn get_column_name(&self, _table_id: crate::ast::TableInternalId, _col_idx: usize) -> String {
"".to_string()
}
fn get_table_name(&self, _id: crate::ast::TableInternalId) -> &str {
@@ -758,7 +758,7 @@ impl ToTokens for Expr {
Self::Column { table, column, .. } => {
s.append(TK_ID, Some(context.get_table_name(*table)))?;
s.append(TK_DOT, None)?;
s.append(TK_ID, Some(context.get_column_name(*table, *column)))
s.append(TK_ID, Some(&context.get_column_name(*table, *column)))
}
Self::InList { lhs, not, rhs } => {
lhs.to_tokens_with_context(s, context)?;

View File

@@ -12,7 +12,7 @@ pub trait ToSqlContext {
/// Currently not considering aliases
fn get_table_name(&self, id: TableInternalId) -> &str;
/// Given a table id and a column index, get the column name
fn get_column_name(&self, table_id: TableInternalId, col_idx: usize) -> &str;
fn get_column_name(&self, table_id: TableInternalId, col_idx: usize) -> String;
}
#[cfg(test)]
@@ -22,8 +22,12 @@ mod tests {
struct TestContext;
impl ToSqlContext for TestContext {
fn get_column_name(&self, _table_id: crate::ast::TableInternalId, _col_idx: usize) -> &str {
"placeholder_column"
fn get_column_name(
&self,
_table_id: crate::ast::TableInternalId,
_col_idx: usize,
) -> String {
"placeholder_column".to_string()
}
fn get_table_name(&self, _id: crate::ast::TableInternalId) -> &str {

View File

@@ -54,7 +54,11 @@ mod tests {
// Placeholders for compilation
// Context only necessary parsing inside turso_core or in the simulator
impl ToSqlContext for TestContext {
fn get_column_name(&self, _table_id: crate::ast::TableInternalId, _col_idx: usize) -> &str {
fn get_column_name(
&self,
_table_id: crate::ast::TableInternalId,
_col_idx: usize,
) -> String {
todo!()
}