1use std::slice;
16
17use itertools::Itertools;
18use risingwave_common::catalog::PG_CATALOG_SCHEMA_NAME;
19use risingwave_common::types::{DataType, MapType, StructType};
20use risingwave_common::util::iter_util::zip_eq_fast;
21use risingwave_common::{bail_no_function, bail_not_implemented, not_implemented};
22use risingwave_sqlparser::ast::{
23 Array, BinaryOperator, DataType as AstDataType, EscapeChar, Expr, Function, JsonPredicateType,
24 ObjectName, Query, TrimWhereField, UnaryOperator,
25};
26
27use crate::binder::Binder;
28use crate::binder::expr::function::is_sys_function_without_args;
29use crate::error::{ErrorCode, Result, RwError};
30use crate::expr::{
31 Expr as _, ExprImpl, ExprRewriter as _, ExprType, FunctionCall, InputRef,
32 InputRefScopeRewriter, Parameter, SubqueryKind,
33};
34
35mod binary_op;
36mod column;
37mod function;
38mod order_by;
39mod subquery;
40mod value;
41
42const CASE_WHEN_ARMS_OPTIMIZE_LIMIT: usize = 30;
48
49impl Binder {
50 pub fn bind_expr(&mut self, expr: &Expr) -> Result<ExprImpl> {
58 self.bind_expr_inner(expr).map_err(|e| {
59 RwError::from(ErrorCode::BindErrorRoot {
60 expr: expr.to_string(),
61 error: Box::new(e),
62 })
63 })
64 }
65
66 fn bind_expr_inner(&mut self, expr: &Expr) -> Result<ExprImpl> {
67 match expr {
68 Expr::Value(v) => Ok(ExprImpl::Literal(Box::new(self.bind_value(v)?))),
70 Expr::TypedString { data_type, value } => {
71 let s: ExprImpl = self.bind_string(value)?.into();
72 s.cast_explicit(&bind_data_type(data_type)?)
73 .map_err(Into::into)
74 }
75 Expr::Row(exprs) => self.bind_row(exprs),
76 Expr::Identifier(ident) => {
78 if is_sys_function_without_args(ident) {
79 self.bind_function(&Function::no_arg(ObjectName(vec![ident.clone()])))
84 } else if let Some(ref lambda_args) = self.context.lambda_args {
85 if let Some((arg_idx, arg_type)) = lambda_args.get(&ident.real_value()) {
88 Ok(InputRef::new(*arg_idx, arg_type.clone()).into())
89 } else {
90 Err(
91 ErrorCode::ItemNotFound(format!("Unknown arg: {}", ident.real_value()))
92 .into(),
93 )
94 }
95 } else if let Some(ctx) = self.secure_compare_context.as_ref() {
96 if ident.real_value() == *"headers" {
102 Ok(InputRef::new(0, DataType::Jsonb).into())
103 } else if ctx.secret_name.is_some()
104 && ident.real_value() == *ctx.secret_name.as_ref().unwrap()
105 {
106 Ok(InputRef::new(1, DataType::Varchar).into())
107 } else if ident.real_value() == ctx.payload_name {
108 Ok(InputRef::new(2, DataType::Bytea).into())
109 } else {
110 Err(
111 ErrorCode::ItemNotFound(format!("Unknown arg: {}", ident.real_value()))
112 .into(),
113 )
114 }
115 } else {
116 self.bind_column(slice::from_ref(ident))
117 }
118 }
119 Expr::CompoundIdentifier(idents) => self.bind_column(idents),
120 Expr::FieldIdentifier(field_expr, idents) => {
121 self.bind_single_field_column(field_expr, idents)
122 }
123 Expr::UnaryOp { op, expr } => self.bind_unary_expr(op, expr),
125 Expr::BinaryOp { left, op, right } => self.bind_binary_op(left, op, right),
126 Expr::Nested(expr) => self.bind_expr_inner(expr),
127 Expr::Array(Array { elem: exprs, .. }) => self.bind_array(exprs),
128 Expr::Index { obj, index } => self.bind_index(obj, index),
129 Expr::ArrayRangeIndex { obj, start, end } => {
130 self.bind_array_range_index(obj, start.as_deref(), end.as_deref())
131 }
132 Expr::Function(f) => self.bind_function(f),
133 Expr::Subquery(q) => self.bind_subquery_expr(q, SubqueryKind::Scalar),
134 Expr::Exists(q) => self.bind_subquery_expr(q, SubqueryKind::Existential),
135 Expr::InSubquery {
136 expr,
137 subquery,
138 negated,
139 } => self.bind_in_subquery(expr, subquery, *negated),
140 Expr::Cast { expr, data_type } => self.bind_cast(expr, data_type),
142 Expr::IsNull(expr) => self.bind_is_operator(ExprType::IsNull, expr),
143 Expr::IsNotNull(expr) => self.bind_is_operator(ExprType::IsNotNull, expr),
144 Expr::IsTrue(expr) => self.bind_is_operator(ExprType::IsTrue, expr),
145 Expr::IsNotTrue(expr) => self.bind_is_operator(ExprType::IsNotTrue, expr),
146 Expr::IsFalse(expr) => self.bind_is_operator(ExprType::IsFalse, expr),
147 Expr::IsNotFalse(expr) => self.bind_is_operator(ExprType::IsNotFalse, expr),
148 Expr::IsUnknown(expr) => self.bind_is_unknown(ExprType::IsNull, expr),
149 Expr::IsNotUnknown(expr) => self.bind_is_unknown(ExprType::IsNotNull, expr),
150 Expr::IsDistinctFrom(left, right) => self.bind_distinct_from(left, right),
151 Expr::IsNotDistinctFrom(left, right) => self.bind_not_distinct_from(left, right),
152 Expr::IsJson {
153 expr,
154 negated,
155 item_type,
156 unique_keys: false,
157 } => self.bind_is_json(expr, *negated, *item_type),
158 Expr::Case {
159 operand,
160 conditions,
161 results,
162 else_result,
163 } => self.bind_case(
164 operand.as_deref(),
165 conditions,
166 results,
167 else_result.as_deref(),
168 ),
169 Expr::Between {
170 expr,
171 negated,
172 low,
173 high,
174 } => self.bind_between(expr, *negated, low, high),
175 Expr::Like {
176 negated,
177 expr,
178 pattern,
179 escape_char,
180 } => self.bind_like(ExprType::Like, expr, *negated, pattern, *escape_char),
181 Expr::ILike {
182 negated,
183 expr,
184 pattern,
185 escape_char,
186 } => self.bind_like(ExprType::ILike, expr, *negated, pattern, *escape_char),
187 Expr::SimilarTo {
188 expr,
189 negated,
190 pattern,
191 escape_char,
192 } => self.bind_similar_to(expr, *negated, pattern, *escape_char),
193 Expr::InList {
194 expr,
195 list,
196 negated,
197 } => self.bind_in_list(expr, list, *negated),
198 Expr::Extract { field, expr } => self.bind_extract(field, expr),
200 Expr::AtTimeZone {
201 timestamp,
202 time_zone,
203 } => self.bind_at_time_zone(timestamp, time_zone),
204 Expr::Trim {
206 expr,
207 trim_where,
208 trim_what,
209 } => self.bind_trim(expr, trim_where.as_ref(), trim_what.as_deref()),
210 Expr::Substring {
211 expr,
212 substring_from,
213 substring_for,
214 } => self.bind_substring(expr, substring_from.as_deref(), substring_for.as_deref()),
215 Expr::Position { substring, string } => self.bind_position(substring, string),
216 Expr::Overlay {
217 expr,
218 new_substring,
219 start,
220 count,
221 } => self.bind_overlay(expr, new_substring, start, count.as_deref()),
222 Expr::Parameter { index } => self.bind_parameter(*index),
223 Expr::Collate { expr, collation } => self.bind_collate(expr, collation),
224 Expr::ArraySubquery(q) => self.bind_subquery_expr(q, SubqueryKind::Array),
225 Expr::Map { entries } => self.bind_map(entries),
226 Expr::IsJson {
227 unique_keys: true, ..
228 }
229 | Expr::SomeOp(_)
230 | Expr::AllOp(_)
231 | Expr::TryCast { .. }
232 | Expr::GroupingSets(_)
233 | Expr::Cube(_)
234 | Expr::Rollup(_)
235 | Expr::LambdaFunction { .. } => {
236 bail_not_implemented!(issue = 112, "unsupported expression {:?}", expr)
237 }
238 }
239 }
240
241 pub(super) fn bind_extract(&mut self, field: &String, expr: &Expr) -> Result<ExprImpl> {
242 let arg = self.bind_expr_inner(expr)?;
243 let arg_type = arg.return_type();
244 Ok(FunctionCall::new(
245 ExprType::Extract,
246 vec![self.bind_string(field)?.into(), arg],
247 )
248 .map_err(|_| {
249 not_implemented!(
250 issue = 112,
251 "function extract({} from {:?}) doesn't exist",
252 field,
253 arg_type
254 )
255 })?
256 .into())
257 }
258
259 pub(super) fn bind_at_time_zone(&mut self, input: &Expr, time_zone: &Expr) -> Result<ExprImpl> {
260 let input = self.bind_expr_inner(input)?;
261 let time_zone = self.bind_expr_inner(time_zone)?;
262 FunctionCall::new(ExprType::AtTimeZone, vec![input, time_zone]).map(Into::into)
263 }
264
265 pub(super) fn bind_in_list(
266 &mut self,
267 expr: &Expr,
268 list: &[Expr],
269 negated: bool,
270 ) -> Result<ExprImpl> {
271 let left = self.bind_expr_inner(expr)?;
272 let mut in_list_exprs = vec![left.clone()];
273 let mut non_const_exprs = vec![];
274 for elem in list {
275 let expr = self.bind_expr_inner(elem)?;
276 match expr.is_const() || matches!(&expr, ExprImpl::Parameter(_)) {
277 true => in_list_exprs.push(expr),
278 false => non_const_exprs.push(expr),
279 }
280 }
281
282 let mut ret = if in_list_exprs.len() == 1 {
283 None
284 } else {
285 Some(FunctionCall::new(ExprType::In, in_list_exprs)?.into())
286 };
287 for expr in non_const_exprs {
290 if let Some(inner_ret) = ret {
291 ret = Some(
292 FunctionCall::new(
293 ExprType::Or,
294 vec![
295 inner_ret,
296 FunctionCall::new(ExprType::Equal, vec![left.clone(), expr])?.into(),
297 ],
298 )?
299 .into(),
300 );
301 } else {
302 ret = Some(FunctionCall::new(ExprType::Equal, vec![left.clone(), expr])?.into());
303 }
304 }
305 if negated {
306 Ok(
307 FunctionCall::new_unchecked(ExprType::Not, vec![ret.unwrap()], DataType::Boolean)
308 .into(),
309 )
310 } else {
311 Ok(ret.unwrap())
312 }
313 }
314
315 pub(super) fn bind_in_subquery(
316 &mut self,
317 expr: &Expr,
318 subquery: &Query,
319 negated: bool,
320 ) -> Result<ExprImpl> {
321 let bound_expr = self.bind_expr_inner(expr)?;
322 let bound_subquery = self.bind_subquery_expr(subquery, SubqueryKind::In(bound_expr))?;
323 if negated {
324 Ok(
325 FunctionCall::new_unchecked(ExprType::Not, vec![bound_subquery], DataType::Boolean)
326 .into(),
327 )
328 } else {
329 Ok(bound_subquery)
330 }
331 }
332
333 pub(super) fn bind_is_json(
334 &mut self,
335 expr: &Expr,
336 negated: bool,
337 item_type: JsonPredicateType,
338 ) -> Result<ExprImpl> {
339 let mut args = vec![self.bind_expr_inner(expr)?];
340 let type_symbol = match item_type {
342 JsonPredicateType::Value => None,
343 JsonPredicateType::Array => Some("ARRAY"),
344 JsonPredicateType::Object => Some("OBJECT"),
345 JsonPredicateType::Scalar => Some("SCALAR"),
346 };
347 if let Some(s) = type_symbol {
348 args.push(ExprImpl::literal_varchar(s.into()));
349 }
350
351 let is_json = FunctionCall::new(ExprType::IsJson, args)?.into();
352 if negated {
353 Ok(FunctionCall::new(ExprType::Not, vec![is_json])?.into())
354 } else {
355 Ok(is_json)
356 }
357 }
358
359 pub(super) fn bind_unary_expr(&mut self, op: &UnaryOperator, expr: &Expr) -> Result<ExprImpl> {
360 let func_type = match &op {
361 UnaryOperator::Not => ExprType::Not,
362 UnaryOperator::Minus => ExprType::Neg,
363 UnaryOperator::Plus => {
364 return self.rewrite_positive(expr);
365 }
366 UnaryOperator::Custom(name) => match name.as_str() {
367 "~" => ExprType::BitwiseNot,
368 "@" => ExprType::Abs,
369 "|/" => ExprType::Sqrt,
370 "||/" => ExprType::Cbrt,
371 _ => bail_not_implemented!(issue = 112, "unsupported unary expression: {:?}", op),
372 },
373 UnaryOperator::PGQualified(_) => {
374 bail_not_implemented!(issue = 112, "unsupported unary expression: {:?}", op)
375 }
376 };
377 let expr = self.bind_expr_inner(expr)?;
378 FunctionCall::new(func_type, vec![expr]).map(|f| f.into())
379 }
380
381 fn rewrite_positive(&mut self, expr: &Expr) -> Result<ExprImpl> {
383 let expr = self.bind_expr_inner(expr)?;
384 let return_type = expr.return_type();
385 if return_type.is_numeric() {
386 return Ok(expr);
387 }
388 Err(ErrorCode::InvalidInputSyntax(format!("+ {:?}", return_type)).into())
389 }
390
391 pub(super) fn bind_trim(
392 &mut self,
393 expr: &Expr,
394 trim_where: Option<&TrimWhereField>,
396 trim_what: Option<&Expr>,
397 ) -> Result<ExprImpl> {
398 let mut inputs = vec![self.bind_expr_inner(expr)?];
399 let func_type = match trim_where {
400 Some(TrimWhereField::Both) => ExprType::Trim,
401 Some(TrimWhereField::Leading) => ExprType::Ltrim,
402 Some(TrimWhereField::Trailing) => ExprType::Rtrim,
403 None => ExprType::Trim,
404 };
405 if let Some(t) = trim_what {
406 inputs.push(self.bind_expr_inner(t)?);
407 }
408 Ok(FunctionCall::new(func_type, inputs)?.into())
409 }
410
411 fn bind_substring(
412 &mut self,
413 expr: &Expr,
414 substring_from: Option<&Expr>,
415 substring_for: Option<&Expr>,
416 ) -> Result<ExprImpl> {
417 let mut args = vec![
418 self.bind_expr_inner(expr)?,
419 match substring_from {
420 Some(expr) => self.bind_expr_inner(expr)?,
421 None => ExprImpl::literal_int(1),
422 },
423 ];
424 if let Some(expr) = substring_for {
425 args.push(self.bind_expr_inner(expr)?);
426 }
427 FunctionCall::new(ExprType::Substr, args).map(|f| f.into())
428 }
429
430 fn bind_position(&mut self, substring: &Expr, string: &Expr) -> Result<ExprImpl> {
431 let args = vec![
432 self.bind_expr_inner(string)?,
434 self.bind_expr_inner(substring)?,
435 ];
436 FunctionCall::new(ExprType::Position, args).map(Into::into)
437 }
438
439 fn bind_overlay(
440 &mut self,
441 expr: &Expr,
442 new_substring: &Expr,
443 start: &Expr,
444 count: Option<&Expr>,
445 ) -> Result<ExprImpl> {
446 let mut args = vec![
447 self.bind_expr_inner(expr)?,
448 self.bind_expr_inner(new_substring)?,
449 self.bind_expr_inner(start)?,
450 ];
451 if let Some(count) = count {
452 args.push(self.bind_expr_inner(count)?);
453 }
454 FunctionCall::new(ExprType::Overlay, args).map(|f| f.into())
455 }
456
457 fn is_binding_inline_sql_udf(&self) -> bool {
458 self.context.sql_udf_arguments.is_some()
459 }
460
461 fn is_binding_subquery_sql_udf(&self) -> bool {
464 self.upper_subquery_contexts
465 .iter()
466 .any(|(context, _)| context.sql_udf_arguments.is_some())
467 }
468
469 fn bind_sql_udf_parameter(&mut self, name: &str) -> Result<ExprImpl> {
471 for (level, context) in std::iter::once(&self.context)
472 .chain((self.upper_subquery_contexts.iter().rev()).map(|(context, _)| context))
473 .enumerate()
474 {
475 if let Some(args) = &context.sql_udf_arguments {
478 if let Some(expr) = args.get(name) {
479 if level == 0 {
482 return Ok(expr.clone());
483 }
484 let mut rewriter = InputRefScopeRewriter::new(context.scope);
485 return Ok(rewriter.rewrite_expr(expr.clone()));
486 } else {
487 break;
490 }
491 }
492 }
493
494 Err(ErrorCode::BindError(format!(
495 "failed to find {} parameter {name}",
496 if name.starts_with('$') {
497 "unnamed"
498 } else {
499 "named"
500 }
501 ))
502 .into())
503 }
504
505 fn bind_parameter(&mut self, index: u64) -> Result<ExprImpl> {
506 if self.is_binding_inline_sql_udf() || self.is_binding_subquery_sql_udf() {
511 let column_name = format!("${index}");
512 return self.bind_sql_udf_parameter(&column_name);
513 }
514
515 Ok(Parameter::new(index, self.param_types.clone()).into())
516 }
517
518 pub(super) fn bind_between(
520 &mut self,
521 expr: &Expr,
522 negated: bool,
523 low: &Expr,
524 high: &Expr,
525 ) -> Result<ExprImpl> {
526 let expr = self.bind_expr_inner(expr)?;
527 let low = self.bind_expr_inner(low)?;
528 let high = self.bind_expr_inner(high)?;
529
530 let func_call = if negated {
531 FunctionCall::new_unchecked(
533 ExprType::Or,
534 vec![
535 FunctionCall::new(ExprType::LessThan, vec![expr.clone(), low])?.into(),
536 FunctionCall::new(ExprType::GreaterThan, vec![expr, high])?.into(),
537 ],
538 DataType::Boolean,
539 )
540 } else {
541 FunctionCall::new_unchecked(
543 ExprType::And,
544 vec![
545 FunctionCall::new(ExprType::GreaterThanOrEqual, vec![expr.clone(), low])?
546 .into(),
547 FunctionCall::new(ExprType::LessThanOrEqual, vec![expr, high])?.into(),
548 ],
549 DataType::Boolean,
550 )
551 };
552
553 Ok(func_call.into())
554 }
555
556 fn bind_like(
557 &mut self,
558 expr_type: ExprType,
559 expr: &Expr,
560 negated: bool,
561 pattern: &Expr,
562 escape_char: Option<EscapeChar>,
563 ) -> Result<ExprImpl> {
564 if matches!(pattern, Expr::AllOp(_) | Expr::SomeOp(_)) {
565 if escape_char.is_some() {
566 bail_not_implemented!(
572 "LIKE with both ALL|ANY pattern and escape character is not supported"
573 )
574 }
575 let op = match (expr_type, negated) {
577 (ExprType::Like, false) => BinaryOperator::Custom("~~".to_owned()),
578 (ExprType::Like, true) => BinaryOperator::Custom("!~~".to_owned()),
579 (ExprType::ILike, false) => BinaryOperator::Custom("~~*".to_owned()),
580 (ExprType::ILike, true) => BinaryOperator::Custom("!~~*".to_owned()),
581 _ => unreachable!(),
582 };
583 return self.bind_binary_op(expr, &op, pattern);
584 }
585 let expr = self.bind_expr_inner(expr)?;
586 let pattern = self.bind_expr_inner(pattern)?;
587 match (expr.return_type(), pattern.return_type()) {
588 (DataType::Varchar, DataType::Varchar) => {}
589 (string_ty, pattern_ty) => match expr_type {
590 ExprType::Like => bail_no_function!("like({}, {})", string_ty, pattern_ty),
591 ExprType::ILike => bail_no_function!("ilike({}, {})", string_ty, pattern_ty),
592 _ => unreachable!(),
593 },
594 }
595 let args = match escape_char {
596 Some(escape_char) => {
597 let escape_char = ExprImpl::literal_varchar(escape_char.to_string());
598 vec![expr, pattern, escape_char]
599 }
600 None => vec![expr, pattern],
601 };
602 let func_call = FunctionCall::new_unchecked(expr_type, args, DataType::Boolean);
603 let func_call = if negated {
604 FunctionCall::new_unchecked(ExprType::Not, vec![func_call.into()], DataType::Boolean)
605 } else {
606 func_call
607 };
608 Ok(func_call.into())
609 }
610
611 pub(super) fn bind_similar_to(
613 &mut self,
614 expr: &Expr,
615 negated: bool,
616 pattern: &Expr,
617 escape_char: Option<EscapeChar>,
618 ) -> Result<ExprImpl> {
619 let expr = self.bind_expr_inner(expr)?;
620 let pattern = self.bind_expr_inner(pattern)?;
621
622 let esc_inputs = if let Some(escape_char) = escape_char {
623 let escape_char = ExprImpl::literal_varchar(escape_char.to_string());
624 vec![pattern, escape_char]
625 } else {
626 vec![pattern]
627 };
628
629 let esc_call =
630 FunctionCall::new_unchecked(ExprType::SimilarToEscape, esc_inputs, DataType::Varchar);
631
632 let regex_call = FunctionCall::new_unchecked(
633 ExprType::RegexpEq,
634 vec![expr, esc_call.into()],
635 DataType::Boolean,
636 );
637 let func_call = if negated {
638 FunctionCall::new_unchecked(ExprType::Not, vec![regex_call.into()], DataType::Boolean)
639 } else {
640 regex_call
641 };
642
643 Ok(func_call.into())
644 }
645
646 fn check_constant_case_when_optimization(
649 &mut self,
650 conditions: &[Expr],
651 results_expr: &[ExprImpl],
652 operand: Option<&Expr>,
653 fallback: Option<&ExprImpl>,
654 constant_case_when_eval_inputs: &mut Vec<ExprImpl>,
655 ) -> bool {
656 let operand_value;
658
659 if let Some(operand) = operand {
660 let Ok(operand) = self.bind_expr_inner(operand) else {
661 return false;
662 };
663 if !operand.is_const() {
664 return false;
665 }
666 operand_value = operand;
667 } else {
668 return false;
669 }
670
671 for (condition, result) in zip_eq_fast(conditions, results_expr) {
672 if let Expr::Value(_) = condition.clone() {
673 let Ok(res) = self.bind_expr_inner(condition) else {
674 return false;
675 };
676 if res == operand_value {
678 constant_case_when_eval_inputs.push(result.clone());
679 return true;
680 }
681 } else {
682 return false;
683 }
684 }
685
686 debug_assert!(
688 constant_case_when_eval_inputs.is_empty(),
689 "expect `inputs` to be empty"
690 );
691
692 let Some(fallback) = fallback else {
693 return false;
694 };
695
696 constant_case_when_eval_inputs.push(fallback.clone());
697 true
698 }
699
700 fn compare_or_set(col_expr: &mut Option<Expr>, test_expr: &Expr) -> bool {
703 let Expr::Identifier(test_ident) = test_expr else {
704 return false;
705 };
706 if let Some(expr) = col_expr {
707 let Expr::Identifier(ident) = expr else {
708 return false;
709 };
710 if ident.real_value() != test_ident.real_value() {
711 return false;
712 }
713 } else {
714 *col_expr = Some(Expr::Identifier(test_ident.clone()));
715 }
716 true
717 }
718
719 fn check_invariant(left: &Expr, op: &BinaryOperator, right: &Expr) -> bool {
723 if op != &BinaryOperator::Eq {
724 return false;
725 }
726 if let Expr::Identifier(_) = left {
727 let Expr::Value(_) = right else {
729 return false;
730 };
731 } else {
732 let Expr::Value(_) = left else {
734 return false;
735 };
736 let Expr::Identifier(_) = right else {
737 return false;
738 };
739 }
740 true
741 }
742
743 fn try_extract_simple_form(
748 &mut self,
749 ident_expr: &Expr,
750 constant_expr: &Expr,
751 column_expr: &mut Option<Expr>,
752 inputs: &mut Vec<ExprImpl>,
753 ) -> bool {
754 if !Self::compare_or_set(column_expr, ident_expr) {
755 return false;
756 }
757 let Ok(bound_expr) = self.bind_expr_inner(constant_expr) else {
758 return false;
759 };
760 inputs.push(bound_expr);
761 true
762 }
763
764 fn check_convert_simple_form(
768 &mut self,
769 conditions: &[Expr],
770 results_expr: &[ExprImpl],
771 fallback: Option<ExprImpl>,
772 constant_lookup_inputs: &mut Vec<ExprImpl>,
773 ) -> bool {
774 let mut column_expr = None;
775
776 for (condition, result) in zip_eq_fast(conditions, results_expr) {
777 if let Expr::BinaryOp { left, op, right } = condition {
778 if !Self::check_invariant(left, op, right) {
779 return false;
780 }
781 if let Expr::Identifier(_) = &**left {
782 if !self.try_extract_simple_form(
783 left,
784 right,
785 &mut column_expr,
786 constant_lookup_inputs,
787 ) {
788 return false;
789 }
790 } else if !self.try_extract_simple_form(
791 right,
792 left,
793 &mut column_expr,
794 constant_lookup_inputs,
795 ) {
796 return false;
797 }
798 constant_lookup_inputs.push(result.clone());
799 } else {
800 return false;
801 }
802 }
803
804 let Some(operand) = column_expr else {
806 return false;
807 };
808 let Ok(bound_operand) = self.bind_expr_inner(&operand) else {
809 return false;
810 };
811 constant_lookup_inputs.insert(0, bound_operand);
812
813 if let Some(expr) = fallback {
815 constant_lookup_inputs.push(expr);
816 }
817
818 true
819 }
820
821 fn check_bind_case_optimization(
825 &mut self,
826 conditions: &[Expr],
827 results_expr: &[ExprImpl],
828 operand: Option<&Expr>,
829 fallback: Option<ExprImpl>,
830 constant_lookup_inputs: &mut Vec<ExprImpl>,
831 ) -> bool {
832 if conditions.len() < CASE_WHEN_ARMS_OPTIMIZE_LIMIT {
833 return false;
834 }
835
836 if let Some(operand) = operand {
837 let Ok(operand) = self.bind_expr_inner(operand) else {
838 return false;
839 };
840 if operand.is_const() {
844 return false;
845 }
846 constant_lookup_inputs.push(operand);
847 } else {
848 return self.check_convert_simple_form(
851 conditions,
852 results_expr,
853 fallback,
854 constant_lookup_inputs,
855 );
856 }
857
858 for (condition, result) in zip_eq_fast(conditions, results_expr) {
859 if let Expr::Value(_) = condition {
860 let Ok(input) = self.bind_expr_inner(condition) else {
861 return false;
862 };
863 constant_lookup_inputs.push(input);
864 } else {
865 return false;
868 }
869
870 constant_lookup_inputs.push(result.clone());
871 }
872
873 if let Some(expr) = fallback {
875 constant_lookup_inputs.push(expr);
876 }
877
878 true
879 }
880
881 pub(super) fn bind_case(
882 &mut self,
883 operand: Option<&Expr>,
884 conditions: &[Expr],
885 results: &[Expr],
886 else_result: Option<&Expr>,
887 ) -> Result<ExprImpl> {
888 let mut inputs = Vec::new();
889 let results_expr: Vec<ExprImpl> = results
890 .iter()
891 .map(|expr| self.bind_expr_inner(expr))
892 .collect::<Result<_>>()?;
893 let else_result_expr = else_result
894 .map(|expr| self.bind_expr_inner(expr))
895 .transpose()?;
896
897 let mut constant_lookup_inputs = Vec::new();
898 let mut constant_case_when_eval_inputs = Vec::new();
899
900 let constant_case_when_flag = self.check_constant_case_when_optimization(
901 conditions,
902 &results_expr,
903 operand,
904 else_result_expr.as_ref(),
905 &mut constant_case_when_eval_inputs,
906 );
907
908 if constant_case_when_flag {
909 if constant_case_when_eval_inputs.len() != 1 {
911 return Err(ErrorCode::BindError(
912 "expect `constant_case_when_eval_inputs` only contains a single bound expression".to_owned()
913 )
914 .into());
915 }
916 return Ok(constant_case_when_eval_inputs[0].take());
918 }
919
920 let optimize_flag = self.check_bind_case_optimization(
922 conditions,
923 &results_expr,
924 operand,
925 else_result_expr.clone(),
926 &mut constant_lookup_inputs,
927 );
928
929 if optimize_flag {
930 return Ok(FunctionCall::new(ExprType::ConstantLookup, constant_lookup_inputs)?.into());
931 }
932
933 for (condition, result) in zip_eq_fast(conditions, results_expr) {
934 let condition = condition.clone();
935 let condition = match operand {
936 Some(t) => Expr::BinaryOp {
937 left: t.clone().into(),
938 op: BinaryOperator::Eq,
939 right: Box::new(condition),
940 },
941 None => condition,
942 };
943 inputs.push(
944 self.bind_expr_inner(&condition)
945 .and_then(|expr| expr.enforce_bool_clause("CASE WHEN"))?,
946 );
947 inputs.push(result);
948 }
949
950 if let Some(expr) = else_result_expr {
952 inputs.push(expr);
953 }
954
955 if inputs.iter().any(ExprImpl::has_table_function) {
956 return Err(
957 ErrorCode::BindError("table functions are not allowed in CASE".into()).into(),
958 );
959 }
960
961 Ok(FunctionCall::new(ExprType::Case, inputs)?.into())
962 }
963
964 pub(super) fn bind_is_operator(
965 &mut self,
966 func_type: ExprType,
967 expr: &Expr,
968 ) -> Result<ExprImpl> {
969 let expr = self.bind_expr_inner(expr)?;
970 Ok(FunctionCall::new(func_type, vec![expr])?.into())
971 }
972
973 pub(super) fn bind_is_unknown(&mut self, func_type: ExprType, expr: &Expr) -> Result<ExprImpl> {
974 let expr = self
975 .bind_expr_inner(expr)?
976 .cast_implicit(&DataType::Boolean)?;
977 Ok(FunctionCall::new(func_type, vec![expr])?.into())
978 }
979
980 pub(super) fn bind_distinct_from(&mut self, left: &Expr, right: &Expr) -> Result<ExprImpl> {
981 let left = self.bind_expr_inner(left)?;
982 let right = self.bind_expr_inner(right)?;
983 let func_call = FunctionCall::new(ExprType::IsDistinctFrom, vec![left, right]);
984 Ok(func_call?.into())
985 }
986
987 pub(super) fn bind_not_distinct_from(&mut self, left: &Expr, right: &Expr) -> Result<ExprImpl> {
988 let left = self.bind_expr_inner(left)?;
989 let right = self.bind_expr_inner(right)?;
990 let func_call = FunctionCall::new(ExprType::IsNotDistinctFrom, vec![left, right]);
991 Ok(func_call?.into())
992 }
993
994 pub(super) fn bind_cast(&mut self, expr: &Expr, data_type: &AstDataType) -> Result<ExprImpl> {
995 match &data_type {
996 AstDataType::Regclass => {
999 let input = self.bind_expr_inner(expr)?;
1000 Ok(input.cast_to_regclass()?)
1001 }
1002 AstDataType::Regproc => {
1003 let lhs = self.bind_expr_inner(expr)?;
1004 let lhs_ty = lhs.return_type();
1005 if lhs_ty == DataType::Varchar {
1006 Ok(lhs)
1010 } else {
1011 Err(ErrorCode::BindError(format!("Can't cast {} to regproc", lhs_ty)).into())
1012 }
1013 }
1014 AstDataType::Char(_) => self.bind_cast_inner(expr, &DataType::Varchar),
1028 _ => self.bind_cast_inner(expr, &bind_data_type(data_type)?),
1029 }
1030 }
1031
1032 pub fn bind_cast_inner(&mut self, expr: &Expr, data_type: &DataType) -> Result<ExprImpl> {
1033 match (expr, data_type) {
1034 (Expr::Array(Array { elem: expr, .. }), DataType::List(list_type)) => {
1035 self.bind_array_cast(expr, list_type.elem())
1036 }
1037 (Expr::Map { entries }, DataType::Map(m)) => self.bind_map_cast(entries, m),
1038 (expr, data_type) => {
1039 let lhs = self.bind_expr_inner(expr)?;
1040 lhs.cast_explicit(data_type).map_err(Into::into)
1041 }
1042 }
1043 }
1044
1045 pub fn bind_collate(&mut self, expr: &Expr, collation: &ObjectName) -> Result<ExprImpl> {
1046 if !["C", "POSIX"].contains(&collation.real_value().as_str()) {
1047 bail_not_implemented!("Collate collation other than `C` or `POSIX` is not implemented");
1048 }
1049
1050 let bound_inner = self.bind_expr_inner(expr)?;
1051 let ret_type = bound_inner.return_type();
1052
1053 match ret_type {
1054 DataType::Varchar => {}
1055 _ => {
1056 return Err(ErrorCode::NotSupported(
1057 format!("{} is not a collatable data type", ret_type),
1058 "The only built-in collatable data types are `varchar`, please check your type"
1059 .into(),
1060 )
1061 .into());
1062 }
1063 }
1064
1065 Ok(bound_inner)
1066 }
1067}
1068
1069pub fn bind_data_type(data_type: &AstDataType) -> Result<DataType> {
1070 let new_err = || not_implemented!("unsupported data type: {:}", data_type);
1071 let data_type = match data_type {
1072 AstDataType::Boolean => DataType::Boolean,
1073 AstDataType::SmallInt => DataType::Int16,
1074 AstDataType::Int => DataType::Int32,
1075 AstDataType::BigInt => DataType::Int64,
1076 AstDataType::Real | AstDataType::Float(Some(1..=24)) => DataType::Float32,
1077 AstDataType::Double | AstDataType::Float(Some(25..=53) | None) => DataType::Float64,
1078 AstDataType::Float(Some(0 | 54..)) => unreachable!(),
1079 AstDataType::Decimal(None, None) => DataType::Decimal,
1080 AstDataType::Varchar | AstDataType::Text => DataType::Varchar,
1081 AstDataType::Date => DataType::Date,
1082 AstDataType::Time(false) => DataType::Time,
1083 AstDataType::Timestamp(false) => DataType::Timestamp,
1084 AstDataType::Timestamp(true) => DataType::Timestamptz,
1085 AstDataType::Interval => DataType::Interval,
1086 AstDataType::Array(datatype) => DataType::list(bind_data_type(datatype)?),
1087 AstDataType::Char(..) => {
1088 bail_not_implemented!("CHAR is not supported, please use VARCHAR instead")
1089 }
1090 AstDataType::Struct(types) => bind_struct_type(
1091 types
1092 .iter()
1093 .map(|f| Ok((f.name.real_value(), bind_data_type(&f.data_type)?)))
1094 .collect::<Result<Vec<_>>>()?,
1095 )?
1096 .into(),
1097 AstDataType::Map(kv) => {
1098 let key = bind_data_type(&kv.0)?;
1099 let value = bind_data_type(&kv.1)?;
1100 DataType::Map(MapType::try_from_kv(key, value).map_err(ErrorCode::BindError)?)
1101 }
1102 AstDataType::Custom(qualified_type_name) => {
1103 let idents = qualified_type_name
1104 .0
1105 .iter()
1106 .map(|n| n.real_value())
1107 .collect_vec();
1108 let name = if idents.len() == 1 {
1109 idents[0].as_str() } else if idents.len() == 2 && idents[0] == PG_CATALOG_SCHEMA_NAME {
1111 idents[1].as_str() } else {
1113 return Err(new_err().into());
1114 };
1115
1116 match name {
1119 "int2" => DataType::Int16,
1120 "int4" => DataType::Int32,
1121 "int8" => DataType::Int64,
1122 "rw_int256" => DataType::Int256,
1123 "float4" => DataType::Float32,
1124 "float8" => DataType::Float64,
1125 "timestamptz" => DataType::Timestamptz,
1126 "text" => DataType::Varchar,
1127 "serial" => {
1128 return Err(ErrorCode::NotSupported(
1129 "Column type SERIAL is not supported".into(),
1130 "Please remove the SERIAL column".into(),
1131 )
1132 .into());
1133 }
1134 _ => return Err(new_err().into()),
1135 }
1136 }
1137 AstDataType::Bytea => DataType::Bytea,
1138 AstDataType::Jsonb => DataType::Jsonb,
1139 AstDataType::Variant => DataType::Variant,
1140 AstDataType::Vector(size) => match (1..=DataType::VEC_MAX_SIZE).contains(&(*size as _)) {
1141 true => DataType::Vector(*size as _),
1142 false => {
1143 return Err(ErrorCode::BindError(format!(
1144 "vector size {} is out of range [1, {}]",
1145 size,
1146 DataType::VEC_MAX_SIZE
1147 ))
1148 .into());
1149 }
1150 },
1151 AstDataType::Regclass
1152 | AstDataType::Regproc
1153 | AstDataType::Uuid
1154 | AstDataType::Decimal(_, _)
1155 | AstDataType::Time(true) => return Err(new_err().into()),
1156 };
1157 Ok(data_type)
1158}
1159
1160pub(crate) fn bind_struct_type(
1161 fields: impl IntoIterator<Item = (impl Into<String>, DataType)>,
1162) -> Result<StructType> {
1163 let struct_type = StructType::new(fields);
1164 if let Some(name) = struct_type.find_duplicate_field_name() {
1165 return Err(ErrorCode::InvalidInputSyntax(format!(
1166 "struct field \"{name}\" specified more than once"
1167 ))
1168 .into());
1169 }
1170 Ok(struct_type)
1171}
1172
1173#[cfg(test)]
1174mod tests {
1175 use risingwave_sqlparser::ast::{Ident, StructField};
1176
1177 use super::*;
1178
1179 fn field(name: Ident, data_type: AstDataType) -> StructField {
1180 StructField { name, data_type }
1181 }
1182
1183 fn unquoted(name: &str, data_type: AstDataType) -> StructField {
1184 field(Ident::new_unchecked(name), data_type)
1185 }
1186
1187 fn quoted(name: &str, data_type: AstDataType) -> StructField {
1188 field(Ident::with_quote_unchecked('"', name), data_type)
1189 }
1190
1191 fn assert_duplicate_field_rejected(data_type: AstDataType) {
1192 assert!(bind_data_type(&data_type).is_err());
1193 }
1194
1195 #[test]
1196 fn bind_struct_rejects_duplicate_field_names() {
1197 assert_duplicate_field_rejected(AstDataType::Struct(vec![
1198 unquoted("a", AstDataType::Int),
1199 unquoted("a", AstDataType::Varchar),
1200 ]));
1201
1202 assert_duplicate_field_rejected(AstDataType::Struct(vec![
1204 unquoted("Value", AstDataType::Int),
1205 unquoted("VALUE", AstDataType::BigInt),
1206 ]));
1207
1208 assert_duplicate_field_rejected(AstDataType::Struct(vec![
1210 quoted("Value", AstDataType::Int),
1211 quoted("Value", AstDataType::BigInt),
1212 ]));
1213 }
1214
1215 #[test]
1216 fn bind_struct_rejects_duplicates_in_nested_types() {
1217 let duplicate_struct = || {
1218 AstDataType::Struct(vec![
1219 unquoted("a", AstDataType::Int),
1220 unquoted("a", AstDataType::Varchar),
1221 ])
1222 };
1223
1224 assert_duplicate_field_rejected(AstDataType::Struct(vec![unquoted(
1225 "nested",
1226 duplicate_struct(),
1227 )]));
1228 assert_duplicate_field_rejected(AstDataType::Array(Box::new(duplicate_struct())));
1229 assert_duplicate_field_rejected(AstDataType::Map(Box::new((
1230 AstDataType::Varchar,
1231 duplicate_struct(),
1232 ))));
1233 }
1234
1235 #[test]
1236 fn bind_struct_accepts_distinct_quoted_field_names() {
1237 let data_type = bind_data_type(&AstDataType::Struct(vec![
1238 unquoted("Value", AstDataType::Int),
1239 quoted("Value", AstDataType::Varchar),
1240 quoted("VALUE", AstDataType::Boolean),
1241 ]))
1242 .unwrap();
1243
1244 let struct_type = data_type.as_struct();
1245 assert_eq!(
1246 struct_type.names().collect_vec(),
1247 ["value", "Value", "VALUE"]
1248 );
1249 assert_eq!(
1250 struct_type.types().cloned().collect_vec(),
1251 [DataType::Int32, DataType::Varchar, DataType::Boolean]
1252 );
1253 }
1254
1255 #[test]
1256 fn bind_generated_struct_rejects_duplicate_field_names() {
1257 assert!(bind_struct_type([("a", DataType::Int32), ("a", DataType::Varchar)]).is_err());
1258 assert!(bind_struct_type([("a", DataType::Int32), ("A", DataType::Varchar)]).is_ok());
1259 }
1260}