You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/03/12 22:31:51 UTC
[24/41] PHOENIX-130 Separate execution of slow (integration) tests
from fast unit tests (Gabriel Reid)
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java
new file mode 100644
index 0000000..e1080e1
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java
@@ -0,0 +1,220 @@
+/*
+ * 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.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.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.schema.ReadOnlyTableException;
+import org.junit.Test;
+
+public class ViewIT extends BaseViewIT {
+
+ @Test
+ public void testReadOnlyView() throws Exception {
+ Connection earlierCon = DriverManager.getConnection(getUrl());
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE TABLE t (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)";
+ conn.createStatement().execute(ddl);
+ ddl = "CREATE VIEW v (v2 VARCHAR) AS SELECT * FROM t WHERE k > 5";
+ conn.createStatement().execute(ddl);
+ try {
+ conn.createStatement().execute("UPSERT INTO v VALUES(1)");
+ fail();
+ } catch (ReadOnlyTableException e) {
+
+ }
+ for (int i = 0; i < 10; i++) {
+ conn.createStatement().execute("UPSERT INTO t VALUES(" + i + ")");
+ }
+ conn.commit();
+
+ int count = 0;
+ ResultSet rs = conn.createStatement().executeQuery("SELECT k FROM v");
+ while (rs.next()) {
+ count++;
+ assertEquals(count + 5, rs.getInt(1));
+ }
+ assertEquals(4, count);
+ count = 0;
+ rs = earlierCon.createStatement().executeQuery("SELECT k FROM v");
+ while (rs.next()) {
+ count++;
+ assertEquals(count + 5, rs.getInt(1));
+ }
+ assertEquals(4, count);
+ }
+
+
+ @Test
+ public void testReadOnlyOnReadOnlyView() throws Exception {
+ testReadOnlyView();
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE VIEW v2 AS SELECT * FROM v WHERE k < 9";
+ conn.createStatement().execute(ddl);
+ try {
+ conn.createStatement().execute("UPSERT INTO v2 VALUES(1)");
+ fail();
+ } catch (ReadOnlyTableException e) {
+
+ }
+
+ int count = 0;
+ ResultSet rs = conn.createStatement().executeQuery("SELECT k FROM v2");
+ while (rs.next()) {
+ count++;
+ assertEquals(count + 5, rs.getInt(1));
+ }
+ assertEquals(3, count);
+ }
+
+ @Test
+ public void testNonSaltedUpdatableViewWithIndex() throws Exception {
+ testUpdatableViewWithIndex(null);
+ }
+
+ @Test
+ public void testUpdatableOnUpdatableView() throws Exception {
+ testUpdatableView(null);
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE VIEW v2 AS SELECT * FROM v WHERE k3 = 2";
+ conn.createStatement().execute(ddl);
+ ResultSet rs = conn.createStatement().executeQuery("SELECT k1, k2, k3 FROM v2");
+ assertTrue(rs.next());
+ assertEquals(1, rs.getInt(1));
+ assertEquals(109, rs.getInt(2));
+ assertEquals(2, rs.getInt(3));
+ assertFalse(rs.next());
+
+ conn.createStatement().execute("UPSERT INTO v2(k2) VALUES(122)");
+ conn.commit();
+ rs = conn.createStatement().executeQuery("SELECT k1, k2, k3 FROM v2 WHERE k2 >= 120");
+ assertTrue(rs.next());
+ assertEquals(1, rs.getInt(1));
+ assertEquals(122, rs.getInt(2));
+ assertEquals(2, rs.getInt(3));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testReadOnlyOnUpdatableView() throws Exception {
+ testUpdatableView(null);
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE VIEW v2 AS SELECT * FROM v WHERE k3 > 1 and k3 < 50";
+ conn.createStatement().execute(ddl);
+ ResultSet rs = conn.createStatement().executeQuery("SELECT k1, k2, k3 FROM v2");
+ assertTrue(rs.next());
+ assertEquals(1, rs.getInt(1));
+ assertEquals(109, rs.getInt(2));
+ assertEquals(2, rs.getInt(3));
+ assertFalse(rs.next());
+
+ try {
+ conn.createStatement().execute("UPSERT INTO v2 VALUES(1)");
+ fail();
+ } catch (ReadOnlyTableException e) {
+
+ }
+
+ conn.createStatement().execute("UPSERT INTO t(k1, k2,k3) VALUES(1, 122, 5)");
+ conn.commit();
+ rs = conn.createStatement().executeQuery("SELECT k1, k2, k3 FROM v2 WHERE k2 >= 120");
+ assertTrue(rs.next());
+ assertEquals(1, rs.getInt(1));
+ assertEquals(122, rs.getInt(2));
+ assertEquals(5, rs.getInt(3));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testDisallowDropOfReferencedColumn() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE TABLE t (k1 INTEGER NOT NULL, k2 INTEGER NOT NULL, v1 DECIMAL, CONSTRAINT pk PRIMARY KEY (k1, k2))";
+ conn.createStatement().execute(ddl);
+ ddl = "CREATE VIEW v1(v2 VARCHAR, v3 VARCHAR) AS SELECT * FROM t WHERE v1 = 1.0";
+ conn.createStatement().execute(ddl);
+
+ try {
+ conn.createStatement().execute("ALTER VIEW v1 DROP COLUMN v1");
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode());
+ }
+
+ ddl = "CREATE VIEW v2 AS SELECT * FROM v1 WHERE v2 != 'foo'";
+ conn.createStatement().execute(ddl);
+
+ try {
+ conn.createStatement().execute("ALTER VIEW v2 DROP COLUMN v1");
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode());
+ }
+ try {
+ conn.createStatement().execute("ALTER VIEW v2 DROP COLUMN v2");
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode());
+ }
+ conn.createStatement().execute("ALTER VIEW v2 DROP COLUMN v3");
+
+ }
+
+ @Test
+ public void testReadOnlyViewWithCaseSensitiveTableNames() throws Exception {
+ Connection earlierCon = DriverManager.getConnection(getUrl());
+ Connection conn = DriverManager.getConnection(getUrl());
+ String ddl = "CREATE TABLE \"case_SENSITIVE_table\" (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)";
+ conn.createStatement().execute(ddl);
+ ddl = "CREATE VIEW \"v\" (v2 VARCHAR) AS SELECT * FROM \"case_SENSITIVE_table\" WHERE k > 5";
+ conn.createStatement().execute(ddl);
+ try {
+ conn.createStatement().execute("UPSERT INTO \"v\" VALUES(1)");
+ fail();
+ } catch (ReadOnlyTableException e) {
+
+ }
+ for (int i = 0; i < 10; i++) {
+ conn.createStatement().execute("UPSERT INTO \"case_SENSITIVE_table\" VALUES(" + i + ")");
+ }
+ conn.commit();
+
+ int count = 0;
+ ResultSet rs = conn.createStatement().executeQuery("SELECT k FROM \"v\"");
+ while (rs.next()) {
+ count++;
+ assertEquals(count + 5, rs.getInt(1));
+ }
+ assertEquals(4, count);
+ count = 0;
+ rs = earlierCon.createStatement().executeQuery("SELECT k FROM \"v\"");
+ while (rs.next()) {
+ count++;
+ assertEquals(count + 5, rs.getInt(1));
+ }
+ assertEquals(4, count);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseIndexIT.java
new file mode 100644
index 0000000..6d1e995
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseIndexIT.java
@@ -0,0 +1,29 @@
+/*
+ * 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 org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
+import org.apache.phoenix.util.SchemaUtil;
+
+public class BaseIndexIT extends BaseHBaseManagedTimeIT {
+ public static final String SCHEMA_NAME = "";
+ public static final String DATA_TABLE_NAME = "T";
+ public static final String INDEX_TABLE_NAME = "I";
+ public static final String DATA_TABLE_FULL_NAME = SchemaUtil.getTableName(SCHEMA_NAME, "T");
+ public static final String INDEX_TABLE_FULL_NAME = SchemaUtil.getTableName(SCHEMA_NAME, "I");
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseMutableIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseMutableIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseMutableIndexIT.java
new file mode 100644
index 0000000..4495877
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/BaseMutableIndexIT.java
@@ -0,0 +1,134 @@
+/*
+ * 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.TEST_PROPERTIES;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.phoenix.util.TestUtil;
+
+public class BaseMutableIndexIT extends BaseIndexIT {
+ public BaseMutableIndexIT() {
+ }
+
+ protected static void createTestTable() throws SQLException {
+ String ddl = "create table if not exists " + DATA_TABLE_FULL_NAME + "(" +
+ " varchar_pk VARCHAR NOT NULL, " +
+ " char_pk CHAR(5) NOT NULL, " +
+ " int_pk INTEGER NOT NULL, "+
+ " long_pk BIGINT NOT NULL, " +
+ " decimal_pk DECIMAL(31, 10) NOT NULL, " +
+ " a.varchar_col1 VARCHAR, " +
+ " a.char_col1 CHAR(5), " +
+ " a.int_col1 INTEGER, " +
+ " a.long_col1 BIGINT, " +
+ " a.decimal_col1 DECIMAL(31, 10), " +
+ " b.varchar_col2 VARCHAR, " +
+ " b.char_col2 CHAR(5), " +
+ " b.int_col2 INTEGER, " +
+ " b.long_col2 BIGINT, " +
+ " b.decimal_col2 DECIMAL, " +
+ " b.date_col DATE " +
+ " CONSTRAINT pk PRIMARY KEY (varchar_pk, char_pk, int_pk, long_pk DESC, decimal_pk))";
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.createStatement().execute(ddl);
+ conn.close();
+ }
+
+ // Populate the test table with data.
+ protected static void populateTestTable() throws SQLException {
+ populateTestTable(null);
+ }
+ // Populate the test table with data.
+ protected static void populateTestTable(Date date) throws SQLException {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ try {
+ String upsert = "UPSERT INTO " + DATA_TABLE_FULL_NAME
+ + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ PreparedStatement 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.1"));
+ stmt.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 2);
+ stmt.setLong(9, 2L);
+ stmt.setBigDecimal(10, new BigDecimal("2.1"));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 3);
+ stmt.setLong(14, 3L);
+ stmt.setBigDecimal(15, new BigDecimal("3.1"));
+ stmt.setDate(16, date == null ? null : new Date(date.getTime() + TestUtil.MILLIS_IN_DAY));
+ stmt.executeUpdate();
+
+ stmt.setString(1, "varchar2");
+ stmt.setString(2, "char2");
+ stmt.setInt(3, 2);
+ stmt.setLong(4, 2L);
+ stmt.setBigDecimal(5, new BigDecimal("2.2"));
+ stmt.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 3);
+ stmt.setLong(9, 3L);
+ stmt.setBigDecimal(10, new BigDecimal("3.2"));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 4);
+ stmt.setLong(14, 4L);
+ stmt.setBigDecimal(15, new BigDecimal("4.2"));
+ stmt.setDate(16, date);
+ stmt.executeUpdate();
+
+ stmt.setString(1, "varchar3");
+ stmt.setString(2, "char3");
+ stmt.setInt(3, 3);
+ stmt.setLong(4, 3L);
+ stmt.setBigDecimal(5, new BigDecimal("3.3"));
+ stmt.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 4);
+ stmt.setLong(9, 4L);
+ stmt.setBigDecimal(10, new BigDecimal("4.3"));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 5);
+ stmt.setLong(14, 5L);
+ stmt.setBigDecimal(15, new BigDecimal("5.3"));
+ stmt.setDate(16, date == null ? null : new Date(date.getTime() + 2 * TestUtil.MILLIS_IN_DAY));
+ stmt.executeUpdate();
+
+ conn.commit();
+ } finally {
+ conn.close();
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/DropViewIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/DropViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/DropViewIT.java
new file mode 100644
index 0000000..499b69e
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/DropViewIT.java
@@ -0,0 +1,99 @@
+/*
+ * 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.HBASE_NATIVE;
+import static org.apache.phoenix.util.TestUtil.HBASE_NATIVE_SCHEMA_NAME;
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Maps;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.SchemaUtil;
+
+public class DropViewIT extends BaseMutableIndexIT {
+ private static final byte[] HBASE_NATIVE_BYTES = SchemaUtil.getTableNameAsBytes(HBASE_NATIVE_SCHEMA_NAME, HBASE_NATIVE);
+ private static final byte[] FAMILY_NAME = Bytes.toBytes(SchemaUtil.normalizeIdentifier("1"));
+
+ @BeforeClass
+ public static void doSetup() throws Exception {
+ Map<String,String> props = Maps.newHashMapWithExpectedSize(1);
+ // Drop the HBase table metadata for this test
+ props.put(QueryServices.DROP_METADATA_ATTRIB, Boolean.toString(true));
+ // Must update config before starting server
+ startServer(getUrl(), new ReadOnlyProps(props.entrySet().iterator()));
+ }
+
+ @Test
+ public void testDropViewKeepsHTable() throws Exception {
+ HBaseAdmin admin = driver.getConnectionQueryServices(getUrl(), TEST_PROPERTIES).getAdmin();
+ try {
+ try {
+ admin.disableTable(HBASE_NATIVE_BYTES);
+ admin.deleteTable(HBASE_NATIVE_BYTES);
+ } catch (org.apache.hadoop.hbase.TableNotFoundException e) {
+ }
+ HTableDescriptor descriptor = new HTableDescriptor(HBASE_NATIVE_BYTES);
+ HColumnDescriptor columnDescriptor = new HColumnDescriptor(FAMILY_NAME);
+ columnDescriptor.setKeepDeletedCells(true);
+ descriptor.addFamily(columnDescriptor);
+ admin.createTable(descriptor);
+ } finally {
+ admin.close();
+ }
+
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.createStatement().execute("create view " + HBASE_NATIVE +
+ " (uint_key unsigned_int not null," +
+ " ulong_key unsigned_long not null," +
+ " string_key varchar not null,\n" +
+ " \"1\".uint_col unsigned_int," +
+ " \"1\".ulong_col unsigned_long" +
+ " CONSTRAINT pk PRIMARY KEY (uint_key, ulong_key, string_key))\n" +
+ HColumnDescriptor.DATA_BLOCK_ENCODING + "='" + DataBlockEncoding.NONE + "'");
+ conn.createStatement().execute("drop view " + HBASE_NATIVE);
+
+ admin = driver.getConnectionQueryServices(getUrl(), TEST_PROPERTIES).getAdmin();
+ try {
+ try {
+ admin.disableTable(HBASE_NATIVE_BYTES);
+ admin.deleteTable(HBASE_NATIVE_BYTES);
+ } catch (org.apache.hadoop.hbase.TableNotFoundException e) {
+ fail(); // The underlying HBase table should still exist
+ }
+ } finally {
+ admin.close();
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ImmutableIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ImmutableIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ImmutableIndexIT.java
new file mode 100644
index 0000000..cd3a8fb
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ImmutableIndexIT.java
@@ -0,0 +1,367 @@
+/*
+ * 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.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.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.util.QueryUtil;
+import org.junit.Test;
+
+
+public class ImmutableIndexIT extends BaseHBaseManagedTimeIT {
+ // Populate the test table with data.
+ private static void populateTestTable() throws SQLException {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ try {
+ String upsert = "UPSERT INTO " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ PreparedStatement 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.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 2);
+ stmt.setLong(9, 2L);
+ stmt.setBigDecimal(10, new BigDecimal(2.0));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 3);
+ stmt.setLong(14, 3L);
+ stmt.setBigDecimal(15, new BigDecimal(3.0));
+ stmt.executeUpdate();
+
+ stmt.setString(1, "varchar2");
+ stmt.setString(2, "char2");
+ stmt.setInt(3, 2);
+ stmt.setLong(4, 2L);
+ stmt.setBigDecimal(5, new BigDecimal(2.0));
+ stmt.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 3);
+ stmt.setLong(9, 3L);
+ stmt.setBigDecimal(10, new BigDecimal(3.0));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 4);
+ stmt.setLong(14, 4L);
+ stmt.setBigDecimal(15, new BigDecimal(4.0));
+ stmt.executeUpdate();
+
+ stmt.setString(1, "varchar3");
+ stmt.setString(2, "char3");
+ stmt.setInt(3, 3);
+ stmt.setLong(4, 3L);
+ stmt.setBigDecimal(5, new BigDecimal(3.0));
+ stmt.setString(6, "varchar_a");
+ stmt.setString(7, "chara");
+ stmt.setInt(8, 4);
+ stmt.setLong(9, 4L);
+ stmt.setBigDecimal(10, new BigDecimal(4.0));
+ stmt.setString(11, "varchar_b");
+ stmt.setString(12, "charb");
+ stmt.setInt(13, 5);
+ stmt.setLong(14, 5L);
+ stmt.setBigDecimal(15, new BigDecimal(5.0));
+ stmt.executeUpdate();
+
+ conn.commit();
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Test
+ public void testIndexWithNullableFixedWithCols() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (char_col1 ASC, int_col1 ASC)"
+ + " INCLUDE (long_col1, long_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ String query = "SELECT char_col1, int_col1 from " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE;
+ ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + query);
+ assertEquals("CLIENT PARALLEL 1-WAY FULL SCAN OVER INDEX_TEST.IDX", QueryUtil.getExplainPlan(rs));
+
+ rs = conn.createStatement().executeQuery(query);
+ assertTrue(rs.next());
+ assertEquals("chara", rs.getString(1));
+ 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 IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE);
+
+ query = "SELECT char_col1, int_col1 from " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE;
+ rs = conn.createStatement().executeQuery(query);
+ assertTrue(rs.next());
+
+ query = "SELECT char_col1, int_col1 from IDX ";
+ try{
+ rs = conn.createStatement().executeQuery(query);
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.TABLE_UNDEFINED.getErrorCode(), e.getErrorCode());
+ }
+
+
+ }
+
+ private void assertImmutableRows(Connection conn, String fullTableName, boolean expectedValue) throws SQLException {
+ PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
+ assertEquals(expectedValue, pconn.getMetaDataCache().getTable(new PTableKey(pconn.getTenantId(), fullTableName)).isImmutableRows());
+ }
+
+ @Test
+ public void testAlterTableWithImmutability() throws Exception {
+
+ String query;
+ ResultSet rs;
+ String fullTableName = "T";
+
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+
+ conn.createStatement().execute(
+ "CREATE TABLE t (k VARCHAR NOT NULL PRIMARY KEY, v VARCHAR) ");
+
+ query = "SELECT * FROM t";
+ rs = conn.createStatement().executeQuery(query);
+ assertFalse(rs.next());
+
+ assertImmutableRows(conn,fullTableName, false);
+ conn.createStatement().execute("ALTER TABLE t SET IMMUTABLE_ROWS=true");
+ assertImmutableRows(conn,fullTableName, true);
+
+
+ conn.createStatement().execute("ALTER TABLE t SET immutable_rows=false");
+ assertImmutableRows(conn,fullTableName, false);
+ }
+
+ @Test
+ public void testDeleteFromAllPKColumnIndex() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (long_pk, varchar_pk)"
+ + " INCLUDE (long_col1, long_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ ResultSet rs;
+
+ rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE);
+ assertTrue(rs.next());
+ assertEquals(3,rs.getInt(1));
+ rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + "IDX");
+ assertTrue(rs.next());
+ assertEquals(3,rs.getInt(1));
+
+ String dml = "DELETE from " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE +
+ " WHERE long_col2 = 4";
+ assertEquals(1,conn.createStatement().executeUpdate(dml));
+ conn.commit();
+
+ String query = "SELECT /*+ NO_INDEX */ long_pk FROM " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE;
+ 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 " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE;
+ 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 " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + "IDX" ;
+ 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 IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE);
+ }
+
+
+ @Test
+ public void testDropIfImmutableKeyValueColumn() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (long_col1)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ ResultSet rs;
+
+ rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE);
+ assertTrue(rs.next());
+ assertEquals(3,rs.getInt(1));
+ rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + "IDX");
+ assertTrue(rs.next());
+ assertEquals(3,rs.getInt(1));
+
+ conn.setAutoCommit(true);
+ String dml = "DELETE from " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE +
+ " WHERE long_col2 = 4";
+ try {
+ conn.createStatement().execute(dml);
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.NO_DELETE_IF_IMMUTABLE_INDEX.getErrorCode(), e.getErrorCode());
+ }
+
+ conn.createStatement().execute("DROP TABLE " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE);
+ }
+
+ @Test
+ public void testGroupByCount() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (int_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ ResultSet rs;
+
+ rs = conn.createStatement().executeQuery("SELECT int_col2, COUNT(*) FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE + " GROUP BY int_col2");
+ assertTrue(rs.next());
+ assertEquals(1,rs.getInt(2));
+ }
+
+ @Test
+ public void testSelectDistinctOnTableWithSecondaryImmutableIndex() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (int_col2)";
+ Connection conn = null;
+ PreparedStatement stmt = null;
+
+ try {
+ try {
+ conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ ResultSet rs = conn.createStatement().executeQuery("SELECT distinct int_col2 FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE + " 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());
+ } finally {
+ if (stmt != null) {
+ stmt.close();
+ }
+ }
+ } finally {
+ if (conn != null) {
+ conn.close();
+ }
+ }
+ }
+
+ @Test
+ public void testInClauseWithIndexOnColumnOfUsignedIntType() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ populateTestTable();
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (int_col1)";
+ try {
+ try {
+ conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ ResultSet rs = conn.createStatement().executeQuery("SELECT int_col1 FROM " +INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE + " 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());
+ } finally {
+ if(stmt != null) {
+ stmt.close();
+ }
+ }
+ } finally {
+ if(conn != null) {
+ conn.close();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
new file mode 100644
index 0000000..d81140b
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexMetadataIT.java
@@ -0,0 +1,380 @@
+/*
+ * 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.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.AmbiguousColumnException;
+import org.apache.phoenix.schema.PIndexState;
+import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.PTableType;
+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 BaseHBaseManagedTimeIT {
+
+ 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.getMetaDataCache().getTable(new PTableKey(pconn.getTenantId(), fullTableName)).getIndexMaintainers(ptr);
+ 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.getMetaDataCache().getTable(new PTableKey(pconn.getTenantId(), fullTableName)).getIndexMaintainers(ptr);
+ assertTrue(ptr.getLength() == 0);
+ }
+
+ @Test
+ public void testIndexCreation() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ try {
+ ensureTableCreated(getUrl(), MUTABLE_INDEX_DATA_TABLE);
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE
+ + " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ + " INCLUDE (int_col1, int_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ // Verify the metadata for index is correct.
+ ResultSet rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, false, false);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 1, "A:VARCHAR_COL1", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 2, "B:VARCHAR_COL2", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 3, ":INT_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 4, ":VARCHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 5, ":CHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 6, ":LONG_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 7, ":DECIMAL_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 8, "A:INT_COL1", null);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX", 9, "B:INT_COL2", null);
+ assertFalse(rs.next());
+
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), StringUtil.escapeLike("IDX"), 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, MUTABLE_INDEX_DATA_TABLE, "IDX");
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(1));
+ assertFalse(rs.next());
+
+ assertActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " UNUSABLE";
+ conn.createStatement().execute(ddl);
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "IDX", new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(3));
+ assertEquals(PIndexState.INACTIVE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ assertActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " USABLE";
+ conn.createStatement().execute(ddl);
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "IDX", new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(3));
+ assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ assertActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " DISABLE";
+ conn.createStatement().execute(ddl);
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "IDX", new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(3));
+ assertEquals(PIndexState.DISABLE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ assertNoActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ try {
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " USABLE";
+ conn.createStatement().execute(ddl);
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.INVALID_INDEX_STATE_TRANSITION.getErrorCode(), e.getErrorCode());
+ }
+ try {
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " UNUSABLE";
+ conn.createStatement().execute(ddl);
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.INVALID_INDEX_STATE_TRANSITION.getErrorCode(), e.getErrorCode());
+ }
+
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE + " REBUILD";
+ conn.createStatement().execute(ddl);
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "IDX", new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(3));
+ assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ assertActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ ddl = "DROP INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE;
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ assertNoActiveIndex(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE);
+
+ // Assert the rows for index table is completely removed.
+ rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, 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, MUTABLE_INDEX_DATA_TABLE, "IDX");
+ assertFalse(rs.next());
+
+ // Create another two indexes, and drops the table, verifies the indexes are dropped as well.
+ ddl = "CREATE INDEX IDX1 ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE
+ + " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ + " INCLUDE (int_col1, int_col2)";
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ ddl = "CREATE INDEX IDX2 ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE
+ + " (varchar_col1 ASC, varchar_col2 ASC, int_pk DESC)"
+ + " INCLUDE (long_pk, int_col2)";
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, false, false);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 1, "A:VARCHAR_COL1", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 2, "B:VARCHAR_COL2", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 3, ":INT_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 4, ":VARCHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 5, ":CHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 6, ":LONG_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 7, ":DECIMAL_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 8, "A:INT_COL1", null);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1", 9, "B:INT_COL2", null);
+
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 1, "A:VARCHAR_COL1", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 2, "B:VARCHAR_COL2", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 3, ":INT_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 4, ":VARCHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 5, ":CHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 6, ":LONG_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 7, ":DECIMAL_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2", 8, "B:INT_COL2", null);
+ assertFalse(rs.next());
+
+ ddl = "DROP TABLE " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + MUTABLE_INDEX_DATA_TABLE;
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, false, false);
+ assertFalse(rs.next());
+ rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX1");
+ assertFalse(rs.next());
+ rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, MUTABLE_INDEX_DATA_TABLE, "IDX2");
+ 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 = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ try {
+ ensureTableCreated(getUrl(), INDEX_DATA_TABLE);
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (char_col1 ASC, int_col2 ASC, long_col2 DESC)"
+ + " INCLUDE (int_col1)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ // Verify the CHAR, INT and LONG are converted to right type.
+ ResultSet rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, false, false);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 1, "A:CHAR_COL1", Order.ASC, Types.VARCHAR);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 2, "B:INT_COL2", Order.ASC, Types.DECIMAL);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 3, "B:LONG_COL2", Order.DESC, Types.DECIMAL);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 4, ":VARCHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 5, ":CHAR_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 6, ":INT_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 7, ":LONG_PK", Order.DESC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 8, ":DECIMAL_PK", Order.ASC);
+ assertIndexInfoMetadata(rs, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX", 9, "A:INT_COL1", null);
+ assertFalse(rs.next());
+
+ rs = IndexTestUtil.readDataTableIndexRow(conn, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, "IDX");
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(1));
+ assertFalse(rs.next());
+
+ ddl = "ALTER INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE + " UNUSABLE";
+ conn.createStatement().execute(ddl);
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(INDEX_DATA_SCHEMA), "IDX", new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals("IDX", rs.getString(3));
+ assertEquals(PIndexState.INACTIVE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ ddl = "DROP INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE;
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ // Assert the rows for index table is completely removed.
+ rs = conn.getMetaData().getIndexInfo(null, INDEX_DATA_SCHEMA, INDEX_DATA_TABLE, 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, INDEX_DATA_TABLE, "IDX");
+ 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 = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ try {
+ ensureTableCreated(getUrl(), TestUtil.INDEX_DATA_TABLE);
+ String ddl = "CREATE INDEX IDX ON " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR + INDEX_DATA_TABLE
+ + " (a.int_col1, a.long_col1, b.int_col2, b.long_col2)"
+ + " INCLUDE(int_col1, int_col2)";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ fail("Should have caught exception.");
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.COLUMN_EXIST_IN_DEF.getErrorCode(), e.getErrorCode());
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Test
+ public void testIndexDefinitionWithSameColumnNamesInTwoFamily() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ String ddl = "create table test_table (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))";
+ PreparedStatement stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+
+ ddl = "CREATE INDEX IDX1 ON test_table (a.int_col, b.int_col)";
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ try {
+ ddl = "CREATE INDEX IDX2 ON test_table (int_col)";
+ stmt = conn.prepareStatement(ddl);
+ stmt.execute();
+ fail("Should have caught exception");
+ } catch (AmbiguousColumnException e) {
+ assertEquals(SQLExceptionCode.AMBIGUOUS_COLUMN.getErrorCode(), e.getErrorCode());
+ } finally {
+ conn.close();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexTestUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexTestUtil.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexTestUtil.java
new file mode 100644
index 0000000..42cfd12
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexTestUtil.java
@@ -0,0 +1,167 @@
+/*
+ * 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.jdbc.PhoenixDatabaseMetaData.COLUMN_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_FAMILY;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TENANT_ID;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.Mutation;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import com.google.common.collect.Lists;
+
+import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PColumnFamily;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PRow;
+import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.RowKeySchema;
+import org.apache.phoenix.util.IndexUtil;
+import org.apache.phoenix.util.MetaDataUtil;
+import org.apache.phoenix.util.SchemaUtil;
+
+public class IndexTestUtil {
+
+ // the normal db metadata interface is insufficient for all fields needed for an
+ // index table test.
+ private static final String SELECT_DATA_INDEX_ROW = "SELECT " + COLUMN_FAMILY
+ + " FROM "
+ + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_CATALOG_TABLE
+ + "\" WHERE "
+ + TENANT_ID + " IS NULL AND " + TABLE_SCHEM + "=? AND " + TABLE_NAME + "=? AND " + COLUMN_NAME + " IS NULL AND " + COLUMN_FAMILY + "=?";
+
+ public static ResultSet readDataTableIndexRow(Connection conn, String schemaName, String tableName, String indexName) throws SQLException {
+ PreparedStatement stmt = conn.prepareStatement(SELECT_DATA_INDEX_ROW);
+ stmt.setString(1, schemaName);
+ stmt.setString(2, tableName);
+ stmt.setString(3, indexName);
+ return stmt.executeQuery();
+ }
+
+
+ private static void coerceDataValueToIndexValue(PColumn dataColumn, PColumn indexColumn, ImmutableBytesWritable ptr) {
+ PDataType dataType = dataColumn.getDataType();
+ // TODO: push to RowKeySchema?
+ SortOrder dataModifier = dataColumn.getSortOrder();
+ PDataType indexType = indexColumn.getDataType();
+ SortOrder indexModifier = indexColumn.getSortOrder();
+ // We know ordinal position will match pk position, because you cannot
+ // alter an index table.
+ indexType.coerceBytes(ptr, dataType, dataModifier, indexModifier);
+ }
+
+ public static List<Mutation> generateIndexData(PTable index, PTable table,
+ List<Mutation> dataMutations, ImmutableBytesWritable ptr, KeyValueBuilder builder)
+ throws SQLException {
+ List<Mutation> indexMutations = Lists.newArrayListWithExpectedSize(dataMutations.size());
+ for (Mutation dataMutation : dataMutations) {
+ indexMutations.addAll(generateIndexData(index, table, dataMutation, ptr, builder));
+ }
+ return indexMutations;
+ }
+
+ public static List<Mutation> generateIndexData(PTable indexTable, PTable dataTable,
+ Mutation dataMutation, ImmutableBytesWritable ptr, KeyValueBuilder builder)
+ throws SQLException {
+ byte[] dataRowKey = dataMutation.getRow();
+ RowKeySchema dataRowKeySchema = dataTable.getRowKeySchema();
+ List<PColumn> dataPKColumns = dataTable.getPKColumns();
+ int i = 0;
+ int indexOffset = 0;
+ Boolean hasValue;
+ // Skip salt column
+ int maxOffset = dataRowKey.length;
+ dataRowKeySchema.iterator(dataRowKey, ptr, dataTable.getBucketNum() == null ? i : ++i);
+ List<PColumn> indexPKColumns = indexTable.getPKColumns();
+ List<PColumn> indexColumns = indexTable.getColumns();
+ int nIndexColumns = indexPKColumns.size();
+ int maxIndexValues = indexColumns.size() - nIndexColumns - indexOffset;
+ BitSet indexValuesSet = new BitSet(maxIndexValues);
+ byte[][] indexValues = new byte[indexColumns.size() - indexOffset][];
+ while ((hasValue = dataRowKeySchema.next(ptr, i, maxOffset)) != null) {
+ if (hasValue) {
+ PColumn dataColumn = dataPKColumns.get(i);
+ PColumn indexColumn = indexTable.getColumn(IndexUtil.getIndexColumnName(dataColumn));
+ coerceDataValueToIndexValue(dataColumn, indexColumn, ptr);
+ indexValues[indexColumn.getPosition()-indexOffset] = ptr.copyBytes();
+ }
+ i++;
+ }
+ PRow row;
+ long ts = MetaDataUtil.getClientTimeStamp(dataMutation);
+ if (dataMutation instanceof Delete && dataMutation.getFamilyMap().values().isEmpty()) {
+ indexTable.newKey(ptr, indexValues);
+ row = indexTable.newRow(builder, ts, ptr);
+ row.delete();
+ } else {
+ // If no column families in table, then nothing to look for
+ if (!dataTable.getColumnFamilies().isEmpty()) {
+ for (Map.Entry<byte[],List<KeyValue>> entry : dataMutation.getFamilyMap().entrySet()) {
+ PColumnFamily family = dataTable.getColumnFamily(entry.getKey());
+ for (KeyValue kv : entry.getValue()) {
+ byte[] cq = kv.getQualifier();
+ if (Bytes.compareTo(QueryConstants.EMPTY_COLUMN_BYTES, cq) != 0) {
+ try {
+ PColumn dataColumn = family.getColumn(cq);
+ PColumn indexColumn = indexTable.getColumn(IndexUtil.getIndexColumnName(family.getName().getString(), dataColumn.getName().getString()));
+ ptr.set(kv.getBuffer(),kv.getValueOffset(),kv.getValueLength());
+ coerceDataValueToIndexValue(dataColumn, indexColumn, ptr);
+ indexValues[indexPKColumns.indexOf(indexColumn)-indexOffset] = ptr.copyBytes();
+ if (!SchemaUtil.isPKColumn(indexColumn)) {
+ indexValuesSet.set(indexColumn.getPosition()-nIndexColumns-indexOffset);
+ }
+ } catch (ColumnNotFoundException e) {
+ // Ignore as this means that the data column isn't in the index
+ }
+ }
+ }
+ }
+ }
+ indexTable.newKey(ptr, indexValues);
+ row = indexTable.newRow(builder, ts, ptr);
+ int pos = 0;
+ while ((pos = indexValuesSet.nextSetBit(pos)) >= 0) {
+ int index = nIndexColumns + indexOffset + pos++;
+ PColumn indexColumn = indexColumns.get(index);
+ row.setValue(indexColumn, indexValues[index]);
+ }
+ }
+ return row.toRowMutations();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/8d6e2a58/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexFailureIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexFailureIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexFailureIT.java
new file mode 100644
index 0000000..7bb9776
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexFailureIT.java
@@ -0,0 +1,124 @@
+/*
+ * 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.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.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.TableNotFoundException;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Maps;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.query.ConnectionQueryServices;
+import org.apache.phoenix.schema.PIndexState;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.StringUtil;
+
+/**
+ *
+ * Test for failure of region server to write to index table. Keep in its own
+ * separate test, as otherwise it makes tests run after it fail.
+ *
+ *
+ * @since 2.1
+ */
+public class MutableIndexFailureIT extends BaseMutableIndexIT {
+ @BeforeClass
+ public static void doSetup() throws Exception {
+ Map<String,String> props = Maps.newHashMapWithExpectedSize(1);
+ props.put("hbase.client.retries.number", Integer.toString(2));
+ props.put("hbase.client.pause", Integer.toString(5000));
+ // Must update config before starting server
+ startServer(getUrl(), new ReadOnlyProps(props.entrySet().iterator()));
+ }
+
+
+ private static void destroyIndexTable() throws Exception {
+ Properties props = new Properties(TEST_PROPERTIES);
+ ConnectionQueryServices services = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class).getQueryServices();
+ HBaseAdmin admin = services.getAdmin();
+ try {
+ admin.disableTable(INDEX_TABLE_FULL_NAME);
+ admin.deleteTable(INDEX_TABLE_FULL_NAME);
+ } catch (TableNotFoundException e) {
+ } finally {
+ admin.close();
+ }
+ }
+
+ @Test
+ public void testWriteFailureDisablesIndex() throws Exception {
+ String query;
+ ResultSet rs;
+
+ Properties props = new Properties(TEST_PROPERTIES);
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ conn.setAutoCommit(false);
+ conn.createStatement().execute("CREATE TABLE " + DATA_TABLE_FULL_NAME + " (k VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, v2 VARCHAR)");
+ query = "SELECT * FROM " + DATA_TABLE_FULL_NAME;
+ rs = conn.createStatement().executeQuery(query);
+ assertFalse(rs.next());
+
+ conn.createStatement().execute("CREATE INDEX " + INDEX_TABLE_NAME + " ON " + DATA_TABLE_FULL_NAME + " (v1) INCLUDE (v2)");
+ query = "SELECT * FROM " + INDEX_TABLE_FULL_NAME;
+ rs = conn.createStatement().executeQuery(query);
+ assertFalse(rs.next());
+
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(SCHEMA_NAME), INDEX_TABLE_NAME, new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals(INDEX_TABLE_NAME, rs.getString(3));
+ assertEquals(PIndexState.ACTIVE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+
+ destroyIndexTable();
+
+ PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + DATA_TABLE_FULL_NAME + " VALUES(?,?,?)");
+ stmt.setString(1,"a");
+ stmt.setString(2, "x");
+ stmt.setString(3, "1");
+ stmt.execute();
+ try {
+ conn.commit();
+ fail();
+ } catch (SQLException e) {
+ }
+
+ // Verify the metadata for index is correct.
+ rs = conn.getMetaData().getTables(null, StringUtil.escapeLike(SCHEMA_NAME), INDEX_TABLE_NAME, new String[] {PTableType.INDEX.toString()});
+ assertTrue(rs.next());
+ assertEquals(INDEX_TABLE_NAME, rs.getString(3));
+ assertEquals(PIndexState.DISABLE.toString(), rs.getString("INDEX_STATE"));
+ assertFalse(rs.next());
+ }
+}
\ No newline at end of file