@Test public void testParallelUpsertSelect() throws Exception { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); props.setProperty(QueryServices.MUTATE_BATCH_SIZE_ATTRIB, Integer.toString(3)); props.setProperty(QueryServices.SCAN_CACHE_SIZE_ATTRIB, Integer.toString(3)); props.setProperty(QueryServices.SCAN_RESULT_CHUNK_SIZE, Integer.toString(3)); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(false); conn.createStatement().execute("CREATE SEQUENCE S1"); conn.createStatement() .execute( "CREATE TABLE SALTEDT1 (pk INTEGER PRIMARY KEY, val INTEGER) SALT_BUCKETS=4,TRANSACTIONAL=true"); conn.createStatement() .execute("CREATE TABLE T2 (pk INTEGER PRIMARY KEY, val INTEGER) TRANSACTIONAL=true"); for (int i = 0; i < 100; i++) { conn.createStatement() .execute("UPSERT INTO SALTEDT1 VALUES (NEXT VALUE FOR S1, " + (i % 10) + ")"); } conn.commit(); conn.setAutoCommit(true); int upsertCount = conn.createStatement().executeUpdate("UPSERT INTO T2 SELECT pk, val FROM SALTEDT1"); assertEquals(100, upsertCount); conn.close(); }
@Test public void testRowTimestampDisabled() throws SQLException { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); try (Connection conn = DriverManager.getConnection(getUrl(), props)) { conn.setAutoCommit(false); Statement stmt = conn.createStatement(); try { stmt.execute( "CREATE TABLE DEMO(k VARCHAR, v VARCHAR, d DATE NOT NULL, CONSTRAINT PK PRIMARY KEY(k,d ROW_TIMESTAMP)) TRANSACTIONAL=true"); fail(); } catch (SQLException e) { assertEquals( SQLExceptionCode.CANNOT_CREATE_TXN_TABLE_WITH_ROW_TIMESTAMP.getErrorCode(), e.getErrorCode()); } stmt.execute( "CREATE TABLE DEMO(k VARCHAR, v VARCHAR, d DATE NOT NULL, CONSTRAINT PK PRIMARY KEY(k,d ROW_TIMESTAMP))"); try { stmt.execute("ALTER TABLE DEMO SET TRANSACTIONAL=true"); fail(); } catch (SQLException e) { assertEquals( SQLExceptionCode.CANNOT_ALTER_TO_BE_TXN_WITH_ROW_TIMESTAMP.getErrorCode(), e.getErrorCode()); } } }
@Test public void testQueryWithLimitAndStats() throws Exception { long ts = nextTimestamp(); ensureTableCreated(getUrl(), KEYONLY_NAME, null, ts); initTableValues(ts + 1, 100); TestUtil.analyzeTable(getUrl(), ts + 10, KEYONLY_NAME); Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 50)); Connection conn = DriverManager.getConnection(getUrl(), props); String query = "SELECT i1 FROM KEYONLY LIMIT 1"; ResultSet rs = conn.createStatement().executeQuery(query); assertTrue(rs.next()); assertEquals(0, rs.getInt(1)); assertFalse(rs.next()); rs = conn.createStatement().executeQuery("EXPLAIN " + query); assertEquals( "CLIENT SERIAL 1-WAY FULL SCAN OVER KEYONLY\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + " SERVER 1 ROW LIMIT\n" + "CLIENT 1 ROW LIMIT", QueryUtil.getExplainPlan(rs)); conn.close(); }
@Test public void testCreateTenantSpecificTable() throws Exception { // ensure we didn't create a physical HBase table for the tenant-specific table HBaseAdmin admin = driver .getConnectionQueryServices(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES)) .getAdmin(); assertEquals(0, admin.listTables(TENANT_TABLE_NAME).length); }
@Test public void testCreateTableToBeTransactional() throws Exception { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); String ddl = "CREATE TABLE TEST_TRANSACTIONAL_TABLE (k varchar primary key) transactional=true"; conn.createStatement().execute(ddl); PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class); PTable table = pconn.getTable(new PTableKey(null, "TEST_TRANSACTIONAL_TABLE")); HTableInterface htable = pconn.getQueryServices().getTable(Bytes.toBytes("TEST_TRANSACTIONAL_TABLE")); assertTrue(table.isTransactional()); assertTrue( htable .getTableDescriptor() .getCoprocessors() .contains(TransactionProcessor.class.getName())); try { ddl = "ALTER TABLE TEST_TRANSACTIONAL_TABLE SET transactional=false"; conn.createStatement().execute(ddl); fail(); } catch (SQLException e) { assertEquals(SQLExceptionCode.TX_MAY_NOT_SWITCH_TO_NON_TX.getErrorCode(), e.getErrorCode()); } HBaseAdmin admin = pconn.getQueryServices().getAdmin(); HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("TXN_TEST_EXISTING")); desc.addFamily(new HColumnDescriptor(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES)); admin.createTable(desc); ddl = "CREATE TABLE TXN_TEST_EXISTING (k varchar primary key) transactional=true"; conn.createStatement().execute(ddl); assertEquals( Boolean.TRUE.toString(), admin .getTableDescriptor(TableName.valueOf("TXN_TEST_EXISTING")) .getValue(TxConstants.READ_NON_TX_DATA)); // Should be ok, as HBase metadata should match existing metadata. ddl = "CREATE TABLE IF NOT EXISTS TEST_TRANSACTIONAL_TABLE (k varchar primary key)"; try { conn.createStatement().execute(ddl); fail(); } catch (SQLException e) { assertEquals(SQLExceptionCode.TX_MAY_NOT_SWITCH_TO_NON_TX.getErrorCode(), e.getErrorCode()); } ddl += " transactional=true"; conn.createStatement().execute(ddl); table = pconn.getTable(new PTableKey(null, "TEST_TRANSACTIONAL_TABLE")); htable = pconn.getQueryServices().getTable(Bytes.toBytes("TEST_TRANSACTIONAL_TABLE")); assertTrue(table.isTransactional()); assertTrue( htable .getTableDescriptor() .getCoprocessors() .contains(TransactionProcessor.class.getName())); }
private static void startServer(String url) throws Exception { assertNull(driver); // only load the test driver if we are testing locally - for integration tests, we want to // test on a wider scale if (PhoenixEmbeddedDriver.isTestUrl(url)) { driver = initDriver(ReadOnlyProps.EMPTY_PROPS); assertTrue(DriverManager.getDriver(url) == driver); driver.connect(url, PropertiesUtil.deepCopy(TEST_PROPERTIES)); } }
@Test public void testFalseOrFalse() throws SQLException { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); ResultSet rs = conn.createStatement() .executeQuery("SELECT (FALSE OR FALSE) AS B FROM SYSTEM.CATALOG LIMIT 1"); assertTrue(rs.next()); assertFalse(rs.getBoolean(1)); conn.close(); }
protected static void initTableValues(long ts, int nRows) throws Exception { String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + ts; Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(url, props); PreparedStatement stmt = conn.prepareStatement("upsert into " + "KEYONLY VALUES (?, ?)"); for (int i = 0; i < nRows; i++) { stmt.setInt(1, i); stmt.setInt(2, i + 1); stmt.execute(); } conn.commit(); conn.close(); }
public static PhoenixTestDriver registerDriver(String url, ReadOnlyProps props) throws Exception { PhoenixTestDriver newDriver = new PhoenixTestDriver(props); DriverManager.registerDriver(newDriver); Driver oldDriver = DriverManager.getDriver(url); if (oldDriver != newDriver) { destroyDriver(oldDriver); } Properties driverProps = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = newDriver.connect(url, driverProps); conn.close(); return newDriver; }
@Test public void testCheckpointAndRollback() throws Exception { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(false); try { String fullTableName = "T"; Statement stmt = conn.createStatement(); stmt.execute( "CREATE TABLE " + fullTableName + "(k VARCHAR PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) TRANSACTIONAL=true"); stmt.executeUpdate("upsert into " + fullTableName + " values('x', 'a', 'a')"); conn.commit(); stmt.executeUpdate( "upsert into " + fullTableName + "(k,v1) SELECT k,v1||'a' FROM " + fullTableName); ResultSet rs = stmt.executeQuery("select k, v1, v2 from " + fullTableName); assertTrue(rs.next()); assertEquals("x", rs.getString(1)); assertEquals("aa", rs.getString(2)); assertEquals("a", rs.getString(3)); assertFalse(rs.next()); stmt.executeUpdate( "upsert into " + fullTableName + "(k,v1) SELECT k,v1||'a' FROM " + fullTableName); rs = stmt.executeQuery("select k, v1, v2 from " + fullTableName); assertTrue(rs.next()); assertEquals("x", rs.getString(1)); assertEquals("aaa", rs.getString(2)); assertEquals("a", rs.getString(3)); assertFalse(rs.next()); conn.rollback(); // assert original row exists in fullTableName1 rs = stmt.executeQuery("select k, v1, v2 from " + fullTableName); assertTrue(rs.next()); assertEquals("x", rs.getString(1)); assertEquals("a", rs.getString(2)); assertEquals("a", rs.getString(3)); assertFalse(rs.next()); } finally { conn.close(); } }
@Test public void testReCreateTxnTableAfterDroppingExistingNonTxnTable() throws SQLException { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(false); Statement stmt = conn.createStatement(); stmt.execute("CREATE TABLE DEMO(k VARCHAR PRIMARY KEY, v1 VARCHAR, v2 VARCHAR)"); stmt.execute("DROP TABLE DEMO"); stmt.execute( "CREATE TABLE DEMO(k VARCHAR PRIMARY KEY, v1 VARCHAR, v2 VARCHAR) TRANSACTIONAL=true"); stmt.execute("CREATE INDEX DEMO_IDX ON DEMO (v1) INCLUDE(v2)"); assertTrue( conn.unwrap(PhoenixConnection.class) .getTable(new PTableKey(null, "DEMO")) .isTransactional()); assertTrue( conn.unwrap(PhoenixConnection.class) .getTable(new PTableKey(null, "DEMO_IDX")) .isTransactional()); }
@Test public void testGetSplitsWithSkipScanFilter() throws Exception { byte[][] splits = new byte[][] {Ka1A, Ka1B, Ka1E, Ka1G, Ka1I, Ka2A}; createTestTable(getUrl(), DDL, splits, null); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class); PTable table = pconn.getMetaDataCache().getTable(new PTableKey(pconn.getTenantId(), TABLE_NAME)); TableRef tableRef = new TableRef(table); List<HRegionLocation> regions = pconn .getQueryServices() .getAllTableRegions(tableRef.getTable().getPhysicalName().getBytes()); List<KeyRange> ranges = getSplits(tableRef, scan, regions, scanRanges); assertEquals( "Unexpected number of splits: " + ranges.size(), expectedSplits.size(), ranges.size()); for (int i = 0; i < expectedSplits.size(); i++) { assertEquals(expectedSplits.get(i), ranges.get(i)); } }
// TODO: share this with ConnectionQueryServicesImpl @Override public void init(String url, Properties props) throws SQLException { if (initialized) { if (initializationException != null) { throw initializationException; } return; } synchronized (this) { if (initialized) { if (initializationException != null) { throw initializationException; } return; } SQLException sqlE = null; PhoenixConnection metaConnection = null; try { Properties scnProps = PropertiesUtil.deepCopy(props); scnProps.setProperty( PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(MetaDataProtocol.MIN_SYSTEM_TABLE_TIMESTAMP)); scnProps.remove(PhoenixRuntime.TENANT_ID_ATTRIB); String globalUrl = JDBCUtil.removeProperty(url, PhoenixRuntime.TENANT_ID_ATTRIB); metaConnection = new PhoenixConnection(this, globalUrl, scnProps, newEmptyMetaData()); try { metaConnection.createStatement().executeUpdate(QueryConstants.CREATE_TABLE_METADATA); } catch (TableAlreadyExistsException ignore) { // Ignore, as this will happen if the SYSTEM.TABLE already exists at this fixed timestamp. // A TableAlreadyExistsException is not thrown, since the table only exists *after* this // fixed timestamp. } try { int nSaltBuckets = getSequenceSaltBuckets(); String createTableStatement = Sequence.getCreateTableStatement(nSaltBuckets); metaConnection.createStatement().executeUpdate(createTableStatement); } catch (NewerTableAlreadyExistsException ignore) { // Ignore, as this will happen if the SYSTEM.SEQUENCE already exists at this fixed // timestamp. // A TableAlreadyExistsException is not thrown, since the table only exists *after* this // fixed timestamp. } try { metaConnection .createStatement() .executeUpdate(QueryConstants.CREATE_STATS_TABLE_METADATA); } catch (NewerTableAlreadyExistsException ignore) { // Ignore, as this will happen if the SYSTEM.SEQUENCE already exists at this fixed // timestamp. // A TableAlreadyExistsException is not thrown, since the table only exists *after* this // fixed timestamp. } try { metaConnection.createStatement().executeUpdate(QueryConstants.CREATE_FUNCTION_METADATA); } catch (NewerTableAlreadyExistsException ignore) { } } catch (SQLException e) { sqlE = e; } finally { try { if (metaConnection != null) metaConnection.close(); } catch (SQLException e) { if (sqlE != null) { sqlE.setNextException(e); } else { sqlE = e; } } finally { try { if (sqlE != null) { initializationException = sqlE; throw sqlE; } } finally { initialized = true; } } } } }
@Test public void testPKOrNotPKInOREvaluation() throws SQLException { Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(false); String create = "CREATE TABLE DIE ( ID INTEGER NOT NULL PRIMARY KEY,NAME VARCHAR(50))"; PreparedStatement createStmt = conn.prepareStatement(create); createStmt.execute(); PreparedStatement stmt = conn.prepareStatement("upsert into " + "DIE VALUES (?, ?)"); stmt.setInt(1, 1); stmt.setString(2, "Tester1"); stmt.execute(); stmt.setInt(1, 2); stmt.setString(2, "Tester2"); stmt.execute(); stmt.setInt(1, 3); stmt.setString(2, "Tester3"); stmt.execute(); stmt.setInt(1, 4); stmt.setString(2, "LikeTester1"); stmt.execute(); stmt.setInt(1, 5); stmt.setString(2, "LikeTester2"); stmt.execute(); stmt.setInt(1, 6); stmt.setString(2, "LikeTesterEnd"); stmt.execute(); stmt.setInt(1, 7); stmt.setString(2, "LikeTesterEnd2"); stmt.execute(); stmt.setInt(1, 8); stmt.setString(2, "Tester3"); stmt.execute(); stmt.setInt(1, 9); stmt.setString(2, "Tester4"); stmt.execute(); stmt.setInt(1, 10); stmt.setString(2, "Tester5"); stmt.execute(); stmt.setInt(1, 11); stmt.setString(2, "Tester6"); stmt.execute(); stmt.setInt(1, 12); stmt.setString(2, "tester6"); stmt.execute(); stmt.setInt(1, 13); stmt.setString(2, "lester1"); stmt.execute(); stmt.setInt(1, 14); stmt.setString(2, "le50ster1"); stmt.execute(); stmt.setInt(1, 15); stmt.setString(2, "LE50ster1"); stmt.execute(); stmt.setInt(1, 16); stmt.setString(2, "LiketesterEnd"); stmt.execute(); stmt.setInt(1, 17); stmt.setString(2, "la50ster1"); stmt.execute(); stmt.setInt(1, 18); stmt.setString(2, "lA50ster0"); stmt.execute(); stmt.setInt(1, 19); stmt.setString(2, "lA50ster2"); stmt.execute(); stmt.setInt(1, 20); stmt.setString(2, "la50ster0"); stmt.execute(); stmt.setInt(1, 21); stmt.setString(2, "la50ster2"); stmt.execute(); stmt.setInt(1, 22); stmt.setString(2, "La50ster3"); stmt.execute(); stmt.setInt(1, 23); stmt.setString(2, "la50ster3"); stmt.execute(); stmt.setInt(1, 24); stmt.setString(2, "l[50ster3"); stmt.execute(); stmt.setInt(1, 25); stmt.setString(2, "Tester1"); stmt.execute(); stmt.setInt(1, 26); stmt.setString(2, "Tester100"); stmt.execute(); conn.commit(); String select = "Select * from DIE where ID=6 or Name between 'Tester1' and 'Tester3'"; ResultSet rs; rs = conn.createStatement().executeQuery(select); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertTrue(rs.next()); assertEquals(2, rs.getInt(1)); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); assertTrue(rs.next()); assertEquals(6, rs.getInt(1)); assertTrue(rs.next()); assertEquals(8, rs.getInt(1)); assertTrue(rs.next()); assertEquals(25, rs.getInt(1)); assertTrue(rs.next()); assertEquals(26, rs.getInt(1)); conn.close(); }
@Test public void testExternalTxContext() throws Exception { ResultSet rs; Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(false); PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class); TransactionSystemClient txServiceClient = pconn.getQueryServices().getTransactionSystemClient(); String fullTableName = "T"; Statement stmt = conn.createStatement(); stmt.execute( "CREATE TABLE " + fullTableName + "(K VARCHAR PRIMARY KEY, V1 VARCHAR, V2 VARCHAR) TRANSACTIONAL=true"); HTableInterface htable = pconn.getQueryServices().getTable(Bytes.toBytes(fullTableName)); stmt.executeUpdate("upsert into " + fullTableName + " values('x', 'a', 'a')"); conn.commit(); try (Connection newConn = DriverManager.getConnection(getUrl(), props)) { rs = newConn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); } // Use HBase level Tephra APIs to start a new transaction TransactionAwareHTable txAware = new TransactionAwareHTable(htable, TxConstants.ConflictDetection.ROW); TransactionContext txContext = new TransactionContext(txServiceClient, txAware); txContext.start(); // Use HBase APIs to add a new row Put put = new Put(Bytes.toBytes("z")); put.addColumn( QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, QueryConstants.EMPTY_COLUMN_BYTES, QueryConstants.EMPTY_COLUMN_VALUE_BYTES); put.addColumn( QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, Bytes.toBytes("V1"), Bytes.toBytes("b")); txAware.put(put); // Use Phoenix APIs to add new row (sharing the transaction context) pconn.setTransactionContext(txContext); conn.createStatement().executeUpdate("upsert into " + fullTableName + " values('y', 'c', 'c')"); // New connection should not see data as it hasn't been committed yet try (Connection newConn = DriverManager.getConnection(getUrl(), props)) { rs = newConn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); } // Use new connection to create a row with a conflict Connection connWithConflict = DriverManager.getConnection(getUrl(), props); connWithConflict .createStatement() .execute("upsert into " + fullTableName + " values('z', 'd', 'd')"); // Existing connection should see data even though it hasn't been committed yet rs = conn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); // Use Tephra APIs directly to finish (i.e. commit) the transaction txContext.finish(); // Confirm that attempt to commit row with conflict fails try { connWithConflict.commit(); fail(); } catch (SQLException e) { assertEquals( SQLExceptionCode.TRANSACTION_CONFLICT_EXCEPTION.getErrorCode(), e.getErrorCode()); } finally { connWithConflict.close(); } // New connection should now see data as it has been committed try (Connection newConn = DriverManager.getConnection(getUrl(), props)) { rs = newConn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); } // Repeat the same as above, but this time abort the transaction txContext = new TransactionContext(txServiceClient, txAware); txContext.start(); // Use HBase APIs to add a new row put = new Put(Bytes.toBytes("j")); put.addColumn( QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, QueryConstants.EMPTY_COLUMN_BYTES, QueryConstants.EMPTY_COLUMN_VALUE_BYTES); put.addColumn( QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, Bytes.toBytes("V1"), Bytes.toBytes("e")); txAware.put(put); // Use Phoenix APIs to add new row (sharing the transaction context) pconn.setTransactionContext(txContext); conn.createStatement().executeUpdate("upsert into " + fullTableName + " values('k', 'f', 'f')"); // Existing connection should see data even though it hasn't been committed yet rs = conn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(5, rs.getInt(1)); connWithConflict .createStatement() .execute("upsert into " + fullTableName + " values('k', 'g', 'g')"); rs = connWithConflict.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(4, rs.getInt(1)); // Use Tephra APIs directly to abort (i.e. rollback) the transaction txContext.abort(); rs = conn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); // Should succeed since conflicting row was aborted connWithConflict.commit(); // New connection should now see data as it has been committed try (Connection newConn = DriverManager.getConnection(getUrl(), props)) { rs = newConn.createStatement().executeQuery("select count(*) from " + fullTableName); assertTrue(rs.next()); assertEquals(4, rs.getInt(1)); } // Even using HBase APIs directly, we shouldn't find 'j' since a delete marker would have been // written to hide it. Result result = htable.get(new Get(Bytes.toBytes("j"))); assertTrue(result.isEmpty()); }
@Test public void testKeyOnly() throws Exception { long ts = nextTimestamp(); ensureTableCreated(getUrl(), KEYONLY_NAME, null, ts); initTableValues(ts + 1); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30)); Connection conn3 = DriverManager.getConnection(getUrl(), props); analyzeTable(conn3, KEYONLY_NAME); conn3.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 50)); Connection conn5 = DriverManager.getConnection(getUrl(), props); String query = "SELECT i1, i2 FROM KEYONLY"; PreparedStatement statement = conn5.prepareStatement(query); ResultSet rs = statement.executeQuery(); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(2, rs.getInt(2)); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); assertEquals(4, rs.getInt(2)); assertFalse(rs.next()); List<KeyRange> splits = getAllSplits(conn5, "KEYONLY"); assertEquals(2, splits.size()); conn5.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 60)); Connection conn6 = DriverManager.getConnection(getUrl(), props); conn6.createStatement().execute("ALTER TABLE KEYONLY ADD s1 varchar"); conn6.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 70)); Connection conn7 = DriverManager.getConnection(getUrl(), props); PreparedStatement stmt = conn7.prepareStatement("upsert into " + "KEYONLY VALUES (?, ?, ?)"); stmt.setInt(1, 5); stmt.setInt(2, 6); stmt.setString(3, "foo"); stmt.execute(); conn7.commit(); conn7.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 80)); Connection conn8 = DriverManager.getConnection(getUrl(), props); analyzeTable(conn8, KEYONLY_NAME); conn8.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 90)); Connection conn9 = DriverManager.getConnection(getUrl(), props); query = "SELECT i1 FROM KEYONLY"; statement = conn9.prepareStatement(query); rs = statement.executeQuery(); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); assertTrue(rs.next()); assertEquals(5, rs.getInt(1)); assertFalse(rs.next()); query = "SELECT i1,s1 FROM KEYONLY"; statement = conn9.prepareStatement(query); rs = statement.executeQuery(); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals(null, rs.getString(2)); assertTrue(rs.next()); assertEquals(3, rs.getInt(1)); assertEquals(null, rs.getString(2)); assertTrue(rs.next()); assertEquals(5, rs.getInt(1)); assertEquals("foo", rs.getString(2)); assertFalse(rs.next()); conn9.close(); }
private void testGetTenantIdExpression(boolean isSalted) throws Exception { Connection conn = DriverManager.getConnection(getUrl()); conn.setAutoCommit(true); String tableName = "FOO_" + (isSalted ? "SALTED" : "UNSALTED"); conn.createStatement() .execute( "CREATE TABLE " + tableName + " (k1 VARCHAR NOT NULL, k2 VARCHAR, CONSTRAINT PK PRIMARY KEY(K1,K2)) MULTI_TENANT=true" + (isSalted ? ",SALT_BUCKETS=3" : "")); conn.createStatement().execute("CREATE SEQUENCE s1"); conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('t1','x')"); conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('t2','y')"); Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES); props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, "t1"); Connection tsconn = DriverManager.getConnection(getUrl(), props); tsconn.createStatement().execute("CREATE SEQUENCE s1"); Expression e1 = PhoenixRuntime.getTenantIdExpression(tsconn, PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME); HTableInterface htable1 = tsconn .unwrap(PhoenixConnection.class) .getQueryServices() .getTable(PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME_BYTES); assertTenantIds(e1, htable1, new FirstKeyOnlyFilter(), new String[] {"", "t1"}); tsconn.createStatement().execute("CREATE VIEW A.BAR(V1 VARCHAR) AS SELECT * FROM " + tableName); Expression e2 = PhoenixRuntime.getTenantIdExpression(tsconn, PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME); HTableInterface htable2 = conn.unwrap(PhoenixConnection.class) .getQueryServices() .getTable(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES); assertTenantIds(e2, htable2, getUserTableAndViewsFilter(), new String[] {"", "t1"}); Expression e3 = PhoenixRuntime.getTenantIdExpression(conn, tableName); HTableInterface htable3 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(tableName)); assertTenantIds(e3, htable3, new FirstKeyOnlyFilter(), new String[] {"t1", "t2"}); conn.createStatement().execute("CREATE TABLE BAS (k1 VARCHAR PRIMARY KEY)"); Expression e4 = PhoenixRuntime.getTenantIdExpression(conn, "BAS"); assertNull(e4); tsconn.createStatement().execute("CREATE INDEX I1 ON A.BAR(V1)"); Expression e5 = PhoenixRuntime.getTenantIdExpression(tsconn, "A.I1"); HTableInterface htable5 = tsconn .unwrap(PhoenixConnection.class) .getQueryServices() .getTable(Bytes.toBytes(MetaDataUtil.VIEW_INDEX_TABLE_PREFIX + tableName)); assertTenantIds(e5, htable5, new FirstKeyOnlyFilter(), new String[] {"t1"}); conn.createStatement().execute("CREATE INDEX I2 ON " + tableName + "(k2)"); Expression e6 = PhoenixRuntime.getTenantIdExpression(conn, "I2"); HTableInterface htable6 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes("I2")); assertTenantIds(e6, htable6, new FirstKeyOnlyFilter(), new String[] {"t1", "t2"}); tableName = "BAR_" + (isSalted ? "SALTED" : "UNSALTED"); conn.createStatement() .execute( "CREATE TABLE " + tableName + " (k1 VARCHAR NOT NULL, k2 VARCHAR, CONSTRAINT PK PRIMARY KEY(K1,K2)) " + (isSalted ? "SALT_BUCKETS=3" : "")); conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('t1','x')"); conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('t2','y')"); Expression e7 = PhoenixRuntime.getFirstPKColumnExpression(conn, tableName); HTableInterface htable7 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(tableName)); assertTenantIds(e7, htable7, new FirstKeyOnlyFilter(), new String[] {"t1", "t2"}); }
private static List<KeyRange> getSplits( final TableRef tableRef, final Scan scan, final List<HRegionLocation> regions, final ScanRanges scanRanges) throws SQLException { final List<TableRef> tableRefs = Collections.singletonList(tableRef); ColumnResolver resolver = new ColumnResolver() { @Override public List<PFunction> getFunctions() { return Collections.emptyList(); } @Override public List<TableRef> getTables() { return tableRefs; } @Override public TableRef resolveTable(String schemaName, String tableName) throws SQLException { throw new UnsupportedOperationException(); } @Override public ColumnRef resolveColumn(String schemaName, String tableName, String colName) throws SQLException { throw new UnsupportedOperationException(); } @Override public PFunction resolveFunction(String functionName) throws SQLException { throw new UnsupportedOperationException(); } @Override public boolean hasUDFs() { return false; } }; PhoenixConnection connection = DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES)) .unwrap(PhoenixConnection.class); final PhoenixStatement statement = new PhoenixStatement(connection); final StatementContext context = new StatementContext(statement, resolver, scan, new SequenceManager(statement)); context.setScanRanges(scanRanges); ParallelIterators parallelIterators = new ParallelIterators( new QueryPlan() { @Override public StatementContext getContext() { return context; } @Override public ParameterMetaData getParameterMetaData() { return PhoenixParameterMetaData.EMPTY_PARAMETER_META_DATA; } @Override public ExplainPlan getExplainPlan() throws SQLException { return ExplainPlan.EMPTY_PLAN; } @Override public ResultIterator iterator(ParallelScanGrouper scanGrouper) throws SQLException { return ResultIterator.EMPTY_ITERATOR; } @Override public ResultIterator iterator() throws SQLException { return ResultIterator.EMPTY_ITERATOR; } @Override public long getEstimatedSize() { return 0; } @Override public TableRef getTableRef() { return tableRef; } @Override public RowProjector getProjector() { return RowProjector.EMPTY_PROJECTOR; } @Override public Integer getLimit() { return null; } @Override public OrderBy getOrderBy() { return OrderBy.EMPTY_ORDER_BY; } @Override public GroupBy getGroupBy() { return GroupBy.EMPTY_GROUP_BY; } @Override public List<KeyRange> getSplits() { return null; } @Override public FilterableStatement getStatement() { return SelectStatement.SELECT_ONE; } @Override public boolean isDegenerate() { return false; } @Override public boolean isRowKeyOrdered() { return true; } @Override public List<List<Scan>> getScans() { return null; } @Override public boolean useRoundRobinIterator() { return false; } }, null, new SpoolingResultIterator.SpoolingResultIteratorFactory( context.getConnection().getQueryServices())); List<KeyRange> keyRanges = parallelIterators.getSplits(); return keyRanges; }