core/translate: Add support for default values in INSERT statements

This commit is contained in:
Diego Reis 2025-04-04 01:32:13 -03:00
parent 38d842d675
commit 43daba9942
3 changed files with 51 additions and 1 deletions

View file

@ -297,6 +297,8 @@ struct ColumnMapping<'a> {
/// If Some(i), use the i-th value from the VALUES tuple
/// If None, use NULL (column was not specified in INSERT statement)
value_index: Option<usize>,
/// The default value for the column, if defined
default_value: Option<&'a Expr>,
}
/// Resolves how each column in a table should be populated during an INSERT.
@ -352,6 +354,7 @@ fn resolve_columns_for_insert<'a>(
.map(|(i, col)| ColumnMapping {
column: col,
value_index: if i < num_values { Some(i) } else { None },
default_value: col.default.as_ref(),
})
.collect());
}
@ -362,6 +365,7 @@ fn resolve_columns_for_insert<'a>(
.map(|col| ColumnMapping {
column: col,
value_index: None,
default_value: col.default.as_ref(),
})
.collect();
@ -423,8 +427,10 @@ fn populate_column_registers(
if write_directly_to_rowid_reg {
program.emit_insn(Insn::SoftNull { reg: target_reg });
}
} else if let Some(default_expr) = mapping.default_value {
translate_expr(program, None, default_expr, target_reg, resolver)?;
} else {
// Column was not specified - use NULL if it is nullable, otherwise error
// Column was not specified as has no DEFAULT - use NULL if it is nullable, otherwise error
// Rowid alias columns can be NULL because we will autogenerate a rowid in that case.
let is_nullable = !mapping.column.primary_key || mapping.column.is_rowid_alias;
if is_nullable {

View file

@ -28,3 +28,4 @@ source $testdir/scalar-functions-printf.test
source $testdir/transactions.test
source $testdir/update.test
source $testdir/drop_table.test
source $testdir/default_value.test

View file

@ -0,0 +1,43 @@
#!/usr/bin/env tclsh
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test_on_specific_db {:memory:} default-value-text {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT DEFAULT 'default_value');
INSERT INTO t1 (x) VALUES (1);
SELECT y FROM t1 WHERE x = 1;
} {default_value}
do_execsql_test_on_specific_db {:memory:} default-value-integer {
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER DEFAULT 42);
INSERT INTO t2 (x) VALUES (1);
SELECT y FROM t2 WHERE x = 1;
} {42}
do_execsql_test_on_specific_db {:memory:} default-value-real {
CREATE TABLE t3(x INTEGER PRIMARY KEY, y REAL DEFAULT 3.14);
INSERT INTO t3 (x) VALUES (1);
SELECT y FROM t3 WHERE x = 1;
} {3.14}
do_execsql_test_on_specific_db {:memory:} default-value-null {
CREATE TABLE t5(x INTEGER PRIMARY KEY, y TEXT DEFAULT NULL);
INSERT INTO t5 (x) VALUES (1);
SELECT y FROM t5 WHERE x = 1;
} {}
do_execsql_test_on_specific_db {:memory:} default-value-boolean {
CREATE TABLE t6(x INTEGER PRIMARY KEY, y BOOLEAN DEFAULT 1);
INSERT INTO t6 (x) VALUES (1);
SELECT y FROM t6 WHERE x = 1;
} {1}
do_execsql_test_on_specific_db {:memory:} default-value-function {
CREATE TABLE t7(x INTEGER PRIMARY KEY, y INTEGER DEFAULT (ABS(-5)));
INSERT INTO t7 (x) VALUES (1);
SELECT y FROM t7 WHERE x = 1;
} {5}