1mod ast_literal;
2mod data_type;
3mod ddl;
4mod error;
5mod expr;
6mod function;
7mod operator;
8mod query;
9
10pub use self::{
11 data_type::translate_data_type,
12 ddl::{translate_column_def, translate_operate_function_arg},
13 error::TranslateError,
14 expr::{translate_expr, translate_order_by_expr},
15 query::{alias_or_name, translate_query, translate_select_item},
16};
17
18use {
19 crate::{
20 ast::{Assignment, ForeignKey, ReferentialAction, Statement, Variable},
21 result::Result,
22 },
23 ddl::translate_alter_table_operation,
24 sqlparser::ast::{
25 Assignment as SqlAssignment, AssignmentTarget as SqlAssignmentTarget,
26 CommentDef as SqlCommentDef, CreateFunctionBody as SqlCreateFunctionBody,
27 CreateIndex as SqlCreateIndex, CreateTable as SqlCreateTable, Delete as SqlDelete,
28 FromTable as SqlFromTable, Ident as SqlIdent, Insert as SqlInsert,
29 ObjectName as SqlObjectName, ObjectType as SqlObjectType,
30 ReferentialAction as SqlReferentialAction, Statement as SqlStatement,
31 TableConstraint as SqlTableConstraint, TableFactor, TableWithJoins,
32 },
33};
34
35pub fn translate(sql_statement: &SqlStatement) -> Result<Statement> {
36 match sql_statement {
37 SqlStatement::Query(query) => translate_query(query).map(Statement::Query),
38 SqlStatement::Insert(SqlInsert {
39 table_name,
40 columns,
41 source,
42 ..
43 }) => {
44 let table_name = translate_object_name(table_name)?;
45 let columns = translate_idents(columns);
46 let source = source
47 .as_deref()
48 .ok_or_else(|| {
49 TranslateError::DefaultValuesOnInsertNotSupported(table_name.clone()).into()
50 })
51 .and_then(translate_query)?;
52
53 Ok(Statement::Insert {
54 table_name,
55 columns,
56 source,
57 })
58 }
59 SqlStatement::Update {
60 table,
61 assignments,
62 selection,
63 ..
64 } => Ok(Statement::Update {
65 table_name: translate_table_with_join(table)?,
66 assignments: assignments
67 .iter()
68 .map(translate_assignment)
69 .collect::<Result<_>>()?,
70 selection: selection.as_ref().map(translate_expr).transpose()?,
71 }),
72 SqlStatement::Delete(SqlDelete {
73 from, selection, ..
74 }) => {
75 let from = match from {
76 SqlFromTable::WithFromKeyword(from) => from,
77 SqlFromTable::WithoutKeyword(_) => {
78 return Err(TranslateError::UnreachableOmittingFromInDelete.into());
79 }
80 };
81 let table_name = from
82 .iter()
83 .map(translate_table_with_join)
84 .next()
85 .ok_or(TranslateError::UnreachableEmptyTable)??;
86
87 Ok(Statement::Delete {
88 table_name,
89 selection: selection.as_ref().map(translate_expr).transpose()?,
90 })
91 }
92 SqlStatement::CreateTable(SqlCreateTable {
93 if_not_exists,
94 name,
95 columns,
96 query,
97 engine,
98 constraints,
99 comment,
100 ..
101 }) => {
102 let columns = columns
103 .iter()
104 .map(translate_column_def)
105 .collect::<Result<Vec<_>>>()?;
106
107 let columns = (!columns.is_empty()).then_some(columns);
108
109 let name = translate_object_name(name)?;
110
111 let foreign_keys = constraints
112 .iter()
113 .map(translate_foreign_key)
114 .collect::<Result<Vec<_>>>()?;
115
116 Ok(Statement::CreateTable {
117 if_not_exists: *if_not_exists,
118 name,
119 columns,
120 source: match query {
121 Some(v) => Some(translate_query(v).map(Box::new)?),
122 None => None,
123 },
124 engine: engine
125 .as_ref()
126 .map(|table_engine| table_engine.name.to_owned()),
127 foreign_keys,
128 comment: comment.as_ref().map(|comment| match comment {
129 SqlCommentDef::WithEq(comment)
130 | SqlCommentDef::WithoutEq(comment)
131 | SqlCommentDef::AfterColumnDefsWithoutEq(comment) => comment.to_owned(),
132 }),
133 })
134 }
135 SqlStatement::AlterTable {
136 name, operations, ..
137 } => {
138 if operations.len() > 1 {
139 return Err(TranslateError::UnsupportedMultipleAlterTableOperations.into());
140 }
141
142 let operation = operations
143 .iter()
144 .next()
145 .ok_or(TranslateError::UnreachableEmptyAlterTableOperation)?;
146
147 Ok(Statement::AlterTable {
148 name: translate_object_name(name)?,
149 operation: translate_alter_table_operation(operation)?,
150 })
151 }
152 SqlStatement::Drop {
153 object_type: SqlObjectType::Table,
154 if_exists,
155 names,
156 cascade,
157 ..
158 } => Ok(Statement::DropTable {
159 if_exists: *if_exists,
160 names: names
161 .iter()
162 .map(translate_object_name)
163 .collect::<Result<Vec<_>>>()?,
164 cascade: *cascade,
165 }),
166 SqlStatement::DropFunction {
167 if_exists,
168 func_desc,
169 ..
170 } => Ok(Statement::DropFunction {
171 if_exists: *if_exists,
172 names: func_desc
173 .iter()
174 .map(|v| translate_object_name(&v.name))
175 .collect::<Result<Vec<_>>>()?,
176 }),
177 SqlStatement::CreateIndex(SqlCreateIndex {
178 name,
179 table_name,
180 columns,
181 ..
182 }) => {
183 if columns.len() > 1 {
184 return Err(TranslateError::CompositeIndexNotSupported.into());
185 }
186
187 let Some(name) = name else {
188 return Err(TranslateError::UnsupportedUnnamedIndex.into());
189 };
190
191 let name = translate_object_name(name)?;
192
193 if name.to_uppercase() == "PRIMARY" {
194 return Err(TranslateError::ReservedIndexName(name).into());
195 };
196
197 Ok(Statement::CreateIndex {
198 name,
199 table_name: translate_object_name(table_name)?,
200 column: translate_order_by_expr(&columns[0])?,
201 })
202 }
203 SqlStatement::Drop {
204 object_type: SqlObjectType::Index,
205 names,
206 ..
207 } => {
208 if names.len() > 1 {
209 return Err(TranslateError::TooManyParamsInDropIndex.into());
210 }
211
212 let object_name = &names[0].0;
213 if object_name.len() != 2 {
214 return Err(TranslateError::InvalidParamsInDropIndex.into());
215 }
216
217 let table_name = object_name[0].value.to_owned();
218 let name = object_name[1].value.to_owned();
219
220 if name.to_uppercase() == "PRIMARY" {
221 return Err(TranslateError::CannotDropPrimary.into());
222 };
223
224 Ok(Statement::DropIndex { name, table_name })
225 }
226 SqlStatement::StartTransaction { .. } => Ok(Statement::StartTransaction),
227 SqlStatement::Commit { .. } => Ok(Statement::Commit),
228 SqlStatement::Rollback { .. } => Ok(Statement::Rollback),
229 SqlStatement::ShowTables {
230 filter: None,
231 db_name: None,
232 ..
233 } => Ok(Statement::ShowVariable(Variable::Tables)),
234 SqlStatement::ShowFunctions { filter: None } => {
235 Ok(Statement::ShowVariable(Variable::Functions))
236 }
237 SqlStatement::ShowVariable { variable } => match (variable.len(), variable.first()) {
238 (1, Some(keyword)) => match keyword.value.to_uppercase().as_str() {
239 "VERSION" => Ok(Statement::ShowVariable(Variable::Version)),
240 v => Err(TranslateError::UnsupportedShowVariableKeyword(v.to_owned()).into()),
241 },
242 (3, Some(keyword)) => match keyword.value.to_uppercase().as_str() {
243 "INDEXES" => match variable.get(2) {
244 Some(tablename) => Ok(Statement::ShowIndexes(tablename.value.to_owned())),
245 _ => Err(TranslateError::UnsupportedShowVariableStatement(
246 sql_statement.to_string(),
247 )
248 .into()),
249 },
250 _ => Err(TranslateError::UnsupportedShowVariableStatement(
251 sql_statement.to_string(),
252 )
253 .into()),
254 },
255 _ => Err(
256 TranslateError::UnsupportedShowVariableStatement(sql_statement.to_string()).into(),
257 ),
258 },
259 SqlStatement::ShowColumns { table_name, .. } => Ok(Statement::ShowColumns {
260 table_name: translate_object_name(table_name)?,
261 }),
262 SqlStatement::CreateFunction {
263 or_replace,
264 name,
265 args,
266 function_body: Some(SqlCreateFunctionBody::Return(return_)),
267 ..
268 } => {
269 let args = args
270 .as_ref()
271 .map(|args| {
272 args.iter()
273 .map(translate_operate_function_arg)
274 .collect::<Result<Vec<_>>>()
275 })
276 .transpose()?;
277 Ok(Statement::CreateFunction {
278 or_replace: *or_replace,
279 name: translate_object_name(name)?,
280 args: args.unwrap_or_default(),
281 return_: translate_expr(return_)?,
282 })
283 }
284 SqlStatement::CreateFunction { .. } => {
285 Err(TranslateError::UnsupportedEmptyFunctionBody.into())
286 }
287 _ => Err(TranslateError::UnsupportedStatement(sql_statement.to_string()).into()),
288 }
289}
290
291pub fn translate_assignment(sql_assignment: &SqlAssignment) -> Result<Assignment> {
292 let SqlAssignment { target, value } = sql_assignment;
293
294 let id = match target {
295 SqlAssignmentTarget::Tuple(_) => {
296 return Err(TranslateError::TupleAssignmentOnUpdateNotSupported(
297 sql_assignment.to_string(),
298 )
299 .into());
300 }
301 SqlAssignmentTarget::ColumnName(SqlObjectName(id)) => id,
302 };
303
304 if id.len() > 1 {
305 return Err(
306 TranslateError::CompoundIdentOnUpdateNotSupported(sql_assignment.to_string()).into(),
307 );
308 }
309
310 Ok(Assignment {
311 id: id
312 .first()
313 .ok_or(TranslateError::UnreachableEmptyIdent)?
314 .value
315 .to_owned(),
316 value: translate_expr(value)?,
317 })
318}
319
320fn translate_table_with_join(table: &TableWithJoins) -> Result<String> {
321 if !table.joins.is_empty() {
322 return Err(TranslateError::JoinOnUpdateNotSupported.into());
323 }
324 match &table.relation {
325 TableFactor::Table { name, .. } => translate_object_name(name),
326 t => Err(TranslateError::UnsupportedTableFactor(t.to_string()).into()),
327 }
328}
329
330fn translate_object_name(sql_object_name: &SqlObjectName) -> Result<String> {
331 let sql_object_name = &sql_object_name.0;
332 if sql_object_name.len() > 1 {
333 let compound_object_name = translate_idents(sql_object_name).join(".");
334 return Err(TranslateError::CompoundObjectNotSupported(compound_object_name).into());
335 }
336
337 sql_object_name
338 .first()
339 .map(|v| v.value.to_owned())
340 .ok_or_else(|| TranslateError::UnreachableEmptyObject.into())
341}
342
343pub fn translate_idents(idents: &[SqlIdent]) -> Vec<String> {
344 idents.iter().map(|v| v.value.to_owned()).collect()
345}
346
347pub fn translate_referential_action(
348 action: &Option<SqlReferentialAction>,
349) -> Result<ReferentialAction> {
350 use SqlReferentialAction::*;
351
352 let action = action.unwrap_or(NoAction);
353
354 match action {
355 NoAction | Restrict => Ok(ReferentialAction::NoAction),
356 _ => Err(TranslateError::UnsupportedConstraint(action.to_string()).into()),
357 }
358}
359
360pub fn translate_foreign_key(table_constraint: &SqlTableConstraint) -> Result<ForeignKey> {
361 match table_constraint {
362 SqlTableConstraint::ForeignKey {
363 name,
364 columns,
365 foreign_table,
366 referred_columns,
367 on_delete,
368 on_update,
369 ..
370 } => {
371 let referencing_column_name = columns.first().map(|i| i.value.clone()).ok_or(
372 TranslateError::UnreachableForeignKeyColumns(
373 columns.iter().map(|i| i.to_string()).collect::<String>(),
374 ),
375 )?;
376
377 let referenced_column_name = referred_columns
378 .first()
379 .ok_or(TranslateError::UnreachableForeignKeyColumns(
380 columns.iter().map(|i| i.to_string()).collect::<String>(),
381 ))?
382 .value
383 .clone();
384
385 let referenced_table_name = translate_object_name(foreign_table)?;
386
387 let name = match name {
388 Some(name) => name.value.clone(),
389 None => {
390 format!(
391 "FK_{referencing_column_name}-{referenced_table_name}_{referenced_column_name}"
392 )
393 }
394 };
395
396 Ok(ForeignKey {
397 name,
398 referencing_column_name,
399 referenced_table_name,
400 referenced_column_name,
401 on_delete: translate_referential_action(on_delete)?,
402 on_update: translate_referential_action(on_update)?,
403 })
404 }
405 _ => Err(TranslateError::UnsupportedConstraint(table_constraint.to_string()).into()),
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use {super::*, crate::parse_sql::parse};
412
413 #[test]
414 fn statement() {
415 let sql = "INSERT INTO Foo DEFAULT VALUES";
416 let actual = parse(sql).and_then(|parsed| translate(&parsed[0]));
417 let expected =
418 Err(TranslateError::DefaultValuesOnInsertNotSupported("Foo".to_owned()).into());
419
420 assert_eq!(actual, expected);
421 }
422
423 #[test]
424 fn test_tuple_assignment_on_update_not_supported() {
425 let sql = "UPDATE Foo SET (a, b) = (1, 2)";
426 let actual = parse(sql).and_then(|parsed| translate(&parsed[0]));
427 let expected = Err(TranslateError::TupleAssignmentOnUpdateNotSupported(
428 "(a, b) = (1, 2)".to_owned(),
429 )
430 .into());
431
432 assert_eq!(actual, expected);
433 }
434}