[
https://issues.apache.org/jira/browse/PHOENIX-514?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14302338#comment-14302338
]
ASF GitHub Bot commented on PHOENIX-514:
----------------------------------------
Github user twdsilva commented on a diff in the pull request:
https://github.com/apache/phoenix/pull/34#discussion_r23970428
--- Diff:
phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ExpressionIndexIT.java
---
@@ -0,0 +1,774 @@
+/*
+ * 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.index;
+
+import static org.apache.phoenix.util.TestUtil.INDEX_DATA_SCHEMA;
+import static org.apache.phoenix.util.TestUtil.INDEX_DATA_TABLE;
+import static org.apache.phoenix.util.TestUtil.MUTABLE_INDEX_DATA_TABLE;
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.util.DateUtil;
+import org.apache.phoenix.util.PropertiesUtil;
+import org.apache.phoenix.util.QueryUtil;
+import org.junit.Test;
+
+public class ExpressionIndexIT extends BaseHBaseManagedTimeIT {
+
+ private static final int NUM_MILLIS_IN_DAY = 86400000;
+
+ @Test
+ public void testImmutableIndexCreationAndUpdate() throws Exception {
+ helpTestCreateAndUpdate(false, false);
+ }
+
+ @Test
+ public void testImmutableLocalIndexCreationAndUpdate() throws
Exception {
+ helpTestCreateAndUpdate(false, true);
+ }
+
+ @Test
+ public void testMutableIndexCreationAndUpdate() throws Exception {
+ helpTestCreateAndUpdate(true, false);
+ }
+
+ @Test
+ public void testMutableLocalIndexCreationAndUpdate() throws Exception {
+ helpTestCreateAndUpdate(true, true);
+ }
+
+ /**
+ * Adds a row to the index data table
+ *
+ * @param i
+ * row number
+ */
+ private void insertRow(PreparedStatement stmt, int i) throws
SQLException {
+ // insert row
+ stmt.setString(1, "varchar" + String.valueOf(i));
+ stmt.setString(2, "char" + String.valueOf(i));
+ stmt.setInt(3, i);
+ stmt.setLong(4, i);
+ stmt.setBigDecimal(5, new BigDecimal(Double.valueOf(i)));
+ Date date = new Date(DateUtil.parseDate("2015-01-01
00:00:00").getTime() + (i - 1) * NUM_MILLIS_IN_DAY);
+ stmt.setDate(6, date);
+ stmt.setString(7, "a.varchar" + String.valueOf(i));
+ stmt.setString(8, "a.char" + String.valueOf(i));
+ stmt.setInt(9, i);
+ stmt.setLong(10, i);
+ stmt.setBigDecimal(11, new BigDecimal((double)i));
+ stmt.setDate(12, date);
+ stmt.setString(13, "b.varchar" + String.valueOf(i));
+ stmt.setString(14, "b.char" + String.valueOf(i));
+ stmt.setInt(15, i);
+ stmt.setLong(16, i);
+ stmt.setBigDecimal(17, new BigDecimal((double)i));
+ stmt.setDate(18, date);
+ stmt.executeUpdate();
+ }
+
+ private void verifyResult(ResultSet rs, int i) throws SQLException {
+ assertTrue(rs.next());
+ assertEquals("VARCHAR" + String.valueOf(i) + "_" +
StringUtils.rightPad("CHAR" + String.valueOf(i), 6, ' ')
+ + "_A.VARCHAR" + String.valueOf(i) + "_" +
StringUtils.rightPad("B.CHAR" + String.valueOf(i), 10, ' '),
+ rs.getString(1));
+ assertEquals(i * 4, rs.getInt(2));
+ Date date = new Date(DateUtil.parseDate("2015-01-01
00:00:00").getTime() + (i) * NUM_MILLIS_IN_DAY);
+ assertEquals(date, rs.getDate(3));
+ assertEquals(date, rs.getDate(4));
+ assertEquals(date, rs.getDate(5));
+ assertEquals("varchar" + String.valueOf(i), rs.getString(6));
+ assertEquals("char" + String.valueOf(i), rs.getString(7));
+ assertEquals(i, rs.getInt(8));
+ assertEquals(i, rs.getLong(9));
+ assertEquals(i, rs.getDouble(10), 0.000001);
+ assertEquals(i, rs.getLong(11));
+ assertEquals(i, rs.getLong(12));
+ }
+
+ protected void helpTestCreateAndUpdate(boolean mutable, boolean
localIndex) throws Exception {
+ String dataTableName = mutable ? MUTABLE_INDEX_DATA_TABLE :
INDEX_DATA_TABLE;
+ String fullDataTableName = INDEX_DATA_SCHEMA +
QueryConstants.NAME_SEPARATOR + dataTableName;
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ try {
+ conn.setAutoCommit(false);
+ populateDataTable(conn, dataTableName);
+
+ // create an expression index
+ String ddl = "CREATE "
+ + (localIndex ? "LOCAL" : "")
+ + " INDEX IDX ON "
+ + fullDataTableName
+ + " ((UPPER(varchar_pk) || '_' || UPPER(char_pk) ||
'_' || UPPER(varchar_col1) || '_' || UPPER(char_col2)),"
+ + " (decimal_pk+int_pk+decimal_col2+int_col1)," + "
date_pk+1, date1+1, date2+1 )"
+ + " INCLUDE (long_col1, long_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ // run select query with expression in WHERE clause
+ String whereSql = "SELECT long_col1, long_col2 from "
+ + fullDataTableName
+ + " WHERE UPPER(varchar_pk) || '_' || UPPER(char_pk)
|| '_' || UPPER(varchar_col1) || '_' || UPPER(char_col2) = ?"
+ + " AND decimal_pk+int_pk+decimal_col2+int_col1=?"
+ // since a.date1 and b.date2 are NULLABLE and date is
fixed width, these expressions are stored as
+ // DECIMAL in the index (which is not fixed width)
+ + " AND date_pk+1=? AND date1+1=? AND date2+1=?";
+ stmt = conn.prepareStatement(whereSql);
+ stmt.setString(1, "VARCHAR1_CHAR1 _A.VARCHAR1_B.CHAR1 ");
+ stmt.setInt(2, 4);
+ Date date = DateUtil.parseDate("2015-01-02 00:00:00");
+ stmt.setDate(3, date);
+ stmt.setDate(4, date);
+ stmt.setDate(5, date);
+
+ // verify that the query does a range scan on the index table
+ ResultSet rs = stmt.executeQuery("EXPLAIN " + whereSql);
+ assertEquals(
+ localIndex ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER
_LOCAL_IDX_INDEX_TEST."
+ + dataTableName
+ + " [-32768,'VARCHAR1_CHAR1
_A.VARCHAR1_B.CHAR1 ',4,'2015-01-02
00:00:00.000',1,420,156,800,000,1,420,156,800,000]\nCLIENT MERGE SORT"
+ : "CLIENT PARALLEL 1-WAY RANGE SCAN OVER
INDEX_TEST.IDX ['VARCHAR1_CHAR1 _A.VARCHAR1_B.CHAR1 ',4,'2015-01-02
00:00:00.000',1,420,156,800,000,1,420,156,800,000]",
+ QueryUtil.getExplainPlan(rs));
+
+ // verify that the correct results are returned
+ rs = stmt.executeQuery();
+ assertTrue(rs.next());
+ assertEquals(1, rs.getInt(1));
+ assertEquals(1, rs.getInt(2));
+ assertFalse(rs.next());
+
+ // verify all rows in data table are present in index table
+ String indexSelectSql = "SELECT UPPER(varchar_pk) || '_' ||
UPPER(char_pk) || '_' || UPPER(varchar_col1) || '_' || UPPER(char_col2), "
+ + "decimal_pk+int_pk+decimal_col2+int_col1, "
+ + "date_pk+1, date1+1, date2+1, "
+ + "varchar_pk, char_pk, int_pk, long_pk, decimal_pk, "
+ + "long_col1, long_col2 "
+ + "from "
+ + fullDataTableName;
+ rs = conn.createStatement().executeQuery("EXPLAIN " +
indexSelectSql);
+ assertEquals(localIndex ? "CLIENT PARALLEL 1-WAY RANGE SCAN
OVER _LOCAL_IDX_" + fullDataTableName
+ + " [-32768]\nCLIENT MERGE SORT" : "CLIENT PARALLEL
1-WAY FULL SCAN OVER INDEX_TEST.IDX",
+ QueryUtil.getExplainPlan(rs));
+ rs = conn.createStatement().executeQuery(indexSelectSql);
+ verifyResult(rs, 1);
+ verifyResult(rs, 2);
+
+ // Insert two more rows to the index data table
+ String upsert = "UPSERT INTO " + fullDataTableName
+ + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?)";
+ stmt = conn.prepareStatement(upsert);
+ insertRow(stmt, 3);
+ insertRow(stmt, 4);
+ conn.commit();
+
+ rs = conn.createStatement().executeQuery(indexSelectSql);
+ verifyResult(rs, 1);
+ verifyResult(rs, 2);
+ // verify that two rows added after index was created were
also added to
+ // the index table
+ verifyResult(rs, 3);
+ verifyResult(rs, 4);
+
+ // update the first row
+ upsert = "UPSERT INTO "
+ + fullDataTableName
+ + "(varchar_pk, char_pk, int_pk, long_pk, decimal_pk,
date_pk, a.varchar_col1) VALUES(?, ?, ?, ?, ?, ?, ?)";
+
+ stmt = conn.prepareStatement(upsert);
+ stmt.setString(1, "varchar1");
+ stmt.setString(2, "char1");
+ stmt.setInt(3, 1);
+ stmt.setLong(4, 1l);
+ stmt.setBigDecimal(5, new BigDecimal(1.0));
+ stmt.setDate(6, DateUtil.parseDate("2015-01-01 00:00:00"));
+ stmt.setString(7, "a.varchar_updated");
+ stmt.executeUpdate();
+ conn.commit();
+
+ // verify only one row was updated in the data table
+ String selectSql = "UPPER(varchar_pk) || '_' || UPPER(char_pk)
|| '_' || UPPER(varchar_col1) || '_' || UPPER(char_col2) from "
+ + fullDataTableName;
+ rs = conn.createStatement().executeQuery("SELECT /*+ NO_INDEX
*/ " + selectSql);
+ assertTrue(rs.next());
+ assertEquals("VARCHAR1_CHAR1 _A.VARCHAR_UPDATED_B.CHAR1 ",
rs.getString(1));
+ assertTrue(rs.next());
+ assertEquals("VARCHAR2_CHAR2 _A.VARCHAR2_B.CHAR2 ",
rs.getString(1));
+ assertTrue(rs.next());
+ assertEquals("VARCHAR3_CHAR3 _A.VARCHAR3_B.CHAR3 ",
rs.getString(1));
+ assertTrue(rs.next());
+ assertEquals("VARCHAR4_CHAR4 _A.VARCHAR4_B.CHAR4 ",
rs.getString(1));
+ assertFalse(rs.next());
+
+ // verify that the rows in the index table are also updated
+ rs = conn.createStatement().executeQuery("SELECT " +
selectSql);
+ assertTrue(rs.next());
+ // if the data table is immutable, the index table will have
one more
+ // row
--- End diff --
Its because of the fixed width char columns.
> Support functional indexes
> --------------------------
>
> Key: PHOENIX-514
> URL: https://issues.apache.org/jira/browse/PHOENIX-514
> Project: Phoenix
> Issue Type: Task
> Reporter: James Taylor
> Assignee: Thomas D'Silva
> Labels: enhancement
>
> Instead of only defining the set of columns from the data table that make up
> an index, you should be able to use expressions. For example:
> CREATE INDEX upper_last_name_idx ON person (UPPER(last_name))
> Then in queries that use UPPER(last_name), we can replace them with column
> references to the index table.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)