blob: fd6703e02885b1db2773476ca8a95052cb86989c [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.util.TestUtil.INDEX_DATA_SCHEMA;
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.sql.Connection;
import java.sql.DatabaseMetaData;
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.sql.Types;
import java.util.Properties;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
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.query.QueryConstants;
import org.apache.phoenix.schema.AmbiguousColumnException;
import org.apache.phoenix.schema.ColumnAlreadyExistsException;
import org.apache.phoenix.schema.PIndexState;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableKey;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.schema.types.PDate;
import org.apache.phoenix.schema.types.PLong;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.StringUtil;
import org.apache.phoenix.util.TestUtil;
import org.junit.Test;
public class IndexMetadataIT extends ParallelStatsDisabledIT {
private enum Order {ASC, DESC};
private static void assertIndexInfoMetadata(ResultSet rs, String schemaName, String dataTableName, String indexName, int colPos, String colName, Order order) throws SQLException {
assertTrue(rs.next());
assertEquals(null,rs.getString(1));
assertEquals(schemaName, rs.getString(2));
assertEquals(dataTableName, rs.getString(3));
assertEquals(Boolean.TRUE, rs.getBoolean(4));
assertEquals(null,rs.getString(5));
assertEquals(indexName, rs.getString(6));
assertEquals(DatabaseMetaData.tableIndexOther, rs.getShort(7));
assertEquals(colPos, rs.getShort(8));
assertEquals(colName, rs.getString(9));
assertEquals(order == Order.ASC ? "A" : order == Order.DESC ? "D" : null, rs.getString(10));
assertEquals(0,rs.getInt(11));
assertTrue(rs.wasNull());
assertEquals(0,rs.getInt(12));
assertTrue(rs.wasNull());
assertEquals(null,rs.getString(13));
}
private static void assertIndexInfoMetadata(ResultSet rs, String schemaName, String dataTableName, String indexName, int colPos, String colName, Order order, int type) throws SQLException {
assertTrue(rs.next());
assertEquals(null,rs.getString(1));
assertEquals(schemaName, rs.getString(2));
assertEquals(dataTableName, rs.getString(3));
assertEquals(Boolean.TRUE, rs.getBoolean(4));
assertEquals(null,rs.getString(5));
assertEquals(indexName, rs.getString(6));
assertEquals(DatabaseMetaData.tableIndexOther, rs.getShort(7));
assertEquals(colPos, rs.getShort(8));
assertEquals(colName, rs.getString(9));
assertEquals(order == Order.ASC ? "A" : order == Order.DESC ? "D" : null, rs.getString(10));
assertEquals(0,rs.getInt(11));
assertTrue(rs.wasNull());
assertEquals(0,rs.getInt(12));
assertTrue(rs.wasNull());
assertEquals(null,rs.getString(13));
assertEquals(type,rs.getInt(14));
}
private static void assertActiveIndex(Connection conn, String schemaName, String tableName) throws SQLException {
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
String fullTableName = SchemaUtil.getTableName(schemaName, tableName);
conn.createStatement().executeQuery("SELECT count(*) FROM " + fullTableName).next(); // client side cache will update
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
pconn.getTable(new PTableKey(pconn.getTenantId(), fullTableName)).getIndexMaintainers(ptr, pconn);
assertTrue(ptr.getLength() > 0);
}
private static void assertNoActiveIndex(Connection conn, String schemaName, String tableName) throws SQLException {
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
String fullTableName = SchemaUtil.getTableName(schemaName, tableName);
conn.createStatement().executeQuery("SELECT count(*) FROM " + fullTableName).next(); // client side cache will update
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
pconn.getTable(new PTableKey(pconn.getTenantId(), fullTableName)).getIndexMaintainers(ptr, pconn);
assertTrue(ptr.getLength() == 0);
}
@Test
public void testIndexCreateDrop() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String indexDataTable = generateUniqueName();
String fullIndexDataTable = INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
String indexName = generateUniqueName();
try {
String tableDDL = "create table " + fullIndexDataTable + TestUtil.TEST_TABLE_SCHEMA;
conn.createStatement().execute(tableDDL);
String ddl = "CREATE INDEX " + indexName + " ON " + fullIndexDataTable
+ " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ " INCLUDE (int_col1, int_col2)";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
ResultSet rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 1, "A:VARCHAR_COL1", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 2, "B:VARCHAR_COL2", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 3, ":INT_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 4, ":VARCHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 5, ":CHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 6, ":LONG_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 7, ":DECIMAL_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 8, ":DATE_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 9, "A:INT_COL1", null);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 10, "B:INT_COL2", null);
assertFalse(rs.next());
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), StringUtil.escapeLike(indexName ), new String[] {PTableType.INDEX.getValue().getString() });
assertTrue(rs.next());
assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
// Verify that there is a row inserted into the data table for the index table.
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName );
assertTrue(rs.next());
assertEquals(indexName , rs.getString(1));
assertFalse(rs.next());
assertActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " UNUSABLE";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.INACTIVE.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
assertActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " USABLE";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
assertActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " DISABLE";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.DISABLE.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
assertNoActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
try {
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " USABLE";
conn.createStatement().execute(ddl);
fail();
} catch (SQLException e) {
assertEquals(SQLExceptionCode.INVALID_INDEX_STATE_TRANSITION.getErrorCode(), e.getErrorCode());
}
try {
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " UNUSABLE";
conn.createStatement().execute(ddl);
fail();
} catch (SQLException e) {
assertEquals(SQLExceptionCode.INVALID_INDEX_STATE_TRANSITION.getErrorCode(), e.getErrorCode());
}
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " REBUILD";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
assertActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " REBUILD ASYNC";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.BUILDING.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
ddl = "DROP INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute(ddl);
assertNoActiveIndex(conn, INDEX_DATA_SCHEMA, indexDataTable);
// Assert the rows for index table is completely removed.
rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertFalse(rs.next());
// Assert the row in the original data table is removed.
// Verify that there is a row inserted into the data table for the index table.
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName );
assertFalse(rs.next());
// Create another two indexes, and drops the table, verifies the indexes are dropped as well.
ddl = "CREATE INDEX " + indexName + "1 ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable
+ " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ " INCLUDE (int_col1, int_col2)";
conn.createStatement().execute(ddl);
ddl = "CREATE INDEX " + indexName + "2 ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable
+ " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ " INCLUDE (long_pk, int_col2)";
conn.createStatement().execute(ddl);
rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 1, "A:VARCHAR_COL1", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 2, "B:VARCHAR_COL2", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 3, ":INT_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 4, ":VARCHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 5, ":CHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 6, ":LONG_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 7, ":DECIMAL_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 8, ":DATE_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 9, "A:INT_COL1", null);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1", 10, "B:INT_COL2", null);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 1, "A:VARCHAR_COL1", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 2, "B:VARCHAR_COL2", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 3, ":INT_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 4, ":VARCHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 5, ":CHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 6, ":LONG_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 7, ":DECIMAL_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 8, ":DATE_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2", 9, "B:INT_COL2", null);
assertFalse(rs.next());
// Create another table in the same schema
String diffTableNameInSameSchema = INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + "2";
conn.createStatement().execute("CREATE TABLE " + diffTableNameInSameSchema + "(k INTEGER PRIMARY KEY)");
try {
conn.createStatement().execute("DROP INDEX " + indexName + "1 ON " + diffTableNameInSameSchema);
fail("Should have realized index " + indexName + "1 is not on the table");
} catch (TableNotFoundException ignore) {
}
ddl = "DROP TABLE " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute(ddl);
rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertFalse(rs.next());
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName + "1");
assertFalse(rs.next());
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName + "2");
assertFalse(rs.next());
} finally {
conn.close();
}
}
@Test
public void testIndexDefinitionWithNullableFixedWidthColInPK() throws Exception {
// If we have nullable fixed width column in the PK, we convert those types into a compatible variable type
// column. The definition is defined in IndexUtil.getIndexColumnDataType.
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
String indexDataTable = generateUniqueName();
String indexName = generateUniqueName();
conn.setAutoCommit(false);
try {
String fullTableName = INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute("create table " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + "IMMUTABLE_ROWS=true");
String ddl = "CREATE INDEX " + indexName + " ON " + fullTableName
+ " (char_col1 ASC, int_col2 ASC, long_col2 DESC)"
+ " INCLUDE (int_col1)";
conn.createStatement().execute(ddl);
// Verify the CHAR, INT and LONG are converted to right type.
ResultSet rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 1, "A:CHAR_COL1", Order.ASC, Types.VARCHAR);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 2, "B:INT_COL2", Order.ASC, Types.DECIMAL);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 3, "B:LONG_COL2", Order.DESC, Types.DECIMAL);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 4, ":VARCHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 5, ":CHAR_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 6, ":INT_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 7, ":LONG_PK", Order.DESC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 8, ":DECIMAL_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 9, ":DATE_PK", Order.ASC);
assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, indexDataTable, indexName , 10, "A:INT_COL1", null);
assertFalse(rs.next());
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName );
assertTrue(rs.next());
assertEquals(indexName , rs.getString(1));
assertFalse(rs.next());
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " UNUSABLE";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), indexName , new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals(indexName , rs.getString(3));
assertEquals(PIndexState.INACTIVE.toString(), rs.getString("INDEX_STATE"));
assertFalse(rs.next());
ddl = "DROP INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute(ddl);
// Assert the rows for index table is completely removed.
rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertFalse(rs.next());
// Assert the row in the original data table is removed.
// Verify that there is a row inserted into the data table for the index table.
rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, indexDataTable, indexName );
assertFalse(rs.next());
} finally {
conn.close();
}
}
@Test
public void testAlterIndexWithLowerCaseName() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String indexName = "\"lowerCaseIndex\"";
String indexDataTable = generateUniqueName();
try {
String fullTableName = INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute("create table " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + "IMMUTABLE_ROWS=true");
String ddl = "CREATE INDEX " + indexName + " ON " + fullTableName
+ " (char_col1 ASC, int_col2 ASC, long_col2 DESC)"
+ " INCLUDE (int_col1)";
conn.createStatement().execute(ddl);
ddl = "ALTER INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable + " UNUSABLE";
conn.createStatement().execute(ddl);
// Verify the metadata for index is correct.
ResultSet rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "lowerCaseIndex", new String[] {PTableType.INDEX.toString()});
assertTrue(rs.next());
assertEquals("lowerCaseIndex", rs.getString(3));
ddl = "DROP INDEX " + indexName + " ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute(ddl);
// Assert the rows for index table is completely removed.
rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, indexDataTable, false, false);
assertFalse(rs.next());
} finally {
conn.close();
}
}
@Test
public void testIndexDefinitionWithRepeatedColumns() throws Exception {
// Test index creation when the columns is included in both the PRIMARY and INCLUDE section. Test de-duplication.
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String indexDataTable = generateUniqueName();
String indexName = generateUniqueName();
try {
String fullTableName = INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + indexDataTable;
conn.createStatement().execute("create table " + fullTableName + TestUtil.TEST_TABLE_SCHEMA + "IMMUTABLE_ROWS=true");
String ddl = "CREATE INDEX " + indexName + " ON " + fullTableName
+ " (a.int_col1, a.long_col1, b.int_col2, b.long_col2)"
+ " INCLUDE(int_col1, int_col2)";
conn.createStatement().execute(ddl);
fail("Should have caught exception.");
} catch (SQLException e) {
assertEquals(SQLExceptionCode.COLUMN_EXIST_IN_DEF.getErrorCode(), e.getErrorCode());
} finally {
conn.close();
}
}
@Test
public void testTableWithSameColumnNames() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
try {
String ddl = "create table test_table (char_pk varchar not null,"
+ " int_col integer, long_col integer, int_col integer"
+ " constraint pk primary key (char_pk))";
conn.createStatement().execute(ddl);
fail("Should have caught exception");
} catch (ColumnAlreadyExistsException e) {
assertEquals(SQLExceptionCode.COLUMN_EXIST_IN_DEF.getErrorCode(), e.getErrorCode());
} finally {
conn.close();
}
}
@Test
public void testTableWithSameColumnNamesWithFamily() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
try {
String ddl = "create table test_table (char_pk varchar not null,"
+ " a.int_col integer, a.long_col integer,"
+ " a.int_col integer, b.long_col integer"
+ " constraint pk primary key (char_pk))";
conn.createStatement().execute(ddl);
fail("Should have caught exception");
} catch (ColumnAlreadyExistsException e) {
assertEquals(SQLExceptionCode.COLUMN_EXIST_IN_DEF.getErrorCode(), e.getErrorCode());
} finally {
conn.close();
}
}
@Test
public void testIndexDefinitionWithSameColumnNamesInTwoFamily() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String testTable = generateUniqueName();
String indexName = generateUniqueName();
String ddl = "create table " + testTable + " (char_pk varchar not null,"
+ " a.int_col integer, a.long_col integer,"
+ " b.int_col integer, b.long_col integer"
+ " constraint pk primary key (char_pk))";
conn.createStatement().execute(ddl);
ddl = "CREATE INDEX " + indexName + "1 ON " + testTable + " (a.int_col, b.int_col)";
conn.createStatement().execute(ddl);
try {
ddl = "CREATE INDEX " + indexName + "2 ON " + testTable + " (int_col)";
conn.createStatement().execute(ddl);
fail("Should have caught exception");
} catch (AmbiguousColumnException e) {
assertEquals(SQLExceptionCode.AMBIGUOUS_COLUMN.getErrorCode(), e.getErrorCode());
} finally {
conn.close();
}
}
@Test
public void testBinaryNonnullableIndex() throws Exception {
Connection conn = DriverManager.getConnection(getUrl());
String testTable = generateUniqueName();
String indexName = generateUniqueName();
try {
String ddl =
"CREATE TABLE " + testTable + " ( "
+ "v1 BINARY(64) NOT NULL, "
+ "v2 VARCHAR, "
+ "v3 BINARY(64), "
+ "v4 VARCHAR "
+ "CONSTRAINT PK PRIMARY KEY (v1))";
conn.createStatement().execute(ddl);
conn.commit();
try {
conn.createStatement().execute("CREATE INDEX " + indexName + " ON " + testTable + " (v3) INCLUDE (v4)");
fail("Should have seen SQLExceptionCode.VARBINARY_IN_ROW_KEY");
} catch (SQLException e) {
assertEquals(SQLExceptionCode.VARBINARY_IN_ROW_KEY.getErrorCode(), e.getErrorCode());
}
try {
conn.createStatement().execute("CREATE INDEX " + indexName + "3 ON " + testTable + " (v2, v3) INCLUDE (v4)");
fail("Should have seen SQLExceptionCode.VARBINARY_IN_ROW_KEY");
} catch (SQLException e) {
assertEquals(SQLExceptionCode.VARBINARY_IN_ROW_KEY.getErrorCode(), e.getErrorCode());
}
conn.createStatement().execute("CREATE INDEX " + indexName + "4 ON " + testTable + " (v4) INCLUDE (v2)");
conn.commit();
conn.createStatement().execute("CREATE INDEX varbinLastInRow ON " + testTable + " (v1, v3)");
conn.commit();
conn.createStatement().execute( "CREATE INDEX " + indexName + "5 ON " + testTable + " (v2) INCLUDE (v4, v3, v1)");
conn.commit();
conn.createStatement().executeQuery(
"select v1,v2,v3,v4 FROM " + testTable + " where v2 = 'abc' and v3 != 'a'");
} finally {
conn.close();
}
}
@Test
public void testAsyncCreatedDate() throws Exception {
Date d0 = new Date(System.currentTimeMillis());
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String testTable = generateUniqueName();
String ddl = "create table " + testTable + " (k varchar primary key, v1 varchar, v2 varchar, v3 varchar)";
conn.createStatement().execute(ddl);
String indexName = "ASYNCIND_" + generateUniqueName();
ddl = "CREATE INDEX " + indexName + "1 ON " + testTable + " (v1) ASYNC";
conn.createStatement().execute(ddl);
ddl = "CREATE INDEX " + indexName + "2 ON " + testTable + " (v2) ASYNC";
conn.createStatement().execute(ddl);
ddl = "CREATE INDEX " + indexName + "3 ON " + testTable + " (v3)";
conn.createStatement().execute(ddl);
ResultSet rs = conn.createStatement().executeQuery(
"select table_name, " + PhoenixDatabaseMetaData.ASYNC_CREATED_DATE + " " +
"from system.catalog (" + PhoenixDatabaseMetaData.ASYNC_CREATED_DATE + " " + PDate.INSTANCE.getSqlTypeName() + ") " +
"where " + PhoenixDatabaseMetaData.ASYNC_CREATED_DATE + " is not null and table_name like 'ASYNCIND_%' " +
"order by " + PhoenixDatabaseMetaData.ASYNC_CREATED_DATE
);
assertTrue(rs.next());
assertEquals(indexName + "1", rs.getString(1));
Date d1 = rs.getDate(2);
assertTrue(d1.after(d0));
assertTrue(rs.next());
assertEquals(indexName + "2", rs.getString(1));
Date d2 = rs.getDate(2);
assertTrue(d2.after(d1));
assertFalse(rs.next());
}
@Test
public void testAsyncRebuildTimestamp() throws Exception {
long startTimestamp = System.currentTimeMillis();
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.setAutoCommit(false);
String testTable = generateUniqueName();
String ddl = "create table " + testTable + " (k varchar primary key, v1 varchar, v2 varchar, v3 varchar)";
Statement stmt = conn.createStatement();
stmt.execute(ddl);
String indexName = "R_ASYNCIND_" + generateUniqueName();
ddl = "CREATE INDEX " + indexName + "1 ON " + testTable + " (v1) ";
stmt.execute(ddl);
ddl = "CREATE INDEX " + indexName + "2 ON " + testTable + " (v2) ";
stmt.execute(ddl);
ddl = "CREATE INDEX " + indexName + "3 ON " + testTable + " (v3)";
stmt.execute(ddl);
conn.createStatement().execute("ALTER INDEX "+indexName+"1 ON " + testTable +" DISABLE ");
conn.createStatement().execute("ALTER INDEX "+indexName+"2 ON " + testTable +" REBUILD ");
conn.createStatement().execute("ALTER INDEX "+indexName+"3 ON " + testTable +" REBUILD ASYNC");
ResultSet rs = conn.createStatement().executeQuery(
"select table_name, " + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " " +
"from system.catalog (" + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " " + PLong.INSTANCE.getSqlTypeName() + ") " +
"where " + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " !=0 and table_name like 'R_ASYNCIND_%' " +
"order by table_name");
assertTrue(rs.next());
assertEquals(indexName + "3", rs.getString(1));
long asyncTimestamp = rs.getLong(2);
assertTrue("Async timestamp is recent timestamp", asyncTimestamp > startTimestamp);
PTable table = PhoenixRuntime.getTable(conn, indexName+"3");
assertEquals(table.getTimeStamp(), asyncTimestamp);
assertFalse(rs.next());
conn.createStatement().execute("ALTER INDEX "+indexName+"3 ON " + testTable +" DISABLE");
rs = conn.createStatement().executeQuery(
"select table_name, " + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " " +
"from system.catalog (" + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " " + PLong.INSTANCE.getSqlTypeName() + ") " +
"where " + PhoenixDatabaseMetaData.ASYNC_REBUILD_TIMESTAMP + " !=0 and table_name like 'ASYNCIND_%' " +
"order by table_name" );
assertFalse(rs.next());
}
}