Merge 'Support referring to rowid as _rowid_ or oid' from Jussi Saurio

Closes #3283

Closes #3289
This commit is contained in:
Pekka Enberg
2025-09-24 11:08:32 +03:00
committed by GitHub
6 changed files with 45 additions and 12 deletions

View File

@@ -1,6 +1,7 @@
use crate::function::Func;
use crate::incremental::view::IncrementalView;
use crate::translate::expr::{bind_and_rewrite_expr, walk_expr, ParamState, WalkControl};
use crate::translate::planner::ROWID_STRS;
use parking_lot::RwLock;
/// Simple view structure for non-materialized views
@@ -1792,7 +1793,7 @@ impl Index {
// Unqualified identifier: must be a column of the target table or ROWID
Expr::Id(Name::Ident(n)) | Expr::Id(Name::Quoted(n)) => {
let n = n.as_str();
if !n.eq_ignore_ascii_case("rowid") && !has_col(n) {
if !ROWID_STRS.iter().any(|s| s.eq_ignore_ascii_case(n)) && !has_col(n) {
ok = false;
}
}

View File

@@ -30,6 +30,7 @@ use crate::translate::expr::{
ReturningValueRegisters, WalkControl,
};
use crate::translate::plan::{DeletePlan, JoinedTable, Plan, QueryDestination, Search};
use crate::translate::planner::ROWID_STRS;
use crate::translate::result_row::try_fold_expr_to_i64;
use crate::translate::values::emit_values;
use crate::translate::window::{emit_window_results, init_window, WindowMetadata};
@@ -1817,7 +1818,10 @@ fn rewrite_where_for_update_registers(
}
Expr::Id(ast::Name::Ident(name)) | Expr::Id(ast::Name::Quoted(name)) => {
let normalized = normalize_ident(name.as_str());
if normalized.eq_ignore_ascii_case("rowid") {
if ROWID_STRS
.iter()
.any(|s| s.eq_ignore_ascii_case(&normalized))
{
*e = Expr::Register(rowid_reg);
} else if let Some((idx, c)) = columns.iter().enumerate().find(|(_, c)| {
c.name

View File

@@ -17,7 +17,7 @@ use crate::translate::expr::{
ParamState, ReturningValueRegisters, WalkControl,
};
use crate::translate::plan::TableReferences;
use crate::translate::planner::ROWID;
use crate::translate::planner::ROWID_STRS;
use crate::translate::upsert::{
collect_set_clauses_for_upsert, emit_upsert, resolve_upsert_target, ResolvedUpsertTarget,
};
@@ -1038,8 +1038,8 @@ impl InsertionKey<'_> {
.as_ref()
.expect("rowid alias column must be present")
.as_str(),
InsertionKey::LiteralRowid { .. } => ROWID,
InsertionKey::Autogenerated { .. } => ROWID,
InsertionKey::LiteralRowid { .. } => ROWID_STRS[0],
InsertionKey::Autogenerated { .. } => ROWID_STRS[0],
}
}
}
@@ -1128,7 +1128,10 @@ fn build_insertion<'a>(
} else {
column_mappings[idx_in_table].value_index = Some(value_index);
}
} else if column_name == ROWID {
} else if ROWID_STRS
.iter()
.any(|s| s.eq_ignore_ascii_case(&column_name))
{
// Explicit use of the 'rowid' keyword
if let Some(col_in_table) = table.columns().iter().find(|c| c.is_rowid_alias) {
insertion_key = InsertionKey::RowidAlias(ColMapping {
@@ -1406,7 +1409,7 @@ pub fn rewrite_partial_index_where(
insertion: &Insertion,
) -> crate::Result<WalkControl> {
let col_reg = |name: &str| -> Option<usize> {
if name.eq_ignore_ascii_case("rowid") {
if ROWID_STRS.iter().any(|s| s.eq_ignore_ascii_case(name)) {
Some(insertion.key_register())
} else if let Some(c) = insertion.get_col_mapping_by_name(name) {
if c.column.is_rowid_alias {

View File

@@ -30,7 +30,8 @@ use turso_parser::ast::{
self, As, Expr, FromClause, JoinType, Materialized, Over, QualifiedName, TableInternalId, With,
};
pub const ROWID: &str = "rowid";
/// Valid ways to refer to the rowid of a btree table.
pub const ROWID_STRS: [&str; 3] = ["rowid", "_rowid_", "oid"];
/// This function walks the expression tree and identifies aggregate
/// and window functions.
@@ -1094,7 +1095,10 @@ pub fn parse_row_id<F>(
where
F: FnOnce() -> bool,
{
if column_name.eq_ignore_ascii_case(ROWID) {
if ROWID_STRS
.iter()
.any(|s| s.eq_ignore_ascii_case(column_name))
{
if fn_check() {
crate::bail_parse_error!("ROWID is ambiguous");
}

View File

@@ -7,6 +7,7 @@ use turso_parser::ast::{self, Upsert};
use crate::error::SQLITE_CONSTRAINT_PRIMARYKEY;
use crate::translate::expr::{walk_expr, WalkControl};
use crate::translate::insert::format_unique_violation_desc;
use crate::translate::planner::ROWID_STRS;
use crate::vdbe::insn::CmpInsFlags;
use crate::{
bail_parse_error,
@@ -895,7 +896,7 @@ fn rewrite_expr_to_registers(
// Map a column name to a register within the row image at `base_start`.
let col_reg_from_row_image = |name: &str| -> Option<usize> {
if name.eq_ignore_ascii_case("rowid") {
if ROWID_STRS.iter().any(|s| s.eq_ignore_ascii_case(name)) {
return Some(rowid_reg);
}
let (idx, c) = table.get_column_by_name(name)?;
@@ -917,7 +918,7 @@ fn rewrite_expr_to_registers(
// Handle EXCLUDED.* if enabled
if allow_excluded && ns.eq_ignore_ascii_case("excluded") {
if let Some(ins) = insertion {
if c.eq_ignore_ascii_case("rowid") {
if ROWID_STRS.iter().any(|s| s.eq_ignore_ascii_case(&c)) {
*expr = Expr::Register(ins.key_register());
} else if let Some(cm) = ins.get_col_mapping_by_name(&c) {
*expr = Expr::Register(cm.register);

View File

@@ -766,4 +766,24 @@ foreach {testname limit ans} {
} {
do_execsql_test limit-complex-exprs-$testname \
"SELECT id FROM users ORDER BY id LIMIT $limit" $ans
}
}
do_execsql_test_on_specific_db {:memory:} rowid-references {
CREATE TABLE test_table (id INTEGER);
INSERT INTO test_table VALUES (5),(5);
SELECT
rowid, "rowid", `rowid`, [rowid], _rowid_, "_rowid_", `_rowid_`, [_rowid_], oid, "oid", `oid`, [oid]
FROM test_table
WHERE rowid = 2
AND "rowid" = 2
AND `rowid` = 2
AND [rowid] = 2
AND _rowid_ = 2
AND "_rowid_" = 2
AND `_rowid_` = 2
AND [_rowid_] = 2
AND oid = 2
AND "oid" = 2
AND `oid` = 2
AND [oid] = 2;
} {2|2|2|2|2|2|2|2|2|2|2|2}