Return-Path: X-Original-To: apmail-phoenix-commits-archive@minotaur.apache.org Delivered-To: apmail-phoenix-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 758741042C for ; Wed, 5 Mar 2014 22:57:37 +0000 (UTC) Received: (qmail 90148 invoked by uid 500); 5 Mar 2014 22:56:25 -0000 Delivered-To: apmail-phoenix-commits-archive@phoenix.apache.org Received: (qmail 89256 invoked by uid 500); 5 Mar 2014 22:55:52 -0000 Mailing-List: contact commits-help@phoenix.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@phoenix.incubator.apache.org Delivered-To: mailing list commits@phoenix.incubator.apache.org Received: (qmail 88526 invoked by uid 99); 5 Mar 2014 22:55:34 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Mar 2014 22:55:34 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,RP_MATCHES_RCVD X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 05 Mar 2014 22:55:27 +0000 Received: (qmail 86691 invoked by uid 99); 5 Mar 2014 22:54:51 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Mar 2014 22:54:51 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 3AC64937E29; Wed, 5 Mar 2014 22:54:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jeffreyz@apache.org To: commits@phoenix.incubator.apache.org Date: Wed, 05 Mar 2014 22:55:31 -0000 Message-Id: <670857fad3b64f7fb378693137ecd607@git.apache.org> In-Reply-To: <6712aa6a6ff5432cb9414eaff469087b@git.apache.org> References: <6712aa6a6ff5432cb9414eaff469087b@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [45/50] [abbrv] git commit: PHOENIX-108 More testing around multi-tenancy X-Virus-Checked: Checked by ClamAV on apache.org PHOENIX-108 More testing around multi-tenancy Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/953795c7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/953795c7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/953795c7 Branch: refs/heads/4.0 Commit: 953795c7457ae2132bc8799fd7daaf41dc3de574 Parents: 6228d0b Author: Eli Levine Authored: Tue Mar 4 17:34:46 2014 -0800 Committer: Eli Levine Committed: Tue Mar 4 17:34:46 2014 -0800 ---------------------------------------------------------------------- .../BaseTenantSpecificViewIndexTest.java | 119 +++++++++++++++---- .../end2end/TenantSpecificTablesDDLTest.java | 26 +++- .../TenantSpecificViewIndexSaltedTest.java | 6 +- .../end2end/TenantSpecificViewIndexTest.java | 4 + .../org/apache/phoenix/end2end/ViewTest.java | 35 ++++++ 5 files changed, 160 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/953795c7/phoenix-core/src/test/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexTest.java index 309f5a7..444b669 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexTest.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.end2end; +import static com.google.common.collect.Sets.newHashSet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -24,62 +25,130 @@ import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.Properties; +import java.util.Set; +import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.util.PhoenixRuntime; import org.apache.phoenix.util.QueryUtil; +import org.junit.After; public class BaseTenantSpecificViewIndexTest extends BaseHBaseManagedTimeTest { + + public static final String TENANT1_ID = "tenant1"; + public static final String TENANT2_ID = "tenant2"; + + protected Set> tenantViewsToDelete = newHashSet(); + protected void testUpdatableView(Integer saltBuckets) throws Exception { + createBaseTable("t", saltBuckets); + Connection conn = createTenantConnection(TENANT1_ID); + try { + createAndPopulateTenantView(conn, TENANT1_ID, "t", ""); + createAndVerifyIndex(conn, saltBuckets, TENANT1_ID, ""); + verifyViewData(conn, ""); + } finally { + try { conn.close();} catch (Exception ignored) {} + } + } + + protected void testUpdatableViewsWithSameNameDifferentTenants(Integer saltBuckets) throws Exception { + createBaseTable("t2", saltBuckets); + Connection conn1 = createTenantConnection(TENANT1_ID); + Connection conn2 = createTenantConnection(TENANT2_ID); + try { + String prefixForTenant1Data = "TI"; + String prefixForTenant2Data = "TII"; + + // tenant views with same name for two different tables + createAndPopulateTenantView(conn1, TENANT1_ID, "t2", prefixForTenant1Data); + createAndPopulateTenantView(conn2, TENANT2_ID, "t2", prefixForTenant2Data); + + createAndVerifyIndex(conn1, saltBuckets, TENANT1_ID, prefixForTenant1Data); + createAndVerifyIndex(conn2, saltBuckets, TENANT2_ID, prefixForTenant2Data); + + verifyViewData(conn1, prefixForTenant1Data); + verifyViewData(conn2, prefixForTenant2Data); + } finally { + try { conn1.close();} catch (Exception ignored) {} + try { conn2.close();} catch (Exception ignored) {} + } + } + + private void createBaseTable(String tableName, Integer saltBuckets) throws SQLException { Connection conn = DriverManager.getConnection(getUrl()); - String ddl = "CREATE TABLE t (t_id VARCHAR NOT NULL,\n" + - "k1 INTEGER NOT NULL,\n" + - "k2 INTEGER NOT NULL,\n" + - "v1 VARCHAR,\n" + - "CONSTRAINT pk PRIMARY KEY (t_id, k1, k2))\n" + - "multi_tenant=true" + (saltBuckets == null ? "" : (",salt_buckets="+saltBuckets)); + String ddl = "CREATE TABLE " + tableName + " (t_id VARCHAR NOT NULL,\n" + + "k1 INTEGER NOT NULL,\n" + + "k2 INTEGER NOT NULL,\n" + + "v1 VARCHAR,\n" + + "CONSTRAINT pk PRIMARY KEY (t_id, k1, k2))\n" + + "multi_tenant=true" + (saltBuckets == null ? "" : (",salt_buckets="+saltBuckets)); conn.createStatement().execute(ddl); conn.close(); - - Properties props = new Properties(); - props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, "me"); - conn = DriverManager.getConnection(getUrl(), props); - ddl = "CREATE VIEW v(v2 VARCHAR) AS SELECT * FROM t WHERE k1 = 1"; + } + + private void createAndPopulateTenantView(Connection conn, String tenantId, String baseTable, String valuePrefix) throws SQLException { + String ddl = "CREATE VIEW v(v2 VARCHAR) AS SELECT * FROM " + baseTable + " WHERE k1 = 1"; conn.createStatement().execute(ddl); + tenantViewsToDelete.add(new Pair(tenantId, "v")); for (int i = 0; i < 10; i++) { - conn.createStatement().execute("UPSERT INTO v(k2,v1,v2) VALUES(" + i + ",'v1-" + (i%5) + "','v2-" + (i%2) + "')"); + conn.createStatement().execute("UPSERT INTO v(k2,v1,v2) VALUES(" + i + ",'" + valuePrefix + "v1-" + (i%5) + "','" + valuePrefix + "v2-" + (i%2) + "')"); } conn.commit(); - + } + + private void createAndVerifyIndex(Connection conn, Integer saltBuckets, String tenantId, String valuePrefix) throws SQLException { conn.createStatement().execute("CREATE INDEX i ON v(v2)"); - - String query = "SELECT k1, k2, v2 FROM v WHERE v2='v2-1'"; + ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT k1, k2, v2 FROM v WHERE v2='" + valuePrefix + "v2-1'"); + assertEquals(saltBuckets == null ? + "CLIENT PARALLEL 1-WAY RANGE SCAN OVER I ['" + tenantId + "',-32768,'" + valuePrefix + "v2-1']" : + "CLIENT PARALLEL 4-WAY SKIP SCAN ON 3 KEYS OVER I [0,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1'] - [2,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1']\n" + + "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + } + + private Connection createTenantConnection(String tenantId) throws SQLException { + Properties props = new Properties(); + props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId); + return DriverManager.getConnection(getUrl(), props); + } + + private void verifyViewData(Connection conn, String valuePrefix) throws SQLException { + String query = "SELECT k1, k2, v2 FROM v WHERE v2='" + valuePrefix + "v2-1'"; ResultSet rs = conn.createStatement().executeQuery(query); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(1, rs.getInt(2)); - assertEquals("v2-1", rs.getString(3)); + assertEquals(valuePrefix + "v2-1", rs.getString(3)); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(3, rs.getInt(2)); - assertEquals("v2-1", rs.getString(3)); + assertEquals(valuePrefix + "v2-1", rs.getString(3)); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(5, rs.getInt(2)); - assertEquals("v2-1", rs.getString(3)); + assertEquals(valuePrefix + "v2-1", rs.getString(3)); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(7, rs.getInt(2)); - assertEquals("v2-1", rs.getString(3)); + assertEquals(valuePrefix + "v2-1", rs.getString(3)); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(9, rs.getInt(2)); - assertEquals("v2-1", rs.getString(3)); + assertEquals(valuePrefix + "v2-1", rs.getString(3)); assertFalse(rs.next()); - rs = conn.createStatement().executeQuery("EXPLAIN " + query); - assertEquals(saltBuckets == null ? - "CLIENT PARALLEL 1-WAY RANGE SCAN OVER I ['me',-32768,'v2-1']" : - "CLIENT PARALLEL 4-WAY SKIP SCAN ON 3 KEYS OVER I [0,'me',-32768,'v2-1'] - [2,'me',-32768,'v2-1']\n" + - "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + } + + @After + public void deleteTenantViews() throws Exception { + for (Pair tenantView : tenantViewsToDelete) { + try { + Connection conn = createTenantConnection(tenantView.getFirst()); + conn.createStatement().executeUpdate("drop view " + tenantView.getSecond()); + conn.close(); + } + catch (Exception ignored) {} + } + tenantViewsToDelete.clear(); } } http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/953795c7/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLTest.java index 1d98d8f..1eb1720 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLTest.java @@ -346,6 +346,11 @@ public class TenantSpecificTablesDDLTest extends BaseTenantSpecificTablesTest { @Test public void testTableMetadataScan() throws Exception { + // create a tenant table with same name for a different tenant to make sure we are not picking it up in metadata scans for TENANT_ID + String secondTenantId = "tenant2"; + String secondTenatConnectionURL = PHOENIX_JDBC_TENANT_SPECIFIC_URL.replace(TENANT_ID, secondTenantId); + createTestTable(secondTenatConnectionURL, TENANT_TABLE_DDL, null, nextTimestamp(), false); + Properties props = new Properties(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); Connection conn = DriverManager.getConnection(getUrl(), props); @@ -370,12 +375,16 @@ public class TenantSpecificTablesDDLTest extends BaseTenantSpecificTablesTest { assertNotEquals(TENANT_TABLE_NAME, rs.getString("TABLE_NAME")); } - // null means across all tenant_ids + // null catalog means across all tenant_ids rs = meta.getSuperTables(null, null, StringUtil.escapeLike(TENANT_TABLE_NAME)); assertTrue(rs.next()); assertEquals(TENANT_ID, rs.getString(PhoenixDatabaseMetaData.TABLE_CAT)); assertEquals(TENANT_TABLE_NAME, rs.getString(PhoenixDatabaseMetaData.TABLE_NAME)); assertEquals(PARENT_TABLE_NAME, rs.getString(PhoenixDatabaseMetaData.SUPERTABLE_NAME)); + assertTrue(rs.next()); + assertEquals(secondTenantId, rs.getString(PhoenixDatabaseMetaData.TABLE_CAT)); + assertEquals(TENANT_TABLE_NAME, rs.getString(PhoenixDatabaseMetaData.TABLE_NAME)); + assertEquals(PARENT_TABLE_NAME, rs.getString(PhoenixDatabaseMetaData.SUPERTABLE_NAME)); assertFalse(rs.next()); conn.close(); @@ -395,9 +404,18 @@ public class TenantSpecificTablesDDLTest extends BaseTenantSpecificTablesTest { rs = conn.getMetaData().getCatalogs(); assertTrue(rs.next()); assertEquals(TENANT_ID, rs.getString(PhoenixDatabaseMetaData.TABLE_CAT)); + assertTrue(rs.next()); + assertEquals(secondTenantId, rs.getString(PhoenixDatabaseMetaData.TABLE_CAT)); assertFalse(rs.next()); - } - finally { + } finally { + props.clear(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); + Connection secondTenantCon = DriverManager.getConnection(secondTenatConnectionURL, props); + try { + secondTenantCon.createStatement().executeUpdate("drop view " + TENANT_TABLE_NAME); + } finally { + try {secondTenantCon.close();} catch (Exception ignored) {} + } conn.close(); } @@ -451,4 +469,4 @@ public class TenantSpecificTablesDDLTest extends BaseTenantSpecificTablesTest { assertEquals(table, rs.getString("TABLE_NAME")); assertEquals(SchemaUtil.normalizeIdentifier(column), rs.getString("COLUMN_NAME")); } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/953795c7/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java index ce4a2cf..748fa3e 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexSaltedTest.java @@ -9,5 +9,9 @@ public class TenantSpecificViewIndexSaltedTest extends BaseTenantSpecificViewInd public void testUpdatableSaltedView() throws Exception { testUpdatableView(SALT_BUCKETS); } - + + @Test + public void testUpdatableViewsWithSameNameDifferentTenants() throws Exception { + testUpdatableViewsWithSameNameDifferentTenants(SALT_BUCKETS); + } } http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/953795c7/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java index 49a5a40..18d70d5 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/TenantSpecificViewIndexTest.java @@ -25,4 +25,8 @@ public class TenantSpecificViewIndexTest extends BaseTenantSpecificViewIndexTest testUpdatableView(null); } + @Test + public void testUpdatableViewsWithSameNameDifferentTenants() throws Exception { + testUpdatableViewsWithSameNameDifferentTenants(null); + } } http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/953795c7/phoenix-core/src/test/java/org/apache/phoenix/end2end/ViewTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/end2end/ViewTest.java b/phoenix-core/src/test/java/org/apache/phoenix/end2end/ViewTest.java index b82506c..f81b589 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/end2end/ViewTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/end2end/ViewTest.java @@ -182,4 +182,39 @@ public class ViewTest extends BaseViewTest { 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); + } }