risingwave_frontend/binder/expr/
binary_op.rsuse risingwave_common::bail_not_implemented;
use risingwave_common::types::{DataType, JsonbVal};
use risingwave_sqlparser::ast::{BinaryOperator, Expr};
use crate::binder::Binder;
use crate::error::{ErrorCode, Result};
use crate::expr::{Expr as _, ExprImpl, ExprType, FunctionCall};
impl Binder {
pub(super) fn bind_binary_op(
&mut self,
left: Expr,
op: BinaryOperator,
mut right: Expr,
) -> Result<ExprImpl> {
let bound_left = self.bind_expr_inner(left)?;
let mut func_types = vec![];
right = match right {
Expr::SomeOp(expr) => {
func_types.push(ExprType::Some);
*expr
}
Expr::AllOp(expr) => {
func_types.push(ExprType::All);
*expr
}
right => right,
};
let bound_right = self.bind_expr_inner(right)?;
if matches!(op, BinaryOperator::PathMatch | BinaryOperator::PathExists) {
return Ok(FunctionCall::new_unchecked(
match op {
BinaryOperator::PathMatch => ExprType::JsonbPathMatch,
BinaryOperator::PathExists => ExprType::JsonbPathExists,
_ => unreachable!(),
},
vec![
bound_left,
bound_right,
ExprImpl::literal_jsonb(JsonbVal::empty_object()), ExprImpl::literal_bool(true), ],
DataType::Boolean,
)
.into());
}
func_types.extend(Self::resolve_binary_operator(
op,
&bound_left,
&bound_right,
)?);
FunctionCall::new_binary_op_func(func_types, vec![bound_left, bound_right])
}
fn resolve_binary_operator(
op: BinaryOperator,
bound_left: &ExprImpl,
bound_right: &ExprImpl,
) -> Result<Vec<ExprType>> {
let mut func_types = vec![];
let final_type = match op {
BinaryOperator::Plus => ExprType::Add,
BinaryOperator::Minus => ExprType::Subtract,
BinaryOperator::Multiply => ExprType::Multiply,
BinaryOperator::Divide => ExprType::Divide,
BinaryOperator::Modulo => ExprType::Modulus,
BinaryOperator::NotEq => ExprType::NotEqual,
BinaryOperator::Eq => ExprType::Equal,
BinaryOperator::Lt => ExprType::LessThan,
BinaryOperator::LtEq => ExprType::LessThanOrEqual,
BinaryOperator::Gt => ExprType::GreaterThan,
BinaryOperator::GtEq => ExprType::GreaterThanOrEqual,
BinaryOperator::And => ExprType::And,
BinaryOperator::Or => ExprType::Or,
BinaryOperator::PGLikeMatch => ExprType::Like,
BinaryOperator::PGNotLikeMatch => {
func_types.push(ExprType::Not);
ExprType::Like
}
BinaryOperator::PGILikeMatch => ExprType::ILike,
BinaryOperator::PGNotILikeMatch => {
func_types.push(ExprType::Not);
ExprType::ILike
}
BinaryOperator::BitwiseOr => ExprType::BitwiseOr,
BinaryOperator::BitwiseAnd => ExprType::BitwiseAnd,
BinaryOperator::BitwiseXor => ExprType::Pow,
BinaryOperator::PGBitwiseXor => ExprType::BitwiseXor,
BinaryOperator::PGBitwiseShiftLeft => ExprType::BitwiseShiftLeft,
BinaryOperator::PGBitwiseShiftRight => ExprType::BitwiseShiftRight,
BinaryOperator::Arrow => ExprType::JsonbAccess,
BinaryOperator::LongArrow => ExprType::JsonbAccessStr,
BinaryOperator::HashMinus => ExprType::JsonbDeletePath,
BinaryOperator::HashArrow => ExprType::JsonbExtractPathVariadic,
BinaryOperator::HashLongArrow => ExprType::JsonbExtractPathTextVariadic,
BinaryOperator::Prefix => ExprType::StartsWith,
BinaryOperator::Contains => {
let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
match (left_type, right_type) {
(Some(DataType::List { .. }), Some(DataType::List { .. }))
| (Some(DataType::List { .. }), None)
| (None, Some(DataType::List { .. })) => ExprType::ArrayContains,
(Some(DataType::Jsonb), Some(DataType::Jsonb))
| (Some(DataType::Jsonb), None)
| (None, Some(DataType::Jsonb)) => ExprType::JsonbContains,
(left, right) => {
return Err(ErrorCode::BindError(format!(
"operator does not exist: {} @> {}",
left.map_or_else(|| String::from("unknown"), |x| x.to_string()),
right.map_or_else(|| String::from("unknown"), |x| x.to_string()),
))
.into());
}
}
}
BinaryOperator::Contained => {
let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
match (left_type, right_type) {
(Some(DataType::List { .. }), Some(DataType::List { .. }))
| (Some(DataType::List { .. }), None)
| (None, Some(DataType::List { .. })) => ExprType::ArrayContained,
(Some(DataType::Jsonb), Some(DataType::Jsonb))
| (Some(DataType::Jsonb), None)
| (None, Some(DataType::Jsonb)) => ExprType::JsonbContained,
(left, right) => {
return Err(ErrorCode::BindError(format!(
"operator does not exist: {} <@ {}",
left.map_or_else(|| String::from("unknown"), |x| x.to_string()),
right.map_or_else(|| String::from("unknown"), |x| x.to_string()),
))
.into());
}
}
}
BinaryOperator::Exists => ExprType::JsonbExists,
BinaryOperator::ExistsAny => ExprType::JsonbExistsAny,
BinaryOperator::ExistsAll => ExprType::JsonbExistsAll,
BinaryOperator::Concat => {
let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
match (left_type, right_type) {
(Some(DataType::List { .. }), Some(DataType::List { .. }))
| (Some(DataType::List { .. }), None)
| (None, Some(DataType::List { .. })) => ExprType::ArrayCat,
(Some(DataType::List { .. }), Some(_)) => ExprType::ArrayAppend,
(Some(_), Some(DataType::List { .. })) => ExprType::ArrayPrepend,
(Some(DataType::Varchar), _) | (_, Some(DataType::Varchar)) => {
ExprType::ConcatOp
}
(Some(DataType::Jsonb), Some(DataType::Jsonb))
| (Some(DataType::Jsonb), None)
| (None, Some(DataType::Jsonb)) => ExprType::JsonbConcat,
(Some(t @ DataType::Bytea), Some(DataType::Bytea))
| (Some(t @ DataType::Bytea), None)
| (None, Some(t @ DataType::Bytea)) => {
return Err(ErrorCode::BindError(format!(
"operator not implemented yet: {t} || {t}"
))
.into())
}
(None, _) | (_, None) => ExprType::ConcatOp,
(Some(left_type), Some(right_type)) => {
return Err(ErrorCode::BindError(format!(
"operator does not exist: {} || {}",
left_type, right_type
))
.into());
}
}
}
BinaryOperator::PGRegexMatch => ExprType::RegexpEq,
BinaryOperator::PGRegexNotMatch => {
func_types.push(ExprType::Not);
ExprType::RegexpEq
}
_ => bail_not_implemented!(issue = 112, "binary op: {:?}", op),
};
func_types.push(final_type);
Ok(func_types)
}
}