/* * 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()); } } } }