1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{AggFunc, Case, Cast, Expression, Function, VarArgFunc};
9use crate::generator::GeneratorConfig;
10use crate::tokens::TokenizerConfig;
11
12pub struct CockroachDBDialect;
14
15impl DialectImpl for CockroachDBDialect {
16 fn dialect_type(&self) -> DialectType {
17 DialectType::CockroachDB
18 }
19
20 fn tokenizer_config(&self) -> TokenizerConfig {
21 let mut config = TokenizerConfig::default();
22 config.identifiers.insert('"', '"');
24 config.nested_comments = true;
26 config
27 }
28
29 fn generator_config(&self) -> GeneratorConfig {
30 use crate::generator::IdentifierQuoteStyle;
31 GeneratorConfig {
32 identifier_quote: '"',
33 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
34 dialect: Some(DialectType::CockroachDB),
35 ..Default::default()
36 }
37 }
38
39 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
40 match expr {
41 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
43 original_name: None,
44 expressions: vec![f.this, f.expression],
45 }))),
46
47 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
49 original_name: None,
50 expressions: vec![f.this, f.expression],
51 }))),
52
53 Expression::Coalesce(mut f) => {
55 f.original_name = None;
56 Ok(Expression::Coalesce(f))
57 }
58
59 Expression::TryCast(c) => Ok(Expression::Cast(c)),
61
62 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
64
65 Expression::ILike(op) => Ok(Expression::ILike(op)),
67
68 Expression::CountIf(f) => {
70 let case_expr = Expression::Case(Box::new(Case {
71 operand: None,
72 whens: vec![(f.this.clone(), Expression::number(1))],
73 else_: Some(Expression::number(0)),
74 comments: Vec::new(),
75 }));
76 Ok(Expression::Sum(Box::new(AggFunc {
77 ignore_nulls: None,
78 having_max: None,
79 this: case_expr,
80 distinct: f.distinct,
81 filter: f.filter,
82 order_by: Vec::new(),
83 name: None,
84 limit: None,
85 })))
86 }
87
88 Expression::Rand(r) => {
90 let _ = r.seed;
91 Ok(Expression::Random(crate::expressions::Random))
92 }
93
94 Expression::Function(f) => self.transform_function(*f),
96
97 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
99
100 Expression::Cast(c) => self.transform_cast(*c),
102
103 _ => Ok(expr),
105 }
106 }
107}
108
109impl CockroachDBDialect {
110 fn transform_function(&self, f: Function) -> Result<Expression> {
111 let name_upper = f.name.to_uppercase();
112 match name_upper.as_str() {
113 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
115 original_name: None,
116 expressions: f.args,
117 }))),
118
119 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
121 original_name: None,
122 expressions: f.args,
123 }))),
124
125 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
127 original_name: None,
128 expressions: f.args,
129 }))),
130
131 "NOW" => Ok(Expression::CurrentTimestamp(
133 crate::expressions::CurrentTimestamp {
134 precision: None,
135 sysdate: false,
136 },
137 )),
138
139 "GETDATE" => Ok(Expression::CurrentTimestamp(
141 crate::expressions::CurrentTimestamp {
142 precision: None,
143 sysdate: false,
144 },
145 )),
146
147 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
149
150 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
152
153 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
155 Function::new("STRING_AGG".to_string(), f.args),
156 ))),
157
158 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
160 "STRING_AGG".to_string(),
161 f.args,
162 )))),
163
164 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
166 "SUBSTRING".to_string(),
167 f.args,
168 )))),
169
170 "LENGTH" => Ok(Expression::Function(Box::new(f))),
172
173 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
175 "LENGTH".to_string(),
176 f.args,
177 )))),
178
179 "CHARINDEX" if f.args.len() >= 2 => {
181 let mut args = f.args;
182 let substring = args.remove(0);
183 let string = args.remove(0);
184 Ok(Expression::Function(Box::new(Function::new(
185 "STRPOS".to_string(),
186 vec![string, substring],
187 ))))
188 }
189
190 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
192 "STRPOS".to_string(),
193 f.args,
194 )))),
195
196 "LOCATE" if f.args.len() >= 2 => {
198 let mut args = f.args;
199 let substring = args.remove(0);
200 let string = args.remove(0);
201 Ok(Expression::Function(Box::new(Function::new(
202 "STRPOS".to_string(),
203 vec![string, substring],
204 ))))
205 }
206
207 "STRPOS" => Ok(Expression::Function(Box::new(f))),
209
210 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
212
213 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
215 "ARRAY_LENGTH".to_string(),
216 f.args,
217 )))),
218
219 "CARDINALITY" => Ok(Expression::Function(Box::new(f))),
221
222 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
224
225 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
227 Function::new("TO_CHAR".to_string(), f.args),
228 ))),
229
230 "STRFTIME" if f.args.len() >= 2 => {
232 let mut args = f.args;
233 let format = args.remove(0);
234 let date = args.remove(0);
235 Ok(Expression::Function(Box::new(Function::new(
236 "TO_CHAR".to_string(),
237 vec![date, format],
238 ))))
239 }
240
241 "JSONB_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
243
244 "JSON_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
246
247 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
249 Function::new("JSONB_EXTRACT_PATH_TEXT".to_string(), f.args),
250 ))),
251
252 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
254 Function::new("JSONB_EXTRACT_PATH".to_string(), f.args),
255 ))),
256
257 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(f))),
259
260 "RLIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
262 "REGEXP_LIKE".to_string(),
263 f.args,
264 )))),
265
266 _ => Ok(Expression::Function(Box::new(f))),
268 }
269 }
270
271 fn transform_aggregate_function(
272 &self,
273 f: Box<crate::expressions::AggregateFunction>,
274 ) -> Result<Expression> {
275 let name_upper = f.name.to_uppercase();
276 match name_upper.as_str() {
277 "COUNT_IF" if !f.args.is_empty() => {
279 let condition = f.args.into_iter().next().unwrap();
280 let case_expr = Expression::Case(Box::new(Case {
281 operand: None,
282 whens: vec![(condition, Expression::number(1))],
283 else_: Some(Expression::number(0)),
284 comments: Vec::new(),
285 }));
286 Ok(Expression::Sum(Box::new(AggFunc {
287 ignore_nulls: None,
288 having_max: None,
289 this: case_expr,
290 distinct: f.distinct,
291 filter: f.filter,
292 order_by: Vec::new(),
293 name: None,
294 limit: None,
295 })))
296 }
297
298 _ => Ok(Expression::AggregateFunction(f)),
300 }
301 }
302
303 fn transform_cast(&self, c: Cast) -> Result<Expression> {
304 Ok(Expression::Cast(Box::new(c)))
306 }
307}