diff --git a/e2e_test/batch/basic/boolean.slt.part b/e2e_test/batch/basic/boolean.slt.part index 2892d6b0bef7b..21c7035a7f290 100644 --- a/e2e_test/batch/basic/boolean.slt.part +++ b/e2e_test/batch/basic/boolean.slt.part @@ -127,3 +127,18 @@ select booleq(true,true), boolne('true'::bool,true); ---- t f f t f t t f t t f + +query TTTT +select + true is unknown, + null is unknown, + 't' is not unknown, + 'on' is not unknown; +---- +f t t t + +statement error +select 1 is unknown; + +statement error +select 'a' is not unknown; diff --git a/src/frontend/src/binder/expr/mod.rs b/src/frontend/src/binder/expr/mod.rs index 257291c7c9517..0f9affffd7cc0 100644 --- a/src/frontend/src/binder/expr/mod.rs +++ b/src/frontend/src/binder/expr/mod.rs @@ -129,6 +129,8 @@ impl Binder { Expr::IsNotTrue(expr) => self.bind_is_operator(ExprType::IsNotTrue, *expr), Expr::IsFalse(expr) => self.bind_is_operator(ExprType::IsFalse, *expr), Expr::IsNotFalse(expr) => self.bind_is_operator(ExprType::IsNotFalse, *expr), + Expr::IsUnknown(expr) => self.bind_is_unknown(ExprType::IsNull, *expr), + Expr::IsNotUnknown(expr) => self.bind_is_unknown(ExprType::IsNotNull, *expr), Expr::IsDistinctFrom(left, right) => self.bind_distinct_from(*left, *right), Expr::IsNotDistinctFrom(left, right) => self.bind_not_distinct_from(*left, *right), Expr::Case { @@ -441,6 +443,13 @@ impl Binder { Ok(FunctionCall::new(func_type, vec![expr])?.into()) } + pub(super) fn bind_is_unknown(&mut self, func_type: ExprType, expr: Expr) -> Result<ExprImpl> { + let expr = self + .bind_expr_inner(expr)? + .cast_implicit(DataType::Boolean)?; + Ok(FunctionCall::new(func_type, vec![expr])?.into()) + } + pub(super) fn bind_distinct_from(&mut self, left: Expr, right: Expr) -> Result<ExprImpl> { let left = self.bind_expr_inner(left)?; let right = self.bind_expr_inner(right)?; diff --git a/src/meta/src/manager/catalog/utils.rs b/src/meta/src/manager/catalog/utils.rs index 9d4b383ced07f..122fbbe81b970 100644 --- a/src/meta/src/manager/catalog/utils.rs +++ b/src/meta/src/manager/catalog/utils.rs @@ -266,6 +266,8 @@ impl QueryRewriter<'_> { | Expr::IsNotTrue(expr) | Expr::IsFalse(expr) | Expr::IsNotFalse(expr) + | Expr::IsUnknown(expr) + | Expr::IsNotUnknown(expr) | Expr::InList { expr, .. } | Expr::SomeOp(expr) | Expr::AllOp(expr) diff --git a/src/sqlparser/src/ast/mod.rs b/src/sqlparser/src/ast/mod.rs index 02d66c16b3f8f..11a10e784bdd2 100644 --- a/src/sqlparser/src/ast/mod.rs +++ b/src/sqlparser/src/ast/mod.rs @@ -278,6 +278,10 @@ pub enum Expr { IsFalse(Box<Expr>), /// `IS NOT FALSE` operator IsNotFalse(Box<Expr>), + /// `IS UNKNOWN` operator + IsUnknown(Box<Expr>), + /// `IS NOT UNKNOWN` operator + IsNotUnknown(Box<Expr>), /// `IS DISTINCT FROM` operator IsDistinctFrom(Box<Expr>, Box<Expr>), /// `IS NOT DISTINCT FROM` operator @@ -427,6 +431,8 @@ impl fmt::Display for Expr { Expr::IsNotTrue(ast) => write!(f, "{} IS NOT TRUE", ast), Expr::IsFalse(ast) => write!(f, "{} IS FALSE", ast), Expr::IsNotFalse(ast) => write!(f, "{} IS NOT FALSE", ast), + Expr::IsUnknown(ast) => write!(f, "{} IS UNKNOWN", ast), + Expr::IsNotUnknown(ast) => write!(f, "{} IS NOT UNKNOWN", ast), Expr::InList { expr, list, diff --git a/src/sqlparser/src/parser.rs b/src/sqlparser/src/parser.rs index d669aa631f93f..3812cd8fe0284 100644 --- a/src/sqlparser/src/parser.rs +++ b/src/sqlparser/src/parser.rs @@ -1314,6 +1314,10 @@ impl Parser { Ok(Expr::IsFalse(Box::new(expr))) } else if self.parse_keywords(&[Keyword::NOT, Keyword::FALSE]) { Ok(Expr::IsNotFalse(Box::new(expr))) + } else if self.parse_keyword(Keyword::UNKNOWN) { + Ok(Expr::IsUnknown(Box::new(expr))) + } else if self.parse_keywords(&[Keyword::NOT, Keyword::UNKNOWN]) { + Ok(Expr::IsNotUnknown(Box::new(expr))) } else if self.parse_keyword(Keyword::NULL) { Ok(Expr::IsNull(Box::new(expr))) } else if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) { diff --git a/src/tests/regress/data/expected/boolean.out b/src/tests/regress/data/expected/boolean.out index 032a524a76df9..4728fe2dfdf4a 100644 --- a/src/tests/regress/data/expected/boolean.out +++ b/src/tests/regress/data/expected/boolean.out @@ -455,8 +455,8 @@ SELECT b IS NOT TRUE AS isnottrue, b IS FALSE AS isfalse, b IS NOT FALSE AS isnotfalse, - b IS NULL AS isunknown, - b IS NOT NULL AS isnotunknown + b IS UNKNOWN AS isunknown, + b IS NOT UNKNOWN AS isnotunknown FROM booltbl3 ORDER BY o; d | istrue | isnottrue | isfalse | isnotfalse | isunknown | isnotunknown -------+--------+-----------+---------+------------+-----------+-------------- diff --git a/src/tests/regress/data/sql/boolean.sql b/src/tests/regress/data/sql/boolean.sql index 46e9308e4b8c8..4dd47aaf9d8a7 100644 --- a/src/tests/regress/data/sql/boolean.sql +++ b/src/tests/regress/data/sql/boolean.sql @@ -215,8 +215,8 @@ SELECT b IS NOT TRUE AS isnottrue, b IS FALSE AS isfalse, b IS NOT FALSE AS isnotfalse, - b IS NULL AS isunknown, - b IS NOT NULL AS isnotunknown + b IS UNKNOWN AS isunknown, + b IS NOT UNKNOWN AS isnotunknown FROM booltbl3 ORDER BY o;