blob: b76d61dbe9a73ab9b78e862016a605cf88f09b60 [file] [log] [blame]
/*
* 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.query.QueryConstants.MILLIS_IN_DAY;
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.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
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.sql.Statement;
import java.util.Arrays;
import java.util.Collection;
import java.util.Properties;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory;
import org.apache.phoenix.compile.ColumnResolver;
import org.apache.phoenix.compile.FromCompiler;
import org.apache.phoenix.end2end.ParallelStatsDisabledIT;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.jdbc.PhoenixStatement;
import org.apache.phoenix.parse.NamedTableNode;
import org.apache.phoenix.parse.TableName;
import org.apache.phoenix.query.BaseTest;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableImpl;
import org.apache.phoenix.schema.PTableKey;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.util.DateUtil;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.QueryUtil;
import org.apache.phoenix.util.ReadOnlyProps;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.TestUtil;
import org.apache.phoenix.util.TransactionUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class IndexIT extends ParallelStatsDisabledIT {
private final boolean localIndex;
private final boolean transactional;
private final boolean mutable;
private final String tableDDLOptions;
public IndexIT(boolean localIndex, boolean mutable, boolean transactional, boolean columnEncoded) {
this.localIndex = localIndex;
this.transactional = transactional;
this.mutable = mutable;
StringBuilder optionBuilder = new StringBuilder();
if (!columnEncoded) {
if (optionBuilder.length()!=0)
optionBuilder.append(",");
optionBuilder.append("COLUMN_ENCODED_BYTES=0");
}
if (!mutable) {
if (optionBuilder.length()!=0)
optionBuilder.append(",");
optionBuilder.append("IMMUTABLE_ROWS=true");
if (!columnEncoded) {
optionBuilder.append(",IMMUTABLE_STORAGE_SCHEME="+PTableImpl.ImmutableStorageScheme.ONE_CELL_PER_COLUMN);
}
}
if (transactional) {
if (optionBuilder.length()!=0)
optionBuilder.append(",");
optionBuilder.append(" TRANSACTIONAL=true ");
}
this.tableDDLOptions = optionBuilder.toString();
}
@Parameters(name="IndexIT_localIndex={0},mutable={1},transactional={2},columnEncoded={3}") // name is used by failsafe as file name in reports
public static Collection<Boolean[]> data() {
return Arrays.asList(new Boolean[][] {
{ false, false, false, false }, { false, false, false, true }, { false, false, true, false }, { false, false, true, true },
{ false, true, false, false }, { false, true, false, true }, { false, true, true, false }, { false, true, true, true },
{ true, false, false, false }, { true, false, false, true }, { true, false, true, false }, { true, false, true, true },
{ true, true, false, false }, { true, true, false, true }, { true, true, true, false }, { true, true, true, true }
});
}
@Test
public void testIndexWithNullableFixedWithCols() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName
+ " (char_col1 ASC, int_col1 ASC)"
+ " INCLUDE (long_col1, long_col2)";
stmt.execute(ddl);
String query = "SELECT d.char_col1, int_col1 from " + fullTableName + " as d";
ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex) {
assertEquals(
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + tableName + " [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
"CLIENT MERGE SORT",
QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + indexName + "\n"
+ " SERVER FILTER BY FIRST KEY ONLY", QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("chara", rs.getString(1));
assertEquals("chara", rs.getString("char_col1"));
assertEquals(2, rs.getInt(2));
assertTrue(rs.next());
assertEquals("chara", rs.getString(1));
assertEquals(3, rs.getInt(2));
assertTrue(rs.next());
assertEquals("chara", rs.getString(1));
assertEquals(4, rs.getInt(2));
assertFalse(rs.next());
conn.createStatement().execute("DROP INDEX " + indexName + " ON " + fullTableName);
query = "SELECT char_col1, int_col1 from " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
query = "SELECT char_col1, int_col1 from "+indexName;
try{
rs = conn.createStatement().executeQuery(query);
fail();
} catch (SQLException e) {
assertEquals(SQLExceptionCode.TABLE_UNDEFINED.getErrorCode(), e.getErrorCode());
}
}
}
@Test
public void testDeleteFromAllPKColumnIndex() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName
+ " (long_pk, varchar_pk)"
+ " INCLUDE (long_col1, long_col2)";
stmt.execute(ddl);
ResultSet rs;
rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " + fullTableName);
assertTrue(rs.next());
assertEquals(3,rs.getInt(1));
rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " + fullIndexName);
assertTrue(rs.next());
assertEquals(3,rs.getInt(1));
String dml = "DELETE from " + fullTableName + " WHERE long_col2 = 4";
assertEquals(1,conn.createStatement().executeUpdate(dml));
conn.commit();
String query = "SELECT /*+ NO_INDEX */ long_pk FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
query = "SELECT long_pk FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
conn.createStatement().execute("DROP INDEX " + indexName + " ON " + fullTableName);
}
}
@Test
public void testCreateIndexAfterUpsertStarted() throws Exception {
testCreateIndexAfterUpsertStarted(false,
SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, generateUniqueName()),
SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, generateUniqueName()));
}
@Test
public void testCreateIndexAfterUpsertStartedTxnl() throws Exception {
if (transactional) {
testCreateIndexAfterUpsertStarted(true,
SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, generateUniqueName()),
SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, generateUniqueName()));
}
}
private void testCreateIndexAfterUpsertStarted(boolean readOwnWrites, String fullTableName, String fullIndexName) throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
try (Connection conn1 = DriverManager.getConnection(getUrl(), props)) {
conn1.setAutoCommit(true);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt1 = conn1.createStatement();
stmt1.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ResultSet rs;
rs = conn1.createStatement().executeQuery("SELECT COUNT(*) FROM " + fullTableName);
assertTrue(rs.next());
assertEquals(3,rs.getInt(1));
try (Connection conn2 = DriverManager.getConnection(getUrl(), props)) {
String upsert = "UPSERT INTO " + fullTableName
+ " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
PreparedStatement pstmt2 = conn2.prepareStatement(upsert);
pstmt2.setString(1, "varchar4");
pstmt2.setString(2, "char4");
pstmt2.setInt(3, 4);
pstmt2.setLong(4, 4L);
pstmt2.setBigDecimal(5, new BigDecimal(4.0));
Date date = DateUtil.parseDate("2015-01-01 00:00:00");
pstmt2.setDate(6, date);
pstmt2.setString(7, "varchar_a");
pstmt2.setString(8, "chara");
pstmt2.setInt(9, 2);
pstmt2.setLong(10, 2L);
pstmt2.setBigDecimal(11, new BigDecimal(2.0));
pstmt2.setDate(12, date);
pstmt2.setString(13, "varchar_b");
pstmt2.setString(14, "charb");
pstmt2.setInt(15, 3);
pstmt2.setLong(16, 3L);
pstmt2.setBigDecimal(17, new BigDecimal(3.0));
pstmt2.setDate(18, date);
pstmt2.executeUpdate();
if (readOwnWrites) {
String query = "SELECT long_pk FROM " + fullTableName + " WHERE long_pk=4";
rs = conn2.createStatement().executeQuery(query);
assertTrue(rs.next());
assertFalse(rs.next());
}
String indexName = SchemaUtil.getTableNameFromFullName(fullIndexName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName
+ " (long_pk, varchar_pk)"
+ " INCLUDE (long_col1, long_col2)";
stmt1.execute(ddl);
/*
* Commit upsert after index created through different connection.
* This forces conn2 (which doesn't know about the index yet) to update the metadata
* at commit time, recognize the new index, and generate the correct metadata (or index
* rows for immutable indexes).
*
* For transactional data, this is problematic because the index
* gets a timestamp *after* the commit timestamp of conn2 and thus won't be seen during
* the commit. Also, when the index is being built, the data hasn't yet been committed
* and thus won't be part of the initial index build (fixed by PHOENIX-2446).
*/
conn2.commit();
stmt1 = conn1.createStatement();
rs = stmt1.executeQuery("SELECT COUNT(*) FROM " + fullTableName);
assertTrue(rs.next());
assertEquals(4,rs.getInt(1));
assertEquals(fullIndexName, stmt1.unwrap(PhoenixStatement.class).getQueryPlan().getTableRef().getTable().getName().getString());
String query = "SELECT /*+ NO_INDEX */ long_pk FROM " + fullTableName;
rs = conn1.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertFalse(rs.next());
}
}
}
@Test
public void testDeleteFromNonPKColumnIndex() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName
+ " (long_col1, long_col2)"
+ " INCLUDE (decimal_col1, decimal_col2)";
stmt.execute(ddl);
}
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
ResultSet rs;
rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " + fullTableName);
assertTrue(rs.next());
assertEquals(3,rs.getInt(1));
rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " + fullIndexName);
assertTrue(rs.next());
assertEquals(3,rs.getInt(1));
String dml = "DELETE from " + fullTableName + " WHERE long_col2 = 4";
assertEquals(1,conn.createStatement().executeUpdate(dml));
conn.commit();
// query the data table
String query = "SELECT /*+ NO_INDEX */ long_pk FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
// query the index table
query = "SELECT long_pk FROM " + fullTableName + " ORDER BY long_col1";
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(1L, rs.getLong(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
conn.createStatement().execute("DROP INDEX " + indexName + " ON " + fullTableName);
}
}
@Test
public void testGroupByCount() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName + " (int_col2)";
stmt.execute(ddl);
ResultSet rs;
rs = conn.createStatement().executeQuery("SELECT int_col2, COUNT(*) FROM " + fullTableName + " GROUP BY int_col2");
assertTrue(rs.next());
assertEquals(1,rs.getInt(2));
}
}
@Test
public void testSelectDistinctOnTableWithSecondaryImmutableIndex() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName + " (int_col2)";
conn.createStatement().execute(ddl);
ResultSet rs = conn.createStatement().executeQuery("SELECT distinct int_col2 FROM " + fullTableName + " where int_col2 > 0");
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertTrue(rs.next());
assertEquals(4, rs.getInt(1));
assertTrue(rs.next());
assertEquals(5, rs.getInt(1));
assertFalse(rs.next());
}
}
@Test
public void testInClauseWithIndexOnColumnOfUsignedIntType() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName + " ON " + fullTableName + " (int_col1)";
stmt.execute(ddl);
ResultSet rs = conn.createStatement().executeQuery("SELECT int_col1 FROM " + fullTableName + " where int_col1 IN (1, 2, 3, 4)");
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertTrue(rs.next());
assertEquals(4, rs.getInt(1));
assertFalse(rs.next());
}
}
@Test
public void createIndexOnTableWithSpecifiedDefaultCF() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
String ddl ="CREATE TABLE " + fullTableName
+ " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) DEFAULT_COLUMN_FAMILY='A'" + (!tableDDLOptions.isEmpty() ? "," + tableDDLOptions : "");
Statement stmt = conn.createStatement();
stmt.execute(ddl);
query = "SELECT * FROM " + tableName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
String options = localIndex ? "SALT_BUCKETS=10, MULTI_TENANT=true, IMMUTABLE_ROWS=true, DISABLE_WAL=true" : "";
conn.createStatement().execute(
"CREATE INDEX " + indexName + " ON " + fullTableName + " (v1) INCLUDE (v2) " + options);
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
//check options set correctly on index
TableName indexTableName = TableName.create(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
NamedTableNode indexNode = NamedTableNode.create(null, indexTableName, null);
ColumnResolver resolver = FromCompiler.getResolver(indexNode, conn.unwrap(PhoenixConnection.class));
PTable indexTable = resolver.getTables().get(0).getTable();
// Can't set IMMUTABLE_ROWS, MULTI_TENANT or DEFAULT_COLUMN_FAMILY_NAME on an index
assertNull(indexTable.getDefaultFamilyName());
assertFalse(indexTable.isMultiTenant());
assertEquals(mutable, !indexTable.isImmutableRows()); // Should match table
if(localIndex) {
assertEquals(10, indexTable.getBucketNum().intValue());
assertTrue(indexTable.isWALDisabled());
}
}
}
@Test
public void testIndexWithNullableDateCol() throws Exception {
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
Date date = new Date(System.currentTimeMillis());
TestUtil.createMultiCFTestTable(conn, fullTableName, tableDDLOptions);
populateMultiCFTestTable(fullTableName, date);
String ddl = "CREATE " + (localIndex ? " LOCAL " : "") + " INDEX " + indexName + " ON " + fullTableName + " (date_col)";
conn.createStatement().execute(ddl);
String query = "SELECT int_pk from " + fullTableName ;
ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if (localIndex) {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName +" [1]\n"
+ " SERVER FILTER BY FIRST KEY ONLY\n"
+ "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName + "\n"
+ " SERVER FILTER BY FIRST KEY ONLY", QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertFalse(rs.next());
query = "SELECT date_col from " + fullTableName + " order by date_col" ;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if (localIndex) {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName + " [1]\n"
+ " SERVER FILTER BY FIRST KEY ONLY\n"
+ "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName + "\n"
+ " SERVER FILTER BY FIRST KEY ONLY", QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(date, rs.getDate(1));
assertTrue(rs.next());
assertEquals(new Date(date.getTime() + MILLIS_IN_DAY), rs.getDate(1));
assertTrue(rs.next());
assertEquals(new Date(date.getTime() + 2 * MILLIS_IN_DAY), rs.getDate(1));
assertFalse(rs.next());
}
}
@Test
public void testSelectAllAndAliasWithIndex() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
String ddl = "CREATE TABLE " + fullTableName + " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) " + tableDDLOptions;
conn.createStatement().execute(ddl);
query = "SELECT * FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
ddl = "CREATE " + (localIndex ? " LOCAL " : "") + " INDEX " + indexName + " ON " + fullTableName + " (v2 DESC) INCLUDE (v1)";
conn.createStatement().execute(ddl);
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + fullTableName + " VALUES(?,?,?)");
stmt.setString(1,"a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.execute();
stmt.setString(1,"b");
stmt.setString(2, "y");
stmt.setString(3, "2");
stmt.execute();
conn.commit();
query = "SELECT * FROM " + fullTableName;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex){
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName+" [1]\nCLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName, QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("b",rs.getString(1));
assertEquals("y",rs.getString(2));
assertEquals("2",rs.getString(3));
assertEquals("b",rs.getString("k"));
assertEquals("y",rs.getString("v1"));
assertEquals("2",rs.getString("v2"));
assertTrue(rs.next());
assertEquals("a",rs.getString(1));
assertEquals("x",rs.getString(2));
assertEquals("1",rs.getString(3));
assertEquals("a",rs.getString("k"));
assertEquals("x",rs.getString("v1"));
assertEquals("1",rs.getString("v2"));
assertFalse(rs.next());
query = "SELECT v1 as foo FROM " + fullTableName + " WHERE v2 = '1' ORDER BY foo";
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex){
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +fullTableName + " [1,~'1']\n" +
" SERVER SORTED BY [\"V1\"]\n" +
"CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +fullIndexName + " [~'1']\n" +
" SERVER SORTED BY [\"V1\"]\n" +
"CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("x",rs.getString(1));
assertEquals("x",rs.getString("foo"));
assertFalse(rs.next());
}
}
@Test
public void testSelectCF() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
String ddl = "CREATE TABLE " + fullTableName + " (k VARCHAR NOT NULL PRIMARY KEY, a.v1 VARCHAR, a.v2 VARCHAR, b.v1 VARCHAR) " + tableDDLOptions;
conn.createStatement().execute(ddl);
query = "SELECT * FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
ddl = "CREATE " + (localIndex ? " LOCAL " : "") + " INDEX " + indexName + " ON " + fullTableName + " (v2 DESC) INCLUDE (a.v1)";
conn.createStatement().execute(ddl);
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + fullTableName + " VALUES(?,?,?,?)");
stmt.setString(1,"a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.setString(4, "A");
stmt.execute();
stmt.setString(1,"b");
stmt.setString(2, "y");
stmt.setString(3, "2");
stmt.setString(4, "B");
stmt.execute();
conn.commit();
query = "SELECT * FROM " + fullTableName;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullTableName, QueryUtil.getExplainPlan(rs));
query = "SELECT a.* FROM " + fullTableName;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex) {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName+" [1]\nCLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName, QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("y",rs.getString(1));
assertEquals("2",rs.getString(2));
assertEquals("y",rs.getString("v1"));
assertEquals("2",rs.getString("v2"));
assertTrue(rs.next());
assertEquals("x",rs.getString(1));
assertEquals("1",rs.getString(2));
assertEquals("x",rs.getString("v1"));
assertEquals("1",rs.getString("v2"));
assertFalse(rs.next());
}
}
@Test
public void testUpsertAfterIndexDrop() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
// make sure that the tables are empty, but reachable
conn.createStatement().execute(
"CREATE TABLE " + fullTableName
+ " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR)" + tableDDLOptions);
query = "SELECT * FROM " + fullTableName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
conn.createStatement().execute(
"CREATE " + (localIndex ? "LOCAL " : "") + "INDEX " + indexName + " ON " + fullTableName + " (v1, v2)");
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
// load some data into the table
PreparedStatement stmt =
conn.prepareStatement("UPSERT INTO " + fullTableName + " VALUES(?,?,?)");
stmt.setString(1, "a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.execute();
conn.commit();
// make sure the index is working as expected
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("x", rs.getString(1));
assertEquals("1", rs.getString(2));
assertEquals("a", rs.getString(3));
assertFalse(rs.next());
String ddl = "DROP INDEX " + indexName + " ON " + fullTableName;
stmt = conn.prepareStatement(ddl);
stmt.execute();
stmt = conn.prepareStatement("UPSERT INTO " + fullTableName + "(k, v1) VALUES(?,?)");
stmt.setString(1, "a");
stmt.setString(2, "y");
stmt.execute();
conn.commit();
query = "SELECT * FROM " + fullTableName;
// check that the data table matches as expected
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("a", rs.getString(1));
assertEquals("y", rs.getString(2));
assertFalse(rs.next());
}
}
@Test
public void testMultipleUpdatesAcrossRegions() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
String testTable = fullTableName+"_MULTIPLE_UPDATES";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
// make sure that the tables are empty, but reachable
conn.createStatement().execute(
"CREATE TABLE " + testTable
+ " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) "
+ (!tableDDLOptions.isEmpty() ? tableDDLOptions : "") + " SPLIT ON ('b')");
query = "SELECT * FROM " + testTable;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
conn.createStatement().execute(
"CREATE " + (localIndex ? "LOCAL " : "") + "INDEX " + indexName + " ON " + testTable + " (v1, v2)");
query = "SELECT * FROM " + fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
// load some data into the table
PreparedStatement stmt =
conn.prepareStatement("UPSERT INTO " + testTable + " VALUES(?,?,?)");
stmt.setString(1, "a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.execute();
stmt.setString(1, "b");
stmt.setString(2, "y");
stmt.setString(3, "2");
stmt.execute();
stmt.setString(1, "c");
stmt.setString(2, "z");
stmt.setString(3, "3");
stmt.execute();
conn.commit();
query = "SELECT /*+ NO_INDEX */ * FROM " + testTable;
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("a", rs.getString(1));
assertEquals("x", rs.getString(2));
assertEquals("1", rs.getString(3));
assertTrue(rs.next());
assertEquals("b", rs.getString(1));
assertEquals("y", rs.getString(2));
assertEquals("2", rs.getString(3));
assertTrue(rs.next());
assertEquals("c", rs.getString(1));
assertEquals("z", rs.getString(2));
assertEquals("3", rs.getString(3));
assertFalse(rs.next());
// make sure the index is working as expected
query = "SELECT * FROM " + testTable;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if (localIndex) {
assertEquals("CLIENT PARALLEL 2-WAY RANGE SCAN OVER " + testTable+" [1]\n"
+ " SERVER FILTER BY FIRST KEY ONLY\n"
+ "CLIENT MERGE SORT",
QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName + "\n"
+ " SERVER FILTER BY FIRST KEY ONLY",
QueryUtil.getExplainPlan(rs));
}
// check that the data table matches as expected
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("a", rs.getString(1));
assertEquals("x", rs.getString(2));
assertEquals("1", rs.getString(3));
assertTrue(rs.next());
assertEquals("b", rs.getString(1));
assertEquals("y", rs.getString(2));
assertEquals("2", rs.getString(3));
assertTrue(rs.next());
assertEquals("c", rs.getString(1));
assertEquals("z", rs.getString(2));
assertEquals("3", rs.getString(3));
assertFalse(rs.next());
}
}
@Test
public void testIndexWithCaseSensitiveCols() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
conn.createStatement().execute("CREATE TABLE " + fullTableName + " (k VARCHAR NOT NULL PRIMARY KEY, \"V1\" VARCHAR, \"v2\" VARCHAR)"+tableDDLOptions);
query = "SELECT * FROM "+fullTableName;
rs = conn.createStatement().executeQuery(query);
long ts = conn.unwrap(PhoenixConnection.class).getTable(new PTableKey(null,fullTableName)).getTimeStamp();
assertFalse(rs.next());
conn.createStatement().execute(
"CREATE " + (localIndex ? "LOCAL " : "") + "INDEX " + indexName + " ON " + fullTableName + "(\"v2\") INCLUDE (\"V1\")");
query = "SELECT * FROM "+fullIndexName;
rs = conn.createStatement().executeQuery(query);
assertFalse(rs.next());
PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + fullTableName + " VALUES(?,?,?)");
stmt.setString(1,"a");
stmt.setString(2, "x");
stmt.setString(3, "1");
stmt.execute();
stmt.setString(1,"b");
stmt.setString(2, "y");
stmt.setString(3, "2");
stmt.execute();
conn.commit();
query = "SELECT * FROM " + fullTableName + " WHERE \"v2\" = '1'";
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex){
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName + " [1,'1']\n"
+ "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullIndexName + " ['1']", QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("a",rs.getString(1));
assertEquals("x",rs.getString(2));
assertEquals("1",rs.getString(3));
assertEquals("a",rs.getString("k"));
assertEquals("x",rs.getString("V1"));
assertEquals("1",rs.getString("v2"));
assertFalse(rs.next());
query = "SELECT \"V1\", \"V1\" as foo1, \"v2\" as foo, \"v2\" as \"Foo1\", \"v2\" FROM " + fullTableName + " ORDER BY foo";
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex){
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName + " [1]\nCLIENT MERGE SORT",
QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER "+fullIndexName, QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals("x",rs.getString(1));
assertEquals("x",rs.getString("V1"));
assertEquals("x",rs.getString(2));
assertEquals("x",rs.getString("foo1"));
assertEquals("1",rs.getString(3));
assertEquals("1",rs.getString("Foo"));
assertEquals("1",rs.getString(4));
assertEquals("1",rs.getString("Foo1"));
assertEquals("1",rs.getString(5));
assertEquals("1",rs.getString("v2"));
assertTrue(rs.next());
assertEquals("y",rs.getString(1));
assertEquals("y",rs.getString("V1"));
assertEquals("y",rs.getString(2));
assertEquals("y",rs.getString("foo1"));
assertEquals("2",rs.getString(3));
assertEquals("2",rs.getString("Foo"));
assertEquals("2",rs.getString(4));
assertEquals("2",rs.getString("Foo1"));
assertEquals("2",rs.getString(5));
assertEquals("2",rs.getString("v2"));
assertFalse(rs.next());
assertNoIndexDeletes(conn, ts, fullIndexName);
}
}
private void assertNoIndexDeletes(Connection conn, long minTimestamp, String fullIndexName) throws IOException, SQLException {
if (!this.mutable) {
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable index = pconn.getTable(new PTableKey(null, fullIndexName));
byte[] physicalIndexTable = index.getPhysicalName().getBytes();
try (HTableInterface hIndex = pconn.getQueryServices().getTable(physicalIndexTable)) {
Scan scan = new Scan();
scan.setRaw(true);
if (this.transactional) {
minTimestamp = TransactionUtil.convertToNanoseconds(minTimestamp);
}
scan.setTimeRange(minTimestamp, HConstants.LATEST_TIMESTAMP);
ResultScanner scanner = hIndex.getScanner(scan);
Result result;
while ((result = scanner.next()) != null) {
CellScanner cellScanner = result.cellScanner();
while (cellScanner.advance()) {
Cell current = cellScanner.current();
assertEquals (KeyValue.Type.Put.getCode(), current.getTypeByte());
}
}
};
}
}
@Test
public void testInFilterOnIndexedTable() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
String ddl = "CREATE TABLE " + fullTableName +" (PK1 CHAR(2) NOT NULL PRIMARY KEY, CF1.COL1 BIGINT) " + tableDDLOptions;
conn.createStatement().execute(ddl);
ddl = "CREATE " + (localIndex ? "LOCAL " : "") + "INDEX " + indexName + " ON " + fullTableName + "(COL1)";
conn.createStatement().execute(ddl);
query = "SELECT COUNT(COL1) FROM " + fullTableName +" WHERE COL1 IN (1,25,50,75,100)";
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
}
}
@Test
public void testIndexWithDecimalCol() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
String query;
ResultSet rs;
Date date = new Date(System.currentTimeMillis());
TestUtil.createMultiCFTestTable(conn, fullTableName, tableDDLOptions);
populateMultiCFTestTable(fullTableName, date);
String ddl = null;
ddl = "CREATE " + (localIndex ? "LOCAL " : "") + "INDEX " + indexName + " ON " + fullTableName + " (decimal_pk) INCLUDE (decimal_col1, decimal_col2)";
conn.createStatement().execute(ddl);
query = "SELECT decimal_pk, decimal_col1, decimal_col2 from " + fullTableName ;
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
if(localIndex) {
assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + fullTableName+" [1]\nCLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
} else {
assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER " + fullIndexName, QueryUtil.getExplainPlan(rs));
}
rs = conn.createStatement().executeQuery(query);
assertTrue(rs.next());
assertEquals(new BigDecimal("1.1"), rs.getBigDecimal(1));
assertEquals(new BigDecimal("2.1"), rs.getBigDecimal(2));
assertEquals(new BigDecimal("3.1"), rs.getBigDecimal(3));
assertTrue(rs.next());
assertEquals(new BigDecimal("2.2"), rs.getBigDecimal(1));
assertEquals(new BigDecimal("3.2"), rs.getBigDecimal(2));
assertEquals(new BigDecimal("4.2"), rs.getBigDecimal(3));
assertTrue(rs.next());
assertEquals(new BigDecimal("3.3"), rs.getBigDecimal(1));
assertEquals(new BigDecimal("4.3"), rs.getBigDecimal(2));
assertEquals(new BigDecimal("5.3"), rs.getBigDecimal(3));
assertFalse(rs.next());
}
}
/**
* Ensure that HTD contains table priorities correctly.
*/
@Test
public void testTableDescriptorPriority() throws SQLException, IOException {
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
// Check system tables priorities.
try (HBaseAdmin admin = driver.getConnectionQueryServices(null, null).getAdmin();
Connection c = DriverManager.getConnection(getUrl())) {
ResultSet rs = c.getMetaData().getTables("",
PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA,
null,
new String[] {PTableType.SYSTEM.toString()});
ReadOnlyProps p = c.unwrap(PhoenixConnection.class).getQueryServices().getProps();
while (rs.next()) {
String schemaName = rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM);
String tName = rs.getString(PhoenixDatabaseMetaData.TABLE_NAME);
org.apache.hadoop.hbase.TableName hbaseTableName = SchemaUtil.getPhysicalTableName(SchemaUtil.getTableName(schemaName, tName), p);
HTableDescriptor htd = admin.getTableDescriptor(hbaseTableName);
String val = htd.getValue("PRIORITY");
assertNotNull("PRIORITY is not set for table:" + htd, val);
assertTrue(Integer.parseInt(val)
>= PhoenixRpcSchedulerFactory.getMetadataPriority(config));
}
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + tableDDLOptions;
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexName
+ " ON " + fullTableName + " (long_col1, long_col2)"
+ " INCLUDE (decimal_col1, decimal_col2)";
stmt.execute(ddl);
}
HTableDescriptor dataTable = admin.getTableDescriptor(
org.apache.hadoop.hbase.TableName.valueOf(fullTableName));
String val = dataTable.getValue("PRIORITY");
assertTrue(val == null || Integer.parseInt(val) < HConstants.HIGH_QOS);
if (!localIndex && mutable) {
HTableDescriptor indexTable = admin.getTableDescriptor(
org.apache.hadoop.hbase.TableName.valueOf(indexName));
val = indexTable.getValue("PRIORITY");
assertNotNull("PRIORITY is not set for table:" + indexTable, val);
assertTrue(Integer.parseInt(val) >= PhoenixRpcSchedulerFactory.getIndexPriority(config));
}
}
}
@Test
public void testQueryBackToDataTableWithDescPKColumn() throws SQLException {
doTestQueryBackToDataTableWithDescPKColumn(true);
doTestQueryBackToDataTableWithDescPKColumn(false);
}
private void doTestQueryBackToDataTableWithDescPKColumn(boolean isSecondPKDesc) throws SQLException {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
// create data table and index table
conn.setAutoCommit(true);
Statement stmt = conn.createStatement();
String ddl = "CREATE TABLE " + fullTableName + "(p1 integer not null, p2 integer not null, " +
" a integer, b integer CONSTRAINT PK PRIMARY KEY ";
if (isSecondPKDesc) {
ddl += "(p1, p2 desc))";
} else {
ddl += "(p1 desc, p2))";
}
stmt.executeUpdate(ddl);
ddl = "CREATE "+ (localIndex ? "LOCAL " : "") + " INDEX " + fullIndexName + " on " + fullTableName + "(a)";
stmt.executeUpdate(ddl);
// upsert a single row
String upsert = "UPSERT INTO " + fullTableName + " VALUES(1,2,3,4)";
stmt.executeUpdate(upsert);
// try select with index
// a = 3, should hit index table, but we select column B, so it will query back to data table
String query = "SELECT /*+index(" + fullTableName + " " + fullIndexName + "*/ b from " + fullTableName +
" WHERE a = 3";
ResultSet rs = stmt.executeQuery(query);
assertTrue(rs.next());
assertEquals(4, rs.getInt(1));
assertFalse(rs.next());
rs.close();
stmt.close();
}
}
}