1use serde::Serialize;
16use sqlparser::ast::{
17 Insert as SpInsert, ObjectName, ObjectNamePart, Parens, SetExpr, Statement, TableObject,
18 UnaryOperator, ValueWithSpan, Values,
19};
20use sqlparser::parser::ParserError;
21use sqlparser_derive::{Visit, VisitMut};
22
23use crate::ast::{Expr, Value};
24use crate::error::{Result, UnsupportedSnafu};
25use crate::statements::query::Query as GtQuery;
26
27#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
28pub struct Insert {
29 pub inner: Statement,
31}
32
33macro_rules! parse_fail {
34 ($expr: expr) => {
35 return crate::error::ParseSqlValueSnafu {
36 msg: format!("{:?}", $expr),
37 }
38 .fail();
39 };
40}
41
42impl Insert {
43 pub fn table_name(&self) -> Result<&ObjectName> {
44 match &self.inner {
45 Statement::Insert(insert) => {
46 let TableObject::TableName(name) = &insert.table else {
47 return UnsupportedSnafu {
48 keyword: "TABLE FUNCTION".to_string(),
49 }
50 .fail();
51 };
52 Ok(name)
53 }
54 _ => unreachable!(),
55 }
56 }
57
58 pub fn columns(&self) -> Vec<&String> {
59 match &self.inner {
60 Statement::Insert(insert) => insert
61 .columns
62 .iter()
63 .filter_map(single_part_column_ident)
64 .map(|ident| &ident.value)
65 .collect(),
66 _ => unreachable!(),
67 }
68 }
69
70 pub fn values_body(&self) -> Result<Vec<Vec<Value>>> {
72 match &self.inner {
73 Statement::Insert(SpInsert { source, .. }) => {
74 let rows = source
75 .as_deref()
76 .and_then(|query| match query.body.as_ref() {
77 SetExpr::Values(Values { rows, .. }) => Some(rows),
78 _ => None,
79 });
80 match rows {
81 Some(rows) => sql_exprs_to_values(rows),
82 None => unreachable!(),
83 }
84 }
85 _ => unreachable!(),
86 }
87 }
88
89 pub fn can_extract_values(&self) -> bool {
92 match &self.inner {
93 Statement::Insert(SpInsert { source, .. }) => source
94 .as_deref()
95 .and_then(|query| match query.body.as_ref() {
96 SetExpr::Values(Values { rows, .. }) => Some(rows),
97 _ => None,
98 })
99 .is_some_and(|rows| {
100 rows.iter().all(|es| {
101 es.iter().all(|expr| match expr {
102 Expr::Value(_) => true,
103 Expr::Identifier(ident) => {
104 if ident.quote_style.is_none() {
105 ident.value.to_lowercase() == "default"
106 } else {
107 ident.quote_style == Some('"')
108 }
109 }
110 Expr::UnaryOp { op, expr } => {
111 matches!(op, UnaryOperator::Minus | UnaryOperator::Plus)
112 && matches!(
113 &**expr,
114 Expr::Value(ValueWithSpan {
115 value: Value::Number(_, _),
116 ..
117 })
118 )
119 }
120 _ => false,
121 })
122 })
123 }),
124 _ => false,
125 }
126 }
127
128 pub fn has_non_values_query_source(&self) -> bool {
130 match &self.inner {
131 Statement::Insert(SpInsert {
132 source: Some(query),
133 ..
134 }) => !matches!(&*query.body, SetExpr::Values(_)),
135 _ => false,
136 }
137 }
138
139 pub fn query_body(&self) -> Result<Option<GtQuery>> {
140 Ok(match &self.inner {
141 Statement::Insert(SpInsert {
142 source: Some(query),
143 ..
144 }) => Some(query.as_ref().clone().try_into()?),
145 _ => None,
146 })
147 }
148}
149
150fn sql_exprs_to_values(exprs: &[Parens<Vec<Expr>>]) -> Result<Vec<Vec<Value>>> {
151 let mut values = Vec::with_capacity(exprs.len());
152 for es in exprs.iter() {
153 let mut vs = Vec::with_capacity(es.len());
154 for expr in es.iter() {
155 vs.push(match expr {
156 Expr::Value(v) => v.value.clone(),
157 Expr::Identifier(ident) => {
158 if ident.quote_style.is_none() {
159 if ident.value.to_lowercase() == "default" {
161 Value::Placeholder(ident.value.clone())
162 } else {
163 parse_fail!(expr);
164 }
165 } else {
166 if ident.quote_style == Some('"') {
168 Value::SingleQuotedString(ident.value.clone())
169 } else {
170 parse_fail!(expr);
171 }
172 }
173 }
174 Expr::UnaryOp { op, expr }
175 if matches!(op, UnaryOperator::Minus | UnaryOperator::Plus) =>
176 {
177 if let Expr::Value(ValueWithSpan {
178 value: Value::Number(s, b),
179 ..
180 }) = &**expr
181 {
182 match op {
183 UnaryOperator::Minus => Value::Number(format!("-{s}"), *b),
184 UnaryOperator::Plus => Value::Number(s.clone(), *b),
185 _ => unreachable!(),
186 }
187 } else {
188 parse_fail!(expr);
189 }
190 }
191 _ => {
192 parse_fail!(expr);
193 }
194 });
195 }
196 values.push(vs);
197 }
198 Ok(values)
199}
200
201fn single_part_column_ident(name: &ObjectName) -> Option<&sqlparser::ast::Ident> {
202 let [ObjectNamePart::Identifier(ident)] = name.0.as_slice() else {
203 return None;
204 };
205 Some(ident)
206}
207
208impl TryFrom<Statement> for Insert {
209 type Error = ParserError;
210
211 fn try_from(value: Statement) -> std::result::Result<Self, Self::Error> {
212 let Statement::Insert(insert) = &value else {
213 return Err(ParserError::ParserError(format!(
214 "Not expected to be {value}"
215 )));
216 };
217
218 if let Some(column) = insert
219 .columns
220 .iter()
221 .find(|column| single_part_column_ident(column).is_none())
222 {
223 return Err(ParserError::ParserError(format!(
224 "Expected a single-part insert column name, found {column}"
225 )));
226 }
227
228 Ok(Insert { inner: value })
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235 use crate::dialect::GreptimeDbDialect;
236 use crate::parser::{ParseOptions, ParserContext};
237 use crate::statements::statement::Statement;
238
239 #[test]
240 fn test_insert_value_with_unary_op() {
241 let sql = "INSERT INTO my_table VALUES(-1)";
243 let stmt =
244 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
245 .unwrap()
246 .remove(0);
247 match stmt {
248 Statement::Insert(insert) => {
249 let values = insert.values_body().unwrap();
250 assert_eq!(values, vec![vec![Value::Number("-1".to_string(), false)]]);
251 }
252 _ => unreachable!(),
253 }
254
255 let sql = "INSERT INTO my_table VALUES(+1)";
257 let stmt =
258 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
259 .unwrap()
260 .remove(0);
261 match stmt {
262 Statement::Insert(insert) => {
263 let values = insert.values_body().unwrap();
264 assert_eq!(values, vec![vec![Value::Number("1".to_string(), false)]]);
265 }
266 _ => unreachable!(),
267 }
268 }
269
270 #[test]
271 fn test_insert_column_names_are_single_identifiers() {
272 let stmt = ParserContext::create_with_dialect(
273 "INSERT INTO my_table (host, \"value\") VALUES (1, 2)",
274 &GreptimeDbDialect {},
275 ParseOptions::default(),
276 )
277 .unwrap()
278 .remove(0);
279 let Statement::Insert(insert) = stmt else {
280 unreachable!()
281 };
282 assert_eq!(insert.columns(), vec!["host", "value"]);
283
284 let result = ParserContext::create_with_dialect(
285 "INSERT INTO my_table (metric.host) VALUES (1)",
286 &GreptimeDbDialect {},
287 ParseOptions::default(),
288 );
289 let error = result.unwrap_err().to_string();
290 assert!(
291 error.contains("Expected a single-part insert column name, found metric.host"),
292 "unexpected error: {error}"
293 );
294 }
295
296 #[test]
297 fn test_insert_value_with_default() {
298 let sql = "INSERT INTO my_table VALUES(default)";
300 let stmt =
301 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
302 .unwrap()
303 .remove(0);
304 match stmt {
305 Statement::Insert(insert) => {
306 let values = insert.values_body().unwrap();
307 assert_eq!(values, vec![vec![Value::Placeholder("default".to_owned())]]);
308 }
309 _ => unreachable!(),
310 }
311 }
312
313 #[test]
314 fn test_insert_value_with_default_uppercase() {
315 let sql = "INSERT INTO my_table VALUES(DEFAULT)";
317 let stmt =
318 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
319 .unwrap()
320 .remove(0);
321 match stmt {
322 Statement::Insert(insert) => {
323 let values = insert.values_body().unwrap();
324 assert_eq!(values, vec![vec![Value::Placeholder("DEFAULT".to_owned())]]);
325 }
326 _ => unreachable!(),
327 }
328 }
329
330 #[test]
331 fn test_insert_value_with_quoted_string() {
332 let sql = "INSERT INTO my_table VALUES('default')";
334 let stmt =
335 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
336 .unwrap()
337 .remove(0);
338 match stmt {
339 Statement::Insert(insert) => {
340 let values = insert.values_body().unwrap();
341 assert_eq!(
342 values,
343 vec![vec![Value::SingleQuotedString("default".to_owned())]]
344 );
345 }
346 _ => unreachable!(),
347 }
348
349 let sql = "INSERT INTO my_table VALUES(\"default\")";
351 let stmt =
352 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
353 .unwrap()
354 .remove(0);
355 match stmt {
356 Statement::Insert(insert) => {
357 let values = insert.values_body().unwrap();
358 assert_eq!(
359 values,
360 vec![vec![Value::SingleQuotedString("default".to_owned())]]
361 );
362 }
363 _ => unreachable!(),
364 }
365
366 let sql = "INSERT INTO my_table VALUES(`default`)";
367 let stmt =
368 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
369 .unwrap()
370 .remove(0);
371 match stmt {
372 Statement::Insert(insert) => {
373 assert!(insert.values_body().is_err());
374 }
375 _ => unreachable!(),
376 }
377 }
378
379 #[test]
380 fn test_insert_select() {
381 let sql = "INSERT INTO my_table select * from other_table";
382 let stmt =
383 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
384 .unwrap()
385 .remove(0);
386 match stmt {
387 Statement::Insert(insert) => {
388 let q = insert.query_body().unwrap().unwrap();
389 assert!(insert.has_non_values_query_source());
390 assert!(matches!(
391 &q.inner,
392 sqlparser::ast::Query { body, .. }
393 if matches!(body.as_ref(), SetExpr::Select { .. })
394 ));
395 }
396 _ => unreachable!(),
397 }
398 }
399
400 #[test]
401 fn test_has_non_values_query_source() {
402 let cases = [
403 ("INSERT INTO my_table SELECT * FROM other_table", true),
404 (
405 "INSERT INTO my_table WITH cte AS (SELECT * FROM other_table) SELECT * FROM cte",
406 true,
407 ),
408 (
409 "INSERT INTO my_table SELECT * FROM t1 UNION ALL SELECT * FROM t2",
410 true,
411 ),
412 ("INSERT INTO my_table VALUES(1)", false),
413 ("INSERT INTO my_table VALUES(now())", false),
414 ("INSERT INTO my_table VALUES(1 + 1)", false),
415 ];
416
417 for (sql, expected) in cases {
418 let stmt = ParserContext::create_with_dialect(
419 sql,
420 &GreptimeDbDialect {},
421 ParseOptions::default(),
422 )
423 .unwrap()
424 .remove(0);
425 match stmt {
426 Statement::Insert(insert) => {
427 assert_eq!(insert.has_non_values_query_source(), expected, "{sql}");
428 }
429 _ => unreachable!(),
430 }
431 }
432 }
433}