sqlrite/sql/parser/insert.rs
1use sqlparser::ast::{Expr, Insert, SetExpr, Statement, Value as AstValue, Values};
2
3use crate::error::{Result, SQLRiteError};
4use crate::sql::db::table::{Value, parse_vector_literal};
5
6/// Parsed INSERT statement: target table, declared column list, and one
7/// or more rows of typed values.
8///
9/// `rows` is `Vec<Vec<Option<Value>>>` rather than `Vec<Vec<String>>` so
10/// SQL `NULL` can be represented faithfully as `None` instead of leaking
11/// out as the string sentinel `"Null"` (which used to break INTEGER /
12/// REAL / BOOL inserts and silently round-trip as the literal text
13/// `"Null"` in TEXT columns).
14#[derive(Debug)]
15pub struct InsertQuery {
16 pub table_name: String,
17 pub columns: Vec<String>,
18 pub rows: Vec<Vec<Option<Value>>>,
19}
20
21impl InsertQuery {
22 pub fn new(statement: &Statement) -> Result<InsertQuery> {
23 let tname: Option<String>;
24 let mut columns: Vec<String> = vec![];
25 let mut all_values: Vec<Vec<Option<Value>>> = vec![];
26
27 match statement {
28 Statement::Insert(Insert {
29 table,
30 columns: cols,
31 source,
32 ..
33 }) => {
34 tname = Some(table.to_string());
35 for col in cols {
36 columns.push(col.to_string());
37 }
38
39 let source = source.as_ref().ok_or_else(|| {
40 SQLRiteError::Internal(
41 "INSERT statement is missing a source expression".to_string(),
42 )
43 })?;
44
45 if let SetExpr::Values(Values { rows, .. }) = source.body.as_ref() {
46 for row in rows {
47 let mut value_set: Vec<Option<Value>> = vec![];
48 for e in row {
49 match e {
50 Expr::Value(v) => match &v.value {
51 AstValue::Number(n, _) => {
52 // Try integer first; if the literal has
53 // a decimal point or exponent, i64 fails
54 // and we fall through to f64.
55 if let Ok(i) = n.parse::<i64>() {
56 value_set.push(Some(Value::Integer(i)));
57 } else if let Ok(f) = n.parse::<f64>() {
58 value_set.push(Some(Value::Real(f)));
59 } else {
60 return Err(SQLRiteError::General(format!(
61 "Could not parse numeric literal '{n}'"
62 )));
63 }
64 }
65 AstValue::Boolean(b) => {
66 value_set.push(Some(Value::Bool(*b)));
67 }
68 AstValue::SingleQuotedString(sqs) => {
69 value_set.push(Some(Value::Text(sqs.to_string())));
70 }
71 AstValue::Null => {
72 value_set.push(None);
73 }
74 _ => {}
75 },
76 Expr::Identifier(i) => {
77 // Phase 7a — sqlparser parses bracket-array
78 // literals like `[0.1, 0.2, 0.3]` as
79 // bracket-quoted identifiers (it inherits
80 // MSSQL-style `[name]` quoting). Detect
81 // that by `quote_style == Some('[')` and
82 // parse it eagerly into a typed
83 // `Value::Vector` so the rest of the
84 // pipeline sees a real vector. Dimension
85 // checking against the column declaration
86 // happens at insert_row time.
87 if i.quote_style == Some('[') {
88 let raw = format!("[{}]", i.value);
89 let parsed = parse_vector_literal(&raw).map_err(|e| {
90 SQLRiteError::General(format!(
91 "Could not parse vector literal '{raw}': {e}"
92 ))
93 })?;
94 value_set.push(Some(Value::Vector(parsed)));
95 } else {
96 value_set.push(Some(Value::Text(i.to_string())));
97 }
98 }
99 _ => {}
100 }
101 }
102 all_values.push(value_set);
103 }
104 }
105 }
106 _ => {
107 return Err(SQLRiteError::Internal(
108 "Error parsing insert query".to_string(),
109 ));
110 }
111 }
112
113 match tname {
114 Some(t) => Ok(InsertQuery {
115 table_name: t,
116 columns,
117 rows: all_values,
118 }),
119 None => Err(SQLRiteError::Internal(
120 "Error parsing insert query".to_string(),
121 )),
122 }
123 }
124}