| /* |
| * 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.fail; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.apache.hadoop.hbase.DoNotRetryIOException; |
| import org.apache.hadoop.hbase.HBaseTestingUtility; |
| import org.apache.hadoop.hbase.TableName; |
| import org.apache.hadoop.hbase.client.RegionLocator; |
| import org.apache.phoenix.exception.SQLExceptionCode; |
| import org.apache.phoenix.query.BaseTest; |
| import org.apache.phoenix.query.QueryServices; |
| import org.apache.phoenix.util.PhoenixRuntime; |
| import org.apache.phoenix.util.ReadOnlyProps; |
| import org.apache.phoenix.util.SchemaUtil; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import com.google.common.collect.Maps; |
| |
| @Category(NeedsOwnMiniClusterTest.class) |
| public class SystemCatalogIT extends BaseTest { |
| private HBaseTestingUtility testUtil = null; |
| |
| @BeforeClass |
| public static synchronized void doSetup() throws Exception { |
| Map<String, String> serverProps = Maps.newHashMapWithExpectedSize(1); |
| serverProps.put(QueryServices.SYSTEM_CATALOG_SPLITTABLE, "false"); |
| serverProps.put(QueryServices.ALLOW_SPLITTABLE_SYSTEM_CATALOG_ROLLBACK, "true"); |
| Map<String, String> clientProps = Collections.emptyMap(); |
| setUpTestDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), |
| new ReadOnlyProps(clientProps.entrySet().iterator())); |
| } |
| |
| /** |
| * Make sure that SYSTEM.CATALOG cannot be split if QueryServices.SYSTEM_CATALOG_SPLITTABLE is false |
| */ |
| @Test |
| public void testSystemTableSplit() throws Exception { |
| testUtil = getUtility(); |
| for (int i=0; i<10; i++) { |
| createTable("schema"+i+".table_"+i); |
| } |
| TableName systemCatalog = TableName.valueOf("SYSTEM.CATALOG"); |
| RegionLocator rl = testUtil.getConnection().getRegionLocator(systemCatalog); |
| assertEquals(rl.getAllRegionLocations().size(), 1); |
| try { |
| // now attempt to split SYSTEM.CATALOG |
| testUtil.getAdmin().split(systemCatalog); |
| // make sure the split finishes (there's no synchronous splitting before HBase 2.x) |
| testUtil.getAdmin().disableTable(systemCatalog); |
| testUtil.getAdmin().enableTable(systemCatalog); |
| } catch (DoNotRetryIOException e) { |
| // table is not splittable |
| assert (e.getMessage().contains("NOT splittable")); |
| } |
| |
| // test again... Must still be exactly one region. |
| rl = testUtil.getConnection().getRegionLocator(systemCatalog); |
| assertEquals(1, rl.getAllRegionLocations().size()); |
| } |
| |
| private void createTable(String tableName) throws Exception { |
| try (Connection conn = DriverManager.getConnection(getJdbcUrl()); |
| Statement stmt = conn.createStatement();) { |
| stmt.execute("DROP TABLE IF EXISTS " + tableName); |
| stmt.execute("CREATE TABLE " + tableName |
| + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR CONSTRAINT PK " + |
| "PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT=true"); |
| try (Connection tenant1Conn = getTenantConnection("tenant1")) { |
| String view1DDL = "CREATE VIEW " + tableName + "_view AS SELECT * FROM " + tableName; |
| tenant1Conn.createStatement().execute(view1DDL); |
| } |
| conn.commit(); |
| } |
| } |
| |
| private String getJdbcUrl() { |
| return "jdbc:phoenix:localhost:" + getUtility().getZkCluster().getClientPort() + ":/hbase"; |
| } |
| |
| private Connection getTenantConnection(String tenantId) throws SQLException { |
| Properties tenantProps = new Properties(); |
| tenantProps.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId); |
| return DriverManager.getConnection(getJdbcUrl(), tenantProps); |
| } |
| |
| /** |
| * Ensure that we cannot add a column to a base table if QueryServices.BLOCK_METADATA_CHANGES_REQUIRE_PROPAGATION |
| * is true |
| */ |
| @Test |
| public void testAddingColumnFails() throws Exception { |
| try (Connection conn = DriverManager.getConnection(getJdbcUrl())) { |
| String fullTableName = SchemaUtil.getTableName(generateUniqueName(), generateUniqueName()); |
| String fullViewName = SchemaUtil.getTableName(generateUniqueName(), generateUniqueName()); |
| String ddl = "CREATE TABLE " + fullTableName + " (k1 INTEGER NOT NULL, v1 INTEGER " + |
| "CONSTRAINT pk PRIMARY KEY (k1))"; |
| conn.createStatement().execute(ddl); |
| |
| ddl = "CREATE VIEW " + fullViewName + " AS SELECT * FROM " + fullTableName; |
| conn.createStatement().execute(ddl); |
| |
| try { |
| ddl = "ALTER TABLE " + fullTableName + " ADD v2 INTEGER"; |
| conn.createStatement().execute(ddl); |
| fail(); |
| } |
| catch (SQLException e) { |
| assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode()); |
| } |
| } |
| } |
| } |