Source:
public void testConcurrentAddColumn() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); String fullViewName = SchemaUtil.getTableName(SCHEMA2, SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName()); String tableDdl = "CREATE TABLE " + fullTableName + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)" + tableDDLOptions; conn.createStatement().execute(tableDdl); String ddl = "CREATE VIEW " + fullViewName + " (v2 VARCHAR) AS SELECT * FROM " + fullTableName + " WHERE k = 6"; conn.createStatement().execute(ddl); latch1 = new CountDownLatch(1); latch2 = new CountDownLatch(1); ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); t.setDaemon(true); t.setPriority(Thread.MIN_PRIORITY); return t; } }); Future<Exception> future = executorService.submit(new AddColumnRunnable(fullViewName)); boolean result = latch1.await(2, TimeUnit.MINUTES); if (!result) { fail("The create view rpc look too long"); } tableDdl = "ALTER TABLE " + fullTableName + " ADD v3 INTEGER"; try { conn.createStatement().execute(tableDdl); fail("Creating a view while concurrently dropping the base table should fail"); } catch (ConcurrentTableMutationException e) { } latch2.countDown(); Exception e = future.get(); assertTrue(e == null); tableDdl = "ALTER TABLE " + fullTableName + " ADD v4 INTEGER"; } }

Target:
public void testConcurrentAddColumn() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); String fullViewName1 = SchemaUtil.getTableName(SCHEMA2, SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName()); String fullViewName2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); String tableDdl = "CREATE TABLE " + fullTableName + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)" + tableDDLOptions; conn.createStatement().execute(tableDdl); String ddl = "CREATE VIEW " + fullViewName1 + " (v2 VARCHAR) AS SELECT * FROM " + fullTableName + " WHERE k = 6"; conn.createStatement().execute(ddl); latch1 = new CountDownLatch(1); latch2 = new CountDownLatch(1); ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); t.setDaemon(true); t.setPriority(Thread.MIN_PRIORITY); return t; } }); Future<Exception> future = executorService.submit(new AddColumnRunnable(fullViewName1)); boolean result = latch1.await(2, TimeUnit.MINUTES); if (!result) { fail("The create view rpc look too long"); } tableDdl = "ALTER TABLE " + fullTableName + " ADD v3 INTEGER"; try { conn.createStatement().execute(tableDdl); fail("Creating a view while concurrently dropping the base table should fail"); } catch (ConcurrentTableMutationException e) { } latch2.countDown(); Exception e = future.get(); assertNull(e); ddl = "CREATE VIEW " + fullViewName2 + " (v2 VARCHAR) AS SELECT * FROM " + fullTableName + " WHERE k = 6"; conn.createStatement().execute(ddl); tableDdl = "ALTER VIEW " + fullViewName2 + " ADD v3 INTEGER"; conn.createStatement().execute(tableDdl); } }