diff --git a/bindings/java/rs_src/limbo_statement.rs b/bindings/java/rs_src/limbo_statement.rs index b28ff55b1..c49469cd6 100644 --- a/bindings/java/rs_src/limbo_statement.rs +++ b/bindings/java/rs_src/limbo_statement.rs @@ -138,7 +138,7 @@ pub extern "system" fn Java_tech_turso_core_LimboStatement_columns<'local>( for i in 0..num_columns { let column_name = stmt.stmt.get_column_name(i); - let str = env.new_string(column_name.as_str()).unwrap(); + let str = env.new_string(column_name.into_owned()).unwrap(); env.set_object_array_element(&obj_arr, i as i32, str) .unwrap(); } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 61e6271c9..8c57e7909 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -190,6 +190,39 @@ impl Statement { } } } + + pub fn columns(&self) -> Vec { + let stmt = self.inner.lock().unwrap(); + + let n = stmt.num_columns(); + + let mut cols = Vec::with_capacity(n); + + for i in 0..n { + let name = stmt.get_column_name(i).into_owned(); + cols.push(Column { + name, + decl_type: None, // TODO + }); + } + + cols + } +} + +pub struct Column { + name: String, + decl_type: Option, +} + +impl Column { + pub fn name(&self) -> &str { + &self.name + } + + pub fn decl_type(&self) -> Option<&str> { + self.decl_type.as_deref() + } } pub trait IntoValue { diff --git a/core/lib.rs b/core/lib.rs index e130306f7..67d168640 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -591,7 +591,7 @@ impl Statement { self.program.result_columns.len() } - pub fn get_column_name(&self, idx: usize) -> Cow { + pub fn get_column_name(&self, idx: usize) -> Cow { let column = &self.program.result_columns[idx]; match column.name(&self.program.table_references) { Some(name) => Cow::Borrowed(name), diff --git a/core/translate/plan.rs b/core/translate/plan.rs index 07a8de392..48ce4c854 100644 --- a/core/translate/plan.rs +++ b/core/translate/plan.rs @@ -34,13 +34,26 @@ pub struct ResultSetColumn { } impl ResultSetColumn { - pub fn name<'a>(&'a self, tables: &'a [TableReference]) -> Option<&'a String> { + pub fn name<'a>(&'a self, tables: &'a [TableReference]) -> Option<&'a str> { if let Some(alias) = &self.alias { return Some(alias); } match &self.expr { ast::Expr::Column { table, column, .. } => { - tables[*table].columns()[*column].name.as_ref() + tables[*table].columns()[*column].name.as_deref() + } + ast::Expr::RowId { table, .. } => { + // If there is a rowid alias column, use its name + if let Table::BTree(table) = &tables[*table].table { + if let Some(rowid_alias_column) = table.get_rowid_alias_column() { + if let Some(name) = &rowid_alias_column.1.name { + return Some(name); + } + } + } + + // If there is no rowid alias, use "rowid". + Some("rowid") } _ => None, } @@ -465,7 +478,7 @@ impl TableReference { plan.result_columns .iter() .map(|rc| Column { - name: rc.name(&plan.table_references).map(String::clone), + name: rc.name(&plan.table_references).map(String::from), ty: Type::Text, // FIXME: infer proper type ty_str: "TEXT".to_string(), is_rowid_alias: false, diff --git a/tests/integration/common.rs b/tests/integration/common.rs index a034b36ae..2c668a12f 100644 --- a/tests/integration/common.rs +++ b/tests/integration/common.rs @@ -120,16 +120,16 @@ mod tests { let columns = stmt.num_columns(); assert_eq!(columns, 3); - assert_eq!(stmt.get_column_name(0), "foo".into()); - assert_eq!(stmt.get_column_name(1), "bar".into()); - assert_eq!(stmt.get_column_name(2), "baz".into()); + assert_eq!(stmt.get_column_name(0), "foo"); + assert_eq!(stmt.get_column_name(1), "bar"); + assert_eq!(stmt.get_column_name(2), "baz"); let stmt = conn.prepare("select foo, bar from test;")?; let columns = stmt.num_columns(); assert_eq!(columns, 2); - assert_eq!(stmt.get_column_name(0), "foo".into()); - assert_eq!(stmt.get_column_name(1), "bar".into()); + assert_eq!(stmt.get_column_name(0), "foo"); + assert_eq!(stmt.get_column_name(1), "bar"); let stmt = conn.prepare("delete from test;")?; let columns = stmt.num_columns();