1use super::{DialectImpl, DialectType};
17use crate::error::Result;
18use crate::expressions::{BinaryFunc, CeilFunc, Expression, Function, LikeOp, UnaryFunc};
19use crate::generator::GeneratorConfig;
20use crate::tokens::TokenizerConfig;
21
22pub struct OracleDialect;
24
25impl DialectImpl for OracleDialect {
26 fn dialect_type(&self) -> DialectType {
27 DialectType::Oracle
28 }
29
30 fn tokenizer_config(&self) -> TokenizerConfig {
31 let mut config = TokenizerConfig::default();
32 config.identifiers.insert('"', '"');
34 config.nested_comments = false;
36 config
37 }
38
39 fn generator_config(&self) -> GeneratorConfig {
40 use crate::generator::IdentifierQuoteStyle;
41 GeneratorConfig {
42 identifier_quote: '"',
43 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
44 dialect: Some(DialectType::Oracle),
45 supports_column_join_marks: true,
46 alter_table_include_column_keyword: false,
48 tablesample_keywords: "SAMPLE",
50 alias_post_tablesample: true,
52 tz_to_with_time_zone: true,
54 ..Default::default()
55 }
56 }
57
58 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
59 match expr {
60 Expression::IfNull(f) => Ok(Expression::Nvl(f)),
62
63 Expression::Coalesce(f) if f.expressions.len() == 2 => {
65 let mut exprs = f.expressions;
66 let second = exprs.pop().unwrap();
67 let first = exprs.pop().unwrap();
68 Ok(Expression::Nvl(Box::new(BinaryFunc {
69 original_name: None,
70 this: first,
71 expression: second,
72 inferred_type: None,
73 })))
74 }
75
76 Expression::Nvl(f) => Ok(Expression::Nvl(f)),
78
79 Expression::TryCast(c) => Ok(Expression::Cast(c)),
81
82 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
84
85 Expression::ILike(op) => {
87 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
88 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
89 Ok(Expression::Like(Box::new(LikeOp {
90 left: lower_left,
91 right: lower_right,
92 escape: op.escape,
93 quantifier: op.quantifier,
94 inferred_type: None,
95 })))
96 }
97
98 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
100 "DBMS_RANDOM.VALUE".to_string(),
101 vec![],
102 )))),
103
104 Expression::Rand(_) => Ok(Expression::Function(Box::new(Function::new(
106 "DBMS_RANDOM.VALUE".to_string(),
107 vec![],
108 )))),
109
110 Expression::Concat(op) => Ok(Expression::Concat(op)),
112
113 Expression::Unnest(f) => Ok(Expression::Function(Box::new(Function::new(
116 "TABLE".to_string(),
117 vec![f.this],
118 )))),
119
120 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
122 "TABLE".to_string(),
123 vec![f.this],
124 )))),
125
126 Expression::Function(f) => self.transform_function(*f),
128
129 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
131
132 _ => Ok(expr),
134 }
135 }
136}
137
138impl OracleDialect {
139 fn transform_function(&self, f: Function) -> Result<Expression> {
140 let name_upper = f.name.to_uppercase();
141 match name_upper.as_str() {
142 "IFNULL" if f.args.len() == 2 => {
144 let mut args = f.args;
145 let second = args.pop().unwrap();
146 let first = args.pop().unwrap();
147 Ok(Expression::Nvl(Box::new(BinaryFunc {
148 original_name: None,
149 this: first,
150 expression: second,
151 inferred_type: None,
152 })))
153 }
154
155 "ISNULL" if f.args.len() == 2 => {
157 let mut args = f.args;
158 let second = args.pop().unwrap();
159 let first = args.pop().unwrap();
160 Ok(Expression::Nvl(Box::new(BinaryFunc {
161 original_name: None,
162 this: first,
163 expression: second,
164 inferred_type: None,
165 })))
166 }
167
168 "NVL" if f.args.len() == 2 => {
170 let mut args = f.args;
171 let second = args.pop().unwrap();
172 let first = args.pop().unwrap();
173 Ok(Expression::Nvl(Box::new(BinaryFunc {
174 original_name: None,
175 this: first,
176 expression: second,
177 inferred_type: None,
178 })))
179 }
180
181 "NVL2" => Ok(Expression::Function(Box::new(f))),
183
184 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
186 Function::new("LISTAGG".to_string(), f.args),
187 ))),
188
189 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
191 Function::new("LISTAGG".to_string(), f.args),
192 ))),
193
194 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
196
197 "SUBSTRING" => Ok(Expression::Function(Box::new(Function::new(
199 "SUBSTR".to_string(),
200 f.args,
201 )))),
202
203 "SUBSTR" => Ok(Expression::Function(Box::new(f))),
205
206 "LENGTH" => Ok(Expression::Function(Box::new(f))),
208
209 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
211 f.args.into_iter().next().unwrap(),
212 )))),
213
214 "RANDOM" | "RAND" => Ok(Expression::Function(Box::new(Function::new(
216 "DBMS_RANDOM.VALUE".to_string(),
217 vec![],
218 )))),
219
220 "NOW" => Ok(Expression::CurrentTimestamp(
222 crate::expressions::CurrentTimestamp {
223 precision: None,
224 sysdate: false,
225 },
226 )),
227
228 "GETDATE" => Ok(Expression::Function(Box::new(Function::new(
230 "SYSDATE".to_string(),
231 vec![],
232 )))),
233
234 "CURRENT_TIMESTAMP" => {
237 if f.args.is_empty() {
238 Ok(Expression::CurrentTimestamp(
239 crate::expressions::CurrentTimestamp {
240 precision: None,
241 sysdate: false,
242 },
243 ))
244 } else if f.args.len() == 1 {
245 if let Expression::Literal(crate::expressions::Literal::Number(n)) = &f.args[0]
247 {
248 if let Ok(precision) = n.parse::<u32>() {
249 return Ok(Expression::CurrentTimestamp(
250 crate::expressions::CurrentTimestamp {
251 precision: Some(precision),
252 sysdate: false,
253 },
254 ));
255 }
256 }
257 Ok(Expression::Function(Box::new(f)))
259 } else {
260 Ok(Expression::Function(Box::new(f)))
262 }
263 }
264
265 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
267
268 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
270
271 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
273
274 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
276
277 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
279 "TO_CHAR".to_string(),
280 f.args,
281 )))),
282
283 "STRFTIME" => Ok(Expression::Function(Box::new(Function::new(
285 "TO_CHAR".to_string(),
286 f.args,
287 )))),
288
289 "DATE_TRUNC" => Ok(Expression::Function(Box::new(Function::new(
291 "TRUNC".to_string(),
292 f.args,
293 )))),
294
295 "TRUNC" if f.args.len() == 1 && Self::is_temporal_expr(&f.args[0]) => {
298 let mut args = f.args;
299 args.push(Expression::Literal(crate::expressions::Literal::String("DD".to_string())));
300 Ok(Expression::Function(Box::new(Function::new(
301 "TRUNC".to_string(),
302 args,
303 ))))
304 }
305 "TRUNC" => Ok(Expression::Function(Box::new(f))),
306
307 "EXTRACT" => Ok(Expression::Function(Box::new(f))),
309
310 "POSITION" if f.args.len() == 2 => {
313 let mut args = f.args;
314 let first = args.remove(0);
315 let second = args.remove(0);
316 Ok(Expression::Function(Box::new(Function::new(
318 "INSTR".to_string(),
319 vec![second, first],
320 ))))
321 }
322
323 "STRPOS" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
325 "INSTR".to_string(),
326 f.args,
327 )))),
328
329 "CHARINDEX" if f.args.len() >= 2 => {
331 let mut args = f.args;
332 let substring = args.remove(0);
333 let string = args.remove(0);
334 let mut instr_args = vec![string, substring];
336 if !args.is_empty() {
337 instr_args.push(args.remove(0));
338 }
339 Ok(Expression::Function(Box::new(Function::new(
340 "INSTR".to_string(),
341 instr_args,
342 ))))
343 }
344
345 "INSTR" => Ok(Expression::Function(Box::new(f))),
347
348 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
350 this: f.args.into_iter().next().unwrap(),
351 decimals: None,
352 to: None,
353 }))),
354
355 "CEIL" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
357 this: f.args.into_iter().next().unwrap(),
358 decimals: None,
359 to: None,
360 }))),
361
362 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
365 "LN".to_string(),
366 f.args,
367 )))),
368
369 "LN" => Ok(Expression::Function(Box::new(f))),
371
372 "POWER" | "POW" => Ok(Expression::Function(Box::new(Function::new(
374 "POWER".to_string(),
375 f.args,
376 )))),
377
378 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(f))),
380
381 "JSON_VALUE" => Ok(Expression::Function(Box::new(f))),
383
384 "JSON_QUERY" => Ok(Expression::Function(Box::new(f))),
386
387 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
389 "JSON_VALUE".to_string(),
390 f.args,
391 )))),
392
393 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
395 "JSON_VALUE".to_string(),
396 f.args,
397 )))),
398
399 "SPLIT" => {
402 Ok(Expression::Function(Box::new(Function::new(
404 "REGEXP_SUBSTR".to_string(),
405 f.args,
406 ))))
407 }
408
409 "ADD_MONTHS" => Ok(Expression::Function(Box::new(f))),
411
412 "MONTHS_BETWEEN" => Ok(Expression::Function(Box::new(f))),
414
415 "DATEADD" => {
417 Ok(Expression::Function(Box::new(f)))
419 }
420
421 "DATEDIFF" => Ok(Expression::Function(Box::new(f))),
423
424 "DECODE" => Ok(Expression::Function(Box::new(f))),
426
427 _ => Ok(Expression::Function(Box::new(f))),
429 }
430 }
431
432 fn transform_aggregate_function(
433 &self,
434 f: Box<crate::expressions::AggregateFunction>,
435 ) -> Result<Expression> {
436 let name_upper = f.name.to_uppercase();
437 match name_upper.as_str() {
438 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
440 Function::new("LISTAGG".to_string(), f.args),
441 ))),
442
443 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
445 Function::new("LISTAGG".to_string(), f.args),
446 ))),
447
448 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
451 "COLLECT".to_string(),
452 f.args,
453 )))),
454
455 _ => Ok(Expression::AggregateFunction(f)),
457 }
458 }
459
460 fn is_temporal_expr(expr: &Expression) -> bool {
462 matches!(
463 expr,
464 Expression::CurrentTimestamp(_)
465 | Expression::CurrentDate(_)
466 | Expression::CurrentTime(_)
467 | Expression::Localtimestamp(_)
468 ) || matches!(expr, Expression::Function(f) if {
469 let name = f.name.to_uppercase();
470 name == "SYSDATE" || name == "SYSTIMESTAMP" || name == "TO_DATE" || name == "TO_TIMESTAMP"
471 })
472 }
473}