You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by pb...@apache.org on 2019/05/01 07:36:45 UTC
[phoenix] 07/12: PHOENIX-5181 support Math sin/cos/tan functions
This is an automated email from the ASF dual-hosted git repository.
pboado pushed a commit to branch 5.x-cdh6
in repository https://gitbox.apache.org/repos/asf/phoenix.git
commit 2f225e3680977d3b4e0ace578d6ccacb69994718
Author: Xinyi Yan <xy...@salesforce.com>
AuthorDate: Thu Mar 7 18:48:57 2019 +0000
PHOENIX-5181 support Math sin/cos/tan functions
---
.../phoenix/end2end/MathTrigFunctionEnd2EndIT.java | 94 +++++++++++
.../apache/phoenix/expression/ExpressionType.java | 3 +
.../phoenix/expression/function/CosFunction.java | 56 +++++++
.../phoenix/expression/function/SinFunction.java | 56 +++++++
.../phoenix/expression/function/TanFunction.java | 56 +++++++
.../phoenix/expression/MathTrigFunctionTest.java | 179 +++++++++++++++++++++
6 files changed, 444 insertions(+)
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MathTrigFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MathTrigFunctionEnd2EndIT.java
new file mode 100644
index 0000000..b4f2b4f
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MathTrigFunctionEnd2EndIT.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.end2end;
+
+import static org.apache.phoenix.util.TestUtil.closeStmtAndConn;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+import org.apache.phoenix.expression.function.CosFunction;
+import org.apache.phoenix.expression.function.SinFunction;
+import org.apache.phoenix.expression.function.TanFunction;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * End to end tests for
+ * {@link org.apache.phoenix.expression.function.CosFunction}
+ * {@link org.apache.phoenix.expression.function.SinFunction}
+ * {@link org.apache.phoenix.expression.function.TanFunction}
+ */
+
+public class MathTrigFunctionEnd2EndIT extends ParallelStatsDisabledIT {
+
+ private static final String KEY = "key";
+ private String tableName;
+
+ @Before
+ public void initTable() throws Exception {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ tableName = generateUniqueName();
+
+ try {
+ conn = DriverManager.getConnection(getUrl());
+ String ddl;
+ ddl =
+ "CREATE TABLE " + tableName + " (k VARCHAR NOT NULL PRIMARY KEY, doub DOUBLE)";
+ conn.createStatement().execute(ddl);
+ conn.commit();
+ } finally {
+ closeStmtAndConn(stmt, conn);
+ }
+ }
+
+ private void updateTableSpec(Connection conn, double data, String tableName) throws Exception {
+ PreparedStatement stmt =
+ conn.prepareStatement("UPSERT INTO " + tableName + " VALUES (?, ?)");
+ stmt.setString(1, KEY);
+ stmt.setDouble(2, data);
+ stmt.executeUpdate();
+ conn.commit();
+ }
+
+ private void testNumberSpec(Connection conn, double data, String tableName) throws Exception {
+ updateTableSpec(conn, data, tableName);
+ ResultSet rs =
+ conn.createStatement().executeQuery(
+ "SELECT SIN(doub),COS(doub),TAN(doub) FROM " + tableName);
+ assertTrue(rs.next());
+ Double d = Double.valueOf(data);
+ assertTrue(twoDoubleEquals(rs.getDouble(1), Math.sin(data)));
+ assertTrue(twoDoubleEquals(rs.getDouble(2), Math.cos(data)));
+ assertTrue(twoDoubleEquals(rs.getDouble(3), Math.tan(data)));
+
+ assertTrue(!rs.next());
+ }
+
+ @Test
+ public void test() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ for (double d : new double[] { 0.0, 1.0, -1.0, 123.1234, -123.1234 }) {
+ testNumberSpec(conn, d, tableName);
+ }
+ }
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
index a18928c..8f36e23 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
@@ -188,6 +188,9 @@ public enum ExpressionType {
ArrayRemoveFunction(ArrayRemoveFunction.class),
TransactionProviderNameFunction(TransactionProviderNameFunction.class),
MathPIFunction(MathPIFunction.class),
+ SinFunction(SinFunction.class),
+ CosFunction(CosFunction.class),
+ TanFunction(TanFunction.class),
;
ExpressionType(Class<? extends Expression> clazz) {
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CosFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CosFunction.java
new file mode 100644
index 0000000..b6532d8
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CosFunction.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.types.PDecimal;
+import org.apache.phoenix.schema.types.PDouble;
+
+@BuiltInFunction(name = CosFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class,
+ PDecimal.class }) })
+public class CosFunction extends JavaMathOneArgumentFunction {
+
+ public static final String NAME = "COS";
+
+ public CosFunction() {
+ }
+
+ public CosFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ protected double compute(double firstArg) {
+ return Math.cos(firstArg);
+ }
+
+ @Override
+ public OrderPreserving preservesOrder() {
+ return OrderPreserving.YES;
+ }
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SinFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SinFunction.java
new file mode 100644
index 0000000..3b29f7f
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SinFunction.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.types.PDecimal;
+import org.apache.phoenix.schema.types.PDouble;
+
+@BuiltInFunction(name = SinFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class,
+ PDecimal.class }) })
+public class SinFunction extends JavaMathOneArgumentFunction {
+
+ public static final String NAME = "SIN";
+
+ public SinFunction() {
+ }
+
+ public SinFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ protected double compute(double firstArg) {
+ return Math.sin(firstArg);
+ }
+
+ @Override
+ public OrderPreserving preservesOrder() {
+ return OrderPreserving.YES;
+ }
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TanFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TanFunction.java
new file mode 100644
index 0000000..5951cab
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TanFunction.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.types.PDecimal;
+import org.apache.phoenix.schema.types.PDouble;
+
+@BuiltInFunction(name = TanFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class,
+ PDecimal.class }) })
+public class TanFunction extends JavaMathOneArgumentFunction {
+
+ public static final String NAME = "TAN";
+
+ public TanFunction() {
+ }
+
+ public TanFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ protected double compute(double firstArg) {
+ return Math.tan(firstArg);
+ }
+
+ @Override
+ public OrderPreserving preservesOrder() {
+ return OrderPreserving.YES;
+ }
+}
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/MathTrigFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/MathTrigFunctionTest.java
new file mode 100644
index 0000000..796106f
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/MathTrigFunctionTest.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression;
+
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.CosFunction;
+import org.apache.phoenix.expression.function.SinFunction;
+import org.apache.phoenix.expression.function.TanFunction;
+import org.apache.phoenix.query.BaseTest;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PDecimal;
+import org.apache.phoenix.schema.types.PDouble;
+import org.apache.phoenix.schema.types.PFloat;
+import org.apache.phoenix.schema.types.PInteger;
+import org.apache.phoenix.schema.types.PLong;
+import org.apache.phoenix.schema.types.PNumericType;
+import org.apache.phoenix.schema.types.PSmallint;
+import org.apache.phoenix.schema.types.PTinyint;
+import org.apache.phoenix.schema.types.PUnsignedDouble;
+import org.apache.phoenix.schema.types.PUnsignedFloat;
+import org.apache.phoenix.schema.types.PUnsignedInt;
+import org.apache.phoenix.schema.types.PUnsignedLong;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+/**
+ * Unit tests for {@link SinFunction}
+ * Unit tests for {@link CosFunction}
+ * Unit tests for {@link TanFunction}
+ */
+
+@RunWith(Parameterized.class)
+public class MathTrigFunctionTest {
+
+ private Number[] value;
+ private PNumericType dataType;
+
+ public MathTrigFunctionTest(Number[] value, PNumericType dataType) {
+ this.value = value;
+ this.dataType = dataType;
+ }
+
+ @Parameters(name = "{0} {1}")
+ public static Collection<Object> data() {
+ return Arrays.asList(new Object[][]{
+ {
+ new BigDecimal[]{BigDecimal.valueOf(1.0), BigDecimal.valueOf(0.0),
+ BigDecimal.valueOf(-1.0), BigDecimal.valueOf(123.1234),
+ BigDecimal.valueOf(-123.1234)},
+ PDecimal.INSTANCE
+ },
+ {
+ new Float[]{1.0f, 0.0f, -1.0f, Float.MAX_VALUE, Float.MIN_VALUE,
+ -Float.MAX_VALUE, -Float.MIN_VALUE, 123.1234f, -123.1234f},
+ PFloat.INSTANCE
+ },
+ {
+ new Float[]{1.0f, 0.0f, Float.MAX_VALUE, Float.MIN_VALUE, 123.1234f},
+ PUnsignedFloat.INSTANCE
+ },
+ {
+ new Double[]{1.0, 0.0, -1.0, Double.MAX_VALUE, Double.MIN_VALUE,
+ -Double.MAX_VALUE, -Double.MIN_VALUE, 123.1234, -123.1234},
+ PDouble.INSTANCE
+ },
+ {
+ new Double[]{1.0, 0.0, Double.MAX_VALUE, Double.MIN_VALUE, 123.1234},
+ PUnsignedDouble.INSTANCE
+ },
+ {
+ new Long[]{(long) 1, (long) 0, (long) -1, Long.MAX_VALUE,
+ Long.MIN_VALUE, (long) 123, (long) -123},
+ PLong.INSTANCE
+ },
+ {
+ new Long[]{(long) 1, (long) 0, Long.MAX_VALUE, (long) 123},
+ PUnsignedLong.INSTANCE
+ },
+ {
+ new Integer[]{1, 0, -1, Integer.MAX_VALUE, Integer.MIN_VALUE, 123, -123},
+ PInteger.INSTANCE
+ },
+ {
+ new Integer[]{1, 0, Integer.MAX_VALUE, 123},
+ PUnsignedInt.INSTANCE
+ },
+ {
+ new Short[]{(short) 1, (short) 0, (short) -1, Short.MAX_VALUE,
+ Short.MIN_VALUE, (short) 123, (short) -123},
+ PSmallint.INSTANCE
+ },
+ {
+ new Short[]{(short) 1, (short) 0, Short.MAX_VALUE, (short) 123},
+ PSmallint.INSTANCE
+ },
+ {
+ new Byte[]{(byte) 1, (byte) 0, (byte) -1, Byte.MAX_VALUE,
+ Byte.MIN_VALUE, (byte) 123, (byte) -123},
+ PTinyint.INSTANCE
+ },
+ {
+ new Byte[]{(byte) 1, (byte) 0, Byte.MAX_VALUE, (byte) 123},
+ PTinyint.INSTANCE
+ }
+ });
+ }
+
+ private boolean testExpression(LiteralExpression literal, double expectedResult,
+ String testedFunction) throws SQLException {
+ List<Expression> expressions = Lists.newArrayList((Expression) literal);
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ Expression mathFunction = null;
+
+ if (testedFunction.equals("SIN")) {
+ mathFunction = new SinFunction(expressions);
+ } else if (testedFunction.equals("COS")) {
+ mathFunction = new CosFunction(expressions);
+ } else if (testedFunction.equals("TAN")) {
+ mathFunction = new TanFunction(expressions);
+ }
+
+ boolean ret = mathFunction.evaluate(null, ptr);
+ if (ret) {
+ Double result =
+ (Double) mathFunction.getDataType().toObject(ptr, mathFunction.getSortOrder());
+ assertTrue(BaseTest.twoDoubleEquals(result.doubleValue(), expectedResult));
+ }
+
+ return ret;
+ }
+
+ private void test(Number value, PNumericType dataType, double expectedResult,
+ String testedFunction)
+ throws SQLException {
+ LiteralExpression literal = LiteralExpression.newConstant(value, dataType, SortOrder.ASC);
+ boolean ret1 = testExpression(literal, expectedResult, testedFunction);
+
+ literal = LiteralExpression.newConstant(value, dataType, SortOrder.DESC);
+ boolean ret2 = testExpression(literal, expectedResult, testedFunction);
+ assertEquals(ret1, ret2);
+ }
+
+ @Test
+ public void testBatch()
+ throws SQLException {
+ for (int i = 0; i < value.length; ++i) {
+ test(value[i], dataType, Math.sin(value[i].doubleValue()), "SIN");
+ test(value[i], dataType, Math.cos(value[i].doubleValue()), "COS");
+ test(value[i], dataType, Math.tan(value[i].doubleValue()), "TAN");
+ }
+ }
+}