PHOENIX-1660 Implement missing math built-in functions ABS, POWER, LN, LOG, SQRT, CBRT, EXP (Shuxiong Ye)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/c2927dde Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/c2927dde Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/c2927dde Branch: refs/heads/json Commit: c2927ddec5ab954dd779516ed29b4b7fa4b011d9 Parents: d1934af Author: James Taylor <jamestay...@apache.org> Authored: Mon Jun 15 15:53:44 2015 -0700 Committer: James Taylor <jamestay...@apache.org> Committed: Mon Jun 15 15:53:44 2015 -0700 ---------------------------------------------------------------------- .../phoenix/end2end/AbsFunctionEnd2EndIT.java | 108 +++++++++++ .../phoenix/end2end/CbrtFunctionEnd2EndIT.java | 143 +++++++++++++++ .../phoenix/end2end/ExpFunctionEnd2EndIT.java | 128 +++++++++++++ .../phoenix/end2end/LnLogFunctionEnd2EndIT.java | 143 +++++++++++++++ .../phoenix/end2end/PowerFunctionEnd2EndIT.java | 144 +++++++++++++++ .../phoenix/expression/ExpressionType.java | 14 +- .../expression/function/AbsFunction.java | 66 +++++++ .../expression/function/CbrtFunction.java | 55 ++++++ .../expression/function/ExpFunction.java | 55 ++++++ .../function/JavaMathOneArgumentFunction.java | 43 ++--- .../function/JavaMathTwoArgumentFunction.java | 69 +++++++ .../phoenix/expression/function/LnFunction.java | 55 ++++++ .../expression/function/LogFunction.java | 56 ++++++ .../expression/function/PowerFunction.java | 51 ++++++ .../expression/function/ScalarFunction.java | 4 +- .../expression/function/SqrtFunction.java | 8 +- .../apache/phoenix/schema/types/PDecimal.java | 11 ++ .../phoenix/schema/types/PNumericType.java | 8 + .../phoenix/schema/types/PRealNumber.java | 8 + .../phoenix/schema/types/PWholeNumber.java | 8 + .../phoenix/compile/QueryCompilerTest.java | 68 ++++++- .../phoenix/expression/AbsFunctionTest.java | 180 ++++++++++++++++++ .../phoenix/expression/CbrtFunctionTest.java | 127 +++++++++++++ .../phoenix/expression/ExpFunctionTest.java | 150 +++++++++++++++ .../phoenix/expression/LnLogFunctionTest.java | 182 +++++++++++++++++++ .../phoenix/expression/PowerFunctionTest.java | 182 +++++++++++++++++++ 26 files changed, 2036 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/it/java/org/apache/phoenix/end2end/AbsFunctionEnd2EndIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AbsFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AbsFunctionEnd2EndIT.java new file mode 100644 index 0000000..0c6204c --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AbsFunctionEnd2EndIT.java @@ -0,0 +1,108 @@ +/* + * 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.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import org.apache.phoenix.expression.function.AbsFunction; +import org.junit.Before; +import org.junit.Test; + +/** + * End to end tests for {@link AbsFunction} + */ +public class AbsFunctionEnd2EndIT extends BaseHBaseManagedTimeIT { + + private static final String KEY = "key"; + + @Before + public void initTable() throws Exception { + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl; + ddl = "CREATE TABLE testSigned (k VARCHAR NOT NULL PRIMARY KEY, dec DECIMAL, doub DOUBLE, fl FLOAT, inte INTEGER, lon BIGINT, smalli SMALLINT, tinyi TINYINT)"; + conn.createStatement().execute(ddl); + conn.commit(); + } finally { + closeStmtAndConn(stmt, conn); + } + } + + private void updateSignedTable(Connection conn, double data) throws Exception { + PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testSigned VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, KEY); + Double d = Double.valueOf(data); + stmt.setBigDecimal(2, BigDecimal.valueOf(data)); + stmt.setDouble(3, d.doubleValue()); + stmt.setFloat(4, d.floatValue()); + stmt.setInt(5, d.intValue()); + stmt.setLong(6, d.longValue()); + stmt.setShort(7, d.shortValue()); + stmt.setByte(8, d.byteValue()); + stmt.executeUpdate(); + conn.commit(); + } + + private void testSignedNumberSpec(Connection conn, double data) throws Exception { + updateSignedTable(conn, data); + ResultSet rs = conn.createStatement() .executeQuery("SELECT ABS(dec),ABS(doub),ABS(fl),ABS(inte),ABS(lon),ABS(smalli),ABS(tinyi) FROM testSigned"); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertEquals(rs.getBigDecimal(1).compareTo(BigDecimal.valueOf(data).abs()), 0); + assertEquals(rs.getDouble(2), Math.abs(data), 1e-6); + assertEquals(rs.getFloat(3), Math.abs(d.floatValue()), 1e-6); + assertEquals(rs.getInt(4), Math.abs(d.intValue())); + assertEquals(rs.getLong(5), Math.abs(d.longValue())); + assertEquals(rs.getShort(6), Math.abs(d.shortValue())); + assertEquals(rs.getByte(7), Math.abs(d.byteValue())); + assertTrue(!rs.next()); + + PreparedStatement stmt = conn.prepareStatement("SELECT k FROM testSigned WHERE ABS(dec)=? AND ABS(doub)=? AND ABS(fl)=? AND ABS(inte)=? AND ABS(lon)=? AND ABS(smalli)=? AND ABS(tinyi)=?"); + stmt.setBigDecimal(1, BigDecimal.valueOf(data).abs()); + stmt.setDouble(2, Math.abs(d.doubleValue())); + stmt.setFloat(3, Math.abs(d.floatValue())); + stmt.setInt(4, Math.abs(d.intValue())); + stmt.setLong(5, Math.abs(d.longValue())); + stmt.setShort(6, (short) Math.abs(d.shortValue())); + stmt.setByte(7, (byte) Math.abs(d.byteValue())); + rs = stmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(KEY, rs.getString(1)); + assertTrue(!rs.next()); + } + + @Test + public void testSignedNumber() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + testSignedNumberSpec(conn, 0.0); + testSignedNumberSpec(conn, 1.0); + testSignedNumberSpec(conn, -1.0); + testSignedNumberSpec(conn, 123.1234); + testSignedNumberSpec(conn, -123.1234); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/it/java/org/apache/phoenix/end2end/CbrtFunctionEnd2EndIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CbrtFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CbrtFunctionEnd2EndIT.java new file mode 100644 index 0000000..a632104 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CbrtFunctionEnd2EndIT.java @@ -0,0 +1,143 @@ +/* + * 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.assertEquals; +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.CbrtFunction; +import org.junit.Before; +import org.junit.Test; + +/** + * End to end tests for {@link CbrtFunction} + */ +public class CbrtFunctionEnd2EndIT extends BaseHBaseManagedTimeIT { + + private static final String KEY = "key"; + private static final double ZERO = 1e-8; + + @Before + public void initTable() throws Exception { + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl; + ddl = "CREATE TABLE testSigned (k VARCHAR NOT NULL PRIMARY KEY, doub DOUBLE, fl FLOAT, inte INTEGER, lon BIGINT, smalli SMALLINT, tinyi TINYINT)"; + conn.createStatement().execute(ddl); + ddl = "CREATE TABLE testUnsigned (k VARCHAR NOT NULL PRIMARY KEY, doub UNSIGNED_DOUBLE, fl UNSIGNED_FLOAT, inte UNSIGNED_INT, lon UNSIGNED_LONG, smalli UNSIGNED_SMALLINT, tinyi UNSIGNED_TINYINT)"; + conn.createStatement().execute(ddl); + conn.commit(); + } finally { + closeStmtAndConn(stmt, conn); + } + } + + private void updateSignedTable(Connection conn, double data) throws Exception { + PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testSigned VALUES (?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, KEY); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + stmt.executeUpdate(); + conn.commit(); + } + + private void updateUnsignedTable(Connection conn, double data) throws Exception { + PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testUnsigned VALUES (?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, KEY); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + stmt.executeUpdate(); + conn.commit(); + } + + private void testSignedNumberSpec(Connection conn, double data) throws Exception { + updateSignedTable(conn, data); + ResultSet rs = conn.createStatement().executeQuery("SELECT CBRT(doub),CBRT(fl),CBRT(inte),CBRT(lon),CBRT(smalli),CBRT(tinyi) FROM testSigned"); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(Math.abs(rs.getDouble(1) - Math.cbrt(d.doubleValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(2) - Math.cbrt(d.floatValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(3) - Math.cbrt(d.intValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(4) - Math.cbrt(d.longValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(5) - Math.cbrt(d.shortValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(6) - Math.cbrt(d.byteValue())) < ZERO); + assertTrue(!rs.next()); + PreparedStatement stmt = conn.prepareStatement("SELECT k FROM testSigned WHERE CBRT(doub)>0 AND CBRT(fl)>0 AND CBRT(inte)>0 AND CBRT(lon)>0 AND CBRT(smalli)>0 AND CBRT(tinyi)>0"); + rs = stmt.executeQuery(); + if (data > 0) { + assertTrue(rs.next()); + assertEquals(KEY, rs.getString(1)); + } + assertTrue(!rs.next()); + } + + private void testUnsignedNumberSpec(Connection conn, double data) throws Exception { + updateUnsignedTable(conn, data); + ResultSet rs = conn.createStatement().executeQuery("SELECT CBRT(doub),CBRT(fl),CBRT(inte),CBRT(lon),CBRT(smalli),CBRT(tinyi) FROM testUnsigned"); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(Math.abs(rs.getDouble(1) - Math.cbrt(d.doubleValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(2) - Math.cbrt(d.floatValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(3) - Math.cbrt(d.intValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(4) - Math.cbrt(d.longValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(5) - Math.cbrt(d.shortValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(6) - Math.cbrt(d.byteValue())) < ZERO); + assertTrue(!rs.next()); + PreparedStatement stmt = conn.prepareStatement("SELECT k FROM testUnsigned WHERE CBRT(doub)>0 AND CBRT(fl)>0 AND CBRT(inte)>0 AND CBRT(lon)>0 AND CBRT(smalli)>0 AND CBRT(tinyi)>0"); + rs = stmt.executeQuery(); + if (data > 0) { + assertTrue(rs.next()); + assertEquals(KEY, rs.getString(1)); + } + assertTrue(!rs.next()); + } + + @Test + public void testSignedNumber() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + for (double d : new double[] { 0.0, 1.0, -1.0, 123.1234, -123.1234 }) { + testSignedNumberSpec(conn, d); + } + } + + @Test + public void testUnsignedNumber() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + for (double d : new double[] { 0.0, 1.0, 123.1234 }) { + testUnsignedNumberSpec(conn, d); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/it/java/org/apache/phoenix/end2end/ExpFunctionEnd2EndIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ExpFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ExpFunctionEnd2EndIT.java new file mode 100644 index 0000000..8772400 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ExpFunctionEnd2EndIT.java @@ -0,0 +1,128 @@ +/* + * 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.ExpFunction; +import org.junit.Before; +import org.junit.Test; + +/** + * End to end tests for {@link ExpFunction} + */ +public class ExpFunctionEnd2EndIT extends BaseHBaseManagedTimeIT { + + private static final String KEY = "key"; + private static final double ZERO = 1e-8; + + @Before + public void initTable() throws Exception { + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl; + ddl = "CREATE TABLE testSigned (k VARCHAR NOT NULL PRIMARY KEY, doub DOUBLE, fl FLOAT, inte INTEGER, lon BIGINT, smalli SMALLINT, tinyi TINYINT)"; + conn.createStatement().execute(ddl); + ddl = "CREATE TABLE testUnsigned (k VARCHAR NOT NULL PRIMARY KEY, doub UNSIGNED_DOUBLE, fl UNSIGNED_FLOAT, inte UNSIGNED_INT, lon UNSIGNED_LONG, smalli UNSIGNED_SMALLINT, tinyi UNSIGNED_TINYINT)"; + conn.createStatement().execute(ddl); + conn.commit(); + } finally { + closeStmtAndConn(stmt, conn); + } + } + + private void updateSignedTable(Connection conn, double data) throws Exception { + PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testSigned VALUES (?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, KEY); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + stmt.executeUpdate(); + conn.commit(); + } + + private void updateUnsignedTable(Connection conn, double data) throws Exception { + PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testUnsigned VALUES (?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, KEY); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + stmt.executeUpdate(); + conn.commit(); + } + + private void testSignedNumberSpec(Connection conn, double data) throws Exception { + updateSignedTable(conn, data); + ResultSet rs = conn.createStatement().executeQuery("SELECT EXP(doub),EXP(fl),EXP(inte),EXP(lon),EXP(smalli),EXP(tinyi) FROM testSigned"); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(Math.abs(rs.getDouble(1) - Math.exp(d.doubleValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(2) - Math.exp(d.floatValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(3) - Math.exp(d.intValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(4) - Math.exp(d.longValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(5) - Math.exp(d.shortValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(6) - Math.exp(d.byteValue())) < ZERO); + assertTrue(!rs.next()); + } + + private void testUnsignedNumberSpec(Connection conn, double data) throws Exception { + updateUnsignedTable(conn, data); + ResultSet rs = conn.createStatement().executeQuery("SELECT EXP(doub),EXP(fl),EXP(inte),EXP(lon),EXP(smalli),EXP(tinyi) FROM testUnsigned"); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(Math.abs(rs.getDouble(1) - Math.exp(d.doubleValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(2) - Math.exp(d.floatValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(3) - Math.exp(d.intValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(4) - Math.exp(d.longValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(5) - Math.exp(d.shortValue())) < ZERO); + assertTrue(Math.abs(rs.getDouble(6) - Math.exp(d.byteValue())) < ZERO); + assertTrue(!rs.next()); + } + + @Test + public void testSignedNumber() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + for (double d : new double[] { 0.0, 1.0, 123.1234}) { + testSignedNumberSpec(conn, d); + } + } + + @Test + public void testUnsignedNumber() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + for (double d : new double[] { 0.0, 1.0, 123.1234 }) { + testUnsignedNumberSpec(conn, d); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/it/java/org/apache/phoenix/end2end/LnLogFunctionEnd2EndIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/LnLogFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/LnLogFunctionEnd2EndIT.java new file mode 100644 index 0000000..e2c72ca --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/LnLogFunctionEnd2EndIT.java @@ -0,0 +1,143 @@ +/* + * 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.LnFunction; +import org.apache.phoenix.expression.function.LogFunction; +import org.junit.Before; +import org.junit.Test; + +/** + * End to end tests for {@link LnFunction} and {@link LogFunction} + */ +public class LnLogFunctionEnd2EndIT extends BaseHBaseManagedTimeIT { + + private static final String KEY = "key"; + private static final double ZERO = 1e-9; + + private static boolean twoDoubleEquals(double a, double b) { + if (Double.isNaN(a) ^ Double.isNaN(b)) return false; + if (Double.isNaN(a)) return true; + if (Double.isInfinite(a) ^ Double.isInfinite(b)) return false; + if (Double.isInfinite(a)) { + if ((a > 0) ^ (b > 0)) return false; + else return true; + } + if (Math.abs(a - b) <= ZERO) { + return true; + } else { + return false; + } + } + + @Before + public void initTable() throws Exception { + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl; + ddl = + "CREATE TABLE testSigned (k VARCHAR NOT NULL PRIMARY KEY, doub DOUBLE, fl FLOAT, inte INTEGER, lon BIGINT, smalli SMALLINT, tinyi TINYINT)"; + conn.createStatement().execute(ddl); + ddl = + "CREATE TABLE testUnsigned (k VARCHAR NOT NULL PRIMARY KEY, doub UNSIGNED_DOUBLE, fl UNSIGNED_FLOAT, inte UNSIGNED_INT, lon UNSIGNED_LONG, smalli UNSIGNED_SMALLINT, tinyi UNSIGNED_TINYINT)"; + 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); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + 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 LN(doub),LN(fl),LN(inte),LN(lon),LN(smalli),LN(tinyi) FROM " + + tableName); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.log(d.doubleValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.log(d.floatValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.log(d.intValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.log(d.longValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.log(d.shortValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.log(d.byteValue()))); + + assertTrue(!rs.next()); + rs = + conn.createStatement().executeQuery( + "SELECT LOG(doub),LOG(fl),LOG(inte),LOG(lon),LOG(smalli),LOG(tinyi) FROM " + + tableName); + assertTrue(rs.next()); + d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.log10(d.doubleValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.log10(d.floatValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.log10(d.intValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.log10(d.longValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.log10(d.shortValue()))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.log10(d.byteValue()))); + assertTrue(!rs.next()); + + rs = + conn.createStatement().executeQuery( + "SELECT LOG(doub,3),LOG(fl,3),LOG(inte,3),LOG(lon,3),LOG(smalli,3),LOG(tinyi,3) FROM " + + tableName); + assertTrue(rs.next()); + d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.log(d.doubleValue()) / Math.log(3))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.log(d.floatValue()) / Math.log(3))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.log(d.intValue()) / Math.log(3))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.log(d.longValue()) / Math.log(3))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.log(d.shortValue()) / Math.log(3))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.log(d.byteValue()) / Math.log(3))); + 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, "testSigned"); + if (d >= 0) testNumberSpec(conn, d, "testUnsigned"); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/it/java/org/apache/phoenix/end2end/PowerFunctionEnd2EndIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PowerFunctionEnd2EndIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PowerFunctionEnd2EndIT.java new file mode 100644 index 0000000..691fb61 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PowerFunctionEnd2EndIT.java @@ -0,0 +1,144 @@ +/* + * 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.PowerFunction; +import org.junit.Before; +import org.junit.Test; + +/** + * End to end tests for {@link PowerFunction} + */ +public class PowerFunctionEnd2EndIT extends BaseHBaseManagedTimeIT { + + private static final String KEY = "key"; + private static final double ZERO = 1e-9; + + private static boolean twoDoubleEquals(double a, double b) { + if (Double.isNaN(a) ^ Double.isNaN(b)) return false; + if (Double.isNaN(a)) return true; + if (Double.isInfinite(a) ^ Double.isInfinite(b)) return false; + if (Double.isInfinite(a)) { + if ((a > 0) ^ (b > 0)) return false; + else return true; + } + if (Math.abs(a - b) <= ZERO) { + return true; + } else { + return false; + } + } + + @Before + public void initTable() throws Exception { + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl; + ddl = + "CREATE TABLE testSigned (k VARCHAR NOT NULL PRIMARY KEY, doub DOUBLE, fl FLOAT, inte INTEGER, lon BIGINT, smalli SMALLINT, tinyi TINYINT)"; + conn.createStatement().execute(ddl); + ddl = + "CREATE TABLE testUnsigned (k VARCHAR NOT NULL PRIMARY KEY, doub UNSIGNED_DOUBLE, fl UNSIGNED_FLOAT, inte UNSIGNED_INT, lon UNSIGNED_LONG, smalli UNSIGNED_SMALLINT, tinyi UNSIGNED_TINYINT)"; + 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); + Double d = Double.valueOf(data); + stmt.setDouble(2, d.doubleValue()); + stmt.setFloat(3, d.floatValue()); + stmt.setInt(4, d.intValue()); + stmt.setLong(5, d.longValue()); + stmt.setShort(6, d.shortValue()); + stmt.setByte(7, d.byteValue()); + 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 POWER(doub, 1.5),POWER(fl, 1.5),POWER(inte, 1.5),POWER(lon, 1.5),POWER(smalli, 1.5),POWER(tinyi, 1.5) FROM " + + tableName); + assertTrue(rs.next()); + Double d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.pow(d.doubleValue(), 1.5))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.pow(d.floatValue(), 1.5))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.pow(d.intValue(), 1.5))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.pow(d.longValue(), 1.5))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.pow(d.shortValue(), 1.5))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.pow(d.byteValue(), 1.5))); + + assertTrue(!rs.next()); + rs = + conn.createStatement() + .executeQuery( + "SELECT POWER(doub, 2),POWER(fl, 2),POWER(inte, 2),POWER(lon, 2),POWER(smalli, 2),POWER(tinyi, 2) FROM " + + tableName); + assertTrue(rs.next()); + d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.pow(d.doubleValue(), 2))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.pow(d.floatValue(), 2))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.pow(d.intValue(), 2))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.pow(d.longValue(), 2))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.pow(d.shortValue(), 2))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.pow(d.byteValue(), 2))); + assertTrue(!rs.next()); + + rs = + conn.createStatement().executeQuery( + "SELECT POWER(doub,3),POWER(fl,3),POWER(inte,3),POWER(lon,3),POWER(smalli,3),POWER(tinyi,3) FROM " + + tableName); + assertTrue(rs.next()); + d = Double.valueOf(data); + assertTrue(twoDoubleEquals(rs.getDouble(1), Math.pow(d.doubleValue(), 3))); + assertTrue(twoDoubleEquals(rs.getDouble(2), Math.pow(d.floatValue(), 3))); + assertTrue(twoDoubleEquals(rs.getDouble(3), Math.pow(d.intValue(), 3))); + assertTrue(twoDoubleEquals(rs.getDouble(4), Math.pow(d.longValue(), 3))); + assertTrue(twoDoubleEquals(rs.getDouble(5), Math.pow(d.shortValue(), 3))); + assertTrue(twoDoubleEquals(rs.getDouble(6), Math.pow(d.byteValue(), 3))); + 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, "testSigned"); + if (d >= 0) testNumberSpec(conn, d, "testUnsigned"); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java ---------------------------------------------------------------------- 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 684e620..4f98cb8 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 @@ -19,6 +19,7 @@ package org.apache.phoenix.expression; import java.util.Map; +import org.apache.phoenix.expression.function.AbsFunction; import org.apache.phoenix.expression.function.ArrayAllComparisonExpression; import org.apache.phoenix.expression.function.ArrayAnyComparisonExpression; import org.apache.phoenix.expression.function.ArrayAppendFunction; @@ -29,6 +30,7 @@ import org.apache.phoenix.expression.function.ArrayPrependFunction; import org.apache.phoenix.expression.function.ByteBasedRegexpReplaceFunction; import org.apache.phoenix.expression.function.ByteBasedRegexpSplitFunction; import org.apache.phoenix.expression.function.ByteBasedRegexpSubstrFunction; +import org.apache.phoenix.expression.function.CbrtFunction; import org.apache.phoenix.expression.function.CeilDateExpression; import org.apache.phoenix.expression.function.CeilDecimalExpression; import org.apache.phoenix.expression.function.CeilFunction; @@ -41,6 +43,7 @@ import org.apache.phoenix.expression.function.DecodeFunction; import org.apache.phoenix.expression.function.DistinctCountAggregateFunction; import org.apache.phoenix.expression.function.DistinctValueAggregateFunction; import org.apache.phoenix.expression.function.EncodeFunction; +import org.apache.phoenix.expression.function.ExpFunction; import org.apache.phoenix.expression.function.ExternalSqlTypeIdFunction; import org.apache.phoenix.expression.function.FirstValueFunction; import org.apache.phoenix.expression.function.FloorDateExpression; @@ -53,6 +56,8 @@ import org.apache.phoenix.expression.function.InvertFunction; import org.apache.phoenix.expression.function.LTrimFunction; import org.apache.phoenix.expression.function.LastValueFunction; import org.apache.phoenix.expression.function.LengthFunction; +import org.apache.phoenix.expression.function.LnFunction; +import org.apache.phoenix.expression.function.LogFunction; import org.apache.phoenix.expression.function.LowerFunction; import org.apache.phoenix.expression.function.LpadFunction; import org.apache.phoenix.expression.function.MD5Function; @@ -65,6 +70,7 @@ import org.apache.phoenix.expression.function.NthValueFunction; import org.apache.phoenix.expression.function.PercentRankAggregateFunction; import org.apache.phoenix.expression.function.PercentileContAggregateFunction; import org.apache.phoenix.expression.function.PercentileDiscAggregateFunction; +import org.apache.phoenix.expression.function.PowerFunction; import org.apache.phoenix.expression.function.RTrimFunction; import org.apache.phoenix.expression.function.RandomFunction; import org.apache.phoenix.expression.function.RegexpReplaceFunction; @@ -233,7 +239,13 @@ public enum ExpressionType { ArrayAppendFunction(ArrayAppendFunction.class), UDFExpression(UDFExpression.class), ArrayPrependFunction(ArrayPrependFunction.class), - SqrtFunction(SqrtFunction.class) + SqrtFunction(SqrtFunction.class), + AbsFunction(AbsFunction.class), + CbrtFunction(CbrtFunction.class), + LnFunction(LnFunction.class), + LogFunction(LogFunction.class), + ExpFunction(ExpFunction.class), + PowerFunction(PowerFunction.class) ; ExpressionType(Class<? extends Expression> clazz) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AbsFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AbsFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AbsFunction.java new file mode 100644 index 0000000..6ef1b38 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AbsFunction.java @@ -0,0 +1,66 @@ +/* + * 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.util.List; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +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.tuple.Tuple; +import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PDecimal; +import org.apache.phoenix.schema.types.PNumericType; + +@BuiltInFunction(name = AbsFunction.NAME, args = { @Argument(allowedTypes = PDecimal.class) }) +public class AbsFunction extends ScalarFunction { + + public static final String NAME = "ABS"; + + public AbsFunction() { + } + + public AbsFunction(List<Expression> children) { + super(children); + } + + @Override + public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { + Expression childExpr = children.get(0); + PDataType dataType = childExpr.getDataType(); + if (childExpr.evaluate(tuple, ptr)) { + byte[] bytes = ptr.get(); + int offset = ptr.getOffset(), length = ptr.getLength(); + ptr.set(new byte[getDataType().getByteSize()]); + ((PNumericType) dataType).abs(bytes, offset, length, childExpr.getSortOrder(), ptr); + return true; + } + return false; + } + + @Override + public PDataType getDataType() { + return children.get(0).getDataType(); + } + + @Override + public String getName() { + return AbsFunction.NAME; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CbrtFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CbrtFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CbrtFunction.java new file mode 100644 index 0000000..1c13924 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CbrtFunction.java @@ -0,0 +1,55 @@ +/* + * 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 = CbrtFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }) }) +public class CbrtFunction extends JavaMathOneArgumentFunction { + + public static final String NAME = "CBRT"; + + public CbrtFunction() { + } + + public CbrtFunction(List<Expression> children) throws SQLException { + super(children); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected double compute(double firstArg) { + return Math.cbrt(firstArg); + } + + @Override + public OrderPreserving preservesOrder() { + return OrderPreserving.YES; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ExpFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ExpFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ExpFunction.java new file mode 100644 index 0000000..5c0ca72 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ExpFunction.java @@ -0,0 +1,55 @@ +/* + * 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 = ExpFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }) }) +public class ExpFunction extends JavaMathOneArgumentFunction { + + public static final String NAME = "EXP"; + + public ExpFunction() { + } + + public ExpFunction(List<Expression> children) throws SQLException { + super(children); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected double compute(double firstArg) { + return Math.exp(firstArg); + } + + @Override + public OrderPreserving preservesOrder() { + return OrderPreserving.YES; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathOneArgumentFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathOneArgumentFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathOneArgumentFunction.java index 4ea5367..733f6fc 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathOneArgumentFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathOneArgumentFunction.java @@ -39,39 +39,30 @@ public abstract class JavaMathOneArgumentFunction extends ScalarFunction { protected abstract double compute(double firstArg); - @Override - public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { - Expression childExpr = children.get(0); - PDataType returnType = getDataType(); - if (childExpr.evaluate(tuple, ptr)) { - if (ptr.getLength() == 0) { - return true; - } - double result; - if (childExpr.getDataType() == PDecimal.INSTANCE) { - result = - ((BigDecimal) childExpr.getDataType().toObject(ptr, - childExpr.getSortOrder())).doubleValue(); - } else { - result = - childExpr.getDataType().getCodec() - .decodeDouble(ptr, childExpr.getSortOrder()); - } - ptr.set(new byte[returnType.getByteSize()]); - returnType.getCodec().encodeDouble(compute(result), ptr); - return true; + static double getArg(Expression exp, ImmutableBytesWritable ptr) { + if (exp.getDataType() == PDecimal.INSTANCE) { + return ((BigDecimal) exp.getDataType().toObject(ptr, exp.getSortOrder())).doubleValue(); } else { - return false; + return exp.getDataType().getCodec().decodeDouble(ptr, exp.getSortOrder()); } } @Override - public PDataType getDataType() { - return PDouble.INSTANCE; + public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { + PDataType returnType = getDataType(); + + Expression arg1Expr = children.get(0); + if (!arg1Expr.evaluate(tuple, ptr)) return false; + if (ptr.getLength() == 0) return true; + double arg1 = getArg(arg1Expr, ptr); + + ptr.set(new byte[returnType.getByteSize()]); + returnType.getCodec().encodeDouble(compute(arg1), ptr); + return true; } @Override - public OrderPreserving preservesOrder() { - return OrderPreserving.YES; + public PDataType getDataType() { + return PDouble.INSTANCE; } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathTwoArgumentFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathTwoArgumentFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathTwoArgumentFunction.java new file mode 100644 index 0000000..0d85797 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/JavaMathTwoArgumentFunction.java @@ -0,0 +1,69 @@ +/* + * 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.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.schema.tuple.Tuple; +import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PDouble; +import org.apache.phoenix.util.ByteUtil; + +public abstract class JavaMathTwoArgumentFunction extends ScalarFunction { + + public JavaMathTwoArgumentFunction() { + } + + public JavaMathTwoArgumentFunction(List<Expression> children) throws SQLException { + super(children); + } + + protected abstract double compute(double firstArg, double secondArg); + + @Override + public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { + PDataType returnType = getDataType(); + + Expression arg1Expr = children.get(0); + if (!arg1Expr.evaluate(tuple, ptr)) return false; + if (ptr.getLength() == 0) return true; + double arg1 = JavaMathOneArgumentFunction.getArg(arg1Expr, ptr); + + Expression arg2Expr = (children.size() <= 1) ? null : children.get(1); + double arg2; + if (arg2Expr != null && !arg2Expr.evaluate(tuple, ptr)) return false; + if (arg2Expr == null || ptr.getLength() == 0) { + ptr.set(ByteUtil.EMPTY_BYTE_ARRAY); + return true; + } else { + arg2 = JavaMathOneArgumentFunction.getArg(arg2Expr, ptr); + } + + ptr.set(new byte[returnType.getByteSize()]); + returnType.getCodec().encodeDouble(compute(arg1, arg2), ptr); + return true; + } + + @Override + public PDataType getDataType() { + return PDouble.INSTANCE; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LnFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LnFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LnFunction.java new file mode 100644 index 0000000..4275336 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LnFunction.java @@ -0,0 +1,55 @@ +/* + * 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 = LnFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }) }) +public class LnFunction extends JavaMathOneArgumentFunction { + + public static final String NAME = "LN"; + + public LnFunction() { + } + + public LnFunction(List<Expression> children) throws SQLException { + super(children); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected double compute(double firstArg) { + return Math.log(firstArg); + } + + @Override + public OrderPreserving preservesOrder() { + return OrderPreserving.YES; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LogFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LogFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LogFunction.java new file mode 100644 index 0000000..87b9a79 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/LogFunction.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 = LogFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }), + @Argument(allowedTypes = { PDouble.class, PDecimal.class }, defaultValue = "1e1") }) +public class LogFunction extends JavaMathTwoArgumentFunction { + + public static final String NAME = "LOG"; + + public LogFunction() { + } + + public LogFunction(List<Expression> children) throws SQLException { + super(children); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected double compute(double firstArg, double secondArg) { + return Math.log(firstArg) / Math.log(secondArg); + } + + @Override + public OrderPreserving preservesOrder() { + return OrderPreserving.YES; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PowerFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PowerFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PowerFunction.java new file mode 100644 index 0000000..1125ce1 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/PowerFunction.java @@ -0,0 +1,51 @@ +/* + * 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 = PowerFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }), + @Argument(allowedTypes = { PDouble.class, PDecimal.class }) }) +public class PowerFunction extends JavaMathTwoArgumentFunction { + + public static final String NAME = "POWER"; + + public PowerFunction() { + } + + public PowerFunction(List<Expression> children) throws SQLException { + super(children); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected double compute(double firstArg, double secondArg) { + return Math.pow(firstArg, secondArg); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java index 014bda4..4f44cde 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java @@ -65,13 +65,15 @@ public abstract class ScalarFunction extends FunctionExpression { /** * Determines whether or not a function may be used to form * the start/stop key of a scan + * When OrderPreserving is YES, in order to make order-by optimization + * valid, it should return 0. (refer to {@link RoundDateExpression}) * @return the zero-based position of the argument to traverse * into to look for a primary key column reference, or * {@value #NO_TRAVERSAL} if the function cannot be used to * form the scan key. */ public int getKeyFormationTraversalIndex() { - return NO_TRAVERSAL; + return preservesOrder() == OrderPreserving.NO ? NO_TRAVERSAL : 0; } /** http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SqrtFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SqrtFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SqrtFunction.java index bb5376e..260305a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SqrtFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SqrtFunction.java @@ -24,8 +24,9 @@ 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 = SqrtFunction.NAME, args = { @Argument(allowedTypes = { PDecimal.class }) }) +@BuiltInFunction(name = SqrtFunction.NAME, args = { @Argument(allowedTypes = { PDouble.class, PDecimal.class }) }) public class SqrtFunction extends JavaMathOneArgumentFunction { public static final String NAME = "SQRT"; @@ -46,4 +47,9 @@ public class SqrtFunction extends JavaMathOneArgumentFunction { protected double compute(double firstArg) { return Math.sqrt(firstArg); } + + @Override + public OrderPreserving preservesOrder() { + return OrderPreserving.YES; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java index 199ed28..228aef1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDecimal.java @@ -421,4 +421,15 @@ public class PDecimal extends PRealNumber<BigDecimal> { } return ((signByte & 0x80) == 0) ? -1 : 1; } + + @Override + public void abs(byte[] bytes, int offset, int length, SortOrder sortOrder, + ImmutableBytesWritable outPtr) { + if (sortOrder == SortOrder.DESC) { + bytes = SortOrder.invert(bytes, offset, new byte[length], 0, length); + offset = 0; + } + BigDecimal bigDecimal = toBigDecimal(bytes, offset, length); + outPtr.set(toBytes(bigDecimal.abs())); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PNumericType.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PNumericType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PNumericType.java index 631ac8d..826d9ad 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PNumericType.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PNumericType.java @@ -41,4 +41,12 @@ public abstract class PNumericType<T> extends PDataType<T> { abstract public int signum(byte[] bytes, int offset, int length, SortOrder sortOrder, Integer maxLength, Integer scale); + + abstract public void abs(byte[] bytes, int offset, int length, SortOrder sortOrder, + ImmutableBytesWritable outPtr); + + public final void abs(ImmutableBytesWritable ptr, SortOrder sortOrder, + ImmutableBytesWritable outPtr) { + abs(ptr.get(), ptr.getOffset(), ptr.getLength(), sortOrder, outPtr); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PRealNumber.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PRealNumber.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PRealNumber.java index d074511..4cab433 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PRealNumber.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PRealNumber.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.schema.types; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.schema.IllegalDataException; import org.apache.phoenix.schema.SortOrder; @@ -36,4 +37,11 @@ public abstract class PRealNumber<T> extends PNumericType<T> { } return (d > 0) ? 1 : ((d < 0) ? -1 : 0); } + + @Override + public void abs(byte[] bytes, int offset, int length, SortOrder sortOrder, + ImmutableBytesWritable outPtr) { + double d = getCodec().decodeDouble(bytes, offset, sortOrder); + getCodec().encodeDouble(Math.abs(d), outPtr); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PWholeNumber.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PWholeNumber.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PWholeNumber.java index f1c7d13..a3a1d13 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PWholeNumber.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PWholeNumber.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.schema.types; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.schema.SortOrder; public abstract class PWholeNumber<T> extends PNumericType<T> { @@ -32,4 +33,11 @@ public abstract class PWholeNumber<T> extends PNumericType<T> { long l = getCodec().decodeLong(bytes, offset, sortOrder); return Long.signum(l); } + + @Override + public void abs(byte[] bytes, int offset, int length, SortOrder sortOrder, + ImmutableBytesWritable outPtr) { + long l = getCodec().decodeLong(bytes, offset, sortOrder); + getCodec().encodeLong(Math.abs(l), outPtr); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java index 7be8eae..79721df 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java @@ -34,6 +34,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; @@ -1634,7 +1635,72 @@ public class QueryCompilerTest extends BaseConnectionlessQueryTest { assertLiteralEquals(oneMoreThanMaxLong, p, 11); } - + @Test + public void testMathFunctionOrderByOrderPreservingFwd() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE t (k1 INTEGER not null, k2 double not null, k3 BIGINT not null, v varchar, constraint pk primary key(k1,k2,k3))"); + /* + * "SELECT * FROM T ORDER BY k1, k2", + * "SELECT * FROM T ORDER BY k1, SIGN(k2)", + * "SELECT * FROM T ORDER BY SIGN(k1), k2", + */ + List<String> queryList = new ArrayList<String>(); + queryList.add("SELECT * FROM T ORDER BY k1, k2"); + for (String sub : new String[] { "SIGN", "CBRT", "LN", "LOG", "EXP" }) { + queryList.add(String.format("SELECT * FROM T ORDER BY k1, %s(k2)", sub)); + queryList.add(String.format("SELECT * FROM T ORDER BY %s(k1), k2", sub)); + } + String[] queries = queryList.toArray(new String[queryList.size()]); + for (int i = 0; i < queries.length; i++) { + String query = queries[i]; + QueryPlan plan = conn.createStatement().unwrap(PhoenixStatement.class).compileQuery(query); + assertTrue(plan.getOrderBy() == OrderBy.FWD_ROW_KEY_ORDER_BY); + } + // Negative test + queryList.clear(); + for (String sub : new String[] { "SIGN", "CBRT", "LN", "LOG", "EXP" }) { + queryList.add(String.format("SELECT * FROM T WHERE %s(k2)=2.0", sub)); + } + for (String query : queryList.toArray(new String[queryList.size()])) { + Scan scan = conn.createStatement().unwrap(PhoenixStatement.class).compileQuery(query).getContext().getScan(); + assertNotNull(scan.getFilter()); + assertTrue(scan.getStartRow().length == 0); + assertTrue(scan.getStopRow().length == 0); + } + } + + @Test + public void testMathFunctionOrderByOrderPreservingRev() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE t (k1 INTEGER not null, k2 double not null, k3 BIGINT not null, v varchar, constraint pk primary key(k1,k2 DESC,k3))"); + List<String> queryList = new ArrayList<String>(); + // "SELECT * FROM T ORDER BY k1 DESC, SIGN(k2) DESC, k3 DESC" + queryList.add("SELECT * FROM T ORDER BY k1 DESC"); + queryList.add("SELECT * FROM T ORDER BY k1 DESC, k2"); + queryList.add("SELECT * FROM T ORDER BY k1 DESC, k2, k3 DESC"); + for (String sub : new String[] { "SIGN", "CBRT", "LN", "LOG", "EXP" }) { + queryList.add(String.format("SELECT * FROM T ORDER BY k1 DESC, %s(k2) DESC, k3 DESC", sub)); + } + String[] queries = queryList.toArray(new String[queryList.size()]); + for (int i = 0; i < queries.length; i++) { + String query = queries[i]; + QueryPlan plan = + conn.createStatement().unwrap(PhoenixStatement.class).compileQuery(query); + assertTrue(query, plan.getOrderBy() == OrderBy.REV_ROW_KEY_ORDER_BY); + } + // Negative test + queryList.clear(); + for (String sub : new String[] { "SIGN", "CBRT", "LN", "LOG", "EXP" }) { + queryList.add(String.format("SELECT * FROM T WHERE %s(k2)=2.0", sub)); + } + for (String query : queryList.toArray(new String[queryList.size()])) { + Scan scan = conn.createStatement().unwrap(PhoenixStatement.class).compileQuery(query).getContext().getScan(); + assertNotNull(scan.getFilter()); + assertTrue(scan.getStartRow().length == 0); + assertTrue(scan.getStopRow().length == 0); + } + } + @Test public void testOrderByOrderPreservingFwd() throws Exception { Connection conn = DriverManager.getConnection(getUrl()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/test/java/org/apache/phoenix/expression/AbsFunctionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/AbsFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/AbsFunctionTest.java new file mode 100644 index 0000000..46c0ed0 --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/AbsFunctionTest.java @@ -0,0 +1,180 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.function.AbsFunction; +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.apache.phoenix.schema.types.PUnsignedSmallint; +import org.apache.phoenix.schema.types.PUnsignedTinyint; +import org.junit.Test; + +import com.google.common.collect.Lists; + +/** + * Unit tests for {@link AbsFunction} + */ +public class AbsFunctionTest { + + private static void testExpression(LiteralExpression literal, Number expected) + throws SQLException { + List<Expression> expressions = Lists.newArrayList((Expression) literal); + Expression absFunction = new AbsFunction(expressions); + ImmutableBytesWritable ptr = new ImmutableBytesWritable(); + absFunction.evaluate(null, ptr); + Number result = + (Number) absFunction.getDataType().toObject(ptr, absFunction.getSortOrder()); + assertTrue(result.getClass().equals(expected.getClass())); + if (result instanceof BigDecimal) { + assertTrue(((BigDecimal) result).compareTo((BigDecimal) expected) == 0); + } else { + assertTrue(result.equals(expected)); + } + } + + private static void test(Number value, PNumericType dataType, Number expected) + throws SQLException { + LiteralExpression literal; + literal = LiteralExpression.newConstant(value, dataType, SortOrder.ASC); + testExpression(literal, expected); + literal = LiteralExpression.newConstant(value, dataType, SortOrder.DESC); + testExpression(literal, expected); + } + + private static void + testBatch(Number[] value, PNumericType dataType, ArrayList<Number> expected) + throws SQLException { + assertEquals(value.length, expected.size()); + for (int i = 0; i < value.length; ++i) { + test(value[i], dataType, expected.get(i)); + } + } + + @Test + public void testAbsFunction() throws Exception { + Random random = new Random(); + Number[] value; + ArrayList<Number> expected = new ArrayList<Number>(); + value = new BigDecimal[] { BigDecimal.valueOf(1.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(-1.0), BigDecimal.valueOf(123.1234), + BigDecimal.valueOf(-123.1234) }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(((BigDecimal) value[i]).abs()); + testBatch(value, PDecimal.INSTANCE, expected); + + value = new Float[] { 1.0f, 0.0f, -1.0f, 123.1234f, -123.1234f, Float.MIN_VALUE, + Float.MAX_VALUE, -Float.MIN_VALUE, -Float.MAX_VALUE, random.nextFloat(), + random.nextFloat(), random.nextFloat() }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Float) value[i])); + testBatch(value, PFloat.INSTANCE, expected); + + value = new Float[] { 1.0f, 0.0f, 123.1234f, Float.MIN_VALUE, Float.MAX_VALUE, }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Float) value[i])); + testBatch(value, PUnsignedFloat.INSTANCE, expected); + + value = new Double[] { 1.0, 0.0, -1.0, 123.1234, -123.1234, Double.MIN_VALUE, + Double.MAX_VALUE, -Double.MIN_VALUE, -Double.MAX_VALUE, + random.nextDouble(), random.nextDouble(), random.nextDouble() }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Double) value[i])); + testBatch(value, PDouble.INSTANCE, expected); + + value = new Double[] { 1.0, 0.0, 123.1234, Double.MIN_VALUE, Double.MAX_VALUE, }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Double) value[i])); + testBatch(value, PUnsignedDouble.INSTANCE, expected); + + value = new Long[] { 1L, 0L, -1L, 123L, -123L, Long.MIN_VALUE + 1, Long.MAX_VALUE, + random.nextLong(), random.nextLong(), random.nextLong(), }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Long) value[i])); + testBatch(value, PLong.INSTANCE, expected); + + value = new Long[] { 1L, 0L, 123L, Long.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Long) value[i])); + testBatch(value, PUnsignedLong.INSTANCE, expected); + + value = new Integer[] { 1, 0, -1, 123, -123, Integer.MIN_VALUE + 1, Integer.MAX_VALUE, + random.nextInt(), random.nextInt(), random.nextInt(), }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Integer) value[i])); + testBatch(value, PInteger.INSTANCE, expected); + + value = new Integer[] { 1, 0, 123, Integer.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add(Math.abs((Integer) value[i])); + testBatch(value, PUnsignedInt.INSTANCE, expected); + + value = new Short[] { 1, 0, -1, 123, -123, Short.MIN_VALUE + 1, Short.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add((short) Math.abs((Short) value[i])); + testBatch(value, PSmallint.INSTANCE, expected); + + value = new Short[] { 1, 0, 123, Short.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add((short) Math.abs((Short) value[i])); + testBatch(value, PUnsignedSmallint.INSTANCE, expected); + + value = new Byte[] { 1, 0, -1, 123, -123, Byte.MIN_VALUE + 1, Byte.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add((byte) Math.abs((Byte) value[i])); + testBatch(value, PTinyint.INSTANCE, expected); + + value = new Byte[] { 1, 0, 123, Byte.MAX_VALUE }; + expected.clear(); + for (int i = 0; i < value.length; ++i) + expected.add((byte) Math.abs((Byte) value[i])); + testBatch(value, PUnsignedTinyint.INSTANCE, expected); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/c2927dde/phoenix-core/src/test/java/org/apache/phoenix/expression/CbrtFunctionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/CbrtFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/CbrtFunctionTest.java new file mode 100644 index 0000000..2084896 --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/CbrtFunctionTest.java @@ -0,0 +1,127 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.sql.SQLException; +import java.util.List; +import java.util.Random; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.function.CbrtFunction; +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; + +/** + * Unit tests for {@link CbrtFunction} + */ +public class CbrtFunctionTest { + + private static void testExpression(LiteralExpression literal, double expected) + throws SQLException { + List<Expression> expressions = Lists.newArrayList((Expression) literal); + Expression cbrtFunction = new CbrtFunction(expressions); + ImmutableBytesWritable ptr = new ImmutableBytesWritable(); + cbrtFunction.evaluate(null, ptr); + Double result = + (Double) cbrtFunction.getDataType().toObject(ptr, cbrtFunction.getSortOrder()); + assertTrue(Math.abs(result.doubleValue() - expected) <= 1e-9); + } + + private static void test(Number value, PNumericType dataType, double expected) + throws SQLException { + LiteralExpression literal; + literal = LiteralExpression.newConstant(value, dataType, SortOrder.ASC); + testExpression(literal, expected); + literal = LiteralExpression.newConstant(value, dataType, SortOrder.DESC); + testExpression(literal, expected); + } + + private static void testBatch(Number[] value, PNumericType dataType) throws SQLException { + double[] expected = new double[value.length]; + for (int i = 0; i < expected.length; ++i) { + expected[i] = Math.cbrt(value[i].doubleValue()); + } + assertEquals(value.length, expected.length); + for (int i = 0; i < value.length; ++i) { + test(value[i], dataType, expected[i]); + } + } + + @Test + public void testCbrtFunction() throws Exception { + Random random = new Random(); + + testBatch( + new BigDecimal[] { BigDecimal.valueOf(1.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(-1.0), BigDecimal.valueOf(123.1234), + BigDecimal.valueOf(-123.1234), BigDecimal.valueOf(random.nextDouble()), + BigDecimal.valueOf(random.nextDouble()) }, PDecimal.INSTANCE); + + testBatch(new Float[] { 1.0f, 0.0f, -1.0f, 123.1234f, -123.1234f, random.nextFloat(), + random.nextFloat() }, PFloat.INSTANCE); + + testBatch(new Float[] { 1.0f, 0.0f, 123.1234f, }, PUnsignedFloat.INSTANCE); + + testBatch( + new Double[] { 1.0, 0.0, -1.0, 123.1234, -123.1234, random.nextDouble(), + random.nextDouble() }, PDouble.INSTANCE); + + testBatch(new Double[] { 1.0, 0.0, 123.1234, }, PUnsignedDouble.INSTANCE); + + testBatch( + new Long[] { 1L, 0L, -1L, Long.MAX_VALUE, Long.MIN_VALUE, 123L, -123L, + random.nextLong(), random.nextLong() }, PLong.INSTANCE); + + testBatch(new Long[] { 1L, 0L, Long.MAX_VALUE, 123L }, PUnsignedLong.INSTANCE); + + testBatch( + new Integer[] { 1, 0, -1, Integer.MAX_VALUE, Integer.MIN_VALUE, 123, -123, + random.nextInt(), random.nextInt() }, PInteger.INSTANCE); + + testBatch(new Integer[] { 1, 0, Integer.MAX_VALUE, 123 }, PUnsignedInt.INSTANCE); + + testBatch(new Short[] { (short) 1, (short) 0, (short) -1, Short.MAX_VALUE, Short.MIN_VALUE, + (short) 123, (short) -123 }, PSmallint.INSTANCE); + + testBatch(new Short[] { (short) 1, (short) 0, Short.MAX_VALUE, (short) 123 }, + PSmallint.INSTANCE); + + testBatch(new Byte[] { (byte) 1, (byte) 0, (byte) -1, Byte.MAX_VALUE, Byte.MIN_VALUE, + (byte) 123, (byte) -123 }, PTinyint.INSTANCE); + + testBatch(new Byte[] { (byte) 1, (byte) 0, Byte.MAX_VALUE, (byte) 123 }, PTinyint.INSTANCE); + } +}