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 ..Default::default()
58 }
59 }
60
61 #[cfg(feature = "transpile")]
62
63 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
64 match expr {
65 Expression::IfNull(f) => Ok(Expression::Nvl(f)),
67
68 Expression::Coalesce(f) if f.expressions.len() == 2 => {
70 let mut exprs = f.expressions;
71 let second = exprs.pop().unwrap();
72 let first = exprs.pop().unwrap();
73 Ok(Expression::Nvl(Box::new(BinaryFunc {
74 original_name: None,
75 this: first,
76 expression: second,
77 inferred_type: None,
78 })))
79 }
80
81 Expression::Nvl(f) => Ok(Expression::Nvl(f)),
83
84 Expression::TryCast(c) => Ok(Expression::Cast(c)),
86
87 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
89
90 Expression::ILike(op) => {
92 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left)));
93 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right)));
94 Ok(Expression::Like(Box::new(LikeOp {
95 left: lower_left,
96 right: lower_right,
97 escape: op.escape,
98 quantifier: op.quantifier,
99 inferred_type: None,
100 })))
101 }
102
103 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
105 "DBMS_RANDOM.VALUE".to_string(),
106 vec![],
107 )))),
108
109 Expression::Rand(_) => Ok(Expression::Function(Box::new(Function::new(
111 "DBMS_RANDOM.VALUE".to_string(),
112 vec![],
113 )))),
114
115 Expression::Concat(op) => Ok(Expression::Concat(op)),
117
118 Expression::Unnest(f) => Ok(Expression::Function(Box::new(Function::new(
121 "TABLE".to_string(),
122 vec![f.this],
123 )))),
124
125 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
127 "TABLE".to_string(),
128 vec![f.this],
129 )))),
130
131 Expression::Function(f) => self.transform_function(*f),
133
134 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
136
137 _ => Ok(expr),
139 }
140 }
141}
142
143#[cfg(feature = "transpile")]
144impl OracleDialect {
145 fn transform_function(&self, f: Function) -> Result<Expression> {
146 let name_upper = f.name.to_uppercase();
147 match name_upper.as_str() {
148 "IFNULL" if f.args.len() == 2 => {
150 let mut args = f.args;
151 let second = args.pop().unwrap();
152 let first = args.pop().unwrap();
153 Ok(Expression::Nvl(Box::new(BinaryFunc {
154 original_name: None,
155 this: first,
156 expression: second,
157 inferred_type: None,
158 })))
159 }
160
161 "ISNULL" if f.args.len() == 2 => {
163 let mut args = f.args;
164 let second = args.pop().unwrap();
165 let first = args.pop().unwrap();
166 Ok(Expression::Nvl(Box::new(BinaryFunc {
167 original_name: None,
168 this: first,
169 expression: second,
170 inferred_type: None,
171 })))
172 }
173
174 "NVL" if f.args.len() == 2 => {
176 let mut args = f.args;
177 let second = args.pop().unwrap();
178 let first = args.pop().unwrap();
179 Ok(Expression::Nvl(Box::new(BinaryFunc {
180 original_name: None,
181 this: first,
182 expression: second,
183 inferred_type: None,
184 })))
185 }
186
187 "NVL2" => Ok(Expression::Function(Box::new(f))),
189
190 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
192 Function::new("LISTAGG".to_string(), f.args),
193 ))),
194
195 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
197 Function::new("LISTAGG".to_string(), f.args),
198 ))),
199
200 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
202
203 "SUBSTRING" => Ok(Expression::Function(Box::new(Function::new(
205 "SUBSTR".to_string(),
206 f.args,
207 )))),
208
209 "SUBSTR" => Ok(Expression::Function(Box::new(f))),
211
212 "LENGTH" => Ok(Expression::Function(Box::new(f))),
214
215 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
217 f.args.into_iter().next().unwrap(),
218 )))),
219
220 "RANDOM" | "RAND" => Ok(Expression::Function(Box::new(Function::new(
222 "DBMS_RANDOM.VALUE".to_string(),
223 vec![],
224 )))),
225
226 "NOW" => Ok(Expression::CurrentTimestamp(
228 crate::expressions::CurrentTimestamp {
229 precision: None,
230 sysdate: false,
231 },
232 )),
233
234 "GETDATE" => Ok(Expression::Function(Box::new(Function::new(
236 "SYSDATE".to_string(),
237 vec![],
238 )))),
239
240 "CURRENT_TIMESTAMP" => {
243 if f.args.is_empty() {
244 Ok(Expression::CurrentTimestamp(
245 crate::expressions::CurrentTimestamp {
246 precision: None,
247 sysdate: false,
248 },
249 ))
250 } else if f.args.len() == 1 {
251 if let Expression::Literal(lit) = &f.args[0] {
253 if let crate::expressions::Literal::Number(n) = lit.as_ref() {
254 if let Ok(precision) = n.parse::<u32>() {
255 return Ok(Expression::CurrentTimestamp(
256 crate::expressions::CurrentTimestamp {
257 precision: Some(precision),
258 sysdate: false,
259 },
260 ));
261 }
262 }
263 }
264 Ok(Expression::Function(Box::new(f)))
266 } else {
267 Ok(Expression::Function(Box::new(f)))
269 }
270 }
271
272 "CURRENT_DATE" => Ok(Expression::CurrentDate(crate::expressions::CurrentDate)),
274
275 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
277
278 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
280
281 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
283
284 "DATE_FORMAT" => Ok(Expression::Function(Box::new(Function::new(
286 "TO_CHAR".to_string(),
287 f.args,
288 )))),
289
290 "STRFTIME" => Ok(Expression::Function(Box::new(Function::new(
292 "TO_CHAR".to_string(),
293 f.args,
294 )))),
295
296 "DATE_TRUNC" => Ok(Expression::Function(Box::new(Function::new(
298 "TRUNC".to_string(),
299 f.args,
300 )))),
301
302 "TRUNC" if f.args.len() == 1 && Self::is_temporal_expr(&f.args[0]) => {
305 let mut args = f.args;
306 args.push(Expression::Literal(Box::new(
307 crate::expressions::Literal::String("DD".to_string()),
308 )));
309 Ok(Expression::Function(Box::new(Function::new(
310 "TRUNC".to_string(),
311 args,
312 ))))
313 }
314 "TRUNC" => Ok(Expression::Function(Box::new(f))),
315
316 "EXTRACT" => Ok(Expression::Function(Box::new(f))),
318
319 "POSITION" if f.args.len() == 2 => {
322 let mut args = f.args;
323 let first = args.remove(0);
324 let second = args.remove(0);
325 Ok(Expression::Function(Box::new(Function::new(
327 "INSTR".to_string(),
328 vec![second, first],
329 ))))
330 }
331
332 "STRPOS" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
334 "INSTR".to_string(),
335 f.args,
336 )))),
337
338 "CHARINDEX" if f.args.len() >= 2 => {
340 let mut args = f.args;
341 let substring = args.remove(0);
342 let string = args.remove(0);
343 let mut instr_args = vec![string, substring];
345 if !args.is_empty() {
346 instr_args.push(args.remove(0));
347 }
348 Ok(Expression::Function(Box::new(Function::new(
349 "INSTR".to_string(),
350 instr_args,
351 ))))
352 }
353
354 "INSTR" => Ok(Expression::Function(Box::new(f))),
356
357 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
359 this: f.args.into_iter().next().unwrap(),
360 decimals: None,
361 to: None,
362 }))),
363
364 "CEIL" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
366 this: f.args.into_iter().next().unwrap(),
367 decimals: None,
368 to: None,
369 }))),
370
371 "LOG" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
374 "LN".to_string(),
375 f.args,
376 )))),
377
378 "LN" => Ok(Expression::Function(Box::new(f))),
380
381 "POWER" | "POW" => Ok(Expression::Function(Box::new(Function::new(
383 "POWER".to_string(),
384 f.args,
385 )))),
386
387 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(f))),
389
390 "JSON_VALUE" => Ok(Expression::Function(Box::new(f))),
392
393 "JSON_QUERY" => Ok(Expression::Function(Box::new(f))),
395
396 "JSON_EXTRACT" => Ok(Expression::Function(Box::new(Function::new(
398 "JSON_VALUE".to_string(),
399 f.args,
400 )))),
401
402 "JSON_EXTRACT_SCALAR" => Ok(Expression::Function(Box::new(Function::new(
404 "JSON_VALUE".to_string(),
405 f.args,
406 )))),
407
408 "SPLIT" => {
411 Ok(Expression::Function(Box::new(Function::new(
413 "REGEXP_SUBSTR".to_string(),
414 f.args,
415 ))))
416 }
417
418 "ADD_MONTHS" => Ok(Expression::Function(Box::new(f))),
420
421 "MONTHS_BETWEEN" => Ok(Expression::Function(Box::new(f))),
423
424 "DATEADD" => {
426 Ok(Expression::Function(Box::new(f)))
428 }
429
430 "DATEDIFF" => Ok(Expression::Function(Box::new(f))),
432
433 "DECODE" => Ok(Expression::Function(Box::new(f))),
435
436 _ => Ok(Expression::Function(Box::new(f))),
438 }
439 }
440
441 fn transform_aggregate_function(
442 &self,
443 f: Box<crate::expressions::AggregateFunction>,
444 ) -> Result<Expression> {
445 let name_upper = f.name.to_uppercase();
446 match name_upper.as_str() {
447 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
449 Function::new("LISTAGG".to_string(), f.args),
450 ))),
451
452 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
454 Function::new("LISTAGG".to_string(), f.args),
455 ))),
456
457 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
460 "COLLECT".to_string(),
461 f.args,
462 )))),
463
464 _ => Ok(Expression::AggregateFunction(f)),
466 }
467 }
468
469 fn is_temporal_expr(expr: &Expression) -> bool {
471 matches!(
472 expr,
473 Expression::CurrentTimestamp(_)
474 | Expression::CurrentDate(_)
475 | Expression::CurrentTime(_)
476 | Expression::Localtimestamp(_)
477 ) || matches!(expr, Expression::Function(f) if {
478 let name = f.name.to_uppercase();
479 name == "SYSDATE" || name == "SYSTIMESTAMP" || name == "TO_DATE" || name == "TO_TIMESTAMP"
480 })
481 }
482}