Skip to content

Commit 2ac4d83

Browse files
committed
fix: quote table names in PRAGMA query and handle empty default values correctly
Two issues prevented INSERT validation from working: 1. PRAGMA table_info() requires quoted table names to find tables reliably 2. SQLite returns empty strings for columns without defaults, which were being treated as 'has a default value', causing all columns to pass validation Fixes all 9 INSERT validation tests.
1 parent 793db30 commit 2ac4d83

2 files changed

Lines changed: 25 additions & 7 deletions

File tree

sqlx-sqlite/src/connection/describe.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ fn get_table_columns(
130130
) -> Result<Vec<TableColumnInfo>, Error> {
131131
// PRAGMA table_info returns: cid, name, type, notnull, dflt_value, pk
132132
// Column indices: 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value, 5=pk
133-
let pragma_query = format!("PRAGMA table_info({})", table_name);
133+
let pragma_query = format!("PRAGMA table_info(\"{}\")", table_name);
134134

135135
let mut statement = match VirtualStatement::new(&pragma_query, false) {
136136
Ok(stmt) => stmt,
@@ -151,9 +151,16 @@ fn get_table_columns(
151151
// Get notnull flag
152152
let not_null = stmt.handle.column_int(3) != 0;
153153

154-
// Get default value
154+
// Get default value (SQLite returns empty string for no default)
155155
let dflt_value = match stmt.handle.column_text(4) {
156-
Ok(v) => Some(v.to_string()),
156+
Ok(v) => {
157+
let s = v.to_string();
158+
if s.is_empty() {
159+
None
160+
} else {
161+
Some(s)
162+
}
163+
}
157164
Err(_) => None,
158165
};
159166

tests/sqlite/describe.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,10 @@ async fn it_validates_insert_with_all_required_columns() -> anyhow::Result<()> {
11151115

11161116
// Explicit columns including all NOT NULL fields → should succeed
11171117
let d = conn
1118-
.describe("INSERT INTO test_insert_valid (id, required_a, required_b) VALUES (?, ?, ?)".into_sql_str())
1118+
.describe(
1119+
"INSERT INTO test_insert_valid (id, required_a, required_b) VALUES (?, ?, ?)"
1120+
.into_sql_str(),
1121+
)
11191122
.await;
11201123

11211124
assert!(d.is_ok(), "INSERT with all NOT NULL columns should succeed");
@@ -1170,7 +1173,9 @@ async fn it_validates_insert_missing_multiple_required_columns() -> anyhow::Resu
11701173

11711174
// Missing required_b and required_c → error should list both
11721175
let err = conn
1173-
.describe("INSERT INTO test_insert_multi_missing (id, required_a) VALUES (?, ?)".into_sql_str())
1176+
.describe(
1177+
"INSERT INTO test_insert_multi_missing (id, required_a) VALUES (?, ?)".into_sql_str(),
1178+
)
11741179
.await;
11751180

11761181
assert!(err.is_err());
@@ -1227,7 +1232,10 @@ async fn it_validates_insert_with_column_defaults() -> anyhow::Result<()> {
12271232

12281233
// required_with_default has DEFAULT → not required in INSERT
12291234
let d = conn
1230-
.describe("INSERT INTO test_insert_defaults (id, required_no_default) VALUES (?, ?)".into_sql_str())
1235+
.describe(
1236+
"INSERT INTO test_insert_defaults (id, required_no_default) VALUES (?, ?)"
1237+
.into_sql_str(),
1238+
)
12311239
.await;
12321240

12331241
assert!(
@@ -1255,7 +1263,10 @@ async fn it_validates_insert_case_insensitive() -> anyhow::Result<()> {
12551263
.describe("INSERT INTO testinsertcase (id, requiredcol) VALUES (?, ?)".into_sql_str())
12561264
.await;
12571265

1258-
assert!(d.is_ok(), "Case-insensitive matching should work for SQLite identifiers");
1266+
assert!(
1267+
d.is_ok(),
1268+
"Case-insensitive matching should work for SQLite identifiers"
1269+
);
12591270

12601271
Ok(())
12611272
}

0 commit comments

Comments
 (0)