You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by td...@apache.org on 2015/06/24 22:24:39 UTC

[43/49] phoenix git commit: PHOENIX-1660 Implement missing math built-in functions ABS, POWER, LN, LOG, SQRT, CBRT, EXP (Shuxiong Ye)

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 <ja...@apache.org>
Authored: Mon Jun 15 15:53:44 2015 -0700
Committer: James Taylor <ja...@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);
+    }
+}