1use super::{DialectImpl, DialectType};
17use crate::error::Result;
18use crate::expressions::{BinaryFunc, CeilFunc, Expression, Function, LikeOp, UnaryFunc};
19#[cfg(feature = "generate")]
20use crate::generator::GeneratorConfig;
21use crate::tokens::TokenizerConfig;
22
23pub struct OracleDialect;
25
26impl DialectImpl for OracleDialect {
27 fn dialect_type(&self) -> DialectType {
28 DialectType::Oracle
29 }
30
31 fn tokenizer_config(&self) -> TokenizerConfig {
32 let mut config = TokenizerConfig::default();
33 config.identifiers.insert('"', '"');
35 config.nested_comments = false;
37 config
38 }
39
40 #[cfg(feature = "generate")]
41
42 fn generator_config(&self) -> GeneratorConfig {
43 use crate::generator::IdentifierQuoteStyle;
44 GeneratorConfig {
45 identifier_quote: '"',
46 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
47 dialect: Some(DialectType::Oracle),
48 supports_column_join_marks: true,
49 alter_table_include_column_keyword: false,
51 tablesample_keywords: "SAMPLE",
53 alias_post_tablesample: true,
55 tz_to_with_time_zone: true,
57 unpivot_aliases_are_identifiers: false,
59 ..Default::default()
60 }
61 }
62
63 #[cfg(feature = "transpile")]
64
65 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
66 match expr {
67 Expression::IfNull(f) => Ok(Expression::Nvl(f)),
69
70 Expression::Coalesce(f) if f.expressions.len() == 2 => {
72 let mut exprs = f.expressions;
73 let second = exprs.pop().unwrap();
74 let first = exprs.pop().unwrap();
75 Ok(Expression::Nvl(Box::new(BinaryFunc {
76 original_name: None,
77 this: first,
78 expression: second,
79 inferred_type: None,
80 })))
81 }
82
83 Expression::Nvl(f) => Ok(Expression::Nvl(f)),
85
86 Expression::TryCast(c) => Ok(Expression::Cast(c)),
88
89 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
91
92 Expression::ILike(op) => {
94 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
95 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
96 Ok(Expression::Like(Box::new(LikeOp {
97 left: lower_left,
98 right: lower_right,
99 escape: op.escape,
100 quantifier: op.quantifier,
101 inferred_type: None,
102 })))
103 }
104
105 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
107 "DBMS_RANDOM.VALUE".to_string(),
108 vec![],
109 )))),
110
111 Expression::Rand(_) => Ok(Expression::Function(Box::new(Function::new(
113 "DBMS_RANDOM.VALUE".to_string(),
114 vec![],
115 )))),
116
117 Expression::Concat(op) => Ok(Expression::Concat(op)),
119
120 Expression::Unnest(f) => Ok(Expression::Function(Box::new(Function::new(
123 "TABLE".to_string(),
124 vec![f.this],
125 )))),
126
127 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
129 "TABLE".to_string(),
130 vec![f.this],
131 )))),
132
133 Expression::Function(f) => self.transform_function(*f),
135
136 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
138
139 _ => Ok(expr),
141 }
142 }
143}
144
145#[cfg(feature = "transpile")]
146impl OracleDialect {
147 fn transform_function(&self, f: Function) -> Result<Expression> {
148 let name_upper = f.name.to_uppercase();
149 match name_upper.as_str() {
150 "IFNULL" if f.args.len() == 2 => {
152 let mut args = f.args;
153 let second = args.pop().unwrap();
154 let first = args.pop().unwrap();
155 Ok(Expression::Nvl(Box::new(BinaryFunc {
156 original_name: None,
157 this: first,
158 expression: second,
159 inferred_type: None,
160 })))
161 }
162
163 "ISNULL" if f.args.len() == 2 => {
165 let mut args = f.args;
166 let second = args.pop().unwrap();
167 let first = args.pop().unwrap();
168 Ok(Expression::Nvl(Box::new(BinaryFunc {
169 original_name: None,
170 this: first,
171 expression: second,
172 inferred_type: None,
173 })))
174 }
175
176 "NVL" if f.args.len() == 2 => {
178 let mut args = f.args;
179 let second = args.pop().unwrap();
180 let first = args.pop().unwrap();
181 Ok(Expression::Nvl(Box::new(BinaryFunc {
182 original_name: None,
183 this: first,
184 expression: second,
185 inferred_type: None,
186 })))
187 }
188
189 "NVL2" => Ok(Expression::Function(Box::new(f))),
191
192 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
194 Function::new("LISTAGG".to_string(), f.args),
195 ))),
196
197 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
199 Function::new("LISTAGG".to_string(), f.args),
200 ))),
201
202 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
204
205 "SUBSTRING" => Ok(Expression::Function(Box::new(Function::new(
207 "SUBSTR".to_string(),
208 f.args,
209 )))),
210
211 "SUBSTR" => Ok(Expression::Function(Box::new(f))),
213
214 "LENGTH" => Ok(Expression::Function(Box::new(f))),
216
217 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
219 f.args.into_iter().next().unwrap(),
220 )))),
221
222 "RANDOM" | "RAND" => Ok(Expression::Function(Box::new(Function::new(
224 "DBMS_RANDOM.VALUE".to_string(),
225 vec![],
226 )))),
227
228 "NOW" => Ok(Expression::CurrentTimestamp(
230 crate::expressions::CurrentTimestamp {
231 precision: None,
232 sysdate: false,
233 },
234 )),
235
236 "GETDATE" => Ok(Expression::Function(Box::new(Function::new(
238 "SYSDATE".to_string(),
239 vec![],
240 )))),
241
242 "CURRENT_TIMESTAMP" => {
245 if f.args.is_empty() {
246 Ok(Expression::CurrentTimestamp(
247 crate::expressions::CurrentTimestamp {
248 precision: None,
249 sysdate: false,
250 },
251 ))
252 } else if f.args.len() == 1 {
253 if let Expression::Literal(lit) = &f.args[0] {
255 if let crate::expressions::Literal::Number(n) = lit.as_ref() {
256 if let Ok(precision) = n.parse::<u32>() {
257 return Ok(Expression::CurrentTimestamp(
258 crate::expressions::CurrentTimestamp {
259 precision: Some(precision),
260 sysdate: false,
261 },
262 ));
263 }
264 }
265 }
266 Ok(Expression::Function(Box::new(f)))
268 } else {
269 Ok(Expression::Function(Box::new(f)))
271 }
272 }
273
274 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
276
277 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
279
280 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
282
283 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
285
286 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
288 "TO_CHAR".to_string(),
289 f.args,
290 )))),
291
292 "STRFTIME" => Ok(Expression::Function(Box::new(Function::new(
294 "TO_CHAR".to_string(),
295 f.args,
296 )))),
297
298 "DATE_TRUNC" => Ok(Expression::Function(Box::new(Function::new(
300 "TRUNC".to_string(),
301 f.args,
302 )))),
303
304 "TRUNC" if f.args.len() == 1 && Self::is_temporal_expr(&f.args[0]) => {
307 let mut args = f.args;
308 args.push(Expression::Literal(Box::new(
309 crate::expressions::Literal::String("DD".to_string()),
310 )));
311 Ok(Expression::Function(Box::new(Function::new(
312 "TRUNC".to_string(),
313 args,
314 ))))
315 }
316 "TRUNC" => Ok(Expression::Function(Box::new(f))),
317
318 "EXTRACT" => Ok(Expression::Function(Box::new(f))),
320
321 "POSITION" if f.args.len() == 2 => {
324 let mut args = f.args;
325 let first = args.remove(0);
326 let second = args.remove(0);
327 Ok(Expression::Function(Box::new(Function::new(
329 "INSTR".to_string(),
330 vec![second, first],
331 ))))
332 }
333
334 "STRPOS" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
336 "INSTR".to_string(),
337 f.args,
338 )))),
339
340 "CHARINDEX" if f.args.len() >= 2 => {
342 let mut args = f.args;
343 let substring = args.remove(0);
344 let string = args.remove(0);
345 let mut instr_args = vec![string, substring];
347 if !args.is_empty() {
348 instr_args.push(args.remove(0));
349 }
350 Ok(Expression::Function(Box::new(Function::new(
351 "INSTR".to_string(),
352 instr_args,
353 ))))
354 }
355
356 "INSTR" => Ok(Expression::Function(Box::new(f))),
358
359 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
361 this: f.args.into_iter().next().unwrap(),
362 decimals: None,
363 to: None,
364 }))),
365
366 "CEIL" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
368 this: f.args.into_iter().next().unwrap(),
369 decimals: None,
370 to: None,
371 }))),
372
373 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
376 "LN".to_string(),
377 f.args,
378 )))),
379
380 "LN" => Ok(Expression::Function(Box::new(f))),
382
383 "POWER" | "POW" => Ok(Expression::Function(Box::new(Function::new(
385 "POWER".to_string(),
386 f.args,
387 )))),
388
389 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(f))),
391
392 "JSON_VALUE" => Ok(Expression::Function(Box::new(f))),
394
395 "JSON_QUERY" => Ok(Expression::Function(Box::new(f))),
397
398 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
400 "JSON_VALUE".to_string(),
401 f.args,
402 )))),
403
404 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
406 "JSON_VALUE".to_string(),
407 f.args,
408 )))),
409
410 "SPLIT" => {
413 Ok(Expression::Function(Box::new(Function::new(
415 "REGEXP_SUBSTR".to_string(),
416 f.args,
417 ))))
418 }
419
420 "ADD_MONTHS" => Ok(Expression::Function(Box::new(f))),
422
423 "MONTHS_BETWEEN" => Ok(Expression::Function(Box::new(f))),
425
426 "DATEADD" => {
428 Ok(Expression::Function(Box::new(f)))
430 }
431
432 "DATEDIFF" => Ok(Expression::Function(Box::new(f))),
434
435 "DECODE" => Ok(Expression::Function(Box::new(f))),
437
438 _ => Ok(Expression::Function(Box::new(f))),
440 }
441 }
442
443 fn transform_aggregate_function(
444 &self,
445 f: Box<crate::expressions::AggregateFunction>,
446 ) -> Result<Expression> {
447 let name_upper = f.name.to_uppercase();
448 match name_upper.as_str() {
449 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
451 Function::new("LISTAGG".to_string(), f.args),
452 ))),
453
454 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
456 Function::new("LISTAGG".to_string(), f.args),
457 ))),
458
459 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
462 "COLLECT".to_string(),
463 f.args,
464 )))),
465
466 _ => Ok(Expression::AggregateFunction(f)),
468 }
469 }
470
471 fn is_temporal_expr(expr: &Expression) -> bool {
473 matches!(
474 expr,
475 Expression::CurrentTimestamp(_)
476 | Expression::CurrentDate(_)
477 | Expression::CurrentTime(_)
478 | Expression::Localtimestamp(_)
479 ) || matches!(expr, Expression::Function(f) if {
480 let name = f.name.to_uppercase();
481 name == "SYSDATE" || name == "SYSTIMESTAMP" || name == "TO_DATE" || name == "TO_TIMESTAMP"
482 })
483 }
484}