From d30484c4012cfee52f2abb6c8254461c86ff371f Mon Sep 17 00:00:00 2001 From: Yuming Wang Date: Tue, 16 May 2017 18:40:18 +0800 Subject: [PATCH 1/5] Add cotangent function. --- .../expressions/mathExpressions.scala | 22 +++++++++++++++++++ .../org/apache/spark/sql/functions.scala | 16 ++++++++++++++ .../apache/spark/sql/MathFunctionsSuite.scala | 4 ++++ 3 files changed, 42 insertions(+) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala index de1a46dc4780..46b6dafbef66 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala @@ -543,6 +543,28 @@ case class Sqrt(child: Expression) extends UnaryMathExpression(math.sqrt, "SQRT" """) case class Tan(child: Expression) extends UnaryMathExpression(math.tan, "TAN") +@ExpressionDescription( + usage = "_FUNC_(expr) - Returns the cotangent of `expr`.", + extended = """ + Examples: + > SELECT _FUNC_(1); + 0.6420926159343306 + """) +case class Cot(child: Expression) + extends UnaryMathExpression((x: Double) => 1 / math.tan(x), "COT") { + override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { + nullSafeCodeGen(ctx, ev, c => + s""" + if (${ev.value} == null) { + ${ev.isNull} = true; + } else { + ${ev.value} = 1 / java.lang.Math.tan($c); + } + """ + ) + } +} + @ExpressionDescription( usage = "_FUNC_(expr) - Returns the hyperbolic tangent of `expr`.", extended = """ diff --git a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala index 5edf03666ac2..ded6804a1d19 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala @@ -1990,6 +1990,22 @@ object functions { */ def tan(columnName: String): Column = tan(Column(columnName)) + /** + * Computes the cotangent of the given column. + * + * @group math_funcs + * @since 2.2.0 + */ + def cot(e: Column): Column = withExpr { Cot(e.expr) } + + /** + * Computes the cotangent of the given column name. + * + * @group math_funcs + * @since 2.2.0 + */ + def cot(colName: String): Column = cot(Column(colName)) + /** * Computes the hyperbolic tangent of the given value. * diff --git a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala index c2d08a06569b..d264346e548e 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala @@ -274,6 +274,10 @@ class MathFunctionsSuite extends QueryTest with SharedSQLContext { Row(1, -1)) } + test("cot") { + testOneToOneMathFunction(cot, (d: Double) => 1 / math.tan(d)) + } + test("pow / power") { testTwoToOneMathFunction(pow, pow, math.pow) From 3782512c9d1ff083fb2016e1fabefeee11e8f7bd Mon Sep 17 00:00:00 2001 From: Yuming Wang Date: Thu, 18 May 2017 01:06:17 +0800 Subject: [PATCH 2/5] Registry function, add edge test cases. --- .../spark/sql/catalyst/analysis/FunctionRegistry.scala | 1 + .../spark/sql/catalyst/expressions/mathExpressions.scala | 8 ++------ .../src/main/scala/org/apache/spark/sql/functions.scala | 4 ++-- .../scala/org/apache/spark/sql/MathFunctionsSuite.scala | 3 +++ 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala index 6fc154f8debc..d2042ad00a81 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala @@ -234,6 +234,7 @@ object FunctionRegistry { expression[StringToMap]("str_to_map"), expression[Sqrt]("sqrt"), expression[Tan]("tan"), + expression[Cot]("cot"), expression[Tanh]("tanh"), expression[Add]("+"), diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala index 46b6dafbef66..7707747b93a6 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala @@ -553,13 +553,9 @@ case class Tan(child: Expression) extends UnaryMathExpression(math.tan, "TAN") case class Cot(child: Expression) extends UnaryMathExpression((x: Double) => 1 / math.tan(x), "COT") { override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { - nullSafeCodeGen(ctx, ev, c => + defineCodeGen(ctx, ev, c => s""" - if (${ev.value} == null) { - ${ev.isNull} = true; - } else { - ${ev.value} = 1 / java.lang.Math.tan($c); - } + ${ev.value} = 1 / java.lang.Math.tan($c); """ ) } diff --git a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala index ded6804a1d19..f61f04dd2636 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala @@ -1994,7 +1994,7 @@ object functions { * Computes the cotangent of the given column. * * @group math_funcs - * @since 2.2.0 + * @since 2.3.0 */ def cot(e: Column): Column = withExpr { Cot(e.expr) } @@ -2002,7 +2002,7 @@ object functions { * Computes the cotangent of the given column name. * * @group math_funcs - * @since 2.2.0 + * @since 2.3.0 */ def cot(colName: String): Column = cot(Column(colName)) diff --git a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala index d264346e548e..992df8bf3a56 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala @@ -276,6 +276,9 @@ class MathFunctionsSuite extends QueryTest with SharedSQLContext { test("cot") { testOneToOneMathFunction(cot, (d: Double) => 1 / math.tan(d)) + checkAnswer( + sql(s"SELECT cot(null), cot(0), cot(-1), cot(${Double.MaxValue})"), + Row(null, Double.PositiveInfinity, -0.6420926159343306, -201.53099572900314)) } test("pow / power") { From c80c184d5a9f85e2bff740e8cf96bd9a97d0f8a7 Mon Sep 17 00:00:00 2001 From: Yuming Wang Date: Thu, 18 May 2017 13:04:24 +0800 Subject: [PATCH 3/5] Add test in operators.sql --- .../resources/sql-tests/inputs/operators.sql | 1 + .../sql-tests/results/operators.sql.out | 38 +++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/sql/core/src/test/resources/sql-tests/inputs/operators.sql b/sql/core/src/test/resources/sql-tests/inputs/operators.sql index 6339d69ca647..c34cc2ab556c 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/operators.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/operators.sql @@ -32,6 +32,7 @@ select 1 - 2; select 2 * 5; select 5 % 3; select pmod(-7, 3); +select cot(1); -- check operator precedence. -- We follow Oracle operator precedence in the table below that lists the levels of precedence diff --git a/sql/core/src/test/resources/sql-tests/results/operators.sql.out b/sql/core/src/test/resources/sql-tests/results/operators.sql.out index e0236f41187e..cf6d11c740c2 100644 --- a/sql/core/src/test/resources/sql-tests/results/operators.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/operators.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 34 +-- Number of queries: 35 -- !query 0 @@ -227,60 +227,68 @@ struct -- !query 28 -explain select 'a' || 1 + 2 +select cot(1) -- !query 28 schema -struct +struct -- !query 28 output -== Physical Plan == -*Project [null AS (CAST(concat(a, CAST(1 AS STRING)) AS DOUBLE) + CAST(2 AS DOUBLE))#x] -+- Scan OneRowRelation[] +0.6420926159343306 -- !query 29 -explain select 1 - 2 || 'b' +explain select 'a' || 1 + 2 -- !query 29 schema struct -- !query 29 output == Physical Plan == -*Project [-1b AS concat(CAST((1 - 2) AS STRING), b)#x] +*Project [null AS (CAST(concat(a, CAST(1 AS STRING)) AS DOUBLE) + CAST(2 AS DOUBLE))#x] +- Scan OneRowRelation[] -- !query 30 -explain select 2 * 4 + 3 || 'b' +explain select 1 - 2 || 'b' -- !query 30 schema struct -- !query 30 output == Physical Plan == -*Project [11b AS concat(CAST(((2 * 4) + 3) AS STRING), b)#x] +*Project [-1b AS concat(CAST((1 - 2) AS STRING), b)#x] +- Scan OneRowRelation[] -- !query 31 -explain select 3 + 1 || 'a' || 4 / 2 +explain select 2 * 4 + 3 || 'b' -- !query 31 schema struct -- !query 31 output == Physical Plan == -*Project [4a2.0 AS concat(concat(CAST((3 + 1) AS STRING), a), CAST((CAST(4 AS DOUBLE) / CAST(2 AS DOUBLE)) AS STRING))#x] +*Project [11b AS concat(CAST(((2 * 4) + 3) AS STRING), b)#x] +- Scan OneRowRelation[] -- !query 32 -explain select 1 == 1 OR 'a' || 'b' == 'ab' +explain select 3 + 1 || 'a' || 4 / 2 -- !query 32 schema struct -- !query 32 output == Physical Plan == -*Project [true AS ((1 = 1) OR (concat(a, b) = ab))#x] +*Project [4a2.0 AS concat(concat(CAST((3 + 1) AS STRING), a), CAST((CAST(4 AS DOUBLE) / CAST(2 AS DOUBLE)) AS STRING))#x] +- Scan OneRowRelation[] -- !query 33 -explain select 'a' || 'c' == 'ac' AND 2 == 3 +explain select 1 == 1 OR 'a' || 'b' == 'ab' -- !query 33 schema struct -- !query 33 output == Physical Plan == +*Project [true AS ((1 = 1) OR (concat(a, b) = ab))#x] ++- Scan OneRowRelation[] + + +-- !query 34 +explain select 'a' || 'c' == 'ac' AND 2 == 3 +-- !query 34 schema +struct +-- !query 34 output +== Physical Plan == *Project [false AS ((concat(a, c) = ac) AND (2 = 3))#x] +- Scan OneRowRelation[] From 3bd1e1e04ba56b9a0f8c30a65993a76142e411f3 Mon Sep 17 00:00:00 2001 From: Yuming Wang Date: Fri, 19 May 2017 00:11:09 +0800 Subject: [PATCH 4/5] Remove cot(colName: String) --- .../src/main/scala/org/apache/spark/sql/functions.scala | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala index f61f04dd2636..21f929e56473 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala @@ -1998,14 +1998,6 @@ object functions { */ def cot(e: Column): Column = withExpr { Cot(e.expr) } - /** - * Computes the cotangent of the given column name. - * - * @group math_funcs - * @since 2.3.0 - */ - def cot(colName: String): Column = cot(Column(colName)) - /** * Computes the hyperbolic tangent of the given value. * From ea10dee343671e3d9c79eb0bcddc55a2ee3d1d71 Mon Sep 17 00:00:00 2001 From: Yuming Wang Date: Fri, 19 May 2017 06:58:47 +0800 Subject: [PATCH 5/5] Move cot tests to operators.sql. --- .../expressions/mathExpressions.scala | 6 +- .../org/apache/spark/sql/functions.scala | 8 --- .../resources/sql-tests/inputs/operators.sql | 7 ++- .../sql-tests/results/operators.sql.out | 62 +++++++++++++------ .../apache/spark/sql/MathFunctionsSuite.scala | 7 --- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala index 7707747b93a6..a7bf81e98be8 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala @@ -553,11 +553,7 @@ case class Tan(child: Expression) extends UnaryMathExpression(math.tan, "TAN") case class Cot(child: Expression) extends UnaryMathExpression((x: Double) => 1 / math.tan(x), "COT") { override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { - defineCodeGen(ctx, ev, c => - s""" - ${ev.value} = 1 / java.lang.Math.tan($c); - """ - ) + defineCodeGen(ctx, ev, c => s"${ev.value} = 1 / java.lang.Math.tan($c);") } } diff --git a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala index 21f929e56473..5edf03666ac2 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/functions.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/functions.scala @@ -1990,14 +1990,6 @@ object functions { */ def tan(columnName: String): Column = tan(Column(columnName)) - /** - * Computes the cotangent of the given column. - * - * @group math_funcs - * @since 2.3.0 - */ - def cot(e: Column): Column = withExpr { Cot(e.expr) } - /** * Computes the hyperbolic tangent of the given value. * diff --git a/sql/core/src/test/resources/sql-tests/inputs/operators.sql b/sql/core/src/test/resources/sql-tests/inputs/operators.sql index c34cc2ab556c..1920a108c658 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/operators.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/operators.sql @@ -32,7 +32,6 @@ select 1 - 2; select 2 * 5; select 5 % 3; select pmod(-7, 3); -select cot(1); -- check operator precedence. -- We follow Oracle operator precedence in the table below that lists the levels of precedence @@ -54,3 +53,9 @@ explain select 2 * 4 + 3 || 'b'; explain select 3 + 1 || 'a' || 4 / 2; explain select 1 == 1 OR 'a' || 'b' == 'ab'; explain select 'a' || 'c' == 'ac' AND 2 == 3; + +-- math functions +select cot(1); +select cot(null); +select cot(0); +select cot(-1); diff --git a/sql/core/src/test/resources/sql-tests/results/operators.sql.out b/sql/core/src/test/resources/sql-tests/results/operators.sql.out index cf6d11c740c2..abd18211c70d 100644 --- a/sql/core/src/test/resources/sql-tests/results/operators.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/operators.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 35 +-- Number of queries: 38 -- !query 0 @@ -227,68 +227,92 @@ struct -- !query 28 -select cot(1) +explain select 'a' || 1 + 2 -- !query 28 schema -struct +struct -- !query 28 output -0.6420926159343306 +== Physical Plan == +*Project [null AS (CAST(concat(a, CAST(1 AS STRING)) AS DOUBLE) + CAST(2 AS DOUBLE))#x] ++- Scan OneRowRelation[] -- !query 29 -explain select 'a' || 1 + 2 +explain select 1 - 2 || 'b' -- !query 29 schema struct -- !query 29 output == Physical Plan == -*Project [null AS (CAST(concat(a, CAST(1 AS STRING)) AS DOUBLE) + CAST(2 AS DOUBLE))#x] +*Project [-1b AS concat(CAST((1 - 2) AS STRING), b)#x] +- Scan OneRowRelation[] -- !query 30 -explain select 1 - 2 || 'b' +explain select 2 * 4 + 3 || 'b' -- !query 30 schema struct -- !query 30 output == Physical Plan == -*Project [-1b AS concat(CAST((1 - 2) AS STRING), b)#x] +*Project [11b AS concat(CAST(((2 * 4) + 3) AS STRING), b)#x] +- Scan OneRowRelation[] -- !query 31 -explain select 2 * 4 + 3 || 'b' +explain select 3 + 1 || 'a' || 4 / 2 -- !query 31 schema struct -- !query 31 output == Physical Plan == -*Project [11b AS concat(CAST(((2 * 4) + 3) AS STRING), b)#x] +*Project [4a2.0 AS concat(concat(CAST((3 + 1) AS STRING), a), CAST((CAST(4 AS DOUBLE) / CAST(2 AS DOUBLE)) AS STRING))#x] +- Scan OneRowRelation[] -- !query 32 -explain select 3 + 1 || 'a' || 4 / 2 +explain select 1 == 1 OR 'a' || 'b' == 'ab' -- !query 32 schema struct -- !query 32 output == Physical Plan == -*Project [4a2.0 AS concat(concat(CAST((3 + 1) AS STRING), a), CAST((CAST(4 AS DOUBLE) / CAST(2 AS DOUBLE)) AS STRING))#x] +*Project [true AS ((1 = 1) OR (concat(a, b) = ab))#x] +- Scan OneRowRelation[] -- !query 33 -explain select 1 == 1 OR 'a' || 'b' == 'ab' +explain select 'a' || 'c' == 'ac' AND 2 == 3 -- !query 33 schema struct -- !query 33 output == Physical Plan == -*Project [true AS ((1 = 1) OR (concat(a, b) = ab))#x] +*Project [false AS ((concat(a, c) = ac) AND (2 = 3))#x] +- Scan OneRowRelation[] -- !query 34 -explain select 'a' || 'c' == 'ac' AND 2 == 3 +select cot(1) -- !query 34 schema -struct +struct -- !query 34 output -== Physical Plan == -*Project [false AS ((concat(a, c) = ac) AND (2 = 3))#x] -+- Scan OneRowRelation[] +0.6420926159343306 + + +-- !query 35 +select cot(null) +-- !query 35 schema +struct +-- !query 35 output +NULL + + +-- !query 36 +select cot(0) +-- !query 36 schema +struct +-- !query 36 output +Infinity + + +-- !query 37 +select cot(-1) +-- !query 37 schema +struct +-- !query 37 output +-0.6420926159343306 diff --git a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala index 992df8bf3a56..c2d08a06569b 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/MathFunctionsSuite.scala @@ -274,13 +274,6 @@ class MathFunctionsSuite extends QueryTest with SharedSQLContext { Row(1, -1)) } - test("cot") { - testOneToOneMathFunction(cot, (d: Double) => 1 / math.tan(d)) - checkAnswer( - sql(s"SELECT cot(null), cot(0), cot(-1), cot(${Double.MaxValue})"), - Row(null, Double.PositiveInfinity, -0.6420926159343306, -201.53099572900314)) - } - test("pow / power") { testTwoToOneMathFunction(pow, pow, math.pow)