Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public MetaDataMutationResult getFunctions(PName tenantId,
public MetaDataMutationResult createTable(List<Mutation> tableMetaData, byte[] tableName,
PTableType tableType, Map<String, Object> tableProps,
List<Pair<byte[], Map<String, Object>>> families, byte[][] splits, boolean isNamespaceMapped,
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable) throws SQLException;
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable, boolean createIfNotExists) throws SQLException;

public MetaDataMutationResult dropTable(List<Mutation> tableMetadata, PTableType tableType,
boolean cascade) throws SQLException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,8 @@ boolean ensureNamespaceCreated(String schemaName) throws SQLException {
private TableDescriptor ensureTableCreated(byte[] physicalTableName,
byte[] parentPhysicalTableName, PTableType tableType, Map<String, Object> props,
List<Pair<byte[], Map<String, Object>>> families, byte[][] splits,
boolean modifyExistingMetaData, boolean isNamespaceMapped, boolean isDoNotUpgradePropSet)
boolean modifyExistingMetaData, boolean isNamespaceMapped, boolean isDoNotUpgradePropSet,
boolean createIfNotExists)
throws SQLException {
SQLException sqlE = null;
TableDescriptor existingDesc = null;
Expand Down Expand Up @@ -2052,8 +2053,8 @@ private TableDescriptor ensureTableCreated(byte[] physicalTableName,
return null; // Indicate that no metadata was changed
}

// Do not call modifyTable for SYSTEM tables
if (tableType != PTableType.SYSTEM) {
// Do not call modifyTable for: SYSTEM tables or when CREATE IF NOT EXISTS was used.
if (tableType != PTableType.SYSTEM && !createIfNotExists) {
modifyTable(physicalTableName, newDesc.build(), true);
}
return result;
Expand Down Expand Up @@ -2423,12 +2424,13 @@ private MetaDataMutationResult metaDataCoprocessorExec(String tableName, byte[]

private void ensureViewIndexTableCreated(byte[] physicalTableName, byte[] parentPhysicalTableName,
Map<String, Object> tableProps, List<Pair<byte[], Map<String, Object>>> families,
byte[][] splits, long timestamp, boolean isNamespaceMapped) throws SQLException {
byte[][] splits, long timestamp, boolean isNamespaceMapped, boolean createIfNotExists) throws SQLException {
byte[] physicalIndexName = MetaDataUtil.getViewIndexPhysicalName(physicalTableName);

tableProps.put(MetaDataUtil.IS_VIEW_INDEX_TABLE_PROP_NAME, TRUE_BYTES_AS_STRING);
TableDescriptor desc = ensureTableCreated(physicalIndexName, parentPhysicalTableName,
PTableType.TABLE, tableProps, families, splits, true, isNamespaceMapped, false);
PTableType.TABLE, tableProps, families, splits, true, isNamespaceMapped, false,
createIfNotExists);
if (desc != null) {
if (
!Boolean.TRUE.equals(
Expand Down Expand Up @@ -2522,7 +2524,7 @@ public MetaDataMutationResult createTable(final List<Mutation> tableMetaData,
final byte[] physicalTableName, PTableType tableType, Map<String, Object> tableProps,
final List<Pair<byte[], Map<String, Object>>> families, byte[][] splits,
boolean isNamespaceMapped, final boolean allocateIndexId, final boolean isDoNotUpgradePropSet,
final PTable parentTable) throws SQLException {
final PTable parentTable, boolean createIfNotExists) throws SQLException {
List<Mutation> childLinkMutations = MetaDataUtil.removeChildLinkMutations(tableMetaData);
byte[][] rowKeyMetadata = new byte[3][];
Mutation m = MetaDataUtil.getPutOnlyTableHeaderRow(tableMetaData);
Expand Down Expand Up @@ -2551,7 +2553,7 @@ public MetaDataMutationResult createTable(final List<Mutation> tableMetaData,
// For views this will ensure that metadata already exists
// For tables and indexes, this will create the metadata if it doesn't already exist
ensureTableCreated(physicalTableNameBytes, null, tableType, tableProps, families, splits,
true, isNamespaceMapped, isDoNotUpgradePropSet);
true, isNamespaceMapped, isDoNotUpgradePropSet, createIfNotExists);
}
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
if (tableType == PTableType.INDEX) { // Index on view
Expand All @@ -2562,7 +2564,7 @@ public MetaDataMutationResult createTable(final List<Mutation> tableMetaData,
// For view index, the physical table name is _IDX_+ logical table name format
ensureViewIndexTableCreated(
tenantIdBytes.length == 0 ? null : PNameFactory.newName(tenantIdBytes),
physicalTableName, MetaDataUtil.getClientTimeStamp(m), isNamespaceMapped);
physicalTableName, MetaDataUtil.getClientTimeStamp(m), isNamespaceMapped, createIfNotExists);
}
}
} else if (tableType == PTableType.TABLE && MetaDataUtil.isMultiTenant(m, kvBuilder, ptr)) { // Create
Expand Down Expand Up @@ -2597,7 +2599,7 @@ public MetaDataMutationResult createTable(final List<Mutation> tableMetaData,
}
ensureViewIndexTableCreated(physicalTableNameBytes, physicalTableNameBytes, tableProps,
familiesPlusDefault, MetaDataUtil.isSalted(m, kvBuilder, ptr) ? splits : null,
MetaDataUtil.getClientTimeStamp(m), isNamespaceMapped);
MetaDataUtil.getClientTimeStamp(m), isNamespaceMapped, createIfNotExists);
}

// Avoid the client-server RPC if this is not a view creation
Expand Down Expand Up @@ -2882,13 +2884,13 @@ private static Map<String, Object> createPropertiesMap(Map<Bytes, Bytes> htableP
}

private void ensureViewIndexTableCreated(PName tenantId, byte[] physicalIndexTableName,
long timestamp, boolean isNamespaceMapped) throws SQLException {
long timestamp, boolean isNamespaceMapped, boolean createIfNotExists) throws SQLException {
String name = Bytes
.toString(SchemaUtil.getParentTableNameFromIndexTable(physicalIndexTableName,
MetaDataUtil.VIEW_INDEX_TABLE_PREFIX))
.replace(QueryConstants.NAMESPACE_SEPARATOR, QueryConstants.NAME_SEPARATOR);
PTable table = getTable(tenantId, name, timestamp);
ensureViewIndexTableCreated(table, timestamp, isNamespaceMapped);
ensureViewIndexTableCreated(table, timestamp, isNamespaceMapped, createIfNotExists);
}

private PTable getTable(PName tenantId, String fullTableName, long timestamp)
Expand Down Expand Up @@ -2917,7 +2919,8 @@ private PTable getTable(PName tenantId, String fullTableName, long timestamp)
return table;
}

private void ensureViewIndexTableCreated(PTable table, long timestamp, boolean isNamespaceMapped)
private void ensureViewIndexTableCreated(PTable table, long timestamp, boolean isNamespaceMapped,
boolean createIfNotExists)
throws SQLException {
byte[] physicalTableName = table.getPhysicalName().getBytes();
TableDescriptor htableDesc = this.getTableDescriptor(physicalTableName);
Expand Down Expand Up @@ -2954,7 +2957,7 @@ private void ensureViewIndexTableCreated(PTable table, long timestamp, boolean i
byte[] viewPhysicalTableName = MetaDataUtil
.getNamespaceMappedName(table.getName(), isNamespaceMapped).getBytes(StandardCharsets.UTF_8);
ensureViewIndexTableCreated(viewPhysicalTableName, physicalTableName, tableProps, families,
splits, timestamp, isNamespaceMapped);
splits, timestamp, isNamespaceMapped, createIfNotExists);
}

@Override
Expand Down Expand Up @@ -3092,7 +3095,7 @@ public MetaDataResponse call(MetaDataService instance) throws IOException {
Boolean.TRUE
.equals(PBoolean.INSTANCE.toObject(ptr.get(), ptr.getOffset(), ptr.getLength()))
) {
this.ensureViewIndexTableCreated(table, timestamp, table.isNamespaceMapped());
this.ensureViewIndexTableCreated(table, timestamp, table.isNamespaceMapped(), true);
} else {
this.ensureViewIndexTableDropped(table.getPhysicalName().getBytes(), timestamp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private static List<HRegionLocation> generateRegionLocations(byte[] physicalName
public MetaDataMutationResult createTable(List<Mutation> tableMetaData, byte[] physicalName,
PTableType tableType, Map<String, Object> tableProps,
List<Pair<byte[], Map<String, Object>>> families, byte[][] splits, boolean isNamespaceMapped,
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable)
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable, boolean createIfNotExists)
throws SQLException {
if (
tableType == PTableType.INDEX
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ public MetaDataMutationResult getTable(PName tenantId, byte[] schemaBytes, byte[
public MetaDataMutationResult createTable(List<Mutation> tableMetaData, byte[] physicalName,
PTableType tableType, Map<String, Object> tableProps,
List<Pair<byte[], Map<String, Object>>> families, byte[][] splits, boolean isNamespaceMapped,
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable)
boolean allocateIndexId, boolean isDoNotUpgradePropSet, PTable parentTable, boolean createIfNotExists)
throws SQLException {
return getDelegate().createTable(tableMetaData, physicalName, tableType, tableProps, families,
splits, isNamespaceMapped, allocateIndexId, isDoNotUpgradePropSet, parentTable);
splits, isNamespaceMapped, allocateIndexId, isDoNotUpgradePropSet, parentTable, createIfNotExists);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3807,7 +3807,7 @@ public boolean isViewReferenced() {
MetaDataMutationResult result = connection.getQueryServices().createTable(tableMetaData,
viewType == ViewType.MAPPED || allocateIndexId ? physicalNames.get(0).getBytes() : null,
tableType, tableProps, familyPropList, splits, isNamespaceMapped, allocateIndexId,
UpgradeUtil.isNoUpgradeSet(connection.getClientInfo()), parent);
UpgradeUtil.isNoUpgradeSet(connection.getClientInfo()), parent, statement.ifNotExists());
MutationCode code = result.getMutationCode();
try {
if (code != MutationCode.TABLE_NOT_FOUND) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private void testTableWithSameSchema(boolean notExists, boolean sameClient) thro
// verify no create table rpcs
verify(connectionQueryServices, never()).createTable(anyList(), any(byte[].class),
any(PTableType.class), anyMap(), anyList(), any(byte[][].class), eq(false), eq(false),
eq(false), any(PTable.class));
eq(false), any(PTable.class), eq(false));
reset(connectionQueryServices);

// execute alter table ddl that adds the same column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -1769,4 +1770,82 @@ private int checkGuidePostWidth(String tableName) throws Exception {
}
}

@Test
public void testCreateTableWithIfNotExistsDoesNotMutateExistingHBaseTableProperties() throws Exception {
String tableName = generateUniqueName();
Properties props = new Properties();

// Step 1: Create table with VERSIONS=1 and TTL=86400
String createDdl = "CREATE TABLE " + tableName + " (" + " PK VARCHAR NOT NULL PRIMARY KEY,"
+ " COL1 VARCHAR," + " COL2 INTEGER" + " ) VERSIONS=1, TTL=86400";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createDdl);
}

// Verify initial HBase table properties
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
TableDescriptor descBefore = admin.getDescriptor(TableName.valueOf(tableName));
ColumnFamilyDescriptor[] cfsBefore = descBefore.getColumnFamilies();
assertEquals(1, cfsBefore.length);
assertEquals(1, cfsBefore[0].getMaxVersions());
assertEquals(86400, cfsBefore[0].getTimeToLive());

// Step 2: Execute CREATE TABLE IF NOT EXISTS with different properties
String createIfNotExistsDdl =
"CREATE TABLE IF NOT EXISTS " + tableName + " (" + " PK VARCHAR NOT NULL PRIMARY KEY,"
+ " COL1 VARCHAR," + " COL2 INTEGER" + " ) VERSIONS=5, TTL=120000";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createIfNotExistsDdl);
}

// Step 3: Verify that HBase table properties are NOT changed
TableDescriptor descAfter = admin.getDescriptor(TableName.valueOf(tableName));
ColumnFamilyDescriptor[] cfsAfter = descAfter.getColumnFamilies();
assertEquals(1, cfsAfter.length);
assertEquals("VERSIONS should not be modified by IF NOT EXISTS", 1,
cfsAfter[0].getMaxVersions());
assertEquals("TTL should not be modified by IF NOT EXISTS", 86400, cfsAfter[0].getTimeToLive());
}

@Test
public void testCreateTableWithoutIfNotExistsShouldMutateExistingHBaseTableProperties() throws Exception {
String tableName = generateUniqueName();
Properties props = new Properties();

// Step 1: Create table with VERSIONS=1 and TTL=86400
String createDdl = "CREATE TABLE " + tableName + " (" + " PK VARCHAR NOT NULL PRIMARY KEY,"
+ " COL1 VARCHAR," + " COL2 INTEGER" + " ) VERSIONS=1, TTL=86400";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createDdl);
}

// Verify initial HBase table properties
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
TableDescriptor descBefore = admin.getDescriptor(TableName.valueOf(tableName));
ColumnFamilyDescriptor[] cfsBefore = descBefore.getColumnFamilies();
assertEquals(1, cfsBefore.length);
assertEquals(1, cfsBefore[0].getMaxVersions());
assertEquals(86400, cfsBefore[0].getTimeToLive());

// Step 2: Execute CREATE TABLE without IF NOT EXISTS with different properties
String createWithoutIfNotExistsDdl =
"CREATE TABLE " + tableName + " (" + " PK VARCHAR NOT NULL PRIMARY KEY," + " COL1 VARCHAR,"
+ " COL2 INTEGER" + " ) VERSIONS=6, TTL=120000";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
// Should fail as table exists already.
TableAlreadyExistsException exception = assertThrows(TableAlreadyExistsException.class,
() -> conn.createStatement().execute(createWithoutIfNotExistsDdl));
assertEquals("ERROR 1013 (42M04): Table already exists. tableName=" + tableName,
exception.getMessage());
}

// Step 3: Verify that HBase table properties are changed
TableDescriptor descAfter2 = admin.getDescriptor(TableName.valueOf(tableName));
ColumnFamilyDescriptor[] cfsAfter2 = descAfter2.getColumnFamilies();
assertEquals(1, cfsAfter2.length);
assertEquals("VERSIONS should be modified without IF NOT EXISTS", 6,
cfsAfter2[0].getMaxVersions());
assertEquals("TTL should be modified without IF NOT EXISTS", 120000,
cfsAfter2[0].getTimeToLive());
}
}