From 4a28e241f6f9e41a1c2dbd80919e9a5fae945cdb Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 13:06:08 -0700 Subject: [PATCH 1/7] bitwise and parse/eval --- .../kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt | 1 + partiql-parser/src/main/antlr/PartiQL.g4 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt index cb72c19339..1c256d821c 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt @@ -583,6 +583,7 @@ class ASTPrettyPrinter { is PartiqlAst.Expr.GraphMatch -> TODO("Unsupported GraphMatch AST node") is PartiqlAst.Expr.CallWindow -> TODO("PrettyPrinter doesn't support Window Function yet.") is PartiqlAst.Expr.Timestamp -> TODO() + is PartiqlAst.Expr.BitwiseAnd -> TODO() } private fun toRecursionTreeList(nodes: List, attrOfParent: String? = null): List = diff --git a/partiql-parser/src/main/antlr/PartiQL.g4 b/partiql-parser/src/main/antlr/PartiQL.g4 index dc4b6c61fd..ccf23760cc 100644 --- a/partiql-parser/src/main/antlr/PartiQL.g4 +++ b/partiql-parser/src/main/antlr/PartiQL.g4 @@ -557,7 +557,7 @@ mathOp00 ; mathOp01 - : lhs=mathOp01 op=(PLUS|MINUS) rhs=mathOp02 + : lhs=mathOp01 op=(PLUS|MINUS|AMPERSAND) rhs=mathOp02 | parent=mathOp02 ; From f56de90d11633d0321342a8e74aa8bc1a28fd9f3 Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 13:17:32 -0700 Subject: [PATCH 2/7] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 158497cc48..a84190eed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ Thank you to all who have contributed! ### Added - Support parsing and evaluation of Bitwise AND operator (&). - The Bitwise And Operator only works for integer operands. - - The operator precedence may change based on the pending operator precedence [RFC](https://github.com/partiql/partiql-docs/issues/50). + - The operator precedence may change based on the pending operator precedence [RFC](https://github.com/partiql/partiql-docs/issues/50). ### Changed From 37581e560dd3bb44fe7e874f4b5bd9efaca77e21 Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 15:44:11 -0700 Subject: [PATCH 3/7] chagne type precedence --- CHANGELOG.md | 2 +- .../kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt | 1 - partiql-parser/src/main/antlr/PartiQL.g4 | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84190eed8..373d30332c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ Thank you to all who have contributed! ### Added - Support parsing and evaluation of Bitwise AND operator (&). - - The Bitwise And Operator only works for integer operands. + - The Bitwise And Operator only works for integer operands. - The operator precedence may change based on the pending operator precedence [RFC](https://github.com/partiql/partiql-docs/issues/50). ### Changed diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt index 1c256d821c..cb72c19339 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/prettyprint/ASTPrettyPrinter.kt @@ -583,7 +583,6 @@ class ASTPrettyPrinter { is PartiqlAst.Expr.GraphMatch -> TODO("Unsupported GraphMatch AST node") is PartiqlAst.Expr.CallWindow -> TODO("PrettyPrinter doesn't support Window Function yet.") is PartiqlAst.Expr.Timestamp -> TODO() - is PartiqlAst.Expr.BitwiseAnd -> TODO() } private fun toRecursionTreeList(nodes: List, attrOfParent: String? = null): List = diff --git a/partiql-parser/src/main/antlr/PartiQL.g4 b/partiql-parser/src/main/antlr/PartiQL.g4 index ccf23760cc..dc4b6c61fd 100644 --- a/partiql-parser/src/main/antlr/PartiQL.g4 +++ b/partiql-parser/src/main/antlr/PartiQL.g4 @@ -557,7 +557,7 @@ mathOp00 ; mathOp01 - : lhs=mathOp01 op=(PLUS|MINUS|AMPERSAND) rhs=mathOp02 + : lhs=mathOp01 op=(PLUS|MINUS) rhs=mathOp02 | parent=mathOp02 ; From b9f0ed75b425ab1cad2ba1390ef83237e494a2ff Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 16:26:02 -0700 Subject: [PATCH 4/7] type inferencer --- .../lang/planner/transforms/plan/PlanTyper.kt | 5 ++ .../planner/transforms/plan/RexConverter.kt | 11 ++++ .../PartiQLSchemaInferencerTests.kt | 53 +++++++++++++++++++ .../src/main/resources/partiql_plan.ion | 2 +- 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/PlanTyper.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/PlanTyper.kt index 6dda0b7a73..514885cb3c 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/PlanTyper.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/PlanTyper.kt @@ -493,6 +493,11 @@ internal object PlanTyper : PlanRewriter() { true -> computeReturnTypeForNAry(args, PlanTyper::inferBinaryArithmeticOp) false -> StaticType.NUMERIC // continuation type to prevent incompatible types and unknown errors from propagating } + Rex.Binary.Op.BITWISE_AND -> when (hasValidOperandTypes(args, node.op.name, ctx) { it is IntType }) { + true -> computeReturnTypeForNAry(args, PlanTyper::inferBinaryArithmeticOp) + false -> StaticType.unionOf(StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT) // continuation type to prevent incompatible types and unknown errors from propagating + } + Rex.Binary.Op.CONCAT -> when (hasValidOperandTypes(args, node.op.name, ctx) { it.isText() }) { true -> computeReturnTypeForNAry(args, PlanTyper::inferConcatOp) false -> StaticType.STRING // continuation type to prevent incompatible types and unknown errors from propagating diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/RexConverter.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/RexConverter.kt index 9e4dc0786a..8f34c03b73 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/RexConverter.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/planner/transforms/plan/RexConverter.kt @@ -223,6 +223,17 @@ internal object RexConverter : PartiqlAst.VisitorFold() { ) } + override fun walkExprBitwiseAnd(node: PartiqlAst.Expr.BitwiseAnd, accumulator: Ctx) = visit(node) { + Plan.rexBinary( + lhs = convert(node.operands[0]), + rhs = convert(node.operands[1]), + op = Rex.Binary.Op.BITWISE_AND, + type = StaticType.unionOf( + StaticType.INT2, StaticType.INT4, StaticType.INT8, StaticType.INT + ) + ) + } + override fun walkExprConcat(node: PartiqlAst.Expr.Concat, ctx: Ctx) = visit(node) { Plan.rexBinary( lhs = convert(node.operands[0]), diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt index 4f37b9abf1..8978afae56 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt @@ -26,6 +26,7 @@ import org.partiql.types.BagType import org.partiql.types.ListType import org.partiql.types.StaticType import org.partiql.types.StaticType.Companion.INT +import org.partiql.types.StaticType.Companion.MISSING import org.partiql.types.StaticType.Companion.STRING import org.partiql.types.StaticType.Companion.unionOf import org.partiql.types.StructType @@ -1070,6 +1071,58 @@ class PartiQLSchemaInferencerTests { ) } ), + SuccessTestCase( + name = "BITWISE_AND_1", + query = "1 & 2", + expected = StaticType.INT + ), + // casting to a parameterized type produced Missing. + SuccessTestCase( + name = "BITWISE_AND_2", + query = "CAST(1 AS INT2) & CAST(2 AS INT2)", + expected = StaticType.unionOf(StaticType.INT2, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_3", + query = "CAST(1 AS INT4) & CAST(2 AS INT4)", + expected = StaticType.unionOf(StaticType.INT4, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_4", + query = "CAST(1 AS INT8) & CAST(2 AS INT8)", + expected = StaticType.unionOf(StaticType.INT8, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_5", + query = "CAST(1 AS INT2) & CAST(2 AS INT4)", + expected = StaticType.unionOf(StaticType.INT4, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_6", + query = "CAST(1 AS INT2) & CAST(2 AS INT8)", + expected = StaticType.unionOf(StaticType.INT8, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_7", + query = "CAST(1 AS INT2) & 2", + expected = StaticType.unionOf(StaticType.INT, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_8", + query = "CAST(1 AS INT4) & CAST(2 AS INT8)", + expected = StaticType.unionOf(StaticType.INT8, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_9", + query = "CAST(1 AS INT4) & 2", + expected = StaticType.unionOf(StaticType.INT, MISSING) + ), + SuccessTestCase( + name = "BITWISE_AND_10", + query = "CAST(1 AS INT8) & 2", + expected = StaticType.unionOf(StaticType.INT, MISSING) + ), + ) private fun assertProblemExists(problem: () -> Problem) = ProblemHandler { problems, ignoreSourceLocation -> diff --git a/partiql-plan/src/main/resources/partiql_plan.ion b/partiql-plan/src/main/resources/partiql_plan.ion index 8d9ce2c35d..f29b034cd9 100644 --- a/partiql-plan/src/main/resources/partiql_plan.ion +++ b/partiql-plan/src/main/resources/partiql_plan.ion @@ -178,7 +178,7 @@ rex::[ lhs: rex, rhs: rex, op: [ - PLUS, MINUS, TIMES, DIV, MODULO, CONCAT, + PLUS, MINUS, TIMES, DIV, MODULO, CONCAT, BITWISE_AND, AND, OR, EQ, NEQ, GTE, GT, LT, LTE, ], From 9dfb19497e5167c82bcfafc718a36380a20de643 Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 16:49:54 -0700 Subject: [PATCH 5/7] wiki --- ...meric Data Type & Arithmetic Operations.md | 25 +++++++++++++++++++ partiql-parser/src/main/antlr/PartiQL.g4 | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/wiki/documentation/Numeric Data Type & Arithmetic Operations.md b/docs/wiki/documentation/Numeric Data Type & Arithmetic Operations.md index 25318fd59e..eecacb1c41 100644 --- a/docs/wiki/documentation/Numeric Data Type & Arithmetic Operations.md +++ b/docs/wiki/documentation/Numeric Data Type & Arithmetic Operations.md @@ -206,4 +206,29 @@ Example CAST(5 as decimal(3,2)) % CAST(2 as DECIMAL(3,2)) -- 1 -- IN HONOR PARAMETER MODE CAST(5 as decimal(3,2)) % CAST(2 as DECIMAL(3,2)) -- 1.00 +``` + +### Bitwise And +Performs a bitwise logical AND operation between two integer values. + +Syntax +: `expression & expression` + +Example: +```sql + 2 & 6 -- 0010 & 0110 = 0010 = 2 +``` + +Return Type: +: If one operand is of `INT` type, returns `INT` type. +: Else if one operand is of INT8 type, returns `INT8` type. +: Else if one operand is of INT4 type, returns `INT4` type. +: Else return `INT2` type. + +Note: +: Type precedence of the bitwise operator is lower than the plus/minus operator and higher than the predicates. + +```sql + 2 & 6 + 1 -- 2 & (6 + 1) = 2 & 7 = 2 + (2 & 6) + 1 -- 2 + 1 = 3 ``` \ No newline at end of file diff --git a/partiql-parser/src/main/antlr/PartiQL.g4 b/partiql-parser/src/main/antlr/PartiQL.g4 index dc4b6c61fd..0e266cb2f8 100644 --- a/partiql-parser/src/main/antlr/PartiQL.g4 +++ b/partiql-parser/src/main/antlr/PartiQL.g4 @@ -491,7 +491,7 @@ joinType * 2. Unary plus, minus (ex: -a, +a) * 3. Multiplication, Division, Modulo (ex: a * b) * 4. Addition, Subtraction (ex: a + b) - * 5. Other operators (ex: a || b) + * 5. Other operators (ex: a || b, a & b) * 6. Predicates (ex: a LIKE b, a < b, a IN b, a = b) * 7. IS true/false. Not yet implemented in PartiQL, but defined in SQL-92. (ex: a IS TRUE) * 8. NOT (ex: NOT a) From 100d84058373bd079f954a3cb2052dc69d3996f6 Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Wed, 27 Sep 2023 17:13:31 -0700 Subject: [PATCH 6/7] change log --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 373d30332c..e966df8760 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ Thank you to all who have contributed! ## [Unreleased] ### Added -- Support parsing and evaluation of Bitwise AND operator (&). +- Support parsing, planning and evaluation of Bitwise AND operator (&). - The Bitwise And Operator only works for integer operands. - The operator precedence may change based on the pending operator precedence [RFC](https://github.com/partiql/partiql-docs/issues/50). From 642c6d1e2d8c37248e0062a085c50737cd523ef4 Mon Sep 17 00:00:00 2001 From: Yingtao Liu Date: Thu, 28 Sep 2023 13:41:19 -0700 Subject: [PATCH 7/7] add test cases --- CHANGELOG.md | 2 +- .../kotlin/org/partiql/ast/sql/SqlDialect.kt | 1 + .../PartiQLSchemaInferencerTests.kt | 40 ++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e966df8760..696cd519d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ Thank you to all who have contributed! ## [Unreleased] ### Added -- Support parsing, planning and evaluation of Bitwise AND operator (&). +- Support parsing, planning, and evaluation of Bitwise AND operator (&). - The Bitwise And Operator only works for integer operands. - The operator precedence may change based on the pending operator precedence [RFC](https://github.com/partiql/partiql-docs/issues/50). diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt index b1a623a960..8a0d8118a1 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlDialect.kt @@ -204,6 +204,7 @@ public abstract class SqlDialect : AstBaseVisitor() { Expr.Binary.Op.GTE -> ">=" Expr.Binary.Op.LT -> "<" Expr.Binary.Op.LTE -> "<=" + Expr.Binary.Op.BITWISE_AND -> "&" } var h = head h = visitExpr(node.lhs, h) diff --git a/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt b/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt index 8978afae56..5d6afc4150 100644 --- a/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt +++ b/partiql-lang/src/test/kotlin/org/partiql/lang/planner/transforms/PartiQLSchemaInferencerTests.kt @@ -27,6 +27,7 @@ import org.partiql.types.ListType import org.partiql.types.StaticType import org.partiql.types.StaticType.Companion.INT import org.partiql.types.StaticType.Companion.MISSING +import org.partiql.types.StaticType.Companion.NULL import org.partiql.types.StaticType.Companion.STRING import org.partiql.types.StaticType.Companion.unionOf import org.partiql.types.StructType @@ -1122,7 +1123,44 @@ class PartiQLSchemaInferencerTests { query = "CAST(1 AS INT8) & 2", expected = StaticType.unionOf(StaticType.INT, MISSING) ), - + ErrorTestCase( + name = "BITWISE_AND_NULL_OPERAND", + query = "1 & NULL", + expected = StaticType.NULL, + problemHandler = assertProblemExists { + Problem( + UNKNOWN_PROBLEM_LOCATION, + SemanticProblemDetails.ExpressionAlwaysReturnsNullOrMissing + ) + } + ), + ErrorTestCase( + name = "BITWISE_AND_MISSING_OPERAND", + query = "1 & MISSING", + expected = StaticType.MISSING, + problemHandler = assertProblemExists { + Problem( + UNKNOWN_PROBLEM_LOCATION, + SemanticProblemDetails.ExpressionAlwaysReturnsNullOrMissing + ) + } + ), + ErrorTestCase( + name = "BITWISE_AND_NON_INT_OPERAND", + query = "1 & 'NOT AN INT'", + expected = StaticType.MISSING, + problemHandler = assertProblemExists { + Problem( + UNKNOWN_PROBLEM_LOCATION, + SemanticProblemDetails.IncompatibleDatatypesForOp( + listOf( + INT, STRING + ), + Rex.Binary.Op.BITWISE_AND.name + ) + ) + } + ), ) private fun assertProblemExists(problem: () -> Problem) = ProblemHandler { problems, ignoreSourceLocation ->