Skip to content
Merged
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
58 changes: 35 additions & 23 deletions core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ public TableMetadata getTableMetadata(String namespace, String table) throws Exe
boolean tableExists = false;

try (Connection connection = dataSource.getConnection()) {
rdbEngine.setReadOnly(connection, true);

if (!namespaceExistsInternal(connection, metadataSchema)) {
return null;
}
Expand Down Expand Up @@ -459,6 +461,8 @@ public TableMetadata getImportTableMetadata(
}

try (Connection connection = dataSource.getConnection()) {
rdbEngine.setReadOnly(connection, true);

String catalogName = rdbEngine.getCatalogName(namespace);
String schemaName = rdbEngine.getSchemaName(namespace);

Expand Down Expand Up @@ -545,19 +549,22 @@ public Set<String> getNamespaceTableNames(String namespace) throws ExecutionExce
+ " WHERE "
+ enclose(METADATA_COL_FULL_TABLE_NAME)
+ " LIKE ?";
try (Connection connection = dataSource.getConnection();
PreparedStatement preparedStatement =
connection.prepareStatement(selectTablesOfNamespaceStatement)) {
String prefix = namespace + ".";
preparedStatement.setString(1, prefix + "%");
try (ResultSet results = preparedStatement.executeQuery()) {
Set<String> tableNames = new HashSet<>();
while (results.next()) {
String tableName =
results.getString(METADATA_COL_FULL_TABLE_NAME).substring(prefix.length());
tableNames.add(tableName);
try (Connection connection = dataSource.getConnection()) {
rdbEngine.setReadOnly(connection, true);

try (PreparedStatement preparedStatement =
connection.prepareStatement(selectTablesOfNamespaceStatement)) {
String prefix = namespace + ".";
preparedStatement.setString(1, prefix + "%");
try (ResultSet results = preparedStatement.executeQuery()) {
Set<String> tableNames = new HashSet<>();
while (results.next()) {
String tableName =
results.getString(METADATA_COL_FULL_TABLE_NAME).substring(prefix.length());
tableNames.add(tableName);
}
return tableNames;
}
return tableNames;
}
} catch (SQLException e) {
// An exception will be thrown if the metadata table does not exist when executing the select
Expand All @@ -576,6 +583,8 @@ public boolean namespaceExists(String namespace) throws ExecutionException {
}

try (Connection connection = dataSource.getConnection()) {
rdbEngine.setReadOnly(connection, true);

return namespaceExistsInternal(connection, namespace);
} catch (SQLException e) {
throw new ExecutionException("Checking if the namespace exists failed", e);
Expand Down Expand Up @@ -804,18 +813,21 @@ public Set<String> getNamespaceNames() throws ExecutionException {
+ enclose(METADATA_COL_FULL_TABLE_NAME)
+ " FROM "
+ encloseFullTableName(metadataSchema, METADATA_TABLE);
try (Connection connection = dataSource.getConnection();
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(selectAllTableNames)) {
Set<String> namespaceOfExistingTables = new HashSet<>();
while (rs.next()) {
String fullTableName = rs.getString(METADATA_COL_FULL_TABLE_NAME);
String namespaceName = fullTableName.substring(0, fullTableName.indexOf('.'));
namespaceOfExistingTables.add(namespaceName);
}
namespaceOfExistingTables.add(metadataSchema);
try (Connection connection = dataSource.getConnection()) {
rdbEngine.setReadOnly(connection, true);

try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(selectAllTableNames)) {
Set<String> namespaceOfExistingTables = new HashSet<>();
while (rs.next()) {
String fullTableName = rs.getString(METADATA_COL_FULL_TABLE_NAME);
String namespaceName = fullTableName.substring(0, fullTableName.indexOf('.'));
namespaceOfExistingTables.add(namespaceName);
}
namespaceOfExistingTables.add(metadataSchema);

return namespaceOfExistingTables;
return namespaceOfExistingTables;
}
} catch (SQLException e) {
// An exception will be thrown if the namespace table does not exist when executing the select
// query
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public Optional<Result> get(Get get) throws ExecutionException {
Connection connection = null;
try {
connection = dataSource.getConnection();
rdbEngine.setReadOnly(connection, true);
return jdbcService.get(get, connection);
} catch (SQLException e) {
throw new ExecutionException(
Expand All @@ -97,6 +98,7 @@ public Scanner scan(Scan scan) throws ExecutionException {
Connection connection = null;
try {
connection = dataSource.getConnection();
rdbEngine.setReadOnly(connection, true);
return jdbcService.getScanner(scan, connection);
} catch (SQLException e) {
close(connection);
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/com/scalar/db/storage/jdbc/JdbcUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public static BasicDataSource initDataSource(
}
});

dataSource.setDefaultReadOnly(false);

dataSource.setMinIdle(config.getConnectionPoolMinIdle());
dataSource.setMaxIdle(config.getConnectionPoolMaxIdle());
dataSource.setMaxTotal(config.getConnectionPoolMaxTotal());
Expand All @@ -89,6 +91,9 @@ public static BasicDataSource initDataSourceForTableMetadata(
dataSource.setUrl(config.getJdbcUrl());
config.getUsername().ifPresent(dataSource::setUsername);
config.getPassword().ifPresent(dataSource::setPassword);

dataSource.setDefaultReadOnly(false);

dataSource.setMinIdle(config.getTableMetadataConnectionPoolMinIdle());
dataSource.setMaxIdle(config.getTableMetadataConnectionPoolMaxIdle());
dataSource.setMaxTotal(config.getTableMetadataConnectionPoolMaxTotal());
Expand All @@ -113,6 +118,9 @@ public static BasicDataSource initDataSourceForAdmin(
dataSource.setUrl(config.getJdbcUrl());
config.getUsername().ifPresent(dataSource::setUsername);
config.getPassword().ifPresent(dataSource::setPassword);

dataSource.setDefaultReadOnly(false);

dataSource.setMinIdle(config.getAdminConnectionPoolMinIdle());
dataSource.setMaxIdle(config.getAdminConnectionPoolMaxIdle());
dataSource.setMaxTotal(config.getAdminConnectionPoolMaxTotal());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.scalar.db.storage.jdbc.query.UpsertQuery;
import com.scalar.db.util.TimeRelatedColumnEncodingUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.JDBCType;
import java.sql.ResultSet;
Expand Down Expand Up @@ -336,4 +337,9 @@ public TimestampTZColumn parseTimestampTZColumn(ResultSet resultSet, String colu
public RdbEngineTimeTypeStrategy<Integer, Long, Long, Long> getTimeTypeStrategy() {
return timeTypeEngine;
}

@Override
public void setReadOnly(Connection connection, boolean readOnly) {
// Do nothing. SQLite does not support read-only mode.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.scalar.db.io.TimestampTZColumn;
import com.scalar.db.storage.jdbc.query.SelectQuery;
import com.scalar.db.storage.jdbc.query.UpsertQuery;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.JDBCType;
import java.sql.ResultSet;
Expand Down Expand Up @@ -226,4 +227,8 @@ default String getProjectionsSqlForSelectQuery(TableMetadata metadata, List<Stri
default void throwIfDuplicatedIndexWarning(SQLWarning warning) throws SQLException {
// Do nothing
}

default void setReadOnly(Connection connection, boolean readOnly) throws SQLException {
connection.setReadOnly(readOnly);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
Expand All @@ -19,6 +20,7 @@
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -53,6 +55,8 @@
import org.apache.commons.dbcp2.BasicDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockedStatic;
Expand Down Expand Up @@ -285,6 +289,11 @@ private void getTableMetadata_forX_ShouldReturnTableMetadata(
.addSecondaryIndex("c4")
.build();
assertThat(actualMetadata).isEqualTo(expectedMetadata);
if (rdbEngine == RdbEngine.SQLITE) {
verify(connection, never()).setReadOnly(anyBoolean());
} else {
verify(connection).setReadOnly(true);
}
verify(connection).prepareStatement(expectedSelectStatements);
}

Expand Down Expand Up @@ -1702,6 +1711,11 @@ private void getNamespaceTables_forX_ShouldReturnTableNames(
Set<String> actualTableNames = admin.getNamespaceTableNames(namespace);

// Assert
if (rdbEngine == RdbEngine.SQLITE) {
verify(connection, never()).setReadOnly(anyBoolean());
} else {
verify(connection).setReadOnly(true);
}
verify(connection).prepareStatement(expectedSelectStatement);
assertThat(actualTableNames).containsExactly(table1, table2);
verify(preparedStatement).setString(1, namespace + ".%");
Expand Down Expand Up @@ -1771,6 +1785,11 @@ private void namespaceExists_forXWithExistingNamespace_ShouldReturnTrue(
// Assert
assertThat(admin.namespaceExists(namespace)).isTrue();

if (rdbEngine == RdbEngine.SQLITE) {
verify(connection, never()).setReadOnly(anyBoolean());
} else {
verify(connection).setReadOnly(true);
}
verify(selectStatement).executeQuery();
verify(connection).prepareStatement(expectedSelectStatement);
verify(selectStatement).setString(1, namespace + namespacePlaceholderSuffix);
Expand Down Expand Up @@ -2772,16 +2791,15 @@ private void addNewColumnToTable_ForX_ShouldWorkProperly(
}
}

@Test
public void getImportTableMetadata_ForX_ShouldWorkProperly()
@ParameterizedTest
@EnumSource(RdbEngine.class)
public void getImportTableMetadata_ForX_ShouldWorkProperly(RdbEngine rdbEngine)
throws SQLException, ExecutionException {
for (RdbEngine rdbEngine : RDB_ENGINES.keySet()) {
if (rdbEngine.equals(RdbEngine.SQLITE)) {
getImportTableMetadata_ForSQLite_ShouldThrowUnsupportedOperationException(rdbEngine);
} else {
getImportTableMetadata_ForOtherThanSQLite_ShouldWorkProperly(
rdbEngine, prepareSqlForTableCheck(rdbEngine, NAMESPACE, TABLE));
}
if (rdbEngine.equals(RdbEngine.SQLITE)) {
getImportTableMetadata_ForSQLite_ShouldThrowUnsupportedOperationException(rdbEngine);
} else {
getImportTableMetadata_ForOtherThanSQLite_ShouldWorkProperly(
rdbEngine, prepareSqlForTableCheck(rdbEngine, NAMESPACE, TABLE));
}
}

Expand Down Expand Up @@ -2848,6 +2866,7 @@ public Boolean answer(InvocationOnMock invocation) {
.execute(expectedCheckTableExistStatement);
assertThat(actual.getPartitionKeyNames()).hasSameElementsAs(ImmutableSet.of("pk1", "pk2"));
assertThat(actual.getColumnDataTypes()).containsExactlyEntriesOf(expectedColumns);
verify(connection).setReadOnly(true);
verify(rdbEngineStrategy)
.getDataTypeForScalarDb(
any(JDBCType.class),
Expand Down Expand Up @@ -3310,6 +3329,11 @@ private void getNamespaceNames_ForX_WithExistingTables_ShouldWorkProperly(
Set<String> actual = admin.getNamespaceNames();

// Assert
if (rdbEngine.equals(RdbEngine.SQLITE)) {
verify(connection, never()).setReadOnly(anyBoolean());
} else {
verify(connection).setReadOnly(true);
}
verify(connection).createStatement();
verify(getTableMetadataNamespacesStatementMock)
.executeQuery(getTableMetadataNamespacesStatement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public void whenGetOperationExecuted_shouldCallJdbcService() throws Exception {
jdbcDatabase.get(get);

// Assert
verify(connection).setReadOnly(true);
verify(jdbcService).get(any(), any());
verify(connection).close();
}
Expand All @@ -89,6 +90,7 @@ public void whenGetOperationExecuted_shouldCallJdbcService() throws Exception {
jdbcDatabase.get(get);
})
.isInstanceOf(ExecutionException.class);
verify(connection).setReadOnly(true);
verify(connection).close();
}

Expand All @@ -104,6 +106,7 @@ public void whenScanOperationExecutedAndScannerClosed_shouldCallJdbcService() th
scanner.close();

// Assert
verify(connection).setReadOnly(true);
verify(jdbcService).getScanner(any(), any());
verify(connection).close();
}
Expand All @@ -122,6 +125,7 @@ public void whenScanOperationExecutedAndScannerClosed_shouldCallJdbcService() th
jdbcDatabase.scan(scan);
})
.isInstanceOf(ExecutionException.class);
verify(connection).setReadOnly(true);
verify(connection).close();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public void initDataSource_NonTransactional_ShouldReturnProperDataSource() throw
assertThat(dataSource.getAutoCommitOnReturn()).isEqualTo(true);
assertThat(dataSource.getDefaultTransactionIsolation())
.isEqualTo(Connection.TRANSACTION_SERIALIZABLE);
assertThat(dataSource.getDefaultReadOnly()).isFalse();

assertThat(dataSource.getMinIdle()).isEqualTo(10);
assertThat(dataSource.getMaxIdle()).isEqualTo(20);
Expand Down Expand Up @@ -109,6 +110,7 @@ public void initDataSource_Transactional_ShouldReturnProperDataSource() throws S
assertThat(dataSource.getAutoCommitOnReturn()).isEqualTo(false);
assertThat(dataSource.getDefaultTransactionIsolation())
.isEqualTo(Connection.TRANSACTION_READ_COMMITTED);
assertThat(dataSource.getDefaultReadOnly()).isFalse();

assertThat(dataSource.getMinIdle()).isEqualTo(30);
assertThat(dataSource.getMaxIdle()).isEqualTo(40);
Expand Down Expand Up @@ -180,6 +182,8 @@ public void initDataSourceForTableMetadata_ShouldReturnProperDataSource() throws
assertThat(tableMetadataDataSource.getUsername()).isEqualTo("user");
assertThat(tableMetadataDataSource.getPassword()).isEqualTo("oracle");

assertThat(tableMetadataDataSource.getDefaultReadOnly()).isFalse();

assertThat(tableMetadataDataSource.getMinIdle()).isEqualTo(100);
assertThat(tableMetadataDataSource.getMaxIdle()).isEqualTo(200);
assertThat(tableMetadataDataSource.getMaxTotal()).isEqualTo(300);
Expand Down Expand Up @@ -212,6 +216,8 @@ public void initDataSourceForAdmin_ShouldReturnProperDataSource() throws SQLExce
assertThat(adminDataSource.getUsername()).isEqualTo("user");
assertThat(adminDataSource.getPassword()).isEqualTo("sqlserver");

assertThat(adminDataSource.getDefaultReadOnly()).isFalse();

assertThat(adminDataSource.getMinIdle()).isEqualTo(100);
assertThat(adminDataSource.getMaxIdle()).isEqualTo(200);
assertThat(adminDataSource.getMaxTotal()).isEqualTo(300);
Expand Down