From 73c4223cc92fb6417b709bfa7d5aa3d83effc57a Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 8 May 2024 14:07:36 +0300 Subject: [PATCH 01/52] FIR-32846 replaced throws FireboltException to throws SQLException (#406) --- .../firebolt/jdbc/client/FireboltClient.java | 18 +++++----- .../client/account/FireboltAccountClient.java | 11 +++--- .../account/FireboltAccountRetriever.java | 5 +-- .../FireboltAuthenticationClient.java | 3 +- .../jdbc/client/query/StatementClient.java | 5 +-- .../client/query/StatementClientImpl.java | 14 ++++---- .../jdbc/connection/FireboltConnection.java | 16 ++++----- .../FireboltConnectionServiceSecret.java | 2 +- .../jdbc/resultset/FieldTypeConverter.java | 3 +- .../service/FireboltAccountIdService.java | 4 ++- .../FireboltAuthenticationService.java | 5 +-- .../service/FireboltEngineApiService.java | 13 +++---- .../service/FireboltGatewayUrlService.java | 4 ++- .../service/FireboltStatementService.java | 2 +- .../FireboltPreparedStatement.java | 2 +- .../type/JavaTypeToFireboltSQLString.java | 8 ++--- .../jdbc/type/array/SqlArrayUtil.java | 2 +- .../jdbc/client/FireboltClientTest.java | 3 +- .../account/FireboltAccountClientTest.java | 9 ++--- .../FireboltAuthenticationClientTest.java | 3 +- .../gateway/FireboltGatewayUrlClientTest.java | 5 +-- .../client/query/StatementClientImplTest.java | 14 ++++---- .../FireboltAuthenticationServiceTest.java | 11 +++--- .../FireboltGatewayUrlServiceTest.java | 4 ++- .../service/FireboltStatementServiceTest.java | 4 +-- .../type/JavaTypeToFireboltSQLStringTest.java | 36 +++++++++---------- 26 files changed, 109 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index 76c1f2b92..e0b7d24a2 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -22,6 +22,7 @@ import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.nio.charset.StandardCharsets; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -55,12 +56,11 @@ protected FireboltClient(OkHttpClient httpClient, FireboltConnection connection, } protected T getResource(String uri, String accessToken, Class valueType) - throws IOException, FireboltException { + throws IOException, SQLException { return getResource(uri, uri, accessToken, valueType); } - protected T getResource(String uri, String host, String accessToken, Class valueType) - throws IOException, FireboltException { + protected T getResource(String uri, String host, String accessToken, Class valueType) throws SQLException, IOException { Request rq = createGetRequest(uri, accessToken); try (Response response = execute(rq, host)) { return jsonToObject(getResponseAsString(response), valueType); @@ -85,12 +85,12 @@ private Request createGetRequest(String uri, String accessToken) { return requestBuilder.build(); } - protected Response execute(@NonNull Request request, String host) throws IOException, FireboltException { + protected Response execute(@NonNull Request request, String host) throws IOException, SQLException { return execute(request, host, false); } protected Response execute(@NonNull Request request, String host, boolean isCompress) - throws IOException, FireboltException { + throws IOException, SQLException { Response response = null; try { OkHttpClient client = getClientWithTimeouts(connection.getConnectionTimeout(), connection.getNetworkTimeout()); @@ -132,7 +132,7 @@ protected Request createPostRequest(String uri, String label, String json, Strin return createPostRequest(uri, label, requestBody, accessToken); } - protected void validateResponse(String host, Response response, Boolean isCompress) throws FireboltException { + protected void validateResponse(String host, Response response, Boolean isCompress) throws SQLException { int statusCode = response.code(); if (!isCallSuccessful(statusCode)) { if (statusCode == HTTP_UNAVAILABLE) { @@ -153,18 +153,18 @@ protected void validateResponse(String host, Response response, Boolean isCompre } } - protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws FireboltException { + protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws SQLException { // empty implementation } - protected String getResponseAsString(Response response) throws FireboltException, IOException { + protected String getResponseAsString(Response response) throws SQLException, IOException { if (response.body() == null) { throw new FireboltException("Cannot get resource: the response from the server is empty"); } return response.body().string(); } - private String extractErrorMessage(Response response, boolean isCompress) throws FireboltException { + private String extractErrorMessage(Response response, boolean isCompress) throws SQLException { byte[] entityBytes; try { entityBytes = response.body() != null ? response.body().bytes() : null; diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java index dd0fc331a..8b8bb98f3 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java @@ -12,6 +12,7 @@ import okhttp3.OkHttpClient; import java.io.IOException; +import java.sql.SQLException; import static java.lang.String.format; @@ -37,7 +38,7 @@ public FireboltAccountClient(OkHttpClient httpClient, FireboltConnection firebol * @param accessToken the access token * @return the account */ - public FireboltAccountResponse getAccount(String host, String account, String accessToken) throws FireboltException, IOException { + public FireboltAccountResponse getAccount(String host, String account, String accessToken) throws SQLException, IOException { String uri = format(GET_ACCOUNT_ID_URI, host, account); return getResource(uri, host, accessToken, FireboltAccountResponse.class); } @@ -52,7 +53,7 @@ public FireboltAccountResponse getAccount(String host, String account, String ac * @param accessToken the access token * @return the engine */ - public FireboltEngineResponse getEngine(String host, String accountId, String engineName, String engineId, String accessToken) throws FireboltException, IOException { + public FireboltEngineResponse getEngine(String host, String accountId, String engineName, String engineId, String accessToken) throws SQLException, IOException { String uri = createAccountUri(accountId, host, URI_SUFFIX_ACCOUNT_ENGINE_INFO_BY_ENGINE_ID + engineId); return getResource(uri, host, accessToken, FireboltEngineResponse.class, format("The address of the engine with name %s and id %s could not be found", engineName, engineId)); } @@ -66,7 +67,7 @@ public FireboltEngineResponse getEngine(String host, String accountId, String en * @param accessToken the access token * @return the default engine for the database */ - public FireboltDefaultDatabaseEngineResponse getDefaultEngineByDatabaseName(String host, String accountId, String dbName, String accessToken) throws FireboltException, IOException { + public FireboltDefaultDatabaseEngineResponse getDefaultEngineByDatabaseName(String host, String accountId, String dbName, String accessToken) throws SQLException, IOException { String uri = createAccountUri(accountId, host, URI_SUFFIX_DATABASE_INFO_URL + dbName); return getResource(uri, host, accessToken, FireboltDefaultDatabaseEngineResponse.class, format("The database with the name %s could not be found", dbName)); } @@ -81,13 +82,13 @@ public FireboltDefaultDatabaseEngineResponse getDefaultEngineByDatabaseName(Stri * @return the engine id */ public FireboltEngineIdResponse getEngineId(String host, String accountId, String engineName, String accessToken) - throws FireboltException, IOException { + throws SQLException, IOException { String uri = createAccountUri(accountId, host, URI_SUFFIX_ENGINE_AND_ACCOUNT_ID_BY_ENGINE_NAME + engineName); return getResource(uri, host, accessToken, FireboltEngineIdResponse.class, format("The engine %s could not be found", engineName)); } - private R getResource(String uri, String host, String accessToken, Class responseType, String notFoundErrorMessage) throws FireboltException, IOException { + private R getResource(String uri, String host, String accessToken, Class responseType, String notFoundErrorMessage) throws SQLException, IOException { try { return getResource(uri, host, accessToken, responseType); } catch (FireboltException exception) { diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java index 299d7a284..11a55e1fb 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java @@ -6,6 +6,7 @@ import okhttp3.OkHttpClient; import java.io.IOException; +import java.sql.SQLException; import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; @@ -23,7 +24,7 @@ public FireboltAccountRetriever(OkHttpClient httpClient, FireboltConnection conn this.type = type; } - public T retrieve(String accessToken, String accountName) throws FireboltException { + public T retrieve(String accessToken, String accountName) throws SQLException { try { return getResource(format(URL, host, accountName, path), accessToken, type); } catch (IOException e) { @@ -32,7 +33,7 @@ public T retrieve(String accessToken, String accountName) throws FireboltExcepti } @Override - protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws FireboltException { + protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws SQLException { if (statusCode == HTTP_NOT_FOUND) { String[] fragments = host.split("/"); // Second to last because th last element presents action and the second to last is the account name diff --git a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java index 6c815d608..d65b313ec 100644 --- a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java +++ b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java @@ -10,6 +10,7 @@ import okhttp3.Response; import java.io.IOException; +import java.sql.SQLException; @CustomLog public abstract class FireboltAuthenticationClient extends FireboltClient { @@ -29,7 +30,7 @@ protected FireboltAuthenticationClient(OkHttpClient httpClient, * @return the connection tokens */ public FireboltConnectionTokens postConnectionTokens(String host, String user, String password, String environment) - throws IOException, FireboltException { + throws SQLException, IOException { AuthenticationRequest authenticationRequest = getAuthenticationRequest(user, password, host, environment); String uri = authenticationRequest.getUri(); log.debug("Creating connection with url {}", uri); diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java index 89a5701c3..f777ab12c 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java @@ -1,6 +1,7 @@ package com.firebolt.jdbc.client.query; import java.io.InputStream; +import java.sql.SQLException; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; @@ -12,12 +13,12 @@ public interface StatementClient { * Post SQL statement */ InputStream executeSqlStatement(StatementInfoWrapper statementInfoWrapper, FireboltProperties connectionProperties, - boolean systemEngine, int queryTimeout, boolean standardSql) throws FireboltException; + boolean systemEngine, int queryTimeout, boolean standardSql) throws SQLException; /** * Call endpoint to abort a running SQL statement */ - void abortStatement(String label, FireboltProperties fireboltProperties) throws FireboltException; + void abortStatement(String label, FireboltProperties fireboltProperties) throws SQLException; boolean isStatementRunning(String statementLabel); } diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java index 41d6528d5..2db8719a6 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java @@ -137,7 +137,7 @@ public StatementClientImpl(OkHttpClient httpClient, FireboltConnection connectio @Override public InputStream executeSqlStatement(@NonNull StatementInfoWrapper statementInfoWrapper, @NonNull FireboltProperties connectionProperties, boolean systemEngine, int queryTimeout, - boolean standardSql) throws FireboltException { + boolean standardSql) throws SQLException { QueryIdFetcher.getQueryFetcher(connection.getInfraVersion()).formatStatement(statementInfoWrapper); String formattedStatement = QueryIdFetcher.getQueryFetcher(connection.getInfraVersion()).formatStatement(statementInfoWrapper); Map params = getAllParameters(connectionProperties, statementInfoWrapper, systemEngine, queryTimeout); @@ -156,7 +156,7 @@ public InputStream executeSqlStatement(@NonNull StatementInfoWrapper statementIn } private InputStream executeSqlStatementWithRetryOnUnauthorized(String label, @NonNull FireboltProperties connectionProperties, String formattedStatement, String uri) - throws IOException, FireboltException { + throws SQLException, IOException { try { log.debug("Posting statement with label {} to URI: {}", label, uri); return postSqlStatement(connectionProperties, formattedStatement, uri, label); @@ -171,7 +171,7 @@ private InputStream executeSqlStatementWithRetryOnUnauthorized(String label, @No } private InputStream postSqlStatement(@NonNull FireboltProperties connectionProperties, String formattedStatement, String uri, String label) - throws FireboltException, IOException { + throws SQLException, IOException { Request post = createPostRequest(uri, label, formattedStatement, getConnection().getAccessToken().orElse(null)); Response response = execute(post, connectionProperties.getHost(), connectionProperties.isCompress()); InputStream is = ofNullable(response.body()).map(ResponseBody::byteStream).orElse(null); @@ -181,7 +181,7 @@ private InputStream postSqlStatement(@NonNull FireboltProperties connectionPrope return is; } - public void abortStatement(@NonNull String statementLabel, @NonNull FireboltProperties properties) throws FireboltException { + public void abortStatement(@NonNull String statementLabel, @NonNull FireboltProperties properties) throws SQLException { boolean aborted = abortRunningHttpRequest(statementLabel); if (properties.isSystemEngine()) { throw new FireboltException("Cannot cancel a statement using a system engine", INVALID_REQUEST); @@ -196,7 +196,7 @@ public void abortStatement(@NonNull String statementLabel, @NonNull FireboltProp * @param label label of the statement * @param fireboltProperties the properties */ - private void abortRunningDbStatement(String label, FireboltProperties fireboltProperties, int getIdTimeout) throws FireboltException { + private void abortRunningDbStatement(String label, FireboltProperties fireboltProperties, int getIdTimeout) throws SQLException { try { String id; int attempt = 0; @@ -343,7 +343,7 @@ private Map getCancelParameters(String statementId) { } @Override - protected void validateResponse(String host, Response response, Boolean isCompress) throws FireboltException { + protected void validateResponse(String host, Response response, Boolean isCompress) throws SQLException { super.validateResponse(host, response, isCompress); FireboltConnection connection = getConnection(); if (isCallSuccessful(response.code())) { @@ -362,7 +362,7 @@ protected void validateResponse(String host, Response response, Boolean isCompre } @Override - protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws FireboltException { + protected void validateResponse(String host, int statusCode, String errorMessageFromServer) throws SQLException { if (statusCode == HTTP_INTERNAL_ERROR) { FireboltException ex = missConfigurationErrorMessages.entrySet().stream() .filter(msg -> msg.getKey().matcher(errorMessageFromServer).find()).findFirst() diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index e0ad33118..7cf92e5b4 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -141,7 +141,7 @@ private static int getUrlVersion(String url, Properties connectionSettings) { return 2; } - protected OkHttpClient getHttpClient(FireboltProperties fireboltProperties) throws FireboltException { + protected OkHttpClient getHttpClient(FireboltProperties fireboltProperties) throws SQLException { try { return HttpClientConfig.getInstance() == null ? HttpClientConfig.init(fireboltProperties) : HttpClientConfig.getInstance(); } catch (GeneralSecurityException | IOException e) { @@ -168,15 +168,15 @@ protected void connect() throws SQLException { protected abstract void assertDatabaseExisting(String database) throws SQLException; - public void removeExpiredTokens() throws FireboltException { + public void removeExpiredTokens() throws SQLException { fireboltAuthenticationService.removeConnectionTokens(httpConnectionUrl, loginProperties); } - public Optional getAccessToken() throws FireboltException { + public Optional getAccessToken() throws SQLException { return getAccessToken(sessionProperties); } - protected Optional getAccessToken(FireboltProperties fireboltProperties) throws FireboltException { + protected Optional getAccessToken(FireboltProperties fireboltProperties) throws SQLException { String accessToken = fireboltProperties.getAccessToken(); if (accessToken != null) { if (fireboltProperties.getPrincipal() != null || fireboltProperties.getSecret() != null) { @@ -445,19 +445,19 @@ public void removeClosedStatement(FireboltStatement fireboltStatement) { } } - public void addProperty(@NonNull String key, String value) throws FireboltException { + public void addProperty(@NonNull String key, String value) throws SQLException { changeProperty(p -> p.addProperty(key, value), () -> format("Could not set property %s=%s", key, value)); } - public void addProperty(Entry property) throws FireboltException { + public void addProperty(Entry property) throws SQLException { changeProperty(p -> p.addProperty(property), () -> format("Could not set property %s=%s", property.getKey(), property.getValue())); } - public void reset() throws FireboltException { + public void reset() throws SQLException { changeProperty(FireboltProperties::clearAdditionalProperties, () -> "Could not reset connection"); } - private synchronized void changeProperty(Consumer propertiesEditor, Supplier errorMessageFactory) throws FireboltException { + private synchronized void changeProperty(Consumer propertiesEditor, Supplier errorMessageFactory) throws SQLException { try { FireboltProperties tmpProperties = FireboltProperties.copy(sessionProperties); propertiesEditor.accept(tmpProperties); diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index a35605562..cbe98c27e 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -102,7 +102,7 @@ protected void assertDatabaseExisting(String database) throws SQLException { } } - private FireboltProperties getSessionPropertiesForSystemEngine(String accessToken, String accountName) throws FireboltException { + private FireboltProperties getSessionPropertiesForSystemEngine(String accessToken, String accountName) throws SQLException { String systemEngineEndpoint = fireboltGatewayUrlService.getUrl(accessToken, accountName); FireboltAccount account = fireboltAccountIdService.getValue(accessToken, accountName); infraVersion = account.getInfraVersion(); diff --git a/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java b/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java index 9e3067426..408da4c30 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java @@ -101,8 +101,7 @@ public class FieldTypeConverter { }); } - private static void verify(Class toType, BaseType columnBaseType, BaseType... supportedTypes) - throws FireboltException { + private static void verify(Class toType, BaseType columnBaseType, BaseType... supportedTypes) throws SQLException { if (Arrays.stream(supportedTypes).noneMatch(b -> b.equals(columnBaseType))) { throw new FireboltException( String.format(CONVERSION_NOT_SUPPORTED_EXCEPTION, toType, columnBaseType.getType().getName())); diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java index 1c60bc1b8..13f05cceb 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java @@ -4,6 +4,8 @@ import com.firebolt.jdbc.client.account.FireboltAccountRetriever; import com.firebolt.jdbc.exception.FireboltException; +import java.sql.SQLException; + public class FireboltAccountIdService { private final FireboltAccountRetriever firebolAccountClient; @@ -11,7 +13,7 @@ public FireboltAccountIdService(FireboltAccountRetriever firebo this.firebolAccountClient = firebolAccountClient; } - public FireboltAccount getValue(String accessToken, String account) throws FireboltException { + public FireboltAccount getValue(String accessToken, String account) throws SQLException { return firebolAccountClient.retrieve(accessToken, account); } } diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java index 0063ca3b8..2f4710841 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java @@ -12,6 +12,7 @@ import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.sql.SQLException; import static java.lang.String.format; import static java.util.Optional.ofNullable; @@ -30,7 +31,7 @@ public class FireboltAuthenticationService { private static final String ERROR_MESSAGE_FROM_SERVER = "Failed to connect to Firebolt with the error from the server: %s, see logs for more info."; private final FireboltAuthenticationClient fireboltAuthenticationClient; - public FireboltConnectionTokens getConnectionTokens(String host, FireboltProperties loginProperties) throws FireboltException { + public FireboltConnectionTokens getConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); synchronized (this) { @@ -70,7 +71,7 @@ private long getCachingDurationInSeconds(long expireInSeconds) { * @param host host * @param loginProperties the login properties linked to the tokens */ - public void removeConnectionTokens(String host, FireboltProperties loginProperties) throws FireboltException { + public void removeConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { log.debug("Removing connection token for host {}", host); ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java index d031fa6e2..9a947f2a4 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java @@ -44,8 +44,7 @@ public Engine getEngine(FireboltProperties properties) throws SQLException { * @param accessToken the access token * @return the engine */ - private Engine getEngine(String connectionUrl, FireboltProperties loginProperties, String accessToken) - throws FireboltException { + private Engine getEngine(String connectionUrl, FireboltProperties loginProperties, String accessToken) throws SQLException { String accountId = null; Engine engine; try { @@ -66,8 +65,7 @@ private Engine getEngine(String connectionUrl, FireboltProperties loginPropertie return engine; } - private Engine getEngineWithName(String connectionUrl, String accountId, String engineName, String accessToken) - throws FireboltException, IOException { + private Engine getEngineWithName(String connectionUrl, String accountId, String engineName, String accessToken) throws SQLException, IOException { FireboltEngineIdResponse response = fireboltAccountClient.getEngineId(connectionUrl, accountId, engineName, accessToken); String engineID = ofNullable(response).map(FireboltEngineIdResponse::getEngine) @@ -84,8 +82,7 @@ private Engine getEngineWithName(String connectionUrl, String accountId, String format(ERROR_NO_ENGINE_WITH_NAME, connectionUrl, engineName))); } - private Engine getDefaultEngine(String connectionUrl, String accountId, String database, String accessToken) - throws FireboltException, IOException { + private Engine getDefaultEngine(String connectionUrl, String accountId, String database, String accessToken) throws SQLException, IOException { FireboltDefaultDatabaseEngineResponse defaultEngine = fireboltAccountClient .getDefaultEngineByDatabaseName(connectionUrl, accountId, database, accessToken); @@ -95,11 +92,11 @@ private Engine getDefaultEngine(String connectionUrl, String accountId, String d } private Optional getAccountId(String connectionUrl, String account, String accessToken) - throws FireboltException, IOException { + throws SQLException, IOException { return ofNullable(fireboltAccountClient.getAccount(connectionUrl, account, accessToken)).map(FireboltAccountResponse::getAccountId); } - private void validateEngineIsNotStarting(Engine engine) throws FireboltException { + private void validateEngineIsNotStarting(Engine engine) throws SQLException { String id = engine.getId(); String status = engine.getStatus(); if (id != null && !id.isEmpty() && status != null && !status.isEmpty() && ENGINE_NOT_READY_STATUSES.contains(engine.getStatus())) { diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java b/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java index 4a4c5368f..6e9846597 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java @@ -5,6 +5,8 @@ import com.firebolt.jdbc.exception.FireboltException; import lombok.RequiredArgsConstructor; +import java.sql.SQLException; + @RequiredArgsConstructor public class FireboltGatewayUrlService { @@ -18,7 +20,7 @@ private String addProtocolToUrl(String url) { return url; } - public String getUrl(String accessToken, String account) throws FireboltException { + public String getUrl(String accessToken, String account) throws SQLException { return addProtocolToUrl(fireboltGatewayUrlClient.retrieve(accessToken, account).getEngineUrl()); } } diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java index 7c0563a73..4ac0296ab 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java @@ -54,7 +54,7 @@ public Optional execute(StatementInfoWrapper statementInfoWrapper, return Optional.empty(); } - public void abortStatement(@NonNull String statementLabel, @NonNull FireboltProperties properties) throws FireboltException { + public void abortStatement(@NonNull String statementLabel, @NonNull FireboltProperties properties) throws SQLException { statementClient.abortStatement(statementLabel, properties); } diff --git a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java index e6eafb6da..59ac22d09 100644 --- a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java @@ -280,7 +280,7 @@ public int executeUpdate(String sql) throws SQLException { throw new FireboltException("Cannot call method executeUpdate(String sql) on a PreparedStatement"); } - private void validateParamIndex(int paramIndex) throws FireboltException { + private void validateParamIndex(int paramIndex) throws SQLException { if (rawStatement.getTotalParams() < paramIndex) { throw new FireboltException( format("Cannot set parameter as there is no parameter at index: %d for statement: %s", diff --git a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java index ecdcac89e..e8b0ea327 100644 --- a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java +++ b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java @@ -99,7 +99,7 @@ public enum JavaTypeToFireboltSQLString { this.transformToJavaTypeFunctionWithParameter = transformToJavaTypeFunctionWithParameter; } - public static String transformAny(Object object) throws FireboltException { + public static String transformAny(Object object) throws SQLException { return transformAny(object, () -> getType(object)); } @@ -107,11 +107,11 @@ public static String transformAny(Object object, int sqlType) throws SQLExceptio return transformAny(object, () -> getType(sqlType)); } - private static String transformAny(Object object, Supplier> classSupplier) throws FireboltException { + private static String transformAny(Object object, Supplier> classSupplier) throws SQLException { return object == null ? NULL_VALUE : transformAny(object, classSupplier.get()); } - private static String transformAny(Object object, Class objectType) throws FireboltException { + private static String transformAny(Object object, Class objectType) throws SQLException { JavaTypeToFireboltSQLString converter = Optional.ofNullable(classToType.get(objectType)) .orElseThrow(() -> new FireboltException( format("Cannot convert type %s. The type is not supported.", objectType), @@ -141,7 +141,7 @@ public Class getSourceType() { return sourceType; } - public String transform(Object object, Object ... more) throws FireboltException { + public String transform(Object object, Object ... more) throws SQLException { if (object == null) { return NULL_VALUE; } else { diff --git a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java index 7ed7d81df..04005c315 100644 --- a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java @@ -232,7 +232,7 @@ public static String arrayToString(Object o) throws SQLException { return toString(arr); } - private static String toString(Object[] arr) throws FireboltException { + private static String toString(Object[] arr) throws SQLException { if (arr == null) { return null; } diff --git a/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java b/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java index 34e89b0bd..b5ff5cc9d 100644 --- a/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java @@ -19,6 +19,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.sql.SQLException; import java.util.stream.Stream; import static java.net.HttpURLConnection.HTTP_BAD_GATEWAY; @@ -149,7 +150,7 @@ private static Stream goodJson() { @ParameterizedTest(name = "{0}:{1}") @MethodSource("goodJson") - void goodJsonResponse(Class clazz, String json, T expected) throws IOException, FireboltException { + void goodJsonResponse(Class clazz, String json, T expected) throws SQLException, IOException { assertEquals(expected, mockClient(json).getResource("http://foo", "foo", "token", clazz)); } diff --git a/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java b/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java index 6a7789a63..bcc5cf36c 100644 --- a/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java @@ -16,6 +16,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; +import java.sql.SQLException; import static com.firebolt.jdbc.exception.ExceptionType.RESOURCE_NOT_FOUND; import static java.lang.String.format; @@ -43,28 +44,28 @@ void setUp() { } @Test - void getAccount() throws FireboltException, IOException { + void getAccount() throws SQLException, IOException { String accountId = "123"; injectMockedResponse(httpClient, HTTP_OK, format("{\"account_id\":\"%s\"}", accountId)); // FireboltAccountResponse assertEquals(accountId, client.getAccount("http://host", "account", "token").getAccountId()); } @Test - void getEngine() throws IOException, FireboltException { + void getEngine() throws SQLException, IOException { String endpoint = "http://engine/12345"; injectMockedResponse(httpClient, HTTP_OK, format("{\"engine\": {\"endpoint\": \"%s\", \"current_status\": \"%s\"}}", endpoint, "running")); // FireboltEngineResponse assertEquals("http://engine/12345", client.getEngine("http://host", "account-id", "engine", "engine-id", "token").getEngine().getEndpoint()); } @Test - void getDefaultEngineByDatabaseName() throws FireboltException, IOException { + void getDefaultEngineByDatabaseName() throws SQLException, IOException { String endpoint = "http://engine/12345"; injectMockedResponse(httpClient, HTTP_OK, format("{\"engine_url\": \"%s\"}", endpoint)); // FireboltDefaultDatabaseEngineResponse assertEquals(endpoint, client.getDefaultEngineByDatabaseName("http://host", "account-id", "db", "token").getEngineUrl()); } @Test - void getEngineId() throws FireboltException, IOException { + void getEngineId() throws SQLException, IOException { String engineId = "456"; injectMockedResponse(httpClient, HTTP_OK, format("{\"engine_id\": {\"engine_id\":\"%s\"}}", engineId)); // FireboltEngineIdResponse assertEquals(engineId, client.getEngineId("http://host", "account-id", "db", "token").getEngine().getEngineId()); diff --git a/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java b/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java index ead85c686..c120e3378 100644 --- a/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java @@ -18,6 +18,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; +import java.sql.SQLException; import static com.firebolt.jdbc.client.UserAgentFormatter.userAgent; import static java.net.HttpURLConnection.HTTP_FORBIDDEN; @@ -61,7 +62,7 @@ protected AuthenticationRequest getAuthenticationRequest(String username, String } @Test - void shouldPostConnectionTokens() throws IOException, FireboltException { + void shouldPostConnectionTokens() throws SQLException, IOException { Response response = mock(Response.class); Call call = mock(Call.class); ResponseBody body = mock(ResponseBody.class); diff --git a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java index 342dd6930..ebab5e97b 100644 --- a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java @@ -20,6 +20,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; +import java.sql.SQLException; import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_BAD_GATEWAY; @@ -72,14 +73,14 @@ void setUp() { } @Test - void shouldGetGatewayUrlWhenResponseIsOk() throws IOException, FireboltException { + void shouldGetGatewayUrlWhenResponseIsOk() throws SQLException, IOException { String engineUrl = "http://engine"; injectMockedResponse(httpClient, HTTP_OK, format("{\"engineUrl\": \"%s\"}", engineUrl)); assertEquals(engineUrl, fireboltGatewayUrlClient.retrieve("access_token", "account").getEngineUrl()); } @Test - void shouldGetAccountId() throws IOException, FireboltException { + void shouldGetAccountId() throws SQLException, IOException { FireboltAccount account = new FireboltAccount("12345", "central", 2); injectMockedResponse(httpClient, HTTP_OK, "{\"id\": \"12345\", \"region\":\"central\", \"infraVersion\":2}"); assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); diff --git a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java index f05a05f39..2b41e7f46 100644 --- a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java +++ b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java @@ -79,11 +79,11 @@ class StatementClientImplTest { "false,http://firebolt1:555/?database=db1&output_format=TabSeparatedWithNamesAndTypes&compress=1&max_execution_time=15", "true,http://firebolt1:555/?database=db1&account_id=12345&output_format=TabSeparatedWithNamesAndTypes" }) - void shouldPostSqlQueryWithExpectedUrl(boolean systemEngine, String expectedUrl) throws FireboltException, IOException { + void shouldPostSqlQueryWithExpectedUrl(boolean systemEngine, String expectedUrl) throws SQLException, IOException { assertEquals(expectedUrl, shouldPostSqlQuery(systemEngine).getValue()); } - private Entry shouldPostSqlQuery(boolean systemEngine) throws FireboltException, IOException { + private Entry shouldPostSqlQuery(boolean systemEngine) throws SQLException, IOException { FireboltProperties fireboltProperties = FireboltProperties.builder().database("db1").compress(true).host("firebolt1").port(555).accountId("12345").systemEngine(systemEngine).build(); when(connection.getAccessToken()) .thenReturn(Optional.of("token")); @@ -206,7 +206,7 @@ void shouldRetryOnUnauthorized() throws IOException, SQLException { } @Test - void shouldNotRetryNoMoreThanOnceOnUnauthorized() throws IOException, FireboltException { + void shouldNotRetryNoMoreThanOnceOnUnauthorized() throws SQLException, IOException { Call okCall = getMockedCallWithResponse(200, ""); Call unauthorizedCall = getMockedCallWithResponse(401, ""); when(okHttpClient.newCall(any())).thenReturn(unauthorizedCall).thenReturn(unauthorizedCall).thenReturn(okCall); @@ -230,7 +230,7 @@ void shouldNotRetryNoMoreThanOnceOnUnauthorized() throws IOException, FireboltEx "db1,use database db2,,db1", // no header returned "db1,use database db2,database=db3,db3" // use db2 but switched to db3 }) - void useDatabase(String oldDb, String command, String responseHeader, String expectedDb) throws IOException, SQLException { + void useDatabase(String oldDb, String command, String responseHeader, String expectedDb) throws SQLException, IOException { try (FireboltConnection connection = use("database", oldDb, command, responseHeader)) { assertEquals(expectedDb, connection.getSessionProperties().getDatabase()); } @@ -243,7 +243,7 @@ void useDatabase(String oldDb, String command, String responseHeader, String exp "e1,use engine e2,,e1", // no header returned "e1,use engine e2,engine=e3,e3" // use e2 but switched to e3 }) - void useEngine(String oldEngine, String command, String responseHeader, String expectedEngine) throws IOException, SQLException { + void useEngine(String oldEngine, String command, String responseHeader, String expectedEngine) throws SQLException, IOException { try (FireboltConnection connection = use("engine", oldEngine, command, responseHeader)) { assertEquals(expectedEngine, connection.getSessionProperties().getEngine()); } @@ -344,7 +344,7 @@ private FireboltConnection use(String propName, String propValue, String command } } - private FireboltConnection use(int mockedInfraVersion, Properties props, String useCommand, Map> responseHeaders) throws IOException, SQLException { + private FireboltConnection use(int mockedInfraVersion, Properties props, String useCommand, Map> responseHeaders) throws SQLException, IOException { props.setProperty(FireboltSessionProperty.CONNECTION_TIMEOUT_MILLIS.getKey(), "0"); // simplifies mocking Call useCall = getMockedCallWithResponse(200, "", responseHeaders); Call select1Call = getMockedCallWithResponse(200, ""); @@ -396,7 +396,7 @@ protected void assertDatabaseExisting(String database) { "Engine MyEngine does not exist or not authorized; Please grant at least one role to user associated your service account." }, delimiter = ';') - void shouldThrowUnauthorizedExceptionWhenNoAssociatedUser(String serverErrorMessage, String exceptionMessage) throws IOException, FireboltException { + void shouldThrowUnauthorizedExceptionWhenNoAssociatedUser(String serverErrorMessage, String exceptionMessage) throws SQLException, IOException { when(connection.getAccessToken()).thenReturn(Optional.of("token")); Call unauthorizedCall = getMockedCallWithResponse(500, serverErrorMessage); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java index c48ea4bdb..38d638603 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java @@ -6,6 +6,7 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.sql.SQLException; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; @@ -41,7 +42,7 @@ void setUp() { } @Test - void shouldGetConnectionToken() throws IOException, FireboltException { + void shouldGetConnectionToken() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); FireboltConnectionTokens tokens = new FireboltConnectionTokens("access", 52); when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)).thenReturn(tokens); @@ -51,7 +52,7 @@ void shouldGetConnectionToken() throws IOException, FireboltException { } @Test - void shouldCallClientOnlyOnceWhenServiceCalledTwiceForTheSameHost() throws IOException, FireboltException { + void shouldCallClientOnlyOnceWhenServiceCalledTwiceForTheSameHost() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); FireboltConnectionTokens tokens = new FireboltConnectionTokens("access", 52); when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)).thenReturn(tokens); @@ -62,7 +63,7 @@ void shouldCallClientOnlyOnceWhenServiceCalledTwiceForTheSameHost() throws IOExc } @Test - void shouldGetConnectionTokenAfterRemoving() throws IOException, FireboltException { + void shouldGetConnectionTokenAfterRemoving() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); FireboltConnectionTokens token1 = new FireboltConnectionTokens("one", 52); FireboltConnectionTokens token2 = new FireboltConnectionTokens("two", 52); @@ -78,7 +79,7 @@ void shouldGetConnectionTokenAfterRemoving() throws IOException, FireboltExcepti } @Test - void shouldThrowExceptionWithServerResponseWhenAResponseIsAvailable() throws IOException, FireboltException { + void shouldThrowExceptionWithServerResponseWhenAResponseIsAvailable() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); Mockito.when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)) .thenThrow(new FireboltException("An error happened during authentication", 403, "INVALID PASSWORD")); @@ -91,7 +92,7 @@ void shouldThrowExceptionWithServerResponseWhenAResponseIsAvailable() throws IOE } @Test - void shouldThrowExceptionWithExceptionMessageWhenAResponseIsNotAvailable() throws IOException, FireboltException { + void shouldThrowExceptionWithExceptionMessageWhenAResponseIsNotAvailable() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); Mockito.when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)) .thenThrow(new NullPointerException("NULL!")); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltGatewayUrlServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltGatewayUrlServiceTest.java index 66072e628..6e8401163 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltGatewayUrlServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltGatewayUrlServiceTest.java @@ -6,6 +6,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import java.sql.SQLException; + import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -20,7 +22,7 @@ class FireboltGatewayUrlServiceTest { "https://host?name=value,https://host?name=value", "host?name=value,https://host?name=value", }) - void test(String rawUrl, String expectedUrl) throws FireboltException { + void test(String rawUrl, String expectedUrl) throws SQLException { @SuppressWarnings("unchecked") FireboltAccountRetriever fireboltGatewayUrlClient = mock(FireboltAccountRetriever.class); when(fireboltGatewayUrlClient.retrieve("token", "account")).thenReturn(new GatewayUrlResponse(rawUrl)); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java index d6dbabc1f..2c2e93999 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java @@ -66,7 +66,7 @@ void shouldExecuteQueryWithLocalHostFormatParameters() throws SQLException { } @Test - void shouldCancelQueryWithAllRequiredParams() throws FireboltException { + void shouldCancelQueryWithAllRequiredParams() throws SQLException { FireboltProperties fireboltProperties = fireboltProperties("firebolt1", false); FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); fireboltStatementService.abortStatement("123", fireboltProperties); @@ -127,7 +127,7 @@ void shouldBeEmptyWithNonQueryStatement() throws SQLException { } @Test - void abortStatementHttpRequest() throws FireboltException { + void abortStatementHttpRequest() throws SQLException { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); fireboltStatementService.abortStatement("id", emptyFireboltProperties); verify(statementClient).abortStatement("id", emptyFireboltProperties); diff --git a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java index fa128d163..cf5b952c4 100644 --- a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java +++ b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java @@ -26,18 +26,18 @@ class JavaTypeToFireboltSQLStringTest { @Test - void shouldTransformAnyNullToString() throws FireboltException { + void shouldTransformAnyNullToString() throws SQLException { assertEquals("NULL", JavaTypeToFireboltSQLString.transformAny(null)); } @ParameterizedTest @EnumSource(value = JavaTypeToFireboltSQLString.class) - void shouldTransformNull(JavaTypeToFireboltSQLString type) throws FireboltException { + void shouldTransformNull(JavaTypeToFireboltSQLString type) throws SQLException { assertEquals("NULL", type.transform(null)); } @Test - void shouldTransformBooleanToString() throws FireboltException { + void shouldTransformBooleanToString() throws SQLException { assertEquals("1", JavaTypeToFireboltSQLString.BOOLEAN.transform(true)); assertEquals("0", JavaTypeToFireboltSQLString.BOOLEAN.transform(false)); @@ -46,7 +46,7 @@ void shouldTransformBooleanToString() throws FireboltException { } @Test - void shouldTransformUUIDToString() throws FireboltException { + void shouldTransformUUIDToString() throws SQLException { String uuidValue = "2ac03dc8-f7c9-11ec-b939-0242ac120002"; UUID uuid = UUID.fromString(uuidValue); assertEquals(uuidValue, JavaTypeToFireboltSQLString.UUID.transform(uuid)); @@ -57,7 +57,7 @@ void shouldTransformUUIDToString() throws FireboltException { } @Test - void shouldTransformShortToString() throws FireboltException { + void shouldTransformShortToString() throws SQLException { short s = 123; assertEquals("123", JavaTypeToFireboltSQLString.SHORT.transform(s)); @@ -67,14 +67,14 @@ void shouldTransformShortToString() throws FireboltException { } @Test - void shouldEscapeCharactersWhenTransformingFromString() throws FireboltException { + void shouldEscapeCharactersWhenTransformingFromString() throws SQLException { assertEquals("'105'' OR 1=1--'' '", JavaTypeToFireboltSQLString.STRING.transform("105' OR 1=1--' ")); assertEquals("'105'' OR 1=1--'' '", JavaTypeToFireboltSQLString.transformAny("105' OR 1=1--' ")); } @Test - void shouldTransformLongToString() throws FireboltException { + void shouldTransformLongToString() throws SQLException { assertEquals("105", JavaTypeToFireboltSQLString.LONG.transform(105L)); assertEquals("105", JavaTypeToFireboltSQLString.transformAny(105L)); @@ -83,7 +83,7 @@ void shouldTransformLongToString() throws FireboltException { } @Test - void shouldTransformIntegerToString() throws FireboltException { + void shouldTransformIntegerToString() throws SQLException { assertEquals("105", JavaTypeToFireboltSQLString.INTEGER.transform(105)); assertEquals("105", JavaTypeToFireboltSQLString.transformAny(105)); @@ -92,7 +92,7 @@ void shouldTransformIntegerToString() throws FireboltException { } @Test - void shouldTransformBigIntegerToString() throws FireboltException { + void shouldTransformBigIntegerToString() throws SQLException { assertEquals("1111111111", JavaTypeToFireboltSQLString.BIG_INTEGER.transform(1111111111)); assertEquals("1111111111", JavaTypeToFireboltSQLString.transformAny(1111111111)); @@ -101,7 +101,7 @@ void shouldTransformBigIntegerToString() throws FireboltException { } @Test - void shouldTransformFloatToString() throws FireboltException { + void shouldTransformFloatToString() throws SQLException { assertEquals("1.5", JavaTypeToFireboltSQLString.FLOAT.transform(1.50f)); assertEquals("1.5", JavaTypeToFireboltSQLString.transformAny(1.50f)); @@ -110,7 +110,7 @@ void shouldTransformFloatToString() throws FireboltException { } @Test - void shouldTransformDoubleToString() throws FireboltException { + void shouldTransformDoubleToString() throws SQLException { assertEquals("105.0", JavaTypeToFireboltSQLString.DOUBLE.transform(105)); assertEquals("105", JavaTypeToFireboltSQLString.transformAny(105)); @@ -120,7 +120,7 @@ void shouldTransformDoubleToString() throws FireboltException { @Test @DefaultTimeZone("Europe/London") - void shouldTransformDateToString() throws FireboltException { + void shouldTransformDateToString() throws SQLException { Date d = Date.valueOf(LocalDate.of(2022, 5, 23)); String expectedDateString = "'2022-05-23'"; assertEquals(expectedDateString, JavaTypeToFireboltSQLString.DATE.transform(d)); @@ -128,12 +128,12 @@ void shouldTransformDateToString() throws FireboltException { } @Test - void shouldTransformDateWithDefaultTimezoneToString() throws FireboltException { + void shouldTransformDateWithDefaultTimezoneToString() throws SQLException { assertEquals("'2022-05-23'", JavaTypeToFireboltSQLString.DATE.transform(Date.valueOf(LocalDate.of(2022, 5, 23)), TimeZone.getDefault())); } @Test - void shouldTransformDateWithDefaultTimezoneIdToString() throws FireboltException { + void shouldTransformDateWithDefaultTimezoneIdToString() throws SQLException { assertEquals("'2022-05-23'", JavaTypeToFireboltSQLString.DATE.transform(Date.valueOf(LocalDate.of(2022, 5, 23)), TimeZone.getDefault().getID())); } @@ -144,7 +144,7 @@ void shouldThrowExceptionWhenTransformingDateToStringWithWrongParameter() { } @Test - void shouldTransformTimeStampToString() throws FireboltException { + void shouldTransformTimeStampToString() throws SQLException { Timestamp ts = Timestamp.valueOf(LocalDateTime.of(2022, 5, 23, 12, 57, 13, 173456789)); assertEquals("'2022-05-23 12:57:13.173456789'", JavaTypeToFireboltSQLString.TIMESTAMP.transform(ts)); assertEquals("'2022-05-23 12:57:13.173456789'", JavaTypeToFireboltSQLString.transformAny(ts)); @@ -168,18 +168,18 @@ void shouldTransformArrayOfArray() throws SQLException { } @Test - void shouldTransformJavaArrayOfArray() throws FireboltException { + void shouldTransformJavaArrayOfArray() throws SQLException { String[][] arr = new String[][] { { "a", "b" }, { "c" } }; assertEquals("[['a','b'],['c']]", JavaTypeToFireboltSQLString.ARRAY.transform(arr)); } @Test - void shouldTransformJavaArrayOfPrimitives() throws FireboltException { + void shouldTransformJavaArrayOfPrimitives() throws SQLException { assertEquals("[5]", JavaTypeToFireboltSQLString.ARRAY.transform(new int[] {5})); } @Test - void shouldTransformEmptyArray() throws FireboltException { + void shouldTransformEmptyArray() throws SQLException { assertEquals("[]", JavaTypeToFireboltSQLString.ARRAY.transform(new int[0])); } From 5d3ac714145118255ab4818d5eb9e19c45c20b3a Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 8 May 2024 15:40:47 +0300 Subject: [PATCH 02/52] FIR-32836: log is simplified now - no lombok in log (#405) --- build.gradle | 1 + lombok.config | 1 - .../java/integration/IntegrationTest.java | 2 - .../tests/PreparedStatementArrayTest.java | 2 - .../tests/PreparedStatementTest.java | 3 - .../tests/StatementCancelTest.java | 11 +- .../java/integration/tests/StatementTest.java | 2 - .../integration/tests/SystemEngineTest.java | 17 +-- .../java/integration/tests/TimeoutTest.java | 8 +- .../java/integration/tests/TimestampTest.java | 2 - .../java/com/firebolt/FireboltDriver.java | 13 +- .../firebolt/jdbc/client/FireboltClient.java | 10 +- .../jdbc/client/HttpClientConfig.java | 14 +-- .../jdbc/client/UsageTrackerUtil.java | 13 +- .../client/account/FireboltAccountClient.java | 2 - .../FireboltAuthenticationClient.java | 12 +- .../client/config/OkHttpClientCreator.java | 2 - .../jdbc/client/config/RetryInterceptor.java | 7 +- .../socket/FireboltSSLSocketFactory.java | 10 +- .../config/socket/FireboltSocketFactory.java | 10 +- .../jdbc/client/config/socket/SocketUtil.java | 19 ++- .../client/query/StatementClientImpl.java | 11 +- .../jdbc/connection/FireboltConnection.java | 17 +-- .../com/firebolt/jdbc/connection/UrlUtil.java | 7 +- .../settings/FireboltProperties.java | 2 - .../com/firebolt/jdbc/log/FireboltLogger.java | 35 ------ .../java/com/firebolt/jdbc/log/JDKLogger.java | 111 ------------------ .../com/firebolt/jdbc/log/SLF4JLogger.java | 89 -------------- .../metadata/FireboltDatabaseMetadata.java | 2 - .../jdbc/resultset/FireboltResultSet.java | 14 ++- .../jdbc/resultset/column/Column.java | 9 +- .../jdbc/resultset/column/ColumnType.java | 7 +- .../FireboltAuthenticationService.java | 14 ++- .../service/FireboltEngineApiService.java | 2 - ...ireboltEngineInformationSchemaService.java | 3 - .../service/FireboltStatementService.java | 2 - .../jdbc/statement/FireboltStatement.java | 29 ++--- .../statement/StatementResultWrapper.java | 14 +-- .../jdbc/statement/StatementUtil.java | 9 +- .../FireboltPreparedStatement.java | 10 +- .../rawstatement/RawStatementWrapper.java | 2 - .../java/com/firebolt/jdbc/type/BaseType.java | 1 - .../jdbc/type/array/SqlArrayUtil.java | 10 +- .../firebolt/jdbc/type/date/SqlDateUtil.java | 2 - .../com/firebolt/jdbc/util/CloseableUtil.java | 11 +- .../firebolt/jdbc/util/InputStreamUtil.java | 7 +- .../com/firebolt/jdbc/util/LoggerUtil.java | 51 ++++---- .../com/firebolt/jdbc/util/PropertyUtil.java | 2 - .../com/firebolt/jdbc/util/VersionUtil.java | 9 +- .../java/com/firebolt/FireboltDriverTest.java | 6 +- .../com/firebolt/jdbc/log/JDKLoggerTest.java | 68 ----------- .../firebolt/jdbc/log/LogLevelExample.java | 0 .../firebolt/jdbc/log/SLF4JLoggerTest.java | 68 ----------- .../firebolt/jdbc/util/LoggerUtilTest.java | 16 +-- 54 files changed, 204 insertions(+), 597 deletions(-) delete mode 100644 src/main/java/com/firebolt/jdbc/log/FireboltLogger.java delete mode 100644 src/main/java/com/firebolt/jdbc/log/JDKLogger.java delete mode 100644 src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java delete mode 100644 src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java delete mode 100644 src/test/java/com/firebolt/jdbc/log/LogLevelExample.java delete mode 100644 src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java diff --git a/build.gradle b/build.gradle index be1e56db8..066ca2b14 100644 --- a/build.gradle +++ b/build.gradle @@ -69,6 +69,7 @@ dependencies { implementation 'net.jodah:expiringmap:0.5.11' implementation 'org.apache.commons:commons-text:1.12.0' implementation 'org.lz4:lz4-java:1.8.0' + implementation 'org.slf4j:jul-to-slf4j:2.0.13' implementation fileTree(dir: 'libs', includes: ['*.jar']) diff --git a/lombok.config b/lombok.config index 86058d25d..9ab6f2abe 100644 --- a/lombok.config +++ b/lombok.config @@ -1,4 +1,3 @@ lombok.anyConstructor.addConstructorProperties = true config.stopBubbling = true lombok.addLombokGeneratedAnnotation = true -lombok.log.custom.declaration = com.firebolt.jdbc.log.FireboltLogger com.firebolt.jdbc.util.LoggerUtil.getLogger(NAME) \ No newline at end of file diff --git a/src/integrationTest/java/integration/IntegrationTest.java b/src/integrationTest/java/integration/IntegrationTest.java index d51246930..06549081c 100644 --- a/src/integrationTest/java/integration/IntegrationTest.java +++ b/src/integrationTest/java/integration/IntegrationTest.java @@ -1,7 +1,6 @@ package integration; import com.firebolt.jdbc.client.HttpClientConfig; -import lombok.CustomLog; import lombok.SneakyThrows; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestInstance; @@ -17,7 +16,6 @@ import static com.firebolt.jdbc.connection.FireboltConnectionUserPassword.SYSTEM_ENGINE_NAME; import static org.junit.jupiter.api.Assertions.assertNotNull; -@CustomLog @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Tag("common") public abstract class IntegrationTest { diff --git a/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java b/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java index c0d08f173..7a39e693c 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java @@ -3,7 +3,6 @@ import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; import integration.IntegrationTest; -import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,7 +26,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; -@CustomLog class PreparedStatementArrayTest extends IntegrationTest { enum PreparedStatementValueSetter { ARRAY { diff --git a/src/integrationTest/java/integration/tests/PreparedStatementTest.java b/src/integrationTest/java/integration/tests/PreparedStatementTest.java index 89f0e54c2..306335dc8 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementTest.java @@ -9,7 +9,6 @@ import integration.ConnectionInfo; import integration.IntegrationTest; import lombok.Builder; -import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Value; import org.junit.jupiter.api.AfterEach; @@ -33,7 +32,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; @@ -51,7 +49,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -@CustomLog class PreparedStatementTest extends IntegrationTest { @BeforeEach diff --git a/src/integrationTest/java/integration/tests/StatementCancelTest.java b/src/integrationTest/java/integration/tests/StatementCancelTest.java index a2538307b..83a01c732 100644 --- a/src/integrationTest/java/integration/tests/StatementCancelTest.java +++ b/src/integrationTest/java/integration/tests/StatementCancelTest.java @@ -5,7 +5,6 @@ import com.firebolt.jdbc.statement.FireboltStatement; import integration.EnvironmentCondition; import integration.IntegrationTest; -import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -17,13 +16,15 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; import static integration.EnvironmentCondition.Attribute.databaseVersion; import static integration.EnvironmentCondition.Comparison.GE; import static org.junit.jupiter.api.Assertions.assertEquals; -@CustomLog class StatementCancelTest extends IntegrationTest { + private static final Logger log = Logger.getLogger(StatementCancelTest.class.getName()); @BeforeEach void beforeEach() { @@ -91,11 +92,11 @@ private void verifyThatNoMoreRecordsAreAdded(Connection connection, String table // data is available. long waitForResultTime = insertTime / 2; long waitForResultDelay = waitForResultTime / 10; - log.info("verifyThatNoMoreRecordsAreAdded insertTime={}, waitForResultTime={}", insertTime, waitForResultTime); + log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded insertTime={0}, waitForResultTime={0}", new Object[] {insertTime, waitForResultTime}); int count0; int i = 0; for (count0 = count(connection, tableName); i < 10; count0 = count(connection, tableName), i++) { - log.info("verifyThatNoMoreRecordsAreAdded count0={}", count0); + log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded count0={0}", count0); if (count0 > 0) { break; } @@ -108,7 +109,7 @@ private void verifyThatNoMoreRecordsAreAdded(Connection connection, String table int count1 = count(connection, tableName); Thread.sleep(insertTime); // waiting to see if more records are being added int count2 = count(connection, tableName); - log.info("verifyThatNoMoreRecordsAreAdded count1={}, count2={}", count1, count2); + log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded count1={0}, count2={1}", new Object[] {count1, count2}); assertEquals(count1, count2); } diff --git a/src/integrationTest/java/integration/tests/StatementTest.java b/src/integrationTest/java/integration/tests/StatementTest.java index f8a0579c6..05331d865 100644 --- a/src/integrationTest/java/integration/tests/StatementTest.java +++ b/src/integrationTest/java/integration/tests/StatementTest.java @@ -5,7 +5,6 @@ import integration.ConnectionInfo; import integration.IntegrationTest; import kotlin.collections.ArrayDeque; -import lombok.CustomLog; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -42,7 +41,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -@CustomLog class StatementTest extends IntegrationTest { @BeforeEach diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 00e9cd573..29bbc30ff 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -6,7 +6,6 @@ import integration.ConnectionInfo; import integration.EnvironmentCondition; import integration.IntegrationTest; -import lombok.CustomLog; import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -33,6 +32,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Stream; import static java.lang.String.format; @@ -45,7 +46,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -@CustomLog @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class SystemEngineTest extends IntegrationTest { @@ -59,12 +59,14 @@ public class SystemEngineTest extends IntegrationTest { private static final String TABLE1 = TABLE + "_1"; private static final String TABLE2 = TABLE + "_2"; + private static final Logger log = Logger.getLogger(SystemEngineTest.class.getName()); + @BeforeAll void beforeAll() { try { executeStatementFromFile("/statements/system/ddl.sql", getSystemEngineName()); } catch (Exception e) { - log.warn("Could not execute statement", e); + log.log(Level.WARNING, "Could not execute statement", e); } } @@ -73,7 +75,7 @@ void afterAll() { try { executeStatementFromFile("/statements/system/cleanup.sql", getSystemEngineName()); } catch (Exception e) { - log.warn("Could not execute statement", e); + log.log(Level.WARNING, "Could not execute statement", e); } } @@ -153,7 +155,7 @@ void useDatabase(String entityType) throws SQLException { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); } catch (SQLException e) { // catch just in case to do our best to clean everything even if test has failed - log.warn("Cannot perform query {}", query, e); + log.log(Level.WARNING, "Cannot perform query " + query, e); } } } @@ -273,9 +275,8 @@ void shouldExecuteEngineManagementQueries() throws SQLException { format("DROP DATABASE %s", SECOND_DATABASE_NAME)}) { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); - } catch ( - SQLException e) { // catch just in case to do our best to clean everything even if test has failed - log.warn("Cannot perform query {}", query, e); + } catch (SQLException e) { // catch just in case to do our best to clean everything even if test has failed + log.log(Level.WARNING, "Cannot perform query " + query, e); } } } diff --git a/src/integrationTest/java/integration/tests/TimeoutTest.java b/src/integrationTest/java/integration/tests/TimeoutTest.java index a0e77a348..ac3e14b2e 100644 --- a/src/integrationTest/java/integration/tests/TimeoutTest.java +++ b/src/integrationTest/java/integration/tests/TimeoutTest.java @@ -2,9 +2,7 @@ import com.firebolt.jdbc.connection.FireboltConnection; import integration.EnvironmentCondition; -import integration.EnvironmentCondition.Comparison; import integration.IntegrationTest; -import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -16,16 +14,18 @@ import java.sql.Statement; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; import static integration.EnvironmentCondition.Attribute.databaseVersion; import static integration.EnvironmentCondition.Comparison.GE; import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertTrue; -@CustomLog class TimeoutTest extends IntegrationTest { private static final int MIN_TIME_SECONDS = 350; private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 180000000000L); + private static final Logger log = Logger.getLogger(TimeoutTest.class.getName()); private long startTime; @BeforeEach @@ -37,7 +37,7 @@ void before() { void after() { long endTime = System.nanoTime(); long elapsedTimeSeconds = (endTime - startTime) / 1_000_000_000; - log.info("Time elapsed: {} seconds", elapsedTimeSeconds); + log.log(Level.INFO, "Time elapsed: {0} seconds", elapsedTimeSeconds); assertTrue(elapsedTimeSeconds > MIN_TIME_SECONDS, format("Test is too short. It took %d but should take at least %d seconds", elapsedTimeSeconds, MIN_TIME_SECONDS)); } diff --git a/src/integrationTest/java/integration/tests/TimestampTest.java b/src/integrationTest/java/integration/tests/TimestampTest.java index bfc0e4487..99732ea0e 100644 --- a/src/integrationTest/java/integration/tests/TimestampTest.java +++ b/src/integrationTest/java/integration/tests/TimestampTest.java @@ -3,7 +3,6 @@ import com.firebolt.jdbc.testutils.AssertionUtil; import integration.IntegrationTest; import io.zonky.test.db.postgres.embedded.EmbeddedPostgres; -import lombok.CustomLog; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -37,7 +36,6 @@ import static java.sql.Types.TIMESTAMP_WITH_TIMEZONE; import static org.junit.jupiter.api.Assertions.assertEquals; -@CustomLog @DefaultTimeZone("UTC") class TimestampTest extends IntegrationTest { private static final TimeZone UTC_TZ = TimeZone.getTimeZone("UTC"); diff --git a/src/main/java/com/firebolt/FireboltDriver.java b/src/main/java/com/firebolt/FireboltDriver.java index 96b759a7e..60e7da25e 100644 --- a/src/main/java/com/firebolt/FireboltDriver.java +++ b/src/main/java/com/firebolt/FireboltDriver.java @@ -1,27 +1,28 @@ package com.firebolt; import com.firebolt.jdbc.connection.FireboltConnection; -import com.firebolt.jdbc.exception.FireboltSQLFeatureNotSupportedException; +import com.firebolt.jdbc.util.LoggerUtil; import com.firebolt.jdbc.util.PropertyUtil; import com.firebolt.jdbc.util.VersionUtil; -import lombok.CustomLog; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverPropertyInfo; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; -@CustomLog public class FireboltDriver implements Driver { public static final String JDBC_FIREBOLT = "jdbc:firebolt:"; + private static Logger rootLog; + private static final Logger log; static { try { java.sql.DriverManager.registerDriver(new FireboltDriver()); + rootLog = LoggerUtil.getRootLogger(); + log = Logger.getLogger(FireboltDriver.class.getName()); log.info("Firebolt Driver registered"); } catch (SQLException ex) { throw new RuntimeException("Cannot register the driver"); @@ -59,7 +60,7 @@ public boolean jdbcCompliant() { } @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new FireboltSQLFeatureNotSupportedException(); + public Logger getParentLogger() { + return rootLog; } } diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index e0b7d24a2..8f3657071 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -4,7 +4,6 @@ import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.compress.LZ4InputStream; import com.firebolt.jdbc.util.CloseableUtil; -import lombok.CustomLog; import lombok.Getter; import lombok.NonNull; import okhttp3.Call; @@ -29,6 +28,8 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import static java.lang.String.format; @@ -37,13 +38,13 @@ import static java.util.Optional.ofNullable; @Getter -@CustomLog public abstract class FireboltClient { private static final String HEADER_AUTHORIZATION = "Authorization"; private static final String HEADER_AUTHORIZATION_BEARER_PREFIX_VALUE = "Bearer "; private static final String HEADER_USER_AGENT = "User-Agent"; private static final String HEADER_PROTOCOL_VERSION = "Firebolt-Protocol-Version"; + private static final Logger log = Logger.getLogger(FireboltClient.class.getName()); private final OkHttpClient httpClient; private final String headerUserAgentValue; protected final FireboltConnection connection; @@ -164,12 +165,13 @@ protected String getResponseAsString(Response response) throws SQLException, IOE return response.body().string(); } + @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both private String extractErrorMessage(Response response, boolean isCompress) throws SQLException { byte[] entityBytes; try { entityBytes = response.body() != null ? response.body().bytes() : null; } catch (IOException e) { - log.warn("Could not parse response containing the error message from Firebolt", e); + log.log(Level.WARNING, "Could not parse response containing the error message from Firebolt", e); String errorResponseMessage = format("Server failed to execute query%ninternal error:%n%s", getInternalErrorWithHeadersText(response)); throw new FireboltException(errorResponseMessage, response.code(), e); @@ -184,7 +186,7 @@ private String extractErrorMessage(Response response, boolean isCompress) throws return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)).lines() .collect(Collectors.joining("\n")) + "\n"; } catch (Exception e) { - log.warn("Could not decompress error from server"); + log.log(Level.WARNING, "Could not decompress error from server"); } } return new String(entityBytes, StandardCharsets.UTF_8); diff --git a/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java b/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java index 7849c65a8..557b0746f 100644 --- a/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java +++ b/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java @@ -1,20 +1,18 @@ package com.firebolt.jdbc.client; +import com.firebolt.jdbc.client.config.OkHttpClientCreator; +import com.firebolt.jdbc.connection.settings.FireboltProperties; +import okhttp3.OkHttpClient; + import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.util.logging.Logger; -import com.firebolt.jdbc.client.config.OkHttpClientCreator; -import com.firebolt.jdbc.connection.settings.FireboltProperties; - -import lombok.CustomLog; -import okhttp3.OkHttpClient; - -@CustomLog public class HttpClientConfig { - + private static final Logger log = Logger.getLogger(HttpClientConfig.class.getName()); private static OkHttpClient instance; private HttpClientConfig() { diff --git a/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java b/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java index 55aaa8eca..409c07ddd 100644 --- a/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java +++ b/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java @@ -1,16 +1,17 @@ package com.firebolt.jdbc.client; import com.firebolt.jdbc.util.VersionUtil; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; -@CustomLog @UtilityClass public class UsageTrackerUtil { + private static final Logger log = Logger.getLogger(UsageTrackerUtil.class.getName()); public static final Map CLIENT_MAP = Map.of( "Tableau", "com.tableau", "Looker", "com.looker", @@ -24,7 +25,7 @@ private static String getVersionForClass(String name) { Class c = Class.forName(name); return c.getPackage().getImplementationVersion(); } catch (ClassNotFoundException e) { - log.debug("Unable to get version for class " + name); + log.log(Level.FINE, "Unable to get version for class {0}", name); return ""; } } @@ -38,13 +39,13 @@ public Map getClients(StackTraceElement[] stack, Map connectorEntry : clientMap.entrySet()) { if (s.getClassName().contains(connectorEntry.getValue())) { String version = getVersionForClass(s.getClassName()); - log.debug("Detected running from " + connectorEntry.getKey() + " Version " + version); + log.log(Level.FINE, "Detected running from {0} Version {1}", new Object[] {connectorEntry.getKey(), version}); clients.put(connectorEntry.getKey(), version); } } } if (clients.isEmpty()) { - log.debug("No clients detected for tracking"); + log.log(Level.FINE, "No clients detected for tracking"); } return clients; } @@ -59,7 +60,7 @@ private static Map extractNameToVersion(String namesAndVersions) nameToVersion.put(connectorInfo[0], connectorInfo[1]); } } else { - log.debug(String.format("Incorrect connector format is provided: %s, Expected: ConnA:1.0.2,ConnB:2.9.3", namesAndVersions)); + log.log(Level.FINE, "Incorrect connector format is provided: {0}, Expected: ConnA:1.0.2,ConnB:2.9.3", namesAndVersions); } return nameToVersion; } diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java index 8b8bb98f3..69096c918 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java @@ -8,7 +8,6 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.ExceptionType; import com.firebolt.jdbc.exception.FireboltException; -import lombok.CustomLog; import okhttp3.OkHttpClient; import java.io.IOException; @@ -16,7 +15,6 @@ import static java.lang.String.format; -@CustomLog public class FireboltAccountClient extends FireboltClient { private static final String GET_ACCOUNT_ID_URI = "%s/iam/v2/accounts:getIdByName?accountName=%s"; diff --git a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java index d65b313ec..3c28151b5 100644 --- a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java +++ b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java @@ -3,17 +3,17 @@ import com.firebolt.jdbc.client.FireboltClient; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.FireboltConnectionTokens; -import com.firebolt.jdbc.exception.FireboltException; -import lombok.CustomLog; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; -@CustomLog public abstract class FireboltAuthenticationClient extends FireboltClient { + private static final Logger log = Logger.getLogger(FireboltAuthenticationClient.class.getName()); protected FireboltAuthenticationClient(OkHttpClient httpClient, FireboltConnection connection, String customDrivers, String customClients) { @@ -33,7 +33,7 @@ public FireboltConnectionTokens postConnectionTokens(String host, String user, S throws SQLException, IOException { AuthenticationRequest authenticationRequest = getAuthenticationRequest(user, password, host, environment); String uri = authenticationRequest.getUri(); - log.debug("Creating connection with url {}", uri); + log.log(Level.FINE, "Creating connection with url {0}", uri); Request request = createPostRequest(uri, null, authenticationRequest.getRequestBody(), null); try (Response response = execute(request, host)) { String responseString = getResponseAsString(response); @@ -47,13 +47,13 @@ public FireboltConnectionTokens postConnectionTokens(String host, String user, S private void logToken(FireboltConnectionTokens connectionTokens) { logIfPresent(connectionTokens.getAccessToken(), "Retrieved access_token"); if (connectionTokens.getExpiresInSeconds() >=- 0) { - log.debug("Retrieved expires_in"); + log.log(Level.FINE, "Retrieved expires_in"); } } private void logIfPresent(String token, String message) { if (token != null && !token.isEmpty()) { - log.debug(message); + log.log(Level.FINE, message); } } diff --git a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java index da5fe01e2..e45870b9e 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java +++ b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java @@ -4,7 +4,6 @@ import com.firebolt.jdbc.client.config.socket.FireboltSocketFactory; import com.firebolt.jdbc.connection.settings.FireboltProperties; import lombok.Builder; -import lombok.CustomLog; import lombok.Value; import lombok.experimental.UtilityClass; import okhttp3.ConnectionPool; @@ -36,7 +35,6 @@ * Class to configure the http client using the session settings */ @UtilityClass -@CustomLog public class OkHttpClientCreator { private static final String SSL_STRICT_MODE = "strict"; diff --git a/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java b/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java index 9ab7c6864..8959d5681 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java +++ b/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java @@ -1,6 +1,5 @@ package com.firebolt.jdbc.client.config; -import lombok.CustomLog; import lombok.NonNull; import lombok.RequiredArgsConstructor; import okhttp3.Interceptor; @@ -11,6 +10,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import static java.net.HttpURLConnection.HTTP_BAD_GATEWAY; import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; @@ -18,11 +19,11 @@ import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; @RequiredArgsConstructor -@CustomLog public class RetryInterceptor implements Interceptor { private static final Set RETRYABLE_RESPONSE_CODES = new HashSet<>( Arrays.asList(HTTP_CLIENT_TIMEOUT, HTTP_BAD_GATEWAY, HTTP_UNAVAILABLE, HTTP_GATEWAY_TIMEOUT)); + private static final Logger log = Logger.getLogger(RetryInterceptor.class.getName()); private final int maxRetries; @@ -44,7 +45,7 @@ public Response intercept(@NonNull Chain chain) throws IOException { failureInfo = String.format("Failure #%d - Response code: %d. Retrying to send the request.", tryCount, response.code()); } - log.warn(failureInfo); + log.log(Level.WARNING, failureInfo); // retry the request response.close(); diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java index 5a6fe7e45..c1f3b06a5 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java @@ -1,18 +1,14 @@ package com.firebolt.jdbc.client.config.socket; -import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; +import com.firebolt.jdbc.connection.settings.FireboltProperties; +import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import javax.net.ssl.SSLSocketFactory; - -import com.firebolt.jdbc.connection.settings.FireboltProperties; - -import lombok.CustomLog; +import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; -@CustomLog public class FireboltSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; private final FireboltProperties fireboltProperties; diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java index 299715bda..e424c41b0 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java @@ -1,18 +1,14 @@ package com.firebolt.jdbc.client.config.socket; -import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; +import com.firebolt.jdbc.connection.settings.FireboltProperties; +import javax.net.SocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import javax.net.SocketFactory; - -import com.firebolt.jdbc.connection.settings.FireboltProperties; - -import lombok.CustomLog; +import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; -@CustomLog public class FireboltSocketFactory extends SocketFactory { private static final javax.net.SocketFactory delegate = SocketFactory.getDefault(); private final FireboltProperties fireboltProperties; diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java b/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java index cd70d43ab..61b080b25 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java @@ -1,19 +1,19 @@ package com.firebolt.jdbc.client.config.socket; -import java.io.IOException; -import java.net.Socket; -import java.net.SocketOption; - import com.firebolt.jdbc.connection.settings.FireboltProperties; - import jdk.net.ExtendedSocketOptions; import jdk.net.Sockets; -import lombok.CustomLog; import lombok.experimental.UtilityClass; +import java.io.IOException; +import java.net.Socket; +import java.net.SocketOption; +import java.util.logging.Level; +import java.util.logging.Logger; + @UtilityClass -@CustomLog public class SocketUtil { + private static final Logger log = Logger.getLogger(SocketUtil.class.getName()); public static Socket wrap(Socket s, FireboltProperties fireboltProperties) throws IOException { s.setKeepAlive(true); @@ -23,7 +23,7 @@ public static Socket wrap(Socket s, FireboltProperties fireboltProperties) throw setSocketOption(s, ExtendedSocketOptions.TCP_KEEPCOUNT, fireboltProperties.getTcpKeepCount()); setSocketOption(s, ExtendedSocketOptions.TCP_KEEPINTERVAL, fireboltProperties.getTcpKeepInterval()); } catch (Error | Exception e) { - log.debug("Could not set socket options", e); + log.log(Level.FINE, "Could not set socket options", e); } return s; } @@ -32,8 +32,7 @@ private void setSocketOption(Socket socket, SocketOption option, int va try { Sockets.setOption(socket, option, value); } catch (Exception e) { - log.debug("Could not set the socket option {}. The operation is not supported: {}", option.name(), - e.getMessage()); + log.log(Level.FINE, "Could not set the socket option {0}. The operation is not supported: {1}", new Object[] {option.name(), e.getMessage()}); } } } diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java index 2db8719a6..da6c18bd7 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java @@ -11,7 +11,6 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatement; import com.firebolt.jdbc.util.CloseableUtil; import com.firebolt.jdbc.util.PropertyUtil; -import lombok.CustomLog; import lombok.NonNull; import okhttp3.Call; import okhttp3.Dispatcher; @@ -38,6 +37,8 @@ import java.util.Optional; import java.util.function.BiPredicate; import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; import static com.firebolt.jdbc.connection.settings.FireboltQueryParameterKey.DEFAULT_FORMAT; @@ -49,7 +50,6 @@ import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import static java.util.Optional.ofNullable; -@CustomLog public class StatementClientImpl extends FireboltClient implements StatementClient { private static final String TAB_SEPARATED_WITH_NAMES_AND_TYPES_FORMAT = "TabSeparatedWithNamesAndTypes"; @@ -57,6 +57,7 @@ public class StatementClientImpl extends FireboltClient implements StatementClie Pattern.compile("HTTP status code: 401"), "Please associate user with your service account.", Pattern.compile("Engine .+? does not exist or not authorized"), "Please grant at least one role to user associated your service account." ); + private static final Logger log = Logger.getLogger(StatementClientImpl.class.getName()); private final BiPredicate isCallWithLabel = (call, label) -> call.request().tag() instanceof String && Objects.equals(call.request().tag(), label); // visible for testing @@ -158,11 +159,11 @@ public InputStream executeSqlStatement(@NonNull StatementInfoWrapper statementIn private InputStream executeSqlStatementWithRetryOnUnauthorized(String label, @NonNull FireboltProperties connectionProperties, String formattedStatement, String uri) throws SQLException, IOException { try { - log.debug("Posting statement with label {} to URI: {}", label, uri); + log.log(Level.FINE, "Posting statement with label {0} to URI: {1}", new Object[] {label, uri}); return postSqlStatement(connectionProperties, formattedStatement, uri, label); } catch (FireboltException exception) { if (exception.getType() == UNAUTHORIZED) { - log.debug("Retrying to post statement with label {} following a 401 status code to URI: {}",label, uri); + log.log(Level.FINE, "Retrying to post statement with label {0} following a 401 status code to URI: {1}", new Object[] {label, uri}); return postSqlStatement(connectionProperties, formattedStatement, uri, label); } else { throw exception; @@ -223,7 +224,7 @@ private void abortRunningDbStatement(String label, FireboltProperties fireboltPr if (e.getType() == ExceptionType.INVALID_REQUEST || e.getType() == ExceptionType.RESOURCE_NOT_FOUND) { // 400 on that request indicates that the statement does not exist // 404 - the same when working against "real" v2 engine - log.warn(e.getMessage()); + log.warning(e.getMessage()); } else { throw e; } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 7cf92e5b4..0f3dbe040 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -19,7 +19,6 @@ import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; import com.firebolt.jdbc.util.PropertyUtil; -import lombok.CustomLog; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -51,15 +50,17 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; import static java.lang.String.format; import static java.sql.ResultSet.CLOSE_CURSORS_AT_COMMIT; import static java.sql.ResultSet.TYPE_FORWARD_ONLY; -@CustomLog public abstract class FireboltConnection extends JdbcBase implements Connection { + private static final Logger log = Logger.getLogger(FireboltConnection.class.getName()); private final FireboltAuthenticationService fireboltAuthenticationService; private final FireboltStatementService fireboltStatementService; protected String httpConnectionUrl; @@ -161,7 +162,7 @@ protected void connect() throws SQLException { } databaseMetaData = retrieveMetaData(); - log.debug("Connection opened"); + log.fine("Connection opened"); } protected abstract void authenticate() throws SQLException; @@ -309,7 +310,7 @@ public void abort(Executor executor) throws SQLException { @Override public void close() { - log.debug("Closing connection"); + log.fine("Closing connection"); synchronized (this) { if (isClosed()) { return; @@ -322,13 +323,13 @@ public void close() { try { statement.close(false); } catch (Exception e) { - log.warn("Could not close statement", e); + log.log(Level.WARNING, "Could not close statement", e); } } statements.clear(); } databaseMetaData = null; - log.debug("Connection closed"); + log.warning("Connection closed"); } protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) { @@ -425,9 +426,9 @@ private void validateConnection(FireboltProperties fireboltProperties, boolean i // This error cannot be ignored when testing the connection to validate a param. if (ignoreToManyRequestsError && e instanceof FireboltException && ((FireboltException) e).getType() == ExceptionType.TOO_MANY_REQUESTS) { - log.warn("Too many requests are being sent to the server", e); + log.log(Level.WARNING, "Too many requests are being sent to the server", e); } else { - log.warn("Connection is not valid", e); + log.log(Level.WARNING, "Connection is not valid", e); throw e; } } diff --git a/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java b/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java index 1ceecc168..1142403e2 100644 --- a/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java +++ b/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java @@ -1,7 +1,6 @@ package com.firebolt.jdbc.connection; import com.firebolt.jdbc.connection.settings.FireboltSessionProperty; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.net.MalformedURLException; @@ -12,15 +11,17 @@ import java.util.Optional; import java.util.Properties; import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; import static java.lang.String.CASE_INSENSITIVE_ORDER; import static java.util.stream.Collectors.toMap; -@CustomLog @UtilityClass public class UrlUtil { public static final String JDBC_PREFIX = "jdbc:firebolt:"; + private static final Logger log = Logger.getLogger(UrlUtil.class.getName()); public static Properties extractProperties(String jdbcUrl) { return parseUriQueryPart(jdbcUrl); @@ -39,7 +40,7 @@ private static Properties parseUriQueryPart(String jdbcConnectionString) { if (keyValueTokens.length == 2) { uriProperties.put(keyValueTokens[0], keyValueTokens[1]); } else { - log.warn("Cannot parse key-pair: {}", keyValue); + log.log(Level.WARNING, "Cannot parse key-pair: {0}", keyValue); } } } diff --git a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java index 7c8266863..e3ddc9de0 100644 --- a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java +++ b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java @@ -2,7 +2,6 @@ import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -32,7 +31,6 @@ @AllArgsConstructor @EqualsAndHashCode @Builder(toBuilder = true) -@CustomLog public class FireboltProperties { private static final Pattern DB_PATH_PATTERN = Pattern.compile("/?([a-zA-Z0-9_*\\-]+)"); diff --git a/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java b/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java deleted file mode 100644 index 478c4548a..000000000 --- a/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.firebolt.jdbc.log; - -public interface FireboltLogger { - - void trace(String message); - - void trace(String message, Object... arguments); - - void trace(String message, Throwable t); - - void debug(String message); - - void debug(String message, Object... arguments); - - void debug(String message, Throwable t); - - void info(String message); - - void info(String message, Object... arguments); - - void info(String message, Throwable t); - - void warn(String message); - - void warn(String message, Object... arguments); - - void warn(String message, Throwable t); - - void error(String message); - - void error(String message, Object... arguments); - - void error(String message, Throwable t); - -} diff --git a/src/main/java/com/firebolt/jdbc/log/JDKLogger.java b/src/main/java/com/firebolt/jdbc/log/JDKLogger.java deleted file mode 100644 index ad19f26d5..000000000 --- a/src/main/java/com/firebolt/jdbc/log/JDKLogger.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.firebolt.jdbc.log; - -import java.util.logging.Level; - -public class JDKLogger implements FireboltLogger { - - private final java.util.logging.Logger logger; - - public JDKLogger(String name) { - this.logger = java.util.logging.Logger.getLogger(name); - } - - @Override - public void trace(String message) { - logger.log(Level.FINEST, message); - } - - @Override - public void trace(String message, Object... arguments) { - logger.log(Level.FINEST, addMissingArgumentsIndexes(message), arguments); - } - - @Override - public void trace(String message, Throwable t) { - logger.log(Level.FINEST, message, t); - } - - @Override - public void debug(String message) { - logger.log(Level.FINE, message); - } - - @Override - public void debug(String message, Object... arguments) { - logger.log(Level.FINE, addMissingArgumentsIndexes(message), arguments); - } - - @Override - public void debug(String message, Throwable t) { - logger.log(Level.FINE, message, t); - } - - @Override - public void info(String message) { - logger.log(Level.INFO, message); - } - - @Override - public void info(String message, Object... arguments) { - logger.log(Level.INFO, addMissingArgumentsIndexes(message), arguments); - } - - @Override - public void info(String message, Throwable t) { - logger.log(Level.INFO, message, t); - } - - @Override - public void warn(String message) { - logger.log(Level.WARNING, message); - } - - @Override - public void warn(String message, Object... arguments) { - logger.log(Level.WARNING, addMissingArgumentsIndexes(message), arguments); - } - - @Override - public void warn(String message, Throwable t) { - logger.log(Level.WARNING, message, t); - - } - - @Override - public void error(String message) { - logger.log(Level.SEVERE, message); - } - - @Override - public void error(String message, Object... arguments) { - logger.log(Level.SEVERE, addMissingArgumentsIndexes(message), arguments); - } - - @Override - public void error(String message, Throwable t) { - logger.log(Level.SEVERE, message, t); - } - - /** - * SLF4J and java.util.logging use a different log format. With SLF4J it is not - * required to have argument indexes in the logs (eg: "log.info("hello {}", - * "world");), but it is required for java.util.logging (eg: "log.info("hello - * {1}", "world");) In this project we use the SLF4J way of logging, which is - * why we need to add the missing indexes. - */ - private String addMissingArgumentsIndexes(String message) { - StringBuilder result = new StringBuilder(); - int argumentIndex = 0; - int i = 0; - while (i < message.length()) { - if (message.charAt(i) == '{' && i < message.length() - 1 && message.charAt(i + 1) == '}') { - result.append(String.format("{%d}", argumentIndex++)); - i++; - } else { - result.append(message.charAt(i)); - } - i++; - } - return result.toString(); - } -} diff --git a/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java b/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java deleted file mode 100644 index ba769bbfc..000000000 --- a/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.firebolt.jdbc.log; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SLF4JLogger implements FireboltLogger { - - private final Logger logger; - - public SLF4JLogger(String name) { - logger = LoggerFactory.getLogger(name); - } - - @Override - public void trace(String message) { - logger.trace(message); - } - - @Override - public void trace(String message, Object... arguments) { - logger.trace(message, arguments); - } - - @Override - public void trace(String message, Throwable t) { - logger.trace(message, t); - } - - @Override - public void debug(String message) { - logger.debug(message); - } - - @Override - public void debug(String message, Object... arguments) { - logger.debug(message, arguments); - - } - - @Override - public void debug(String message, Throwable t) { - logger.debug(message, t); - } - - @Override - public void info(String message) { - logger.info(message); - } - - @Override - public void info(String message, Object... arguments) { - logger.info(message, arguments); - } - - @Override - public void info(String message, Throwable t) { - logger.info(message, t); - } - - @Override - public void warn(String message) { - logger.warn(message); - } - - @Override - public void warn(String message, Object... arguments) { - logger.warn(message, arguments); - } - - @Override - public void warn(String message, Throwable t) { - logger.warn(message, t); - } - - @Override - public void error(String message) { - logger.error(message); - } - - @Override - public void error(String message, Object... arguments) { - logger.error(message, arguments); - } - - @Override - public void error(String message, Throwable t) { - logger.error(message, t); - } -} diff --git a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java index 1c2be29e9..d231fd273 100644 --- a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java +++ b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java @@ -8,7 +8,6 @@ import com.firebolt.jdbc.resultset.column.Column; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.util.VersionUtil; -import lombok.CustomLog; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -149,7 +148,6 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -@CustomLog @SuppressWarnings("java:S6204") // compatibility with JDK 11 public class FireboltDatabaseMetadata implements DatabaseMetaData { diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index 4da27584a..2099b5e70 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -16,7 +16,6 @@ import com.firebolt.jdbc.type.array.FireboltArray; import com.firebolt.jdbc.type.array.SqlArrayUtil; import com.firebolt.jdbc.util.LoggerUtil; -import lombok.CustomLog; import org.apache.commons.text.StringEscapeUtils; import javax.sql.rowset.serial.SerialBlob; @@ -53,6 +52,8 @@ import java.util.Map; import java.util.TimeZone; import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -66,10 +67,10 @@ /** * ResultSet for InputStream using the format "TabSeparatedWithNamesAndTypes" */ -@CustomLog public class FireboltResultSet extends JdbcBase implements ResultSet { private static final String FORWARD_ONLY_ERROR = "Cannot call %s() for ResultSet of type TYPE_FORWARD_ONLY"; private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192; // the default of BufferedReader + private static final Logger log = Logger.getLogger(FireboltResultSet.class.getName()); private final BufferedReader reader; private final Map columnNameToColumnNumber; private final FireboltResultSetMetaData resultSetMetaData; @@ -85,9 +86,10 @@ public class FireboltResultSet extends JdbcBase implements ResultSet { private String lastReadValue = null; + @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both public FireboltResultSet(InputStream is, String tableName, String dbName, int bufferSize, boolean isCompressed, FireboltStatement statement, boolean logResultSet) throws SQLException { - log.debug("Creating resultSet..."); + log.fine("Creating resultSet..."); this.statement = statement; if (logResultSet) { is = LoggerUtil.logInputStream(is); @@ -109,10 +111,10 @@ public FireboltResultSet(InputStream is, String tableName, String dbName, int bu columns = next() ? getColumns(fields, currentLine) : new ArrayList<>(); resultSetMetaData = new FireboltResultSetMetaData(dbName, tableName, columns); } catch (Exception e) { - log.error("Could not create ResultSet: {}", e.getMessage(), e); - throw new FireboltException("Cannot read response from DB: error while creating ResultSet ", e); + log.log(Level.SEVERE, e, () -> "Could not create ResultSet: " + e.getMessage()); + throw new FireboltException("Cannot read response from DB: error while creating ResultSet", e); } - log.debug("ResultSet created"); + log.fine("ResultSet created"); } public static FireboltResultSet of(QueryResult queryResult) throws SQLException { diff --git a/src/main/java/com/firebolt/jdbc/resultset/column/Column.java b/src/main/java/com/firebolt/jdbc/resultset/column/Column.java index d0cae2425..8797c5e60 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/column/Column.java +++ b/src/main/java/com/firebolt/jdbc/resultset/column/Column.java @@ -1,23 +1,24 @@ package com.firebolt.jdbc.resultset.column; import lombok.Builder; -import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; +import java.util.logging.Level; +import java.util.logging.Logger; + @Builder @Getter @EqualsAndHashCode @ToString -@CustomLog public final class Column { - + private static final Logger log = Logger.getLogger(Column.class.getName()); private final ColumnType type; private final String columnName; public static Column of(String columnType, String columnName) { - log.debug("Creating column info for column: {} of type: {}", columnName, columnType); + log.log(Level.FINE, "Creating column info for column: {0} of type: {1}", new Object[] {columnName, columnType}); return Column.builder().columnName(columnName).type(ColumnType.of(columnType)).build(); } } diff --git a/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java b/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java index 4e1d23a21..c8ddf6737 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java +++ b/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java @@ -2,7 +2,6 @@ import com.firebolt.jdbc.type.FireboltDataType; import lombok.Builder; -import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -17,6 +16,8 @@ import java.util.Optional; import java.util.Set; import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -27,7 +28,6 @@ /** * This class represents a Column type returned by the server */ -@CustomLog @Builder @Value @EqualsAndHashCode @@ -40,6 +40,7 @@ public class ColumnType { private static final Set TIMEZONES = Arrays.stream(TimeZone.getAvailableIDs()) .collect(Collectors.toCollection(HashSet::new)); private static final Pattern COMMA_WITH_SPACES = Pattern.compile("\\s*,\\s*"); + private static final Logger log = Logger.getLogger(ColumnType.class.getName()); @EqualsAndHashCode.Exclude String name; FireboltDataType dataType; @@ -166,7 +167,7 @@ private static TimeZone getTimeZoneFromArguments(@NonNull String[] arguments) { if (TIMEZONES.contains(id)) { timeZone = TimeZone.getTimeZone(timeZoneArgument.replace("\\'", "")); } else { - log.warn("Could not use the timezone returned by the server with the id {} as it is not supported.", id); + log.log(Level.FINE, "Could not use the timezone returned by the server with the id {0} as it is not supported.", id); } } return timeZone; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java index 2f4710841..a540a1153 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java @@ -4,7 +4,6 @@ import com.firebolt.jdbc.connection.FireboltConnectionTokens; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; -import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import net.jodah.expiringmap.ExpiringMap; @@ -13,6 +12,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; import static java.lang.String.format; import static java.util.Optional.ofNullable; @@ -20,9 +21,9 @@ import static net.jodah.expiringmap.ExpirationPolicy.CREATED; @RequiredArgsConstructor -@CustomLog public class FireboltAuthenticationService { + private static final Logger log = Logger.getLogger(FireboltAuthenticationService.class.getName()); private static final ExpiringMap tokensMap = ExpiringMap.builder() .variableExpiration().build(); private static final long TOKEN_EXPIRATION_OFFSET = 5L; @@ -31,13 +32,14 @@ public class FireboltAuthenticationService { private static final String ERROR_MESSAGE_FROM_SERVER = "Failed to connect to Firebolt with the error from the server: %s, see logs for more info."; private final FireboltAuthenticationClient fireboltAuthenticationClient; + @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both public FireboltConnectionTokens getConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); synchronized (this) { FireboltConnectionTokens foundToken = tokensMap.get(connectionParams); if (foundToken != null) { - log.debug("Using the token of {} from the cache", host); + log.log(Level.FINE, "Using the token of {} from the cache", host); return foundToken; } FireboltConnectionTokens fireboltConnectionTokens = fireboltAuthenticationClient @@ -47,11 +49,11 @@ public FireboltConnectionTokens getConnectionTokens(String host, FireboltPropert return fireboltConnectionTokens; } } catch (FireboltException e) { - log.error("Failed to connect to Firebolt", e); + log.log(Level.SEVERE, "Failed to connect to Firebolt", e); String msg = ofNullable(e.getErrorMessageFromServer()).map(m -> format(ERROR_MESSAGE_FROM_SERVER, m)).orElse(format(ERROR_MESSAGE, e.getMessage())); throw new FireboltException(msg, e); } catch (Exception e) { - log.error("Failed to connect to Firebolt", e); + log.log(Level.SEVERE, "Failed to connect to Firebolt", e); throw new FireboltException(format(ERROR_MESSAGE, e.getMessage()), e); } } @@ -73,7 +75,7 @@ private long getCachingDurationInSeconds(long expireInSeconds) { */ public void removeConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { - log.debug("Removing connection token for host {}", host); + log.log(Level.FINE, "Removing connection token for host {0}", host); ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); tokensMap.remove(connectionParams); } catch (NoSuchAlgorithmException e) { diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java index 9a947f2a4..4c2be433b 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java @@ -8,7 +8,6 @@ import com.firebolt.jdbc.connection.Engine; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; -import lombok.CustomLog; import lombok.RequiredArgsConstructor; import java.io.IOException; @@ -20,7 +19,6 @@ import static java.util.Optional.ofNullable; @RequiredArgsConstructor -@CustomLog public class FireboltEngineApiService implements FireboltEngineService { private static final Set ENGINE_NOT_READY_STATUSES = Set.of( "ENGINE_STATUS_PROVISIONING_STARTED", "ENGINE_STATUS_PROVISIONING_PENDING", diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java index f815ecda6..9791628bb 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java @@ -4,13 +4,11 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; -import lombok.CustomLog; import lombok.RequiredArgsConstructor; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collection; import java.util.TreeSet; import java.util.stream.Stream; @@ -20,7 +18,6 @@ import static java.util.stream.Collectors.toCollection; @RequiredArgsConstructor -@CustomLog public class FireboltEngineInformationSchemaService implements FireboltEngineService { private static final String ENGINE_URL = "url"; private static final String STATUS_FIELD = "status"; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java index 4ac0296ab..37921db3b 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java @@ -10,7 +10,6 @@ import com.firebolt.jdbc.statement.rawstatement.QueryRawStatement; import com.firebolt.jdbc.util.CloseableUtil; import com.firebolt.jdbc.util.InputStreamUtil; -import lombok.CustomLog; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -22,7 +21,6 @@ import static java.util.Optional.ofNullable; @RequiredArgsConstructor -@CustomLog public class FireboltStatementService { private static final String UNKNOWN_TABLE_NAME = "unknown"; diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index 38faf2fef..a73fb4ddf 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -11,7 +11,6 @@ import com.firebolt.jdbc.exception.FireboltUnsupportedOperationException; import com.firebolt.jdbc.service.FireboltStatementService; import com.firebolt.jdbc.util.CloseableUtil; -import lombok.CustomLog; import java.io.InputStream; import java.sql.Connection; @@ -27,13 +26,16 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import static com.firebolt.jdbc.statement.rawstatement.StatementValidatorFactory.createValidator; +import static java.lang.String.format; import static java.util.stream.Collectors.toCollection; -@CustomLog public class FireboltStatement extends JdbcBase implements Statement { + private static final Logger log = Logger.getLogger(FireboltStatement.class.getName()); private final FireboltStatementService statementService; private final FireboltProperties sessionProperties; private final FireboltConnection connection; @@ -54,7 +56,7 @@ public FireboltStatement(FireboltStatementService statementService, FireboltProp this.statementService = statementService; this.sessionProperties = sessionProperties; this.connection = connection; - log.debug("Created Statement"); + log.fine("Created Statement"); } @Override @@ -98,6 +100,7 @@ protected Optional execute(List statements) thr return resultSet; } + @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both private Optional execute(StatementInfoWrapper statementInfoWrapper, boolean verifyNotCancelled, boolean isStandardSql) throws SQLException { createValidator(statementInfoWrapper.getInitialStatement(), connection).validate(statementInfoWrapper.getInitialStatement()); ResultSet resultSet = null; @@ -108,11 +111,10 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper, b } InputStream inputStream = null; try { - log.info("Executing the statement with label {} : {}", statementInfoWrapper.getLabel(), - statementInfoWrapper.getSql()); + log.log(Level.INFO, "Executing the statement with label {0} : {1}", new Object[] {statementInfoWrapper.getLabel(), statementInfoWrapper.getSql()}); if (statementInfoWrapper.getType() == StatementType.PARAM_SETTING) { connection.addProperty(statementInfoWrapper.getParam()); - log.debug("The property from the query {} was stored", runningStatementLabel); + log.log(Level.FINE, "The property from the query {0} was stored", runningStatementLabel); } else { Optional currentRs = statementService.execute(statementInfoWrapper, sessionProperties, isStandardSql, this); if (currentRs.isPresent()) { @@ -121,12 +123,11 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper, b } else { currentUpdateCount = 0; } - log.info("The query with the label {} was executed with success", runningStatementLabel); + log.log(Level.INFO, "The query with the label {0} was executed with success", runningStatementLabel); } } catch (Exception ex) { CloseableUtil.close(inputStream); - log.error(String.format("An error happened while executing the statement with the id %s", - runningStatementLabel), ex); + log.log(Level.SEVERE, ex, () -> format("An error happened while executing the statement with the id %s", runningStatementLabel)); throw ex; } finally { runningStatementLabel = null; @@ -139,7 +140,7 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper, b } } } else { - log.warn("Aborted query with id {}", statementInfoWrapper.getLabel()); + log.log(Level.FINE, "Aborted query with id {0}", statementInfoWrapper.getLabel()); } return Optional.ofNullable(resultSet); } @@ -166,7 +167,7 @@ public void cancel() throws SQLException { } String statementLabel = runningStatementLabel; if (statementLabel != null) { - log.info("Cancelling statement with label " + statementLabel); + log.log(Level.INFO, "Cancelling statement with label {0}", statementLabel); abortStatementRunningOnFirebolt(statementLabel); } } @@ -174,7 +175,7 @@ public void cancel() throws SQLException { private void abortStatementRunningOnFirebolt(String statementLabel) throws SQLException { try { statementService.abortStatement(statementLabel, sessionProperties); - log.debug("Statement with label {} was aborted", statementLabel); + log.log(Level.FINE, "Statement with label {0} was aborted", statementLabel); } catch (FireboltException e) { throw e; } catch (Exception e) { @@ -256,7 +257,7 @@ public int getMaxRows() throws SQLException { @Override public void setMaxRows(int max) throws SQLException { if (max < 0) { - throw new FireboltException(String.format("Illegal maxRows value: %d", max)); + throw new FireboltException(format("Illegal maxRows value: %d", max)); } maxRows = max; } @@ -288,7 +289,7 @@ public void close(boolean removeFromConnection) throws SQLException { connection.removeClosedStatement(this); } cancel(); - log.debug("Statement closed"); + log.fine("Statement closed"); } @Override diff --git a/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java b/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java index c82031324..a67cbd1d6 100644 --- a/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java +++ b/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java @@ -1,16 +1,16 @@ package com.firebolt.jdbc.statement; -import java.io.Closeable; -import java.sql.ResultSet; +import lombok.Data; import javax.annotation.Nullable; - -import lombok.CustomLog; -import lombok.Data; +import java.io.Closeable; +import java.sql.ResultSet; +import java.util.logging.Level; +import java.util.logging.Logger; @Data -@CustomLog public class StatementResultWrapper implements Closeable { + private static final Logger log = Logger.getLogger(StatementResultWrapper.class.getName()); private ResultSet resultSet; private int updateCount; private StatementInfoWrapper statementInfoWrapper; @@ -29,7 +29,7 @@ public void close() { resultSet.close(); } } catch (Exception e) { - log.warn("Could not close ResultSet", e); + log.log(Level.WARNING, "Could not close ResultSet", e); } if (next != null) { next.close(); diff --git a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java index f26c74f49..fca7e8bee 100644 --- a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java +++ b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java @@ -4,7 +4,6 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatementWrapper; import com.firebolt.jdbc.statement.rawstatement.SetParamRawStatement; import com.firebolt.jdbc.util.StringUtil; -import lombok.CustomLog; import lombok.NonNull; import lombok.experimental.UtilityClass; @@ -15,17 +14,19 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; @UtilityClass -@CustomLog public class StatementUtil { private static final String SET_PREFIX = "set"; private static final Pattern SET_WITH_SPACE_REGEX = Pattern.compile(SET_PREFIX + " ", Pattern.CASE_INSENSITIVE); private static final String[] SELECT_KEYWORDS = new String[] { "show", "select", "describe", "exists", "explain", "with", "call" }; + private static final Logger log = Logger.getLogger(StatementUtil.class.getName()); /** * Returns true if the statement is a query (eg: SELECT, SHOW). @@ -180,7 +181,7 @@ public Map getParamMarketsPositions(String sql) { public Entry, Optional> extractDbNameAndTableNamePairFromCleanQuery(String cleanSql) { Optional from = Optional.empty(); if (isQuery(cleanSql)) { - log.debug("Extracting DB and Table name for SELECT: {}", cleanSql); + log.log(Level.FINE, "Extracting DB and Table name for SELECT: {0}", cleanSql); String withoutQuotes = cleanSql.replace("'", "").trim(); String withoutQuotesUpperCase = withoutQuotes.toUpperCase(); if (withoutQuotesUpperCase.startsWith("SELECT")) { @@ -193,7 +194,7 @@ public Entry, Optional> extractDbNameAndTableNamePairFr } else if (withoutQuotesUpperCase.startsWith("SHOW")) { from = Optional.empty(); // Depends on the information requested } else { - log.debug("Could not find table name for query {}. This may happen when there is no table.", cleanSql); + log.log(Level.FINE, "Could not find table name for query {0}. This may happen when there is no table.", cleanSql); } } return Map.entry(extractDbNameFromFromPartOfTheQuery(from.orElse(null)), diff --git a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java index 59ac22d09..aa5911fe5 100644 --- a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java @@ -14,7 +14,6 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatementWrapper; import com.firebolt.jdbc.type.JavaTypeToFireboltSQLString; import com.firebolt.jdbc.util.InputStreamUtil; -import lombok.CustomLog; import lombok.NonNull; import java.io.IOException; @@ -43,6 +42,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import static com.firebolt.jdbc.statement.StatementUtil.replaceParameterMarksWithValues; import static com.firebolt.jdbc.statement.rawstatement.StatementValidatorFactory.createValidator; @@ -51,9 +52,8 @@ import static java.sql.Types.NUMERIC; import static java.sql.Types.VARBINARY; -@CustomLog public class FireboltPreparedStatement extends FireboltStatement implements PreparedStatement { - + private static final Logger log = Logger.getLogger(FireboltPreparedStatement.class.getName()); private final RawStatementWrapper rawStatement; private final List> rows; private Map providedParameters; @@ -65,7 +65,7 @@ public FireboltPreparedStatement(FireboltStatementService statementService, Fire public FireboltPreparedStatement(FireboltStatementService statementService, FireboltProperties sessionProperties, FireboltConnection connection, String sql) { super(statementService, sessionProperties, connection); - log.debug("Populating PreparedStatement object for SQL: {}", sql); + log.log(Level.FINE, "Populating PreparedStatement object for SQL: {0}", sql); this.providedParameters = new HashMap<>(); this.rawStatement = StatementUtil.parseToRawStatementWrapper(sql); rawStatement.getSubStatements().forEach(statement -> createValidator(statement, connection).validate(statement)); @@ -261,7 +261,7 @@ public void setArray(int parameterIndex, Array x) throws SQLException { @Override public int[] executeBatch() throws SQLException { validateStatementIsNotClosed(); - log.debug("Executing batch for statement: {}", rawStatement); + log.log(Level.FINE, "Executing batch for statement: {0}", rawStatement); List inserts = new ArrayList<>(); int[] result = new int[rows.size()]; for (Map row : rows) { diff --git a/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java b/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java index 656f26381..75e967dfb 100644 --- a/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java +++ b/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java @@ -1,13 +1,11 @@ package com.firebolt.jdbc.statement.rawstatement; -import lombok.CustomLog; import lombok.Value; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -@CustomLog @Value public class RawStatementWrapper { diff --git a/src/main/java/com/firebolt/jdbc/type/BaseType.java b/src/main/java/com/firebolt/jdbc/type/BaseType.java index e397fcba2..7d401678d 100644 --- a/src/main/java/com/firebolt/jdbc/type/BaseType.java +++ b/src/main/java/com/firebolt/jdbc/type/BaseType.java @@ -24,7 +24,6 @@ import static com.firebolt.jdbc.type.array.SqlArrayUtil.hexStringToByteArray; /** This class contains the java types the Firebolt datatypes are mapped to */ -@CustomLog public enum BaseType { LONG(Long.class, conversion -> Long.parseLong(checkInfinity(conversion.getValue()))), INTEGER(Integer.class, conversion -> Integer.parseInt(checkInfinity(conversion.getValue()))), diff --git a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java index 04005c315..2ef60ffc1 100644 --- a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java @@ -1,11 +1,9 @@ package com.firebolt.jdbc.type.array; -import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.column.ColumnType; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.JavaTypeToFireboltSQLString; import com.firebolt.jdbc.util.StringUtil; -import lombok.CustomLog; import lombok.NonNull; import javax.annotation.Nullable; @@ -15,6 +13,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Stream; import static java.lang.String.format; @@ -23,15 +23,15 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -@CustomLog public class SqlArrayUtil { private static final Map formatMarkers = Map.of( '[', new Markers('[', ']', '\'', '\''), '{', new Markers('{', '}', '"', '\'') ); + public static final String BYTE_ARRAY_PREFIX = "\\x"; + private static final Logger log = Logger.getLogger(SqlArrayUtil.class.getName()); private final ColumnType columnType; private final Markers markers; - public static final String BYTE_ARRAY_PREFIX = "\\x"; private static final class Markers { private final char leftArrayBracket; @@ -53,7 +53,7 @@ public SqlArrayUtil(ColumnType columnType, Markers markers) { } public static FireboltArray transformToSqlArray(String value, ColumnType columnType) throws SQLException { - log.debug("Transformer array with value {} and type {}", value, columnType); + log.log(Level.FINE, "Transformer array with value {0} and type {1}", new Object[] {value, columnType}); if (isNullValue(value)) { return null; } diff --git a/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java b/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java index 5a77bfb10..d6d8b1347 100644 --- a/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java @@ -1,7 +1,6 @@ package com.firebolt.jdbc.type.date; import com.firebolt.jdbc.CheckedBiFunction; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.sql.Date; @@ -17,7 +16,6 @@ import java.util.function.Function; @UtilityClass -@CustomLog public class SqlDateUtil { public static final long ONE_DAY_MILLIS = 86400000L; diff --git a/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java b/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java index 660576645..c09886fda 100644 --- a/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java @@ -1,14 +1,15 @@ package com.firebolt.jdbc.util; +import lombok.experimental.UtilityClass; + import java.io.Closeable; import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; -import lombok.CustomLog; -import lombok.experimental.UtilityClass; - -@CustomLog @UtilityClass public class CloseableUtil { + private static final Logger log = Logger.getLogger(CloseableUtil.class.getName()); /** * Closes the {@link Closeable} and log any potential {@link IOException} @@ -20,7 +21,7 @@ public void close(Closeable closeable) { try { closeable.close(); } catch (IOException e) { - log.error("An error happened while closing the closeable: {}", e.getMessage()); + log.log(Level.SEVERE, "An error happened while closing the closeable: {0}", e.getMessage()); } } } diff --git a/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java b/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java index 8518f4a37..a1e66e03c 100644 --- a/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java @@ -1,18 +1,19 @@ package com.firebolt.jdbc.util; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.util.logging.Level; +import java.util.logging.Logger; @UtilityClass -@CustomLog public class InputStreamUtil { private static final int K_BYTE = 1024; private static final int BUFFER_SIZE = 8 * K_BYTE; + private static final Logger log = Logger.getLogger(InputStreamUtil.class.getName()); /** * Read all bytes from the input stream if the stream is not null @@ -25,7 +26,7 @@ public void readAllBytes(@Nullable InputStream is) { try { if (is.read() == -1) break; } catch (IOException e) { - log.warn("Could not read entire input stream for non query statement", e); + log.log(Level.WARNING, "Could not read entire input stream for non query statement", e); } } } diff --git a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java index 3092885a3..54b8979ca 100644 --- a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java @@ -1,38 +1,39 @@ package com.firebolt.jdbc.util; -import java.io.*; +import com.firebolt.FireboltDriver; +import lombok.experimental.UtilityClass; +import org.slf4j.bridge.SLF4JBridgeHandler; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; -import com.firebolt.jdbc.log.FireboltLogger; -import com.firebolt.jdbc.log.JDKLogger; -import com.firebolt.jdbc.log.SLF4JLogger; - -import lombok.CustomLog; -import lombok.experimental.UtilityClass; - @UtilityClass -@CustomLog public class LoggerUtil { - private static Boolean slf4jAvailable; + private static final boolean SLF4J_AVAILABLE = isSlf4jJAvailable(); + private static final Logger root = initRootLogger(); + private static final Logger log = Logger.getLogger(LoggerUtil.class.getName()); - /** - * Provides a {@link FireboltLogger} based on whether SLF4J is available or not. - * - * @param name logger name - * @return a {@link FireboltLogger} - */ - public static FireboltLogger getLogger(String name) { - if (slf4jAvailable == null) { - slf4jAvailable = isSlf4jJAvailable(); + private Logger initRootLogger() { + Logger parent = Logger.getLogger(FireboltDriver.class.getPackageName()); + if (SLF4J_AVAILABLE) { + synchronized (LoggerUtil.class) { + parent.addHandler(new SLF4JBridgeHandler()); + parent.setLevel(Level.ALL); + } } + return parent; + } - if (slf4jAvailable) { - return new SLF4JLogger(name); - } else { - return new JDKLogger(name); - } + public static Logger getRootLogger() { + return root; } /** @@ -58,7 +59,7 @@ public InputStream logInputStream(InputStream is) { log.info("======================================"); return new ByteArrayInputStream(baos.toByteArray()); } catch (Exception ex) { - log.warn("Could not log the stream", ex); + log.log(Level.WARNING, "Could not log the stream", ex); } return new ByteArrayInputStream(baos.toByteArray()); } diff --git a/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java b/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java index ae1c90df5..bf6a382dd 100644 --- a/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java @@ -2,7 +2,6 @@ import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.connection.settings.FireboltSessionProperty; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.sql.DriverPropertyInfo; @@ -18,7 +17,6 @@ import static com.firebolt.jdbc.connection.UrlUtil.extractProperties; import static com.firebolt.jdbc.connection.settings.FireboltSessionProperty.getNonDeprecatedProperties; -@CustomLog @UtilityClass public class PropertyUtil { diff --git a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java index 063015272..5e9b1c979 100644 --- a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java @@ -1,6 +1,5 @@ package com.firebolt.jdbc.util; -import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.io.File; @@ -12,11 +11,12 @@ import java.util.Properties; import java.util.jar.Attributes.Name; import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @UtilityClass -@CustomLog public class VersionUtil { private static final Pattern VERSION_PATTERN = Pattern.compile("^\\s*(\\d+)\\.(\\d+).*"); @@ -27,13 +27,14 @@ public class VersionUtil { private static String driverVersion = "3.0.4"; private static String specificationVersion = "4.3"; + private static final Logger log = Logger.getLogger(VersionUtil.class.getName()); static { try { retrieveVersionInfo(); - log.info("Firebolt driver version used: {}", driverVersion); + log.log(Level.INFO, "Firebolt driver version used: {0}", driverVersion); } catch (IOException e) { - log.error("Could not get Project Version defined in the build.gradle file", e); + log.log(Level.SEVERE, "Could not get Project Version defined in the build.gradle file", e); } } diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index d690969e1..0122fa15f 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -12,12 +12,12 @@ import java.sql.Connection; import java.sql.DriverPropertyInfo; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; +import java.util.logging.Logger; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -25,7 +25,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mockConstruction; class FireboltDriverTest { @@ -79,7 +78,8 @@ void acceptsURL(String url, boolean expected) { @Test void getParentLogger() { - assertThrows(SQLFeatureNotSupportedException.class, () -> new FireboltDriver().getParentLogger()); + Logger logger = new FireboltDriver().getParentLogger(); + assertNotNull(logger); } @Test diff --git a/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java b/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java deleted file mode 100644 index a9ba09cc6..000000000 --- a/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.firebolt.jdbc.log; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -class JDKLoggerTest { - - @Test - void shouldLogWithCorrectLevel() { - try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { - Logger logger = mock(Logger.class); - mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); - JDKLogger jdkLogger = new JDKLogger("myTest"); - jdkLogger.debug("This is a debug log"); - jdkLogger.warn("This is a warning log"); - jdkLogger.error("This is an error log"); - jdkLogger.trace("This is a trace log"); - verify(logger).log(Level.FINE, "This is a debug log"); - verify(logger).log(Level.WARNING, "This is a warning log"); - verify(logger).log(Level.SEVERE, "This is an error log"); - verify(logger).log(Level.FINEST, "This is a trace log"); - } - } - - @Test - void shouldLogWithCorrectArgumentIndexes() { - try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { - Logger logger = mock(Logger.class); - mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); - JDKLogger jdkLogger = new JDKLogger("myTest"); - jdkLogger.debug("This debug log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - jdkLogger.warn("This warning log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - jdkLogger.error("This error log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - jdkLogger.trace("This trace log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - Object[] args = new Object[] { "arg1", "arg2", "arg3" }; - verify(logger).log(Level.FINE, "This debug log has some arguments: {0}, {1}, {2}", args); - verify(logger).log(Level.WARNING, "This warning log has some arguments: {0}, {1}, {2}", args); - verify(logger).log(Level.SEVERE, "This error log has some arguments: {0}, {1}, {2}", args); - verify(logger).log(Level.FINEST, "This trace log has some arguments: {0}, {1}, {2}", args); - } - } - - @Test - void shouldLogWithThrowable() { - try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { - Logger logger = mock(Logger.class); - mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); - JDKLogger jdkLogger = new JDKLogger("myTest"); - IllegalArgumentException illegalArgumentException = new IllegalArgumentException(); - jdkLogger.debug("This debug log has an exception", illegalArgumentException); - jdkLogger.warn("This warning log has an exception", illegalArgumentException); - jdkLogger.error("This error log has an exception", illegalArgumentException); - jdkLogger.trace("This trace log has an exception", illegalArgumentException); - verify(logger).log(Level.FINE, "This debug log has an exception", illegalArgumentException); - verify(logger).log(Level.WARNING, "This warning log has an exception", illegalArgumentException); - verify(logger).log(Level.SEVERE, "This error log has an exception", illegalArgumentException); - verify(logger).log(Level.FINEST, "This trace log has an exception", illegalArgumentException); - } - } -} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/log/LogLevelExample.java b/src/test/java/com/firebolt/jdbc/log/LogLevelExample.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java b/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java deleted file mode 100644 index 6b51d0beb..000000000 --- a/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.firebolt.jdbc.log; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class SLF4JLoggerTest { - - @Test - void shouldLogWithCorrectLevel() { - try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { - Logger logger = mock(Logger.class); - mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); - SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); - slf4JLogger.debug("This is a debug log"); - slf4JLogger.warn("This is a warning log"); - slf4JLogger.error("This is an error log"); - slf4JLogger.trace("This is a trace log"); - verify(logger).debug("This is a debug log"); - verify(logger).warn("This is a warning log"); - verify(logger).error("This is an error log"); - verify(logger).trace("This is a trace log"); - } - } - - @Test - void shouldLogWithArguments() { - try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { - Logger logger = mock(Logger.class); - mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); - SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); - slf4JLogger.debug("This debug log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - slf4JLogger.warn("This warning log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - slf4JLogger.error("This error log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - slf4JLogger.trace("This trace log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); - Object[] args = new Object[] { "arg1", "arg2", "arg3" }; - verify(logger).debug("This debug log has some arguments: {}, {}, {}", args); - verify(logger).warn("This warning log has some arguments: {}, {}, {}", args); - verify(logger).error("This error log has some arguments: {}, {}, {}", args); - verify(logger).trace("This trace log has some arguments: {}, {}, {}", args); - } - } - - @Test - void shouldLogWithThrowable() { - try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { - Logger logger = mock(Logger.class); - mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); - SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); - IllegalArgumentException illegalArgumentException = new IllegalArgumentException(); - slf4JLogger.debug("This debug log has an exception", illegalArgumentException); - slf4JLogger.warn("This warning log has an exception", illegalArgumentException); - slf4JLogger.error("This error log has an exception", illegalArgumentException); - slf4JLogger.trace("This trace log has an exception", illegalArgumentException); - verify(logger).debug("This debug log has an exception", illegalArgumentException); - verify(logger).warn("This warning log has an exception", illegalArgumentException); - verify(logger).error("This error log has an exception", illegalArgumentException); - verify(logger).trace("This trace log has an exception", illegalArgumentException); - } - } - -} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java b/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java index 7b334070e..245198ee8 100644 --- a/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java @@ -1,23 +1,23 @@ package com.firebolt.jdbc.util; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import org.junit.jupiter.api.Test; - -import com.firebolt.jdbc.log.FireboltLogger; -import com.firebolt.jdbc.log.SLF4JLogger; +import org.slf4j.bridge.SLF4JBridgeHandler; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.Arrays; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class LoggerUtilTest { @Test void shouldGetSLF4JLoggerWhenAvailable() { - FireboltLogger fireboltLogger = LoggerUtil.getLogger("myLogger"); + Logger fireboltLogger = LoggerUtil.getRootLogger(); // Should be true since SLF4J is available - assertTrue(fireboltLogger instanceof SLF4JLogger); + assertTrue(Arrays.stream(fireboltLogger.getHandlers()).anyMatch(handler -> handler instanceof SLF4JBridgeHandler)); } @Test From 515efe959ecc5bd469975bca31adcdb704321e17 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Mon, 13 May 2024 11:17:49 +0300 Subject: [PATCH 03/52] removed redundant flag standardSql and added more tests (#407) --- .../com/firebolt/jdbc/CheckedSupplier.java | 8 ++ .../jdbc/client/query/StatementClient.java | 9 +- .../client/query/StatementClientImpl.java | 4 +- .../service/FireboltAccountIdService.java | 1 - .../service/FireboltStatementService.java | 6 +- .../jdbc/statement/FireboltStatement.java | 16 ++- .../type/JavaTypeToFireboltSQLString.java | 14 ++- .../java/com/firebolt/FireboltDriverTest.java | 2 +- .../client/query/StatementClientImplTest.java | 10 +- .../connection/FireboltConnectionTest.java | 26 +++-- .../jdbc/resultset/FireboltResultSetTest.java | 9 ++ .../service/FireboltAccountIdServiceTest.java | 21 ++++ .../service/FireboltStatementServiceTest.java | 45 +++----- .../jdbc/statement/FireboltStatementTest.java | 101 +++++++++++++++--- .../FireboltPreparedStatementTest.java | 93 ++++++++++++---- .../type/JavaTypeToFireboltSQLStringTest.java | 19 +++- .../firebolt/jdbc/util/StatementUtilTest.java | 5 + 17 files changed, 274 insertions(+), 115 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/CheckedSupplier.java create mode 100644 src/test/java/com/firebolt/jdbc/service/FireboltAccountIdServiceTest.java diff --git a/src/main/java/com/firebolt/jdbc/CheckedSupplier.java b/src/main/java/com/firebolt/jdbc/CheckedSupplier.java new file mode 100644 index 000000000..c08cfef49 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/CheckedSupplier.java @@ -0,0 +1,8 @@ +package com.firebolt.jdbc; + +import java.sql.SQLException; + +@FunctionalInterface +public interface CheckedSupplier { + R get() throws SQLException; +} \ No newline at end of file diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java index f777ab12c..07d4c500d 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClient.java @@ -1,19 +1,18 @@ package com.firebolt.jdbc.client.query; -import java.io.InputStream; -import java.sql.SQLException; - import com.firebolt.jdbc.connection.settings.FireboltProperties; -import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.statement.StatementInfoWrapper; +import java.io.InputStream; +import java.sql.SQLException; + public interface StatementClient { /** * Post SQL statement */ InputStream executeSqlStatement(StatementInfoWrapper statementInfoWrapper, FireboltProperties connectionProperties, - boolean systemEngine, int queryTimeout, boolean standardSql) throws SQLException; + boolean systemEngine, int queryTimeout) throws SQLException; /** * Call endpoint to abort a running SQL statement diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java index da6c18bd7..61d22e9f6 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java @@ -132,13 +132,11 @@ public StatementClientImpl(OkHttpClient httpClient, FireboltConnection connectio * @param connectionProperties the connection properties * @param systemEngine indicates if system engine is used * @param queryTimeout query timeout - * @param standardSql indicates if standard sql should be used * @return the server response */ @Override public InputStream executeSqlStatement(@NonNull StatementInfoWrapper statementInfoWrapper, - @NonNull FireboltProperties connectionProperties, boolean systemEngine, int queryTimeout, - boolean standardSql) throws SQLException { + @NonNull FireboltProperties connectionProperties, boolean systemEngine, int queryTimeout) throws SQLException { QueryIdFetcher.getQueryFetcher(connection.getInfraVersion()).formatStatement(statementInfoWrapper); String formattedStatement = QueryIdFetcher.getQueryFetcher(connection.getInfraVersion()).formatStatement(statementInfoWrapper); Map params = getAllParameters(connectionProperties, statementInfoWrapper, systemEngine, queryTimeout); diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java index 13f05cceb..fcdefbd08 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAccountIdService.java @@ -2,7 +2,6 @@ import com.firebolt.jdbc.client.account.FireboltAccount; import com.firebolt.jdbc.client.account.FireboltAccountRetriever; -import com.firebolt.jdbc.exception.FireboltException; import java.sql.SQLException; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java index 37921db3b..67d783006 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java @@ -2,7 +2,6 @@ import com.firebolt.jdbc.client.query.StatementClient; import com.firebolt.jdbc.connection.settings.FireboltProperties; -import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.FireboltResultSet; import com.firebolt.jdbc.statement.FireboltStatement; import com.firebolt.jdbc.statement.StatementInfoWrapper; @@ -31,16 +30,15 @@ public class FireboltStatementService { * * @param statementInfoWrapper the statement info * @param properties the connection properties - * @param standardSql indicates if standard sql should be used * @param statement the statement * @return an InputStream with the result */ public Optional execute(StatementInfoWrapper statementInfoWrapper, - FireboltProperties properties, boolean standardSql, FireboltStatement statement) + FireboltProperties properties, FireboltStatement statement) throws SQLException { int queryTimeout = statement.getQueryTimeout(); boolean systemEngine = properties.isSystemEngine(); - InputStream is = statementClient.executeSqlStatement(statementInfoWrapper, properties, systemEngine, queryTimeout, standardSql); + InputStream is = statementClient.executeSqlStatement(statementInfoWrapper, properties, systemEngine, queryTimeout); if (statementInfoWrapper.getType() == StatementType.QUERY) { return Optional.of(createResultSet(is, (QueryRawStatement) statementInfoWrapper.getInitialStatement(), properties, statement)); } else { diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index a73fb4ddf..7af1f96db 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -1,7 +1,6 @@ package com.firebolt.jdbc.statement; import com.firebolt.jdbc.JdbcBase; -import com.firebolt.jdbc.annotation.ExcludeFromJacocoGeneratedReport; import com.firebolt.jdbc.annotation.NotImplemented; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; @@ -87,9 +86,9 @@ protected Optional execute(List statements) thr } for (int i = 0; i < statements.size(); i++) { if (i == 0) { - resultSet = execute(statements.get(i), true, true); + resultSet = execute(statements.get(i)); } else { - execute(statements.get(i), true, true); + execute(statements.get(i)); } } } finally { @@ -101,10 +100,10 @@ protected Optional execute(List statements) thr } @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both - private Optional execute(StatementInfoWrapper statementInfoWrapper, boolean verifyNotCancelled, boolean isStandardSql) throws SQLException { + private Optional execute(StatementInfoWrapper statementInfoWrapper) throws SQLException { createValidator(statementInfoWrapper.getInitialStatement(), connection).validate(statementInfoWrapper.getInitialStatement()); ResultSet resultSet = null; - if (!verifyNotCancelled || isStatementNotCancelled(statementInfoWrapper)) { + if (isStatementNotCancelled(statementInfoWrapper)) { runningStatementLabel = statementInfoWrapper.getLabel(); synchronized (this) { validateStatementIsNotClosed(); @@ -116,7 +115,7 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper, b connection.addProperty(statementInfoWrapper.getParam()); log.log(Level.FINE, "The property from the query {0} was stored", runningStatementLabel); } else { - Optional currentRs = statementService.execute(statementInfoWrapper, sessionProperties, isStandardSql, this); + Optional currentRs = statementService.execute(statementInfoWrapper, sessionProperties, this); if (currentRs.isPresent()) { resultSet = currentRs.get(); currentUpdateCount = -1; // Always -1 when returning a ResultSet @@ -176,8 +175,6 @@ private void abortStatementRunningOnFirebolt(String statementLabel) throws SQLEx try { statementService.abortStatement(statementLabel, sessionProperties); log.log(Level.FINE, "Statement with label {0} was aborted", statementLabel); - } catch (FireboltException e) { - throw e; } catch (Exception e) { throw new FireboltException("Could not abort statement", e); } finally { @@ -384,8 +381,7 @@ public void setCursorName(String name) throws SQLException { } @Override - @ExcludeFromJacocoGeneratedReport - public int getFetchDirection() throws SQLException { + public int getFetchDirection() { return ResultSet.FETCH_FORWARD; } diff --git a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java index e8b0ea327..0eb54c568 100644 --- a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java +++ b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java @@ -2,6 +2,7 @@ import com.firebolt.jdbc.CheckedBiFunction; import com.firebolt.jdbc.CheckedFunction; +import com.firebolt.jdbc.CheckedSupplier; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.type.array.SqlArrayUtil; import com.firebolt.jdbc.type.date.SqlDateUtil; @@ -20,7 +21,6 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.TimeZone; -import java.util.function.Supplier; import java.util.stream.Stream; import static com.firebolt.jdbc.exception.ExceptionType.TYPE_NOT_SUPPORTED; @@ -107,7 +107,7 @@ public static String transformAny(Object object, int sqlType) throws SQLExceptio return transformAny(object, () -> getType(sqlType)); } - private static String transformAny(Object object, Supplier> classSupplier) throws SQLException { + private static String transformAny(Object object, CheckedSupplier> classSupplier) throws SQLException { return object == null ? NULL_VALUE : transformAny(object, classSupplier.get()); } @@ -123,8 +123,14 @@ private static Class getType(Object object) { return object.getClass().isArray() && !byte[].class.equals(object.getClass()) ? Array.class : object.getClass(); } - private static Class getType(int sqlType) { - return jdbcTypeToClass.get(JDBCType.valueOf(sqlType)); + private static Class getType(int sqlType) throws SQLException { + try { + JDBCType jdbcType = JDBCType.valueOf(sqlType); + return Optional.ofNullable(jdbcTypeToClass.get(jdbcType)) + .orElseThrow(() -> new FireboltException(format("Unsupported JDBC type %s", jdbcType), TYPE_NOT_SUPPORTED)); + } catch(IllegalArgumentException e) { + throw new FireboltException(format("Unsupported SQL type %d", sqlType), TYPE_NOT_SUPPORTED); + } } private static CheckedFunction getSQLStringValueOfString() { diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index 0122fa15f..efd8a98a6 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -107,7 +107,7 @@ void version() { }, delimiter = ',') - void getPropertyInfo(String url, String propStr, String expectedInfoStr) throws SQLException { + void getPropertyInfo(String url, String propStr, String expectedInfoStr) { Properties expectedProps = toProperties(expectedInfoStr); assertEquals(expectedProps, toMap(new FireboltDriver().getPropertyInfo(url, toProperties(propStr))).entrySet().stream().filter(e -> expectedProps.containsKey(e.getKey())).collect(Collectors.toMap(Entry::getKey, Entry::getValue))); } diff --git a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java index 2b41e7f46..eae589a79 100644 --- a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java +++ b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java @@ -92,7 +92,7 @@ private Entry shouldPostSqlQuery(boolean systemEngine) throws SQ Call call = getMockedCallWithResponse(200, ""); when(okHttpClient.newCall(any())).thenReturn(call); StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("show databases").get(0); - statementClient.executeSqlStatement(statementInfoWrapper, fireboltProperties, fireboltProperties.isSystemEngine(), 15, true); + statementClient.executeSqlStatement(statementInfoWrapper, fireboltProperties, fireboltProperties.isSystemEngine(), 15); verify(okHttpClient).newCall(requestArgumentCaptor.capture()); Request actualRequest = requestArgumentCaptor.getValue(); @@ -198,7 +198,7 @@ void shouldRetryOnUnauthorized() throws IOException, SQLException { when(okHttpClient.newCall(any())).thenReturn(unauthorizedCall).thenReturn(okCall); StatementClient statementClient = new StatementClientImpl(okHttpClient, connection, "ConnA:1.0.9", "ConnB:2.0.9"); StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("show databases").get(0); - statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5, true); + statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5); verify(okHttpClient, times(2)).newCall(requestArgumentCaptor.capture()); assertEquals("Bearer oldToken", requestArgumentCaptor.getAllValues().get(0).headers().get("Authorization")); // legit:ignore-secrets assertEquals("Bearer newToken", requestArgumentCaptor.getAllValues().get(1).headers().get("Authorization")); // legit:ignore-secrets @@ -212,7 +212,7 @@ void shouldNotRetryNoMoreThanOnceOnUnauthorized() throws SQLException, IOExcepti when(okHttpClient.newCall(any())).thenReturn(unauthorizedCall).thenReturn(unauthorizedCall).thenReturn(okCall); StatementClient statementClient = new StatementClientImpl(okHttpClient, connection, "ConnA:1.0.9", "ConnB:2.0.9"); StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("show databases").get(0); - FireboltException ex = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5, true)); + FireboltException ex = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5)); assertEquals(ExceptionType.UNAUTHORIZED, ex.getType()); verify(okHttpClient, times(2)).newCall(any()); verify(connection, times(2)).removeExpiredTokens(); @@ -403,7 +403,7 @@ void shouldThrowUnauthorizedExceptionWhenNoAssociatedUser(String serverErrorMess when(okHttpClient.newCall(any())).thenReturn(unauthorizedCall); StatementClient statementClient = new StatementClientImpl(okHttpClient, connection, "ConnA:1.0.9", "ConnB:2.0.9"); StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("show databases").get(0); - FireboltException exception = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5, true)); + FireboltException exception = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5)); assertEquals(ExceptionType.UNAUTHORIZED, exception.getType()); assertEquals(format("Could not query Firebolt at %s. %s", HOST, exceptionMessage), exception.getMessage()); } @@ -420,7 +420,7 @@ void shouldThrowIOException(Class exceptionClass, Excep when(okHttpClient.newCall(any())).thenReturn(call); StatementClient statementClient = new StatementClientImpl(okHttpClient, connection, "", ""); StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("select 1").get(0); - FireboltException ex = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5, true)); + FireboltException ex = assertThrows(FireboltException.class, () -> statementClient.executeSqlStatement(statementInfoWrapper, FIREBOLT_PROPERTIES, false, 5)); assertEquals(exceptionType, ex.getType()); assertEquals(exceptionClass, ex.getCause().getClass()); } diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index 869da7628..53a316977 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -74,8 +74,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -190,7 +188,7 @@ void shouldPrepareStatementNoGeneratedKeys() throws SQLException { } private void shouldPrepareStatement(CheckedBiFunction preparedStatementFactoryMethod) throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenReturn(Optional.empty()); try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { PreparedStatement statement = preparedStatementFactoryMethod.apply(fireboltConnection, "INSERT INTO cars(sales, name) VALUES (?, ?)"); @@ -199,7 +197,7 @@ private void shouldPrepareStatement(CheckedBiFunction void notSupported(CheckedFunction getter) throws SQLE @Test void shouldNotSetNewPropertyWhenConnectionIsNotValidWithTheNewProperty() throws SQLException { try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenThrow(new FireboltException(ExceptionType.TOO_MANY_REQUESTS)); assertThrows(FireboltException.class, () -> fireboltConnection.addProperty(Map.entry("custom_1", "1"))); verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), - propertiesArgumentCaptor.capture(), anyBoolean(), any()); + propertiesArgumentCaptor.capture(), any()); assertEquals("1", propertiesArgumentCaptor.getValue().getAdditionalProperties().get("custom_1")); assertEquals("SELECT 1", queryInfoWrapperArgumentCaptor.getValue().getSql()); assertNull(fireboltConnection.getSessionProperties().getAdditionalProperties().get("custom_1")); @@ -315,7 +313,7 @@ void shouldNotSetNewPropertyWhenConnectionIsNotValidWithTheNewProperty() throws @Test void shouldSetNewPropertyWhenConnectionIsValidWithTheNewProperty() throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenReturn(Optional.empty()); try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { @@ -324,7 +322,7 @@ void shouldSetNewPropertyWhenConnectionIsValidWithTheNewProperty() throws SQLExc fireboltConnection.addProperty(newProperties); verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), - propertiesArgumentCaptor.capture(), anyBoolean(), any()); + propertiesArgumentCaptor.capture(), any()); assertEquals("1", propertiesArgumentCaptor.getValue().getAdditionalProperties().get("custom_1")); assertEquals("1", fireboltConnection.getSessionProperties().getAdditionalProperties().get("custom_1")); assertEquals(List.of("SELECT 1"), queryInfoWrapperArgumentCaptor.getAllValues().stream().map(StatementInfoWrapper::getSql).collect(toList())); @@ -333,19 +331,19 @@ void shouldSetNewPropertyWhenConnectionIsValidWithTheNewProperty() throws SQLExc @Test void shouldValidateConnectionWhenCallingIsValid() throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenReturn(Optional.empty()); try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { fireboltConnection.isValid(500); verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), - propertiesArgumentCaptor.capture(), anyBoolean(), any()); + propertiesArgumentCaptor.capture(), any()); assertEquals(List.of("SELECT 1"), queryInfoWrapperArgumentCaptor.getAllValues().stream().map(StatementInfoWrapper::getSql).collect(toList())); } } @Test void shouldIgnore429WhenValidatingConnection() throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenThrow(new FireboltException(ExceptionType.TOO_MANY_REQUESTS)); try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { assertTrue(fireboltConnection.isValid(500)); @@ -354,7 +352,7 @@ void shouldIgnore429WhenValidatingConnection() throws SQLException { @Test void shouldReturnFalseWhenValidatingConnectionThrowsAnException() throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenThrow(new FireboltException(ExceptionType.ERROR)); try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { assertFalse(fireboltConnection.isValid(500)); @@ -378,7 +376,7 @@ void shouldReturnFalseWhenValidatingClosedConnection() throws SQLException { @Test void shouldExtractConnectorOverrides() throws SQLException { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenReturn(Optional.empty()); connectionProperties.put("user_clients", "ConnA:1.0.9,ConnB:2.8.0"); connectionProperties.put("user_drivers", "DriverA:2.0.9,DriverB:3.8.0"); @@ -387,7 +385,7 @@ void shouldExtractConnectorOverrides() throws SQLException { PreparedStatement statement = fireboltConnection.prepareStatement("SELECT 1"); statement.execute(); - verify(fireboltStatementService).execute(any(), propertiesArgumentCaptor.capture(), anyBoolean(), any()); + verify(fireboltStatementService).execute(any(), propertiesArgumentCaptor.capture(), any()); assertNull(propertiesArgumentCaptor.getValue().getAdditionalProperties().get("user_clients")); assertNull(propertiesArgumentCaptor.getValue().getAdditionalProperties().get("user_drivers")); assertNull(fireboltConnection.getSessionProperties().getAdditionalProperties().get("user_clients")); diff --git a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java index 111376628..d599b6c68 100644 --- a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java +++ b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java @@ -291,6 +291,15 @@ void shouldNotBeLastAtLastLine() throws SQLException { assertTrue(resultSet.isLast()); } + @Test + void maxRows() throws SQLException { + inputStream = getInputStreamWithCommonResponseExample(); + when(fireboltStatement.getMaxRows()).thenReturn(1); + resultSet = createResultSet(inputStream); + assertTrue(resultSet.next()); + assertFalse(resultSet.next()); // the result has 2 rows but maxRows=1, so the second next() returns false + } + @Test void shouldReadAllTheData() throws SQLException { inputStream = getInputStreamWithCommonResponseExample(); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltAccountIdServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltAccountIdServiceTest.java new file mode 100644 index 000000000..255724f1c --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/service/FireboltAccountIdServiceTest.java @@ -0,0 +1,21 @@ +package com.firebolt.jdbc.service; + +import com.firebolt.jdbc.client.account.FireboltAccount; +import com.firebolt.jdbc.client.account.FireboltAccountRetriever; +import org.junit.jupiter.api.Test; + +import java.sql.SQLException; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class FireboltAccountIdServiceTest { + @Test + void getValue() throws SQLException { + FireboltAccountRetriever firebolAccountClient = mock(FireboltAccountRetriever.class); + FireboltAccount account = new FireboltAccount("id", "region", 123); + when(firebolAccountClient.retrieve("token", "account")).thenReturn(account); + assertSame(account, new FireboltAccountIdService(firebolAccountClient).getValue("token", "account")); + } +} diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java index 2c2e93999..61d2f5847 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltStatementServiceTest.java @@ -10,7 +10,6 @@ import com.firebolt.jdbc.statement.StatementInfoWrapper; import com.firebolt.jdbc.statement.StatementUtil; import okhttp3.OkHttpClient; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -21,8 +20,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.sql.SQLException; -import java.util.Optional; +import static java.util.Optional.empty; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -45,9 +45,9 @@ void shouldExecuteQueryAndCreateResultSet() throws SQLException { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); FireboltStatement statement = mock(FireboltStatement.class); when(statement.getQueryTimeout()).thenReturn(10); - fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, true, statement); - verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, 10, true); - Assertions.assertEquals(1, mocked.constructed().size()); + fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, statement); + verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, 10); + assertEquals(1, mocked.constructed().size()); } } @@ -59,9 +59,9 @@ void shouldExecuteQueryWithLocalHostFormatParameters() throws SQLException { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); FireboltStatement statement = mock(FireboltStatement.class); when(statement.getQueryTimeout()).thenReturn(-1); - fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, true, statement); - Assertions.assertEquals(1, mocked.constructed().size()); - verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, -1, true); + fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, statement); + assertEquals(1, mocked.constructed().size()); + verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, -1); } } @@ -90,25 +90,9 @@ void shouldExecuteQueryWithParametersForSystemEngine() throws SQLException { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); FireboltStatement statement = mock(FireboltStatement.class); when(statement.getQueryTimeout()).thenReturn(10); - fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, true, statement); - Assertions.assertEquals(1, mocked.constructed().size()); - verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, true, 10, true); - } - } - - @Test - void shouldIncludeNonStandardSqlQueryParamForNonStandardSql() throws SQLException { - try (MockedConstruction mocked = Mockito.mockConstruction(FireboltResultSet.class)) { - - StatementInfoWrapper statementInfoWrapper = StatementUtil.parseToStatementInfoWrappers("SELECT 1").get(0); - FireboltProperties fireboltProperties = fireboltProperties("localhost", true); - - FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); - FireboltStatement statement = mock(FireboltStatement.class); - when(statement.getQueryTimeout()).thenReturn(-1); - fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, false, statement); - Assertions.assertEquals(1, mocked.constructed().size()); - verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, true, -1, false); + fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, statement); + assertEquals(1, mocked.constructed().size()); + verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, true, 10); } } @@ -121,9 +105,8 @@ void shouldBeEmptyWithNonQueryStatement() throws SQLException { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); FireboltStatement statement = mock(FireboltStatement.class); when(statement.getQueryTimeout()).thenReturn(-1); - Assertions.assertEquals(Optional.empty(), fireboltStatementService.execute(statementInfoWrapper, - fireboltProperties, true, statement)); - verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, -1, true); + assertEquals(empty(), fireboltStatementService.execute(statementInfoWrapper, fireboltProperties, statement)); + verify(statementClient).executeSqlStatement(statementInfoWrapper, fireboltProperties, false, -1); } @Test @@ -138,7 +121,7 @@ void abortStatementHttpRequest() throws SQLException { void isStatementRunning(boolean running) { FireboltStatementService fireboltStatementService = new FireboltStatementService(statementClient); when(statementClient.isStatementRunning("id")).thenReturn(running); - Assertions.assertEquals(running, fireboltStatementService.isStatementRunning("id")); + assertEquals(running, fireboltStatementService.isStatementRunning("id")); } private FireboltProperties fireboltProperties(String host, boolean systemEngine) { diff --git a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java index 7ea66a1d2..4a23ef853 100644 --- a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java @@ -8,6 +8,7 @@ import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.FireboltResultSet; import com.firebolt.jdbc.service.FireboltStatementService; +import com.firebolt.jdbc.statement.rawstatement.QueryRawStatement; import com.firebolt.jdbc.type.array.SqlArrayUtil; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,9 +33,16 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.sql.Wrapper; +import java.text.MessageFormat; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; import java.util.stream.Stream; import static java.lang.String.format; @@ -50,13 +58,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; @ExtendWith(MockitoExtension.class) class FireboltStatementTest { @@ -121,8 +129,8 @@ void shouldCloseInputStreamOnClose() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.empty()); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.of(rs)); + when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.empty()); + when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.of(rs)); fireboltStatement.executeQuery("show database"); fireboltStatement.close(); verify(rs).close(); @@ -153,9 +161,9 @@ void shouldExecuteIfUpdateStatementWouldNotReturnAResultSetNoGeneratedKeys() thr private void shouldExecuteIfUpdateStatementWouldNotReturnAResultSet(CheckedBiFunction executor) throws SQLException { try (FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, fireboltConnection)) { - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.empty()); + when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.empty()); assertEquals(0, executor.apply(fireboltStatement, "INSERT INTO cars(sales, name) VALUES (500, 'Ford')")); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(fireboltProperties),anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(fireboltProperties), any()); assertEquals("INSERT INTO cars(sales, name) VALUES (500, 'Ford')", queryInfoWrapperArgumentCaptor.getValue().getSql()); assertEquals(0, fireboltStatement.getUpdateCount()); @@ -176,7 +184,7 @@ private void shouldExecuteStatementThatReturnsResultSet(CheckedBiFunction logMessages = new ArrayList<>(); + Logger log = Logger.getLogger(FireboltStatement.class.getName()); + log.setLevel(Level.ALL); + log.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + logMessages.add(new MessageFormat(record.getMessage()).format(record.getParameters())); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + + String query = "SELECT 1"; + // This trick simulates cancelled statement. getLabel() called first time returns the initial label generated + // when StatementInfoWrapper is created. This value is stored in a collection of currently running queries. + // But next invocation of getLabel() will return other value, so the statement will not be found in list of running + // queries and will be considered as cancelled. + // It is ugly trick, but I do not know better way to simulate cancelled query. + StatementInfoWrapper statementInfoWrapper = new StatementInfoWrapper(query, StatementType.QUERY, null, new QueryRawStatement(query, query, List.of())) { + String label = null; + @Override + public String getLabel() { + if (label != null) { + return label; + } + String currentLabel = super.getLabel(); + label = "other label"; + return currentLabel; + } + }; + fireboltStatement.execute(List.of(statementInfoWrapper)); + assertNull(fireboltStatement.getResultSet()); + fireboltStatement.getMoreResults(CLOSE_CURRENT_RESULT); + verify(fireboltStatementService, times(0)).execute(any(), any(), any()); + assertTrue(logMessages.contains("Aborted query with id other label"), "Expected log message is not found"); + } + + @Test void shouldCloseCurrentAndGetMoreResultWhenCallingGetMoreResultsWithCloseCurrentFlag() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.of(mock(FireboltResultSet.class))); + when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.of(mock(FireboltResultSet.class))); fireboltStatement.execute("SELECT 1; SELECT 2;"); ResultSet resultSet = fireboltStatement.getResultSet(); fireboltStatement.getMoreResults(CLOSE_CURRENT_RESULT); @@ -221,7 +279,7 @@ void shouldCloseCurrentAndGetMoreResultWhenCallingGetMoreResultsWithCloseCurrent void shouldKeepCurrentAndGetMoreResultWhenCallingGetMoreResultsWithKeepCurrentResultFlag() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.of(mock(ResultSet.class))); + when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.of(mock(ResultSet.class))); fireboltStatement.execute("SELECT 1; SELECT 2;"); ResultSet resultSet = fireboltStatement.getResultSet(); fireboltStatement.getMoreResults(Statement.KEEP_CURRENT_RESULT); @@ -236,7 +294,7 @@ void shouldCloseUnclosedAndGetMoreResultWhenCallingGetMoreResultsWithCloseAllRes FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())) + when(fireboltStatementService.execute(any(), any(), any())) .thenReturn(Optional.of(rs)).thenReturn(Optional.of(rs2)).thenReturn(Optional.of(rs3)); fireboltStatement.execute("SELECT 1; SELECT 2; SELECT 3;"); @@ -372,6 +430,23 @@ void fetchSize() throws SQLException { assertThrows(SQLException.class, () -> statement.setFetchSize(-1)); } + @Test + void fetchDirection() throws SQLException { + Statement statement = new FireboltStatement(fireboltStatementService, null, mock(FireboltConnection.class)); + assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); // check initial value + + // set the same value; should succeed + statement.setFetchDirection(ResultSet.FETCH_FORWARD); + assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + + // set wrong values expecting exceptions + assertThrows(SQLException.class, () -> statement.setFetchDirection(ResultSet.FETCH_REVERSE)); + assertThrows(SQLException.class, () -> statement.setFetchDirection(ResultSet.FETCH_UNKNOWN)); + assertThrows(SQLException.class, () -> statement.setFetchDirection(999999)); + // check that returned value is still FETCH_FORWARD + assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + } + @Test void maxFieldSize() throws SQLException { Statement statement = new FireboltStatement(fireboltStatementService, null, mock(FireboltConnection.class)); @@ -418,7 +493,7 @@ void shouldLimitStringByMaxFieldSize(String inputText, int maxFieldSize, String FireboltConnection connection = mock(FireboltConnection.class); StatementClient statementClient = mock(StatementClient.class); String content = format("1\t2\ntext\tbytea\n%s\t%s", inputText == null ? "\\N" : inputText, inputText == null ? "\\N" : SqlArrayUtil.byteArrayToHexString(inputText.getBytes(), false)); - when(statementClient.executeSqlStatement(any(), any(), eq(false), anyInt(), eq(true))).thenReturn(new ByteArrayInputStream(content.getBytes())); + when(statementClient.executeSqlStatement(any(), any(), eq(false), anyInt())).thenReturn(new ByteArrayInputStream(content.getBytes())); FireboltStatementService statementService = new FireboltStatementService(statementClient); FireboltStatement fireboltStatement = new FireboltStatement(statementService, fireboltProperties, connection); when(connection.createStatement()).thenReturn(fireboltStatement); @@ -452,7 +527,7 @@ void shouldExecuteEmptyBatch() throws SQLException { void shouldExecuteBatch() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn( + when(fireboltStatementService.execute(any(), any(), any())).thenReturn( Optional.of(mock(FireboltResultSet.class)), Optional.of(mock(FireboltResultSet.class)), Optional.empty(), Optional.empty(), Optional.of(mock(FireboltResultSet.class)) ); @@ -469,7 +544,7 @@ void shouldExecuteBatch() throws SQLException { void shouldClearBatch() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn( + when(fireboltStatementService.execute(any(), any(), any())).thenReturn( Optional.empty(), Optional.empty() ); diff --git a/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java index 0af897fb1..8d488714a 100644 --- a/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java @@ -28,6 +28,7 @@ import javax.sql.rowset.serial.SerialBlob; import javax.sql.rowset.serial.SerialClob; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; @@ -207,7 +208,7 @@ private static Stream setNumber() { void beforeEach() throws SQLException { when(connection.getSessionProperties()).thenReturn(properties); lenient().when(properties.getBufferSize()).thenReturn(10); - lenient().when(fireboltStatementService.execute(any(), any(), anyBoolean(), any())).thenReturn(Optional.empty()); + lenient().when(fireboltStatementService.execute(any(), any(), any())).thenReturn(Optional.empty()); } @AfterEach @@ -224,7 +225,7 @@ void afterEach() throws SQLException { }) void getMetadata(String query, boolean expectedResultSet) throws SQLException { StatementClient statementClient = mock(StatementClient.class); - when(statementClient.executeSqlStatement(any(), any(), anyBoolean(), anyInt(), anyBoolean())).thenReturn(new ByteArrayInputStream(new byte[0])); + when(statementClient.executeSqlStatement(any(), any(), anyBoolean(), anyInt())).thenReturn(new ByteArrayInputStream(new byte[0])); statement = new FireboltPreparedStatement(new FireboltStatementService(statementClient), connection, query); assertNull(statement.getMetaData()); statement.setObject(1, null); @@ -250,7 +251,7 @@ void shouldExecute() throws SQLException { statement.setArray(7, new FireboltArray(FireboltDataType.TEXT, new String[] {"sedan", "hatchback", "coupe"})); statement.setBytes(8, "HarryFord".getBytes()); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars (sales, make, model, minor_model, color, type, types, signature) VALUES (500,'Ford','FOCUS',NULL,NULL,'sedan',['sedan','hatchback','coupe'],E'\\x48\\x61\\x72\\x72\\x79\\x46\\x6f\\x72\\x64'::BYTEA)", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -268,7 +269,7 @@ void setNullByteArray() throws SQLException { statement.setArray(7, new FireboltArray(FireboltDataType.TEXT, new String[] {"sedan", "hatchback", "coupe"})); statement.setBytes(8, null); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars (sales, make, model, minor_model, color, type, types, signature) VALUES (500,'Ford','FOCUS',NULL,NULL,'sedan',['sedan','hatchback','coupe'],NULL)", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -279,10 +280,34 @@ void setBuffer(String name, Setter setter, String expected) throws SQLException statement = createStatementWithSql("INSERT INTO data (field) VALUES (?)"); setter.set(statement); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals(format("INSERT INTO data (field) VALUES (%s)", expected), queryInfoWrapperArgumentCaptor.getValue().getSql()); } + @Test + void setFailingCharacterStream() throws IOException { + statement = createStatementWithSql("INSERT INTO data (field) VALUES (?)"); + Reader reader = mock(Reader.class); + when(reader.read(any(), anyInt(), anyInt())).thenThrow(new IOException()); + assertEquals(IOException.class, assertThrows(SQLException.class, () -> statement.setCharacterStream(1, reader)).getCause().getClass()); + } + + @Test + void setFailingBinaryStream() throws IOException { + statement = createStatementWithSql("INSERT INTO data (field) VALUES (?)"); + InputStream is = mock(InputStream.class); + when(is.readAllBytes()).thenThrow(new IOException()); + assertEquals(IOException.class, assertThrows(SQLException.class, () -> statement.setBinaryStream(1, is)).getCause().getClass()); + } + + @Test + void setFailingLimitedBinaryStream() throws IOException { + statement = createStatementWithSql("INSERT INTO data (field) VALUES (?)"); + InputStream is = mock(InputStream.class); + when(is.readNBytes(1024)).thenThrow(new IOException()); + assertEquals(IOException.class, assertThrows(SQLException.class, () -> statement.setBinaryStream(1, is, 1024)).getCause().getClass()); + } + @Test void shouldExecuteBatch() throws SQLException { statement = createStatementWithSql("INSERT INTO cars (sales, make) VALUES (?,?)"); @@ -294,7 +319,7 @@ void shouldExecuteBatch() throws SQLException { statement.setObject(2, "Tesla"); statement.addBatch(); statement.executeBatch(); - verify(fireboltStatementService, times(2)).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService, times(2)).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars (sales, make) VALUES (150,'Ford')", queryInfoWrapperArgumentCaptor.getAllValues().get(0).getSql()); assertEquals("INSERT INTO cars (sales, make) VALUES (300,'Tesla')", @@ -324,7 +349,7 @@ void shouldExecuteWithSpecialCharactersInQuery() throws SQLException { String expectedSql = "INSERT INTO cars (model ,sales, make) VALUES ('?',' ?','(?:^|[^\\\\p{L}\\\\p{N}])(?i)(phone)(?:[^\\\\p{L}\\\\p{N}]|$)')"; statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals(expectedSql, queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -339,7 +364,22 @@ void shouldThrowExceptionWhenTooManyParametersAreProvided() throws SQLException } @Test - void shouldThrowsExceptionWhenTryingToExecuteUpdate() throws SQLException { + void shouldExecuteUpdate() throws SQLException { + statement = createStatementWithSql("update cars set sales = ? where make = ?"); + + statement.setObject(1, 150); + statement.setObject(2, "Ford"); + + assertEquals(0, statement.executeUpdate()); // we are not able to return number of affected lines right now + + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); + assertEquals("update cars set sales = 150 where make = 'Ford'", + queryInfoWrapperArgumentCaptor.getValue().getSql()); + } + + + @Test + void shouldThrowsExceptionWhenTryingToExecuteUpdateWithQuery() throws SQLException { statement = createStatementWithSql("update cars set sales = ? where make = ?"); statement.setObject(1, 150); @@ -357,7 +397,7 @@ void shouldSetNull() throws SQLException { statement.setNull(2, 0); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars (sales, make) VALUES (NULL,NULL)", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -369,7 +409,7 @@ void shouldSetBoolean() throws SQLException { statement.setBoolean(1, true); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(available) VALUES (1)", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -385,7 +425,7 @@ void shouldSetUrl(String name, URL url) throws SQLException { statement.setURL(2, url); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals(format("INSERT INTO companies (name, url) VALUES (%s,%s)", sqlQuote(name), sqlQuote(url)), queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -408,7 +448,7 @@ void shouldSetNumber(String name, ParameterizedSetter setter, T value) th setter.set(statement, 1, value); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); } @Test @@ -419,7 +459,7 @@ void shouldSetDate() throws SQLException { statement.setDate(1, new Date(1564527600000L)); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES ('2019-07-31')", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -432,7 +472,7 @@ void shouldSetDateWithCalendar() throws SQLException, ParseException { statement.setDate(1, new Date(calendar.getTimeInMillis()), calendar); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES ('2024-04-19')", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -445,7 +485,7 @@ void shouldSetDateWithNullCalendar() throws SQLException, ParseException { statement.setDate(1, new Date(1564527600000L), null); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES ('2019-07-31')", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -458,7 +498,7 @@ void shouldSetTimeStampWithCalendar() throws SQLException, ParseException { statement.setTimestamp(1, new Timestamp(calendar.getTimeInMillis()), calendar); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES ('2024-04-19 05:11:01')", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -471,7 +511,7 @@ void shouldSetTimeStamp() throws SQLException { statement.setTimestamp(1, new Timestamp(1564571713000L)); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES ('2019-07-31 12:15:13')", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -484,7 +524,7 @@ void shouldSetNullTimeStampWithCalendar() throws SQLException, ParseException { statement.setTimestamp(1, null, calendar); statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals("INSERT INTO cars(release_date) VALUES (NULL)", queryInfoWrapperArgumentCaptor.getValue().getSql()); } @@ -507,7 +547,7 @@ void shouldSetAllObjects() throws SQLException { statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals( "INSERT INTO cars(timestamp, date, float, long, big_decimal, null, boolean, int) VALUES ('2019-07-31 12:15:13','2019-07-31',5.5,5,555555555555.55555555,NULL,1,5)", queryInfoWrapperArgumentCaptor.getValue().getSql()); @@ -531,7 +571,7 @@ void shouldSetAllObjectsWithCorrectSqlType() throws SQLException { statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals( "INSERT INTO cars(timestamp, date, float, long, big_decimal, null, boolean, int) VALUES ('2019-07-31 12:15:13','2019-07-31',5.5,5,555555555555.55555555,NULL,1,5)", @@ -589,8 +629,15 @@ void unsupportedType() { statement = createStatementWithSql("INSERT INTO data (column) VALUES (?)"); assertThrows(SQLException.class, () -> statement.setObject(1, this)); // STRUCT is not supported now, so it can be used as an example of unsupported type - assertThrows(SQLFeatureNotSupportedException.class, () -> statement.setObject(1, this, Types.STRUCT)); - assertThrows(SQLFeatureNotSupportedException.class, () -> statement.setObject(1, this, Types.STRUCT, 5)); + assertThrows(SQLFeatureNotSupportedException.class, () -> statement.setObject(1, "", Types.STRUCT)); + assertThrows(SQLFeatureNotSupportedException.class, () -> statement.setObject(1, "", Types.STRUCT, 5)); + + // this test definitely cannot be passed to the prepared statement, so exception is expected here. + assertThrows(SQLException.class, () -> statement.setObject(1, this, Types.VARCHAR)); + assertThrows(SQLException.class, () -> statement.setObject(1, this)); + + // unsupported SQL Type + assertThrows(SQLFeatureNotSupportedException.class, () -> statement.setObject(1, "", 999999)); } private void shouldSetObjectWithCorrectSqlType(Object value, int type, Integer scale, String expected) throws SQLException { @@ -601,7 +648,7 @@ private void shouldSetObjectWithCorrectSqlType(Object value, int type, Integer s statement.setObject(1, value, type, scale); } statement.execute(); - verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), anyBoolean(), any()); + verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), eq(properties), any()); assertEquals(format("INSERT INTO data (column) VALUES (%s)", expected), queryInfoWrapperArgumentCaptor.getValue().getSql()); } diff --git a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java index cf5b952c4..86c111c17 100644 --- a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java +++ b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java @@ -20,6 +20,7 @@ import static com.firebolt.jdbc.exception.ExceptionType.TYPE_NOT_SUPPORTED; import static com.firebolt.jdbc.exception.ExceptionType.TYPE_TRANSFORMATION_ERROR; +import static com.firebolt.jdbc.type.JavaTypeToFireboltSQLString.NULL_VALUE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -148,7 +149,7 @@ void shouldTransformTimeStampToString() throws SQLException { Timestamp ts = Timestamp.valueOf(LocalDateTime.of(2022, 5, 23, 12, 57, 13, 173456789)); assertEquals("'2022-05-23 12:57:13.173456789'", JavaTypeToFireboltSQLString.TIMESTAMP.transform(ts)); assertEquals("'2022-05-23 12:57:13.173456789'", JavaTypeToFireboltSQLString.transformAny(ts)); - assertEquals("NULL", JavaTypeToFireboltSQLString.TIMESTAMP.transform(null)); + assertEquals(NULL_VALUE, JavaTypeToFireboltSQLString.TIMESTAMP.transform(null)); } @Test @@ -183,6 +184,16 @@ void shouldTransformEmptyArray() throws SQLException { assertEquals("[]", JavaTypeToFireboltSQLString.ARRAY.transform(new int[0])); } + @Test + void shouldTransformNullIntSubArray() throws SQLException { + assertEquals("[NULL]", JavaTypeToFireboltSQLString.ARRAY.transform(new int[][] {null})); + } + + @Test + void shouldTransformNullStringSubArray() throws SQLException { + assertEquals("[NULL]", JavaTypeToFireboltSQLString.ARRAY.transform(new String[][] {null})); + } + @Test void shouldThrowExceptionWhenObjectTypeIsNotSupported() { FireboltException ex = assertThrows(FireboltException.class, () -> JavaTypeToFireboltSQLString.transformAny(Map.of())); @@ -194,4 +205,10 @@ void shouldThrowExceptionWhenObjectCouldNotBeTransformed() { FireboltException ex = assertThrows(FireboltException.class, () -> JavaTypeToFireboltSQLString.ARRAY.transform(Map.of())); assertEquals(TYPE_TRANSFORMATION_ERROR, ex.getType()); } + + @ParameterizedTest + @EnumSource(JavaTypeToFireboltSQLString.class) + void shouldTransformNullValue(JavaTypeToFireboltSQLString type) throws SQLException { + assertEquals(NULL_VALUE, type.transform(null)); + } } diff --git a/src/test/java/com/firebolt/jdbc/util/StatementUtilTest.java b/src/test/java/com/firebolt/jdbc/util/StatementUtilTest.java index 98cde4e33..c688a6764 100644 --- a/src/test/java/com/firebolt/jdbc/util/StatementUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/StatementUtilTest.java @@ -71,6 +71,11 @@ void shouldExtractTimezone() { StatementUtil.extractParamFromSetStatement(query, null)); } + @Test + void shouldReturnEmptyListForEmptySql() { + assertTrue(parseToRawStatementWrapper("").getSubStatements().isEmpty()); + } + @ParameterizedTest @CsvSource(value = { "1,set database='my_db',Could not set parameter. Set parameter 'DATABASE' is not allowed. Try again with 'USE DATABASE' instead of SET.", From 29147379e1cc1f24205bcebd464bd4f2840bbcf7 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 15 May 2024 16:32:27 +0300 Subject: [PATCH 04/52] FIR-32995 fixed numeric types transformations (#410) --- .../jdbc/resultset/FieldTypeConverter.java | 30 ++- .../jdbc/resultset/FireboltResultSet.java | 4 +- .../java/com/firebolt/jdbc/type/BaseType.java | 52 +++-- .../jdbc/resultset/FireboltResultSetTest.java | 215 ++++++++++++++++-- .../firebolt-response-with-numeric-types.csv | 2 +- 5 files changed, 262 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java b/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java index 408da4c30..1ee4537ca 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FieldTypeConverter.java @@ -32,15 +32,15 @@ public class FieldTypeConverter { return BaseType.TEXT.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Integer.class, (value, columnType, column) -> { - verify(Integer.class, columnType, BaseType.INTEGER, BaseType.SHORT); + verifyNumeric(Long.class, columnType); return BaseType.INTEGER.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Long.class, (value, columnType, column) -> { - verify(Long.class, columnType, BaseType.INTEGER, BaseType.SHORT, BaseType.LONG); + verifyNumeric(Long.class, columnType); return BaseType.LONG.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Double.class, (value, columnType, column) -> { - verify(Double.class, columnType, BaseType.DOUBLE, BaseType.REAL, BaseType.INTEGER, BaseType.SHORT, BaseType.LONG, BaseType.BIGINT); + verifyNumeric(Long.class, columnType); return BaseType.DOUBLE.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Boolean.class, (value, columnType, column) -> { @@ -48,20 +48,23 @@ public class FieldTypeConverter { return BaseType.BOOLEAN.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Short.class, (value, columnType, column) -> { - verify(Short.class, columnType, BaseType.SHORT); + verifyNumeric(Long.class, columnType); return BaseType.SHORT.transform(value, column); }); + CLASS_TO_CONVERT_FUNCTION.put(Byte.class, (value, columnType, column) -> { + verifyNumeric(Float.class, columnType); + return BaseType.BYTE.transform(value, column); + }); CLASS_TO_CONVERT_FUNCTION.put(BigInteger.class, (value, columnType, column) -> { - verify(BigInteger.class, columnType, BaseType.INTEGER, BaseType.SHORT, BaseType.LONG, BaseType.BIGINT); + verifyNumeric(Long.class, columnType); return BaseType.BIGINT.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Float.class, (value, columnType, column) -> { - verify(Float.class, columnType, BaseType.REAL, BaseType.INTEGER, BaseType.SHORT, BaseType.LONG, BaseType.BIGINT); + verifyNumeric(Float.class, columnType); return BaseType.REAL.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(BigDecimal.class, (value, columnType, column) -> { - verify(BigDecimal.class, columnType, BaseType.BIGINT, BaseType.NUMERIC, BaseType.INTEGER, BaseType.REAL, - BaseType.DOUBLE); + verifyNumeric(Long.class, columnType); return BaseType.NUMERIC.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(Date.class, (value, columnType, column) -> { @@ -81,8 +84,7 @@ public class FieldTypeConverter { return BaseType.ARRAY.transform(value, column); }); CLASS_TO_CONVERT_FUNCTION.put(OffsetDateTime.class, (value, columnType, column) -> { - verify(OffsetDateTime.class, columnType, BaseType.DATE, BaseType.TIMESTAMP, - BaseType.TIMESTAMP_WITH_TIMEZONE); + verify(OffsetDateTime.class, columnType, BaseType.DATE, BaseType.TIMESTAMP, BaseType.TIMESTAMP_WITH_TIMEZONE); Timestamp ts = BaseType.TIMESTAMP.transform(value, column); return SqlDateUtil.transformFromTimestampToOffsetDateTime.apply(ts); }); @@ -95,12 +97,15 @@ public class FieldTypeConverter { verify(byte[].class, columnType, BaseType.BYTEA); return BaseType.BYTEA.transform(value, column); } else { - return Optional.ofNullable(value).map(v -> BaseType.isNull(v) ? null : v).map(String::getBytes) - .orElse(null); + return Optional.ofNullable(value).map(v -> BaseType.isNull(v) ? null : v).map(String::getBytes).orElse(null); } }); } + private static void verifyNumeric(Class toType, BaseType columnBaseType) throws SQLException { + verify(toType, columnBaseType, BaseType.REAL, BaseType.DOUBLE, BaseType.BYTE, BaseType.SHORT, BaseType.INTEGER, BaseType.LONG, BaseType.BIGINT, BaseType.NUMERIC); + } + private static void verify(Class toType, BaseType columnBaseType, BaseType... supportedTypes) throws SQLException { if (Arrays.stream(supportedTypes).noneMatch(b -> b.equals(columnBaseType))) { throw new FireboltException( @@ -113,6 +118,7 @@ static T convert(Class type, String value, BaseType columnType, Column co throw new FireboltException( String.format(CONVERSION_NOT_SUPPORTED_EXCEPTION, type.getName(), columnType.getType().getName())); } + //noinspection unchecked return (T) CLASS_TO_CONVERT_FUNCTION.get(type).apply(value, columnType, column); } } diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index 2099b5e70..c7fc7ab94 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -224,8 +224,8 @@ public long getLong(String column) throws SQLException { @Override public byte getByte(int columnIndex) throws SQLException { - return ofNullable(getValueAtColumn(columnIndex)).map(v -> isNull(v) ? null : v) - .map(Byte::parseByte).orElse((byte) 0); + Byte value = BaseType.BYTE.transform(getValueAtColumn(columnIndex)); + return value == null ? 0 : value; } @Override diff --git a/src/main/java/com/firebolt/jdbc/type/BaseType.java b/src/main/java/com/firebolt/jdbc/type/BaseType.java index 7d401678d..9bd68af54 100644 --- a/src/main/java/com/firebolt/jdbc/type/BaseType.java +++ b/src/main/java/com/firebolt/jdbc/type/BaseType.java @@ -6,10 +6,10 @@ import com.firebolt.jdbc.type.array.SqlArrayUtil; import com.firebolt.jdbc.type.date.SqlDateUtil; import lombok.Builder; -import lombok.CustomLog; import lombok.Value; import org.apache.commons.text.StringEscapeUtils; +import javax.annotation.Nonnull; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Array; @@ -19,16 +19,20 @@ import java.sql.Timestamp; import java.util.Arrays; import java.util.TimeZone; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import static com.firebolt.jdbc.exception.ExceptionType.TYPE_TRANSFORMATION_ERROR; import static com.firebolt.jdbc.type.array.SqlArrayUtil.BYTE_ARRAY_PREFIX; import static com.firebolt.jdbc.type.array.SqlArrayUtil.hexStringToByteArray; /** This class contains the java types the Firebolt datatypes are mapped to */ public enum BaseType { - LONG(Long.class, conversion -> Long.parseLong(checkInfinity(conversion.getValue()))), - INTEGER(Integer.class, conversion -> Integer.parseInt(checkInfinity(conversion.getValue()))), - SHORT(Short.class, conversion -> Short.parseShort(checkInfinity(conversion.getValue()))), - BIGINT(BigInteger.class, conversion -> new BigInteger(checkInfinity(conversion.getValue()))), + LONG(TypePredicate.mayBeFloatingNumber, Long.class, conversion -> Long.parseLong(checkInfinity(conversion.getValue())), conversion -> Double.valueOf(conversion.getValue()).longValue()), + INTEGER(TypePredicate.mayBeFloatingNumber, Integer.class, conversion -> Integer.parseInt(checkInfinity(conversion.getValue())), conversion -> Integer.parseInt(Long.toString(Double.valueOf(conversion.getValue()).longValue()))), + SHORT(TypePredicate.mayBeFloatingNumber, Short.class, conversion -> Short.parseShort(checkInfinity(conversion.getValue())), conversion -> Short.parseShort(Long.toString(Double.valueOf(conversion.getValue()).longValue()))), + BYTE(TypePredicate.mayBeFloatingNumber, Byte.class, conversion -> Byte.parseByte(checkInfinity(conversion.getValue())), conversion -> Byte.parseByte(Long.toString(Double.valueOf(conversion.getValue()).longValue()))), + BIGINT(TypePredicate.mayBeFloatingNumber, BigInteger.class, conversion -> new BigInteger(checkInfinity(conversion.getValue())), conversion -> BigInteger.valueOf(Double.valueOf(conversion.getValue()).longValue())), TEXT(String.class, conversion -> { String escaped = StringEscapeUtils.unescapeJava(conversion.getValue()); int limit = conversion.getMaxFieldSize(); @@ -70,9 +74,9 @@ public enum BaseType { NUMERIC(BigDecimal.class, conversion -> new BigDecimal(conversion.getValue())), BOOLEAN(Boolean.class, conversion -> { String value = conversion.getValue(); - if ("0".equalsIgnoreCase(value) || "f".equalsIgnoreCase(value)) { + if ("0".equals(value) || "f".equalsIgnoreCase(value)) { return false; - } else if ("1".equalsIgnoreCase(value) || "t".equalsIgnoreCase(value)) { + } else if ("1".equals(value) || "t".equalsIgnoreCase(value)) { return true; } throw new FireboltException(String.format("Cannot cast %s to type boolean", conversion.getValue())); @@ -92,13 +96,25 @@ public enum BaseType { throw new FireboltException("Cannot convert binary string in non-hex format to byte array"); }); + // this class is needed to prevent back reference because the constant is used from the enum constructor + private static final class TypePredicate { + private static final Predicate mayBeFloatingNumber = Pattern.compile("[.eE]").asPredicate(); + } public static final String NULL_VALUE = "\\N"; private final Class type; - private final CheckedFunction transformFunction; + private final Predicate shouldTryFallback; + private final CheckedFunction[] transformFunctions; + + @SafeVarargs + BaseType(Class type, CheckedFunction... transformFunctions) { + this(s -> true, type, transformFunctions); + } - BaseType(Class type, CheckedFunction transformFunction) { + @SafeVarargs + BaseType(Predicate shouldTryFallback, Class type, CheckedFunction... transformFunctions) { this.type = type; - this.transformFunction = transformFunction; + this.shouldTryFallback = shouldTryFallback; + this.transformFunctions = transformFunctions; } private static boolean isPositiveInf(String value) { @@ -142,7 +158,7 @@ public T transform(String value) throws SQLException { return transform(value, null, null, 0); } - public T transform(String value, Column column, TimeZone timeZone, int maxFieldSize) throws SQLException { + public T transform(@Nonnull String value, Column column, TimeZone timeZone, int maxFieldSize) throws SQLException { TimeZone fromTimeZone; if (column != null && column.getType().getTimeZone() != null) { fromTimeZone = column.getType().getTimeZone(); @@ -159,8 +175,18 @@ private T transform(StringToColumnTypeConversion conversion) throws SQLExcep if (isNull(conversion.getValue())) { return null; } - //noinspection unchecked - return (T) transformFunction.apply(conversion); + for (int i = 0; i < transformFunctions.length; i++) { + try { + //noinspection unchecked + return (T) transformFunctions[i].apply(conversion); + } catch (RuntimeException e) { + if (i == transformFunctions.length - 1 || !shouldTryFallback.test(conversion.getValue())) { + throw new FireboltException(e.getMessage(), e, TYPE_TRANSFORMATION_ERROR); + } + } + } + // this can happen only if transformationFunctions is empty that is wrong, but we must satisfy the compiler. + throw new IllegalStateException(); } @Builder diff --git a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java index d599b6c68..c7255c483 100644 --- a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java +++ b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.resultset; +import com.firebolt.jdbc.CheckedFunction; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.statement.FireboltStatement; import com.firebolt.jdbc.util.LoggerUtil; @@ -7,6 +8,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.function.Executable; import org.junitpioneer.jupiter.DefaultTimeZone; import org.mockito.Mock; import org.mockito.MockedStatic; @@ -45,6 +47,7 @@ import java.util.TimeZone; import java.util.concurrent.Callable; +import static com.firebolt.jdbc.exception.ExceptionType.TYPE_TRANSFORMATION_ERROR; import static java.lang.String.format; import static java.sql.ResultSet.TYPE_FORWARD_ONLY; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -327,7 +330,7 @@ void shouldBeBeforeFirstIfFirstRowNotRead() throws SQLException { } @Test - void shouldGetBigDecimal() throws SQLException { + void shouldGetBigDecimalSimple() throws SQLException { inputStream = getInputStreamWithCommonResponseExample(); resultSet = createResultSet(inputStream); resultSet.next(); @@ -1054,20 +1057,200 @@ void shouldReturnDataForNewNonNumericDataTypes() throws SQLException { } @Test - void shouldGetObjectsForNumericTypes() throws SQLException { + void shouldGetByte() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals((byte)1, resultSet.getObject(1, Byte.class)); + assertEquals((byte)1, resultSet.getByte(1)); + + assertTransformationError(2, Byte.class); + assertTransformationError(2, i -> resultSet.getByte(i)); + + assertEquals((byte)1, resultSet.getObject(3, Byte.class)); + assertEquals((byte)1, resultSet.getByte(3)); + + assertEquals((byte)1, resultSet.getObject(4, Byte.class)); + assertEquals((byte)1, resultSet.getByte(4)); + + assertTransformationError(5, Byte.class); + assertTransformationError(5, i -> resultSet.getByte(i)); + + assertTransformationError(6, Byte.class); + assertTransformationError(6, i -> resultSet.getByte(i)); + } + + @Test + void shouldGetShort() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + assertEquals((short)1, resultSet.getObject(1, Short.class)); + assertEquals((short)1, resultSet.getShort(1)); + + assertTransformationError(2, Short.class); + assertTransformationError(2, i -> resultSet.getShort(i)); + + assertEquals((short)1, resultSet.getObject(3, Short.class)); + assertEquals((short)1, resultSet.getShort(3)); + + assertEquals((short)1, resultSet.getObject(4, Short.class)); + assertEquals((short)1, resultSet.getShort(4)); + + assertTransformationError(5, Short.class); + assertTransformationError(5, i -> resultSet.getShort(i)); + + assertEquals((short)30000, resultSet.getObject(6, Short.class)); + assertEquals((short)30000, resultSet.getShort(6)); + } + + @Test + void shouldGetInt() throws SQLException { inputStream = getInputStreamWithNumericTypes(); resultSet = createResultSet(inputStream); resultSet.next(); assertEquals(1, resultSet.getObject(1, Integer.class)); - assertEquals(new BigInteger("1"), resultSet.getObject(1, BigInteger.class)); - assertEquals(1, resultSet.getObject(1, Long.class)); + assertEquals(1, resultSet.getInt(1)); + + assertTransformationError(2, Integer.class); + assertTransformationError(2, i -> resultSet.getInt(i)); + + assertEquals(1, resultSet.getObject(3, Integer.class)); + assertEquals(1, resultSet.getInt(3)); + + assertEquals(1, resultSet.getObject(4, Integer.class)); + assertEquals(1, resultSet.getInt(4)); + + assertEquals(1231232, resultSet.getObject(5, Integer.class)); + assertEquals(1231232, resultSet.getInt(5)); + + assertEquals(30000, resultSet.getObject(6, Integer.class)); + assertEquals(30000, resultSet.getInt(6)); + } + + @Test + void shouldGetLong() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals(1L, resultSet.getObject(1, Long.class)); + assertEquals(1L, resultSet.getLong(1)); + assertEquals(30000000000L, resultSet.getObject(2, Long.class)); + assertEquals(30000000000L, resultSet.getLong(2)); + + assertEquals(1, resultSet.getObject(3, Long.class)); + assertEquals(1, resultSet.getLong(3)); + + assertEquals(1, resultSet.getObject(4, Long.class)); + assertEquals(1, resultSet.getLong(4)); + + assertEquals(1231232L, resultSet.getObject(5, Long.class)); + assertEquals(1231232L, resultSet.getLong(5)); + + assertEquals(30000L, resultSet.getObject(6, Long.class)); + assertEquals(30000L, resultSet.getLong(6)); + } + + @Test + void shouldGetBigInteger() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals(new BigInteger("1"), resultSet.getObject(1, BigInteger.class)); assertEquals(new BigInteger("30000000000"), resultSet.getObject(2, BigInteger.class)); + assertEquals(new BigInteger("1"), resultSet.getObject(3, BigInteger.class)); + assertEquals(new BigInteger("1"), resultSet.getObject(4, BigInteger.class)); + assertEquals(new BigInteger("1231232"), resultSet.getObject(5, BigInteger.class)); + assertEquals(new BigInteger("30000"), resultSet.getObject(6, BigInteger.class)); + } + + @Test + void shouldGetFloat() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals(1, resultSet.getObject(1, Float.class)); + assertEquals(1.F, resultSet.getFloat(1)); + + assertEquals(30000000000f, resultSet.getObject(2, Float.class)); + assertEquals(30000000000.F, resultSet.getFloat(2)); + assertEquals(1.23f, resultSet.getObject(3, Float.class)); - assertEquals(new BigDecimal("1.23"), resultSet.getObject(3, BigDecimal.class)); + assertEquals(1.23f, resultSet.getFloat(3)); + + assertEquals(1.23456789012f, resultSet.getObject(4, Float.class)); + assertEquals(1.23456789012f, resultSet.getFloat(4)); + + assertEquals(1231232.123459999990457054844258706536f, resultSet.getObject(5, Float.class), 0.01); + assertEquals(1231232.123459999990457054844258706536f, resultSet.getFloat(5), 0.01); + + assertEquals(30000.F, resultSet.getObject(6, Float.class)); + assertEquals(30000.F, resultSet.getFloat(6)); + } + + @Test + void shouldGetDouble() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals(1, resultSet.getObject(1, Double.class)); + assertEquals(1., resultSet.getDouble(1)); + + assertEquals(30000000000., resultSet.getObject(2, Double.class)); + assertEquals(30000000000., resultSet.getDouble(2)); + + assertEquals(1.23, resultSet.getObject(3, Double.class)); + assertEquals(1.23, resultSet.getDouble(3)); + assertEquals(1.23456789012, resultSet.getObject(4, Double.class)); + assertEquals(new BigDecimal("1.23456789012"), resultSet.getBigDecimal(4)); + + assertEquals(1231232.123459999990457054844258706536, resultSet.getObject(5, Double.class), 0.01); + assertEquals(1231232.123459999990457054844258706536, resultSet.getDouble(5), 0.01); + + assertEquals(30000., resultSet.getObject(6, Double.class)); + assertEquals(30000., resultSet.getDouble(6)); + } + + @Test + void shouldGetBigDecimal() throws SQLException { + inputStream = getInputStreamWithNumericTypes(); + resultSet = createResultSet(inputStream); + resultSet.next(); + + assertEquals(new BigDecimal("1"), resultSet.getObject(1, BigDecimal.class)); + assertEquals(new BigDecimal("1"), resultSet.getBigDecimal(1)); + + assertEquals(new BigDecimal("30000000000"), resultSet.getObject(2, BigDecimal.class)); + assertEquals(new BigDecimal("30000000000"), resultSet.getBigDecimal(2)); + + assertEquals(new BigDecimal("1.23"), resultSet.getObject(3, BigDecimal.class)); + assertEquals(new BigDecimal("1.23"), resultSet.getBigDecimal(3)); + assertEquals(new BigDecimal("1.23456789012"), resultSet.getObject(4, BigDecimal.class)); + assertEquals(new BigDecimal("1.23456789012"), resultSet.getBigDecimal(4)); + assertEquals(new BigDecimal("1231232.123459999990457054844258706536"), resultSet.getObject(5, BigDecimal.class)); + assertEquals(new BigDecimal("1231232.123459999990457054844258706536"), resultSet.getBigDecimal(5)); + + assertEquals(new BigDecimal("30000"), resultSet.getObject(6, BigDecimal.class)); + assertEquals(new BigDecimal("30000"), resultSet.getBigDecimal(6)); + } + + private void assertTransformationError(int columnIndex, Class type) { + assertTransformationError(columnIndex, i -> resultSet.getObject(i, type)); + } + + private void assertTransformationError(int columnIndex, CheckedFunction getter) { + FireboltException e = assertThrows(FireboltException.class, () -> getter.apply(columnIndex)); + assertEquals(TYPE_TRANSFORMATION_ERROR, e.getType()); + assertEquals(NumberFormatException.class, e.getCause().getClass()); } @Test @@ -1102,7 +1285,7 @@ void shouldReturnDataAndTypesForNumericTypes() throws SQLException { assertEquals(38, resultSet.getMetaData().getPrecision(5)); assertEquals(30, resultSet.getMetaData().getScale(5)); assertEquals(new BigDecimal("1231232.123459999990457054844258706536"), resultSet.getObject(5)); - assertEquals(80000, resultSet.getObject(6)); + assertEquals(30000, resultSet.getObject(6)); assertEquals(Types.INTEGER, resultSet.getMetaData().getColumnType(6)); assertEquals(30000000000L, resultSet.getObject(7)); assertEquals(Types.BIGINT, resultSet.getMetaData().getColumnType(7)); @@ -1169,15 +1352,20 @@ void shouldThrowIntegerInfinity() throws SQLException { inputStream = getInputStreamWithInfinity(); resultSet = createResultSet(inputStream); resultSet.next(); - assertThrows(IllegalArgumentException.class, () -> resultSet.getShort(1)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getInt(1)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getLong(1)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getShort(2)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getInt(2)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getLong(2)); + assertIllegalArgumentExceptionCause(() -> resultSet.getShort(1)); + assertIllegalArgumentExceptionCause(() -> resultSet.getInt(1)); + assertIllegalArgumentExceptionCause(() -> resultSet.getLong(1)); + + assertIllegalArgumentExceptionCause(() -> resultSet.getShort(2)); + assertIllegalArgumentExceptionCause(() -> resultSet.getInt(2)); + assertIllegalArgumentExceptionCause(() -> resultSet.getLong(2)); + + assertIllegalArgumentExceptionCause(() -> resultSet.getObject(1, BigInteger.class)); + } - assertThrows(IllegalArgumentException.class, () -> resultSet.getObject(1, BigInteger.class)); + private void assertIllegalArgumentExceptionCause(Executable getter) { + assertEquals(IllegalArgumentException.class, assertThrows(SQLException.class, getter).getCause().getClass()); } @Test @@ -1234,6 +1422,7 @@ void unwrap() throws SQLException { } @Test + @SuppressWarnings("java:S1874") // getUnicodeStream is deprecated byt must be tested void shouldReturnStream() throws SQLException, IOException { inputStream = getInputStreamWithCommonResponseExample(); resultSet = createResultSet(inputStream); diff --git a/src/test/resources/responses/firebolt-response-with-numeric-types.csv b/src/test/resources/responses/firebolt-response-with-numeric-types.csv index 06d562b74..206d16848 100644 --- a/src/test/resources/responses/firebolt-response-with-numeric-types.csv +++ b/src/test/resources/responses/firebolt-response-with-numeric-types.csv @@ -1,3 +1,3 @@ uint8 uint64 float32 float64 decimal an_int a_long a_float a_double a_decimal integer bigint real double precision numeric(38, 30) int long float double Decimal(38, 30) -1 30000000000 1.23 1.23456789012 1231232.123459999990457054844258706536 80000 30000000000 1.23 1.23456789012 1231232.123459999990457054844258706536 \ No newline at end of file +1 30000000000 1.23 1.23456789012 1231232.123459999990457054844258706536 30000 30000000000 1.23 1.23456789012 1231232.123459999990457054844258706536 \ No newline at end of file From a439132fede7df9dc4f609377ddc8510ed284459 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 15 May 2024 16:33:20 +0300 Subject: [PATCH 05/52] FIR-32987: fixed connection to v1 using access token (#409) --- .../java/com/firebolt/jdbc/connection/FireboltConnection.java | 2 +- src/test/java/com/firebolt/FireboltDriverTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 0f3dbe040..46586db2f 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -136,7 +136,7 @@ private static int getUrlVersion(String url, Properties connectionSettings) { } FireboltProperties props = new FireboltProperties(new Properties[] {propertiesFromUrl, connectionSettings}); String principal = props.getPrincipal(); - if (principal != null && principal.contains("@")) { + if (props.getAccessToken() != null || (principal != null && principal.contains("@"))) { return 1; } return 2; diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index efd8a98a6..7808418f4 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -45,6 +45,8 @@ void shouldNotReturnNewConnectionWhenUrlIsInvalid(String url) throws SQLExceptio "FireboltConnectionServiceSecret, jdbc:firebolt://api.dev.firebolt.io/db_name,'client_id=not-email;client_secret=any'", // clientId and client_secret are defined - v2 "FireboltConnectionUserPassword, jdbc:firebolt://api.dev.firebolt.io/db_name?user=sherlok@holmes.uk&password=watson,", // user is email as URL parameter - v1 // legit:ignore-secrets "FireboltConnectionServiceSecret, jdbc:firebolt://api.dev.firebolt.io/db_name?client_id=not-email&client_secret=any,", // clientId and client_secret as URL parameters - v2 + "FireboltConnectionUserPassword, jdbc:firebolt://api.dev.firebolt.io/db_name?access_token=aaabbbccc,", // old URL, no credentials but with access token + "FireboltConnectionServiceSecret,jdbc:firebolt:db_name,", // new URL, no credentials but with access token }) void validateConnectionWhenUrlIsValid(String expectedConnectionTypeName, String jdbcUrl, String propsString) throws SQLException, IOException, ClassNotFoundException { Properties properties = null; From 06e6497968f0f67e6c30b31fa21118e94be20484 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Thu, 16 May 2024 11:43:37 +0300 Subject: [PATCH 06/52] FIR-33037: improvements of the ResultSet getters (#412) --- .../jdbc/resultset/FireboltResultSet.java | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index c7fc7ab94..ece748fc0 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -50,6 +50,7 @@ import java.util.Calendar; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TimeZone; import java.util.TreeMap; import java.util.logging.Level; @@ -180,8 +181,7 @@ public String getString(String column) throws SQLException { @Override public int getInt(int columnIndex) throws SQLException { - Integer value = BaseType.INTEGER.transform(getValueAtColumn(columnIndex)); - return value == null ? 0 : value; + return getValue(columnIndex, BaseType.INTEGER, 0); } @Override @@ -190,15 +190,13 @@ public int getInt(String columnName) throws SQLException { } @Override - public long getLong(int colNum) throws SQLException { - Long value = BaseType.LONG.transform(getValueAtColumn(colNum)); - return value == null ? 0 : value; + public long getLong(int columnIndex) throws SQLException { + return getValue(columnIndex, BaseType.LONG, 0L); } @Override public float getFloat(int columnIndex) throws SQLException { - Float value = BaseType.REAL.transform(getValueAtColumn(columnIndex)); - return value == null ? 0 : value; + return getValue(columnIndex, BaseType.REAL, 0.0F); } @Override @@ -208,8 +206,7 @@ public float getFloat(String columnLabel) throws SQLException { @Override public double getDouble(int columnIndex) throws SQLException { - Double value = BaseType.DOUBLE.transform(getValueAtColumn(columnIndex)); - return value == null ? 0 : value; + return getValue(columnIndex, BaseType.DOUBLE, 0.0); } @Override @@ -224,14 +221,12 @@ public long getLong(String column) throws SQLException { @Override public byte getByte(int columnIndex) throws SQLException { - Byte value = BaseType.BYTE.transform(getValueAtColumn(columnIndex)); - return value == null ? 0 : value; + return getValue(columnIndex, BaseType.BYTE, (byte)0); } @Override public short getShort(int columnIndex) throws SQLException { - Short value = BaseType.SHORT.transform(getValueAtColumn(columnIndex)); - return value == null ? 0 : value; + return getValue(columnIndex, BaseType.SHORT, (short)0); } @Override @@ -244,6 +239,11 @@ public short getShort(String columnLabel) throws SQLException { return getShort(findColumn(columnLabel)); } + private T getValue(int columnIndex, BaseType type, T defaultValue) throws SQLException { + T value = type.transform(getValueAtColumn(columnIndex)); + return value == null ? defaultValue : value; + } + @Override public byte[] getBytes(int colNum) throws SQLException { return ofNullable(getValueAtColumn(colNum)) @@ -280,8 +280,7 @@ public int getType() { @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - String value = getValueAtColumn(columnIndex); - return value == null || value.isEmpty() ? null : BaseType.NUMERIC.transform(value); + return getValue(columnIndex, BaseType.NUMERIC, null); } @Override @@ -291,8 +290,7 @@ public BigDecimal getBigDecimal(String columnLabel) throws SQLException { @Override public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - BigDecimal bigDecimal = getBigDecimal(columnIndex); - return bigDecimal == null ? null : bigDecimal.setScale(scale, RoundingMode.HALF_UP); + return Optional.ofNullable(getBigDecimal(columnIndex)).map(d -> d.setScale(scale, RoundingMode.HALF_UP)).orElse(null); } @Override @@ -302,8 +300,7 @@ public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLExcepti @Override public Array getArray(int columnIndex) throws SQLException { - String value = getValueAtColumn(columnIndex); - return BaseType.ARRAY.transform(value, resultSetMetaData.getColumn(columnIndex)); + return BaseType.ARRAY.transform(getValueAtColumn(columnIndex), resultSetMetaData.getColumn(columnIndex)); } @Override @@ -334,9 +331,7 @@ public Date getDate(int columnIndex) throws SQLException { @Override public Date getDate(int columnIndex, Calendar calendar) throws SQLException { - TimeZone timeZone = calendar != null ? calendar.getTimeZone() : null; - String value = getValueAtColumn(columnIndex); - return BaseType.DATE.transform(value, resultSetMetaData.getColumn(columnIndex), timeZone, 0); + return getDateTime(columnIndex, calendar, BaseType.DATE); } @Override @@ -356,9 +351,7 @@ public Timestamp getTimestamp(String columnLabel) throws SQLException { @Override public Timestamp getTimestamp(int columnIndex, Calendar calendar) throws SQLException { - TimeZone timeZone = calendar != null ? calendar.getTimeZone() : null; - String value = getValueAtColumn(columnIndex); - return BaseType.TIMESTAMP.transform(value, resultSetMetaData.getColumn(columnIndex), timeZone, 0); + return getDateTime(columnIndex, calendar, BaseType.TIMESTAMP); } @Override @@ -368,9 +361,13 @@ public Timestamp getTimestamp(String columnLabel, Calendar calendar) throws SQLE @Override public Time getTime(int columnIndex, Calendar calendar) throws SQLException { + return getDateTime(columnIndex, calendar, BaseType.TIME); + } + + private T getDateTime(int columnIndex, Calendar calendar, BaseType type) throws SQLException { TimeZone timeZone = calendar != null ? calendar.getTimeZone() : null; String value = getValueAtColumn(columnIndex); - return BaseType.TIME.transform(value, resultSetMetaData.getColumn(columnIndex), timeZone, 0); + return type.transform(value, resultSetMetaData.getColumn(columnIndex), timeZone, 0); } @Override From 38312cd81045c67ecb9dbdba9f7ab28041337431 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Thu, 23 May 2024 09:29:04 +0300 Subject: [PATCH 07/52] FIR-33074 implementation of Connection.getClientInfo() (#413) --- .../jdbc/connection/FireboltConnection.java | 14 ++- .../settings/FireboltSessionProperty.java | 106 +++++++++++------- .../connection/FireboltConnectionTest.java | 84 +++++++++----- 3 files changed, 129 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 46586db2f..5445347bb 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -7,6 +7,7 @@ import com.firebolt.jdbc.client.authentication.FireboltAuthenticationClient; import com.firebolt.jdbc.client.query.StatementClientImpl; import com.firebolt.jdbc.connection.settings.FireboltProperties; +import com.firebolt.jdbc.connection.settings.FireboltSessionProperty; import com.firebolt.jdbc.exception.ExceptionType; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.exception.FireboltSQLFeatureNotSupportedException; @@ -54,9 +55,11 @@ import java.util.logging.Logger; import java.util.regex.Pattern; +import static com.firebolt.jdbc.connection.settings.FireboltSessionProperty.getNonDeprecatedProperties; import static java.lang.String.format; import static java.sql.ResultSet.CLOSE_CURSORS_AT_COMMIT; import static java.sql.ResultSet.TYPE_FORWARD_ONLY; +import static java.util.stream.Collectors.toMap; public abstract class FireboltConnection extends JdbcBase implements Connection { @@ -624,24 +627,25 @@ public SQLXML createSQLXML() throws SQLException { } @Override + @NotImplemented public void setClientInfo(String name, String value) throws SQLClientInfoException { // Not supported } @Override - @NotImplemented public String getClientInfo(String name) throws SQLException { - return null; + return Optional.ofNullable(FireboltSessionProperty.byAlias(name.toUpperCase()).getValue(sessionProperties)).map(Object::toString).orElse(null); } @Override - @NotImplemented public Properties getClientInfo() throws SQLException { - return new Properties(); + return getNonDeprecatedProperties().stream() + .filter(key -> key.getValue(sessionProperties) != null) + .collect(toMap(FireboltSessionProperty::getKey, key -> key.getValue(sessionProperties).toString(), (o, t) -> t, Properties::new)); } @Override - @ExcludeFromJacocoGeneratedReport + @NotImplemented public void setClientInfo(Properties properties) throws SQLClientInfoException { // Not supported } diff --git a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltSessionProperty.java b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltSessionProperty.java index 78ca44038..895024665 100644 --- a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltSessionProperty.java +++ b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltSessionProperty.java @@ -1,106 +1,118 @@ package com.firebolt.jdbc.connection.settings; +import lombok.Getter; + import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; -import java.util.Optional; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collector; import java.util.stream.Collectors; +import java.util.stream.Stream; -import lombok.Getter; +import static java.lang.String.CASE_INSENSITIVE_ORDER; +import static java.util.stream.Collectors.toMap; @Getter public enum FireboltSessionProperty { - PATH("path", "", String.class, "Path component of the URI"), - BUFFER_SIZE("buffer_size", 65536, Integer.class, "The buffer used to create the ResultSet in bytes"), - SSL("ssl", true, Boolean.class, "Enable SSL/TLS for the connection"), - SSL_CERTIFICATE_PATH("ssl_certificate_path", "", String.class, "SSL/TLS root certificate", "sslrootcert"), + PATH("path", "", String.class, "Path component of the URI", FireboltProperties::getPath), + BUFFER_SIZE("buffer_size", 65536, Integer.class, "The buffer used to create the ResultSet in bytes", FireboltProperties::getBufferSize), + SSL("ssl", true, Boolean.class, "Enable SSL/TLS for the connection", FireboltProperties::isSsl), + SSL_CERTIFICATE_PATH("ssl_certificate_path", "", String.class, "SSL/TLS root certificate", FireboltProperties::getSslCertificatePath, "sslrootcert"), SSL_MODE("ssl_mode", "strict", String.class, - "SSL mode to verify/not verify the certificate. Supported Types: none (don't verify), strict (verify)", + "SSL mode to verify/not verify the certificate. Supported Types: none (don't verify), strict (verify)", FireboltProperties::getSslMode, "sslmode"), MAX_RETRIES("max_retries", 3, Integer.class, - "Maximum number of retries used by the client to query Firebolt when the response has an invalid status code that is retryable (HTTP_CLIENT_TIMEOUT/408, HTTP_BAD_GATEWAY/502, HTTP_UNAVAILABLE/503 or HTTP_GATEWAY_TIMEOUT/504). Set to 0 to disable "), + "Maximum number of retries used by the client to query Firebolt when the response has an invalid status code that is retryable (HTTP_CLIENT_TIMEOUT/408, HTTP_BAD_GATEWAY/502, HTTP_UNAVAILABLE/503 or HTTP_GATEWAY_TIMEOUT/504). Set to 0 to disable ", FireboltProperties::getMaxRetries), SOCKET_TIMEOUT_MILLIS("socket_timeout_millis", 0, Integer.class, - "maximum time of inactivity between two data packets when exchanging data with the server. A timeout value of zero is interpreted as an infinite timeout. A negative value is interpreted as undefined.", + "maximum time of inactivity between two data packets when exchanging data with the server. A timeout value of zero is interpreted as an infinite timeout. A negative value is interpreted as undefined.", FireboltProperties::getSocketTimeoutMillis, "socket_timeout"), CONNECTION_TIMEOUT_MILLIS("connection_timeout_millis", 60 * 1000, Integer.class, - "Default connect timeout for new connections. A value of 0 means no timeout, otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds", + "Default connect timeout for new connections. A value of 0 means no timeout, otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds", FireboltProperties::getConnectionTimeoutMillis, "connection_timeout"), KEEP_ALIVE_TIMEOUT_MILLIS("connection_keep_alive_timeout_millis", 5 * 60 * 1000, Integer.class, - "How long to keep a connection with the server alive in the pool before closing it.", "keepAliveTimeout"), + "How long to keep a connection with the server alive in the pool before closing it.", FireboltProperties::getKeepAliveTimeoutMillis, "keepAliveTimeout"), MAX_CONNECTIONS_TOTAL("max_connections_total", 300, Integer.class, - "Maximum total connections in the connection pool", "maxTotal"), + "Maximum total connections in the connection pool", FireboltProperties::getMaxConnectionsTotal, "maxTotal"), TCP_KEEP_IDLE("tcp_keep_idle", 60, Integer.class, - "TCP option that defines the number of seconds of idle time before keep-alive initiates a probe. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe after some amount of time."), + "TCP option that defines the number of seconds of idle time before keep-alive initiates a probe. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe after some amount of time.", FireboltProperties::getTcpKeepIdle), TCP_KEEP_COUNT("tcp_keep_count", 10, Integer.class, - "TCP option that defines the maximum number of keep-alive probes to be sent. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe a certain number of times before a connection is considered to be broken."), + "TCP option that defines the maximum number of keep-alive probes to be sent. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe a certain number of times before a connection is considered to be broken.", FireboltProperties::getTcpKeepCount), TCP_KEEP_INTERVAL("tcp_keep_interval", 30, Integer.class, - "TCP option that defines the number of seconds to wait before retransmitting a keep-alive probe. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe after some amount of time."), + "TCP option that defines the number of seconds to wait before retransmitting a keep-alive probe. TCP probes a connection that has been idle for some amount of time. If the remote system does not respond to a keep-alive probe, TCP retransmits the probe after some amount of time.", FireboltProperties::getTcpKeepInterval), COMPRESS( /* * compress should always be used as the HTTP response code is sometimes * incorrect when not using it */ - "compress", true, Boolean.class, "Whether to compress transferred data or not. Compressed by default"), - DATABASE("database", null, String.class, "default database name"), + "compress", true, Boolean.class, "Whether to compress transferred data or not. Compressed by default", FireboltProperties::isCompress), + DATABASE("database", null, String.class, "default database name", FireboltProperties::getDatabase), // Typically client_secret property should be used, but password is the standard JDBC property supported by all tools, so it is silently defined here as alias. Also see CLIENT_ID. - CLIENT_SECRET("client_secret", null, String.class, "client secret - null by default", "password"), + CLIENT_SECRET("client_secret", null, String.class, "client secret - null by default", p -> "****", "password"), // Typically client_id property should be used, but user is the standard JDBC property supported by all tools, so it is silently defined here as alias. Also see CLIENT_SECRET - CLIENT_ID("client_id", null, String.class, "client ID - null by default", "user"), - HOST("host", null, String.class, "Firebolt host - null by default"), - PORT("port", null, Integer.class, "Firebolt port - null by default"), - ENGINE("engine", null, String.class, "engine - null by default", "engine_name"), - ACCOUNT("account", null, String.class, "account - null by default"), - ACCOUNT_ID("account_id", null, String.class, "accountId - null by default"), + CLIENT_ID("client_id", null, String.class, "client ID - null by default", FireboltProperties::getPrincipal, "user"), + HOST("host", null, String.class, "Firebolt host - null by default", FireboltProperties::getHost), + PORT("port", null, Integer.class, "Firebolt port - null by default", FireboltProperties::getPort), + ENGINE("engine", null, String.class, "engine - null by default", FireboltProperties::getEngine, "engine_name"), + ACCOUNT("account", null, String.class, "account - null by default", FireboltProperties::getAccount), + ACCOUNT_ID("account_id", null, String.class, "accountId - null by default", FireboltProperties::getAccountId), LOG_RESULT_SET("log_result_set", false, Boolean.class, - "When set to true, the result of the queries executed are logged with the log level INFO. This has a negative performance impact and should be enabled only for debugging purposes"), - USER_DRIVERS("user_drivers", null, String.class, "user drivers"), - USER_CLIENTS("user_clients", null, String.class, "user clients"), - ACCESS_TOKEN("access_token", null, String.class, "access token"), - ENVIRONMENT("environment", "app", String.class, "Firebolt environment", "env"), + "When set to true, the result of the queries executed are logged with the log level INFO. This has a negative performance impact and should be enabled only for debugging purposes", FireboltProperties::isLogResultSet), + USER_DRIVERS("user_drivers", null, String.class, "user drivers", FireboltProperties::getUserDrivers), + USER_CLIENTS("user_clients", null, String.class, "user clients", FireboltProperties::getUserClients), + ACCESS_TOKEN("access_token", null, String.class, "access token", p -> "***"), + ENVIRONMENT("environment", "app", String.class, "Firebolt environment", FireboltProperties::getEnvironment, "env"), // We keep all the deprecated properties to ensure backward compatibility - but // they do not have any effect. @Deprecated TIME_TO_LIVE_MILLIS("time_to_live_millis", 60 * 1000, Integer.class, - "Maximum life span of connections regardless of their connection_keep_alive_timeout_millis", + "Maximum life span of connections regardless of their connection_keep_alive_timeout_millis", p -> null, "timeToLiveMillis"), @Deprecated - MAX_CONNECTIONS_PER_ROUTE("max_connections_per_route", 500, Integer.class, "Maximum total connections per route", + MAX_CONNECTIONS_PER_ROUTE("max_connections_per_route", 500, Integer.class, "Maximum total connections per route", p -> null, "defaultMaxPerRoute"), @Deprecated USE_PATH_AS_DB("use_path_as_db", null, Boolean.class, - "When set to true (the default) or not specified, the path parameter from the URL is used as the database name"), + "When set to true (the default) or not specified, the path parameter from the URL is used as the database name", p -> null), @Deprecated USE_CONNECTION_POOL("use_connection_pool", true, Boolean.class, - "use connection pool for valid connections. This property is deprecated and setting it has no effect."), + "use connection pool for valid connections. This property is deprecated and setting it has no effect.", p -> null), @Deprecated VALIDATE_AFTER_INACTIVITY_MILLIS("validate_after_inactivity_millis", 3 * 1000, Integer.class, - "Defines period of inactivity in milliseconds after which persistent connections must be re-validated prior to being leased to the consumer. Non-positive value disables connection validation. "), + "Defines period of inactivity in milliseconds after which persistent connections must be re-validated prior to being leased to the consumer. Non-positive value disables connection validation. ", p -> null), @Deprecated CLIENT_BUFFER_SIZE("client_buffer_size", 65536, Integer.class, "The buffer for the Apache client used by the Driver (in bytes). It is the preferred buffer size for the body of the http response. A larger buffer allows more content to be written before anything is actually sent while a smaller buffer decreases server memory load and allows the client to start receiving data quicker.\n" - + "The buffer will be at least as large as the size requested.", + + "The buffer will be at least as large as the size requested.", p -> null, "apache_buffer_size"), @Deprecated AGGRESSIVE_CANCEL("aggressive_cancel", false, Boolean.class, - "enable aggressive cancel. Permits to cancel queries by sending a query to Firebolt rather than calling the /cancel endpoint"); + "enable aggressive cancel. Permits to cancel queries by sending a query to Firebolt rather than calling the /cancel endpoint", p -> null); private final String key; private final Object defaultValue; private final Class clazz; private final String description; + private final Function valueGetter; private final String[] aliases; + private static final Map aliasToProperty = + Arrays.stream(values()).flatMap(FireboltSessionProperty::getAllPropertyMapping).collect(caseInsensitiveMap()); - FireboltSessionProperty(String key, Object defaultValue, Class clazz, String description, String... aliases) { + FireboltSessionProperty(String key, Object defaultValue, Class clazz, String description, Function valueGetter, String... aliases) { this.key = key; this.defaultValue = defaultValue; this.clazz = clazz; this.description = description; + this.valueGetter = valueGetter; this.aliases = aliases != null ? aliases : new String[] {}; } @@ -115,11 +127,27 @@ public static List getNonDeprecatedProperties() { }).collect(Collectors.toList()); } - public static Optional of(String key) { - return Arrays.stream(values()).filter(v -> v.key.equals(key)).findAny(); + public static FireboltSessionProperty byAlias(String keyOrAlias) { + return aliasToProperty.get(keyOrAlias); } public String[] getPossibleValues() { return Boolean.class.equals(clazz) || Boolean.TYPE.equals(clazz) ? new String[] { "true", "false" } : null; } + + public Object getValue(FireboltProperties fireboltProperties) { + return valueGetter.apply(fireboltProperties); + } + + private static Stream getAllAliases(FireboltSessionProperty property) { + return Stream.concat(Stream.of(property.key), Arrays.stream(property.aliases)); + } + + private static Stream> getAllPropertyMapping(FireboltSessionProperty property) { + return getAllAliases(property).map(a -> Map.entry(a, property)); + } + + private static Collector, ?, Map> caseInsensitiveMap() { + return toMap(Entry::getKey, Entry::getValue, (o, t) -> t, () -> new TreeMap<>(CASE_INSENSITIVE_ORDER)); + } } diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index 53a316977..ba305b594 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -137,8 +137,6 @@ private static Stream unsupported() { private static Stream empty() { return Stream.of( - Arguments.of("getClientInfo", (Callable) () -> connection.getClientInfo(), new Properties()), - Arguments.of("getClientInfo(name)", (Callable) () -> connection.getClientInfo("something"), null), Arguments.of("getTypeMap", (Callable) () -> connection.getTypeMap(), Map.of()), Arguments.of("getWarnings", (Callable) () -> connection.getWarnings(), null) ); @@ -502,8 +500,8 @@ void shouldGetConnectionTokenFromProperties(String host, String configuredAccess if (configuredAccessToken != null) { propsWithToken.setProperty(ACCESS_TOKEN.getKey(), configuredAccessToken); } - try (FireboltConnection connection = createConnection(URL, propsWithToken)) { - assertEquals(expectedAccessToken, connection.getAccessToken().orElse(null)); + try (FireboltConnection fireboltConnection = createConnection(URL, propsWithToken)) { + assertEquals(expectedAccessToken, fireboltConnection.getAccessToken().orElse(null)); Mockito.verifyNoMoreInteractions(fireboltAuthenticationService); } } @@ -549,65 +547,65 @@ void shouldUseConnectionTimeoutFromProperties() throws SQLException { @Test void shouldThrowExceptionWhenTryingToUseClosedConnection() throws SQLException { - try (Connection connection = createConnection(URL, connectionProperties)) { - connection.close(); - assertThrows(FireboltException.class, connection::getCatalog); + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + fireboltConnection.close(); + assertThrows(FireboltException.class, fireboltConnection::getCatalog); } } @Test void shouldUnwrapFireboltConnection() throws SQLException { - try (Connection connection = createConnection(URL, connectionProperties)) { - assertTrue(connection.isWrapperFor(FireboltConnection.class)); - assertEquals(connection, connection.unwrap(FireboltConnection.class)); + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + assertTrue(fireboltConnection.isWrapperFor(FireboltConnection.class)); + assertEquals(fireboltConnection, fireboltConnection.unwrap(FireboltConnection.class)); } } @Test void shouldThrowExceptionWhenCannotUnwrap() throws SQLException { - try (Connection connection = createConnection(URL, connectionProperties)) { - assertFalse(connection.isWrapperFor(String.class)); - assertThrows(SQLException.class, () -> connection.unwrap(String.class)); + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + assertFalse(fireboltConnection.isWrapperFor(String.class)); + assertThrows(SQLException.class, () -> fireboltConnection.unwrap(String.class)); } } @Test void shouldGetDatabaseWhenGettingCatalog() throws SQLException { connectionProperties.put("database", "db"); - try (Connection connection = createConnection(URL, connectionProperties)) { - assertEquals("noname", connection.getCatalog()); // retrieved engine's DB's name is "noname". Firebolt treats DB as catalog + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + assertEquals("noname", fireboltConnection.getCatalog()); // retrieved engine's DB's name is "noname". Firebolt treats DB as catalog } } @Test void shouldGetNoneTransactionIsolation() throws SQLException { connectionProperties.put("database", "db"); - try (Connection connection = createConnection(URL, connectionProperties)) { - assertEquals(Connection.TRANSACTION_NONE, connection.getTransactionIsolation()); - connection.setTransactionIsolation(Connection.TRANSACTION_NONE); // should work - assertEquals(Connection.TRANSACTION_NONE, connection.getTransactionIsolation()); + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + assertEquals(Connection.TRANSACTION_NONE, fireboltConnection.getTransactionIsolation()); + fireboltConnection.setTransactionIsolation(Connection.TRANSACTION_NONE); // should work + assertEquals(Connection.TRANSACTION_NONE, fireboltConnection.getTransactionIsolation()); for (int transactionIsolation : new int [] {TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE}) { - assertThrows(SQLFeatureNotSupportedException.class, () -> connection.setTransactionIsolation(transactionIsolation)); + assertThrows(SQLFeatureNotSupportedException.class, () -> fireboltConnection.setTransactionIsolation(transactionIsolation)); } // despite the failed attempts to change transaction isolation to unsupported value it remains TRANSACTION_NONE - assertEquals(Connection.TRANSACTION_NONE, connection.getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_NONE, fireboltConnection.getTransactionIsolation()); } } @Test void shouldThrowExceptionWhenPreparingStatementWIthInvalidResultSetType() throws SQLException { connectionProperties.put("database", "db"); - try (Connection connection = createConnection(URL, connectionProperties)) { + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { assertThrows(SQLFeatureNotSupportedException.class, - () -> connection.prepareStatement("any", TYPE_SCROLL_INSENSITIVE, 0)); + () -> fireboltConnection.prepareStatement("any", TYPE_SCROLL_INSENSITIVE, 0)); } } @Test void createArray() throws SQLException { - try (Connection connection = createConnection(URL, connectionProperties)) { + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { Object[] data = new Object[] {"red", "green", "blue"}; - Array array = connection.createArrayOf("text", data); + Array array = fireboltConnection.createArrayOf("text", data); assertEquals(Types.VARCHAR, array.getBaseType()); assertArrayEquals(data, (Object[])array.getArray()); } @@ -631,23 +629,47 @@ void shouldReturnEmptyResult(String name, Callable function, Object expected) void shouldGetEngineUrlWhenEngineIsProvided() throws SQLException { connectionProperties.put("engine", "engine"); when(fireboltEngineService.getEngine(any())).thenReturn(new Engine("http://my_endpoint", null, null, null, null)); - try (FireboltConnection connection = createConnection(URL, connectionProperties)) { + try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { verify(fireboltEngineService).getEngine(argThat(props -> "engine".equals(props.getEngine()) && "db".equals(props.getDatabase()))); - assertEquals("http://my_endpoint", connection.getSessionProperties().getHost()); + assertEquals("http://my_endpoint", fireboltConnection.getSessionProperties().getHost()); } } @Test void nativeSql() throws SQLException { - try (FireboltConnection connection = createConnection(URL, connectionProperties)) { - assertEquals("SELECT 1", connection.nativeSQL("SELECT 1")); + try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { + assertEquals("SELECT 1", fireboltConnection.nativeSQL("SELECT 1")); } } @Test void unsupportedNativeSql() throws SQLException { - try (FireboltConnection connection = createConnection(URL, connectionProperties)) { - assertThrows(SQLException.class, () -> connection.nativeSQL("SELECT {d '2001-01-01'} FROM TEST")); + try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { + assertThrows(SQLException.class, () -> fireboltConnection.nativeSQL("SELECT {d '2001-01-01'} FROM TEST")); + } + } + + @Test + void getClientInfo() throws SQLException { + try (FireboltConnection fireboltConnection = createConnection(URL, connectionProperties)) { + Properties info = fireboltConnection.getClientInfo(); + // from URL + assertEquals("dev", info.getProperty("environment")); + assertEquals("dev", fireboltConnection.getClientInfo("environment")); // key + assertEquals("dev", fireboltConnection.getClientInfo("env")); // alias + + // from connectionProperties + assertEquals("somebody", info.getProperty("client_id")); + assertEquals("somebody", fireboltConnection.getClientInfo("client_id")); // key + assertEquals("somebody", fireboltConnection.getClientInfo("user")); // alias + + // default value + assertEquals("60", info.getProperty("tcp_keep_idle")); + assertEquals("60", fireboltConnection.getClientInfo("tcp_keep_idle")); + + // deprecated - should not appear + assertFalse(info.containsKey("time_to_live_millis")); + assertNull(fireboltConnection.getClientInfo("time_to_live_millis")); } } From e409bee43efe516e0076b7e5020823c24f669b1b Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Sun, 26 May 2024 15:19:02 +0300 Subject: [PATCH 08/52] FIR-32120: removed redundant throws declarations and fixed some warnings (#415) --- .../java/com/firebolt/FireboltDriver.java | 2 +- .../com/firebolt/jdbc/GenericWrapper.java | 19 + src/main/java/com/firebolt/jdbc/JdbcBase.java | 17 +- .../jdbc/client/account/FireboltAccount.java | 1 + .../metadata/FireboltDatabaseMetadata.java | 905 ++++++++---------- .../jdbc/resultset/FireboltResultSet.java | 29 +- .../resultset/FireboltResultSetMetaData.java | 18 +- .../firebolt/jdbc/statement/ParamMarker.java | 2 +- .../jdbc/statement/StatementUtil.java | 24 +- .../FireboltPreparedStatement.java | 4 +- .../rawstatement/QueryRawStatement.java | 2 +- .../java/com/firebolt/jdbc/type/BaseType.java | 2 +- .../firebolt/jdbc/type/FireboltDataType.java | 2 +- .../type/FireboltDataTypeDisplayNames.java | 1 + .../type/JavaTypeToFireboltSQLString.java | 4 - .../com/firebolt/jdbc/util/LoggerUtil.java | 1 + .../com/firebolt/jdbc/util/VersionUtil.java | 4 +- 17 files changed, 462 insertions(+), 575 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/GenericWrapper.java diff --git a/src/main/java/com/firebolt/FireboltDriver.java b/src/main/java/com/firebolt/FireboltDriver.java index 60e7da25e..d8537117d 100644 --- a/src/main/java/com/firebolt/FireboltDriver.java +++ b/src/main/java/com/firebolt/FireboltDriver.java @@ -15,7 +15,7 @@ public class FireboltDriver implements Driver { public static final String JDBC_FIREBOLT = "jdbc:firebolt:"; - private static Logger rootLog; + private static final Logger rootLog; private static final Logger log; static { diff --git a/src/main/java/com/firebolt/jdbc/GenericWrapper.java b/src/main/java/com/firebolt/jdbc/GenericWrapper.java new file mode 100644 index 000000000..cb2f8059e --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/GenericWrapper.java @@ -0,0 +1,19 @@ +package com.firebolt.jdbc; + +import java.sql.SQLException; +import java.sql.Wrapper; + +public interface GenericWrapper extends Wrapper { + @Override + default T unwrap(@SuppressWarnings("SpellCheckingInspection") Class iface) throws SQLException { + if (iface.isAssignableFrom(getClass())) { + return iface.cast(this); + } + throw new SQLException("Cannot unwrap to " + iface.getName()); + } + + @Override + default boolean isWrapperFor(@SuppressWarnings("SpellCheckingInspection") Class iface) { + return iface.isAssignableFrom(getClass()); + } +} diff --git a/src/main/java/com/firebolt/jdbc/JdbcBase.java b/src/main/java/com/firebolt/jdbc/JdbcBase.java index e12c45417..450f8c455 100644 --- a/src/main/java/com/firebolt/jdbc/JdbcBase.java +++ b/src/main/java/com/firebolt/jdbc/JdbcBase.java @@ -1,25 +1,10 @@ package com.firebolt.jdbc; -import java.sql.SQLException; import java.sql.SQLWarning; -import java.sql.Wrapper; -public class JdbcBase implements Wrapper { +public abstract class JdbcBase implements GenericWrapper { private SQLWarning firstWarning; - @Override - public T unwrap(Class iface) throws SQLException { - if (iface.isAssignableFrom(getClass())) { - return iface.cast(this); - } - throw new SQLException("Cannot unwrap to " + iface.getName()); - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isAssignableFrom(getClass()); - } - public synchronized SQLWarning getWarnings() { return firstWarning; } diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccount.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccount.java index c8d2419bc..3a1750df1 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccount.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccount.java @@ -15,6 +15,7 @@ public FireboltAccount(String id, String region, int infraVersion) { this.infraVersion = infraVersion; } + @SuppressWarnings("unused") // used by FireboltAccountRetriever that in turn calls its base class` method FireboltClient.jsonToObject() that calls this constructor by reflection FireboltAccount(JSONObject json) { this(json.getString("id"), json.getString("region"), json.optInt("infraVersion", 1)); } diff --git a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java index d231fd273..f40348576 100644 --- a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java +++ b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.metadata; +import com.firebolt.jdbc.GenericWrapper; import com.firebolt.jdbc.QueryResult; import com.firebolt.jdbc.annotation.ExcludeFromJacocoGeneratedReport; import com.firebolt.jdbc.annotation.NotImplemented; @@ -20,9 +21,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -149,7 +150,7 @@ import static java.util.stream.Collectors.toList; @SuppressWarnings("java:S6204") // compatibility with JDK 11 -public class FireboltDatabaseMetadata implements DatabaseMetaData { +public class FireboltDatabaseMetadata implements DatabaseMetaData, GenericWrapper { private static final String TABLE = "TABLE"; private static final String VIEW = "VIEW"; @@ -190,24 +191,17 @@ private ResultSet getSchemas(String query) throws SQLException { rows.add(List.of(schemaDescription.getString(TABLE_SCHEM), schemaDescription.getString(TABLE_CATALOG))); } } - return FireboltResultSet.of(QueryResult.builder() - .columns(List.of(QueryResult.Column.builder().name(TABLE_SCHEM).type(TEXT).build(), - QueryResult.Column.builder().name(TABLE_CATALOG).type(TEXT).build())) - .rows(rows).build()); + return createResultSet(Stream.of(entry(TABLE_SCHEM, TEXT), entry(TABLE_CATALOG, TEXT)), rows); } @Override public ResultSet getTableTypes() throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(List.of(QueryResult.Column.builder().name(TABLE_TYPE).type(TEXT).build())) - .rows(List.of(List.of(TABLE), List.of(VIEW))).build()); + return createResultSet(Stream.of(entry(TABLE_TYPE, TEXT)), List.of(List.of(TABLE), List.of(VIEW))); } @Override public ResultSet getCatalogs() throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Collections.singletonList(QueryResult.Column.builder().name(TABLE_CAT).type(TEXT).build())) - .rows(Collections.singletonList(Collections.singletonList(connection.getCatalog()))).build()); + return createResultSet(Stream.of(entry(TABLE_CAT, TEXT)), List.of(List.of(connection.getCatalog()))); } @Override @@ -216,54 +210,28 @@ public Connection getConnection() throws SQLException { } @Override - public String getDatabaseProductName() throws SQLException { + public String getDatabaseProductName() { return "Firebolt"; } @Override - public String getURL() throws SQLException { + public String getURL() { return url; } @Override - public String getDriverName() throws SQLException { + public String getDriverName() { return "Firebolt JDBC Driver"; } @Override - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + public boolean supportsTransactionIsolationLevel(int level) { return level == Connection.TRANSACTION_NONE; } @Override public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { - List columns = Arrays.asList( - QueryResult.Column.builder().name(TABLE_CAT).type(TEXT).build(), - QueryResult.Column.builder().name(TABLE_SCHEM).type(TEXT).build(), - QueryResult.Column.builder().name(TABLE_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(COLUMN_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(TYPE_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(COLUMN_SIZE).type(INTEGER).build(), - QueryResult.Column.builder().name(BUFFER_LENGTH).type(INTEGER).build(), - QueryResult.Column.builder().name(DECIMAL_DIGITS).type(INTEGER).build(), - QueryResult.Column.builder().name(NUM_PREC_RADIX).type(INTEGER).build(), - QueryResult.Column.builder().name(NULLABLE).type(INTEGER).build(), - QueryResult.Column.builder().name(REMARKS).type(TEXT).build(), - QueryResult.Column.builder().name(COLUMN_DEF).type(TEXT).build(), - QueryResult.Column.builder().name(SQL_DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(SQL_DATETIME_SUB).type(INTEGER).build(), - QueryResult.Column.builder().name(CHAR_OCTET_LENGTH).type(INTEGER).build(), - QueryResult.Column.builder().name(ORDINAL_POSITION).type(INTEGER).build(), - QueryResult.Column.builder().name(IS_NULLABLE).type(TEXT).build(), - QueryResult.Column.builder().name(SCOPE_CATALOG).type(TEXT).build(), - QueryResult.Column.builder().name(SCOPE_SCHEMA).type(TEXT).build(), - QueryResult.Column.builder().name(SCOPE_TABLE).type(TEXT).build(), - QueryResult.Column.builder().name(SOURCE_DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(IS_AUTOINCREMENT).type(TEXT).build(), - QueryResult.Column.builder().name(IS_GENERATEDCOLUMN).type(TEXT).build()); - List> rows = new ArrayList<>(); String query = MetadataUtil.getColumnsQuery(schemaPattern, tableNamePattern, columnNamePattern); try (Statement statement = connection.createStatement(); @@ -299,7 +267,33 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa "NO", // IS_AUTOINCREMENT - Not supported "NO")); // IS_GENERATEDCOLUMN - Not supported } - return FireboltResultSet.of(QueryResult.builder().rows(rows).columns(columns).build()); + return createResultSet( + Stream.of( + entry(TABLE_CAT, TEXT), + entry(TABLE_SCHEM, TEXT), + entry(TABLE_NAME, TEXT), + entry(COLUMN_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(TYPE_NAME, TEXT), + entry(COLUMN_SIZE, INTEGER), + entry(BUFFER_LENGTH, INTEGER), + entry(DECIMAL_DIGITS, INTEGER), + entry(NUM_PREC_RADIX, INTEGER), + entry(NULLABLE, INTEGER), + entry(REMARKS, TEXT), + entry(COLUMN_DEF, TEXT), + entry(SQL_DATA_TYPE, INTEGER), + entry(SQL_DATETIME_SUB, INTEGER), + entry(CHAR_OCTET_LENGTH, INTEGER), + entry(ORDINAL_POSITION, INTEGER), + entry(IS_NULLABLE, TEXT), + entry(SCOPE_CATALOG, TEXT), + entry(SCOPE_SCHEMA, TEXT), + entry(SCOPE_TABLE, TEXT), + entry(SOURCE_DATA_TYPE, INTEGER), + entry(IS_AUTOINCREMENT, TEXT), + entry(IS_GENERATEDCOLUMN, TEXT)), + rows); } } @@ -318,10 +312,10 @@ private boolean isColumnNullable(ResultSet columnDescription) throws SQLExceptio @Override public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] typesArr) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of(TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS, TYPE_CAT, TYPE_SCHEM, TYPE_NAME, SELF_REFERENCING_COL_NAME, REF_GENERATION) - .map(name -> QueryResult.Column.builder().name(name).type(TEXT).build()).collect(toList())) - .rows(getTablesData(catalog, schemaPattern, tableNamePattern, typesArr)).build()); + return createResultSet( + Stream.of(TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS, TYPE_CAT, TYPE_SCHEM, TYPE_NAME, SELF_REFERENCING_COL_NAME, REF_GENERATION) + .map(name -> entry(name, TEXT)), + getTablesData(catalog, schemaPattern, tableNamePattern, typesArr)); } private List> getTablesData(String catalog, String schemaPattern, String tableNamePattern, String[] typesArr) throws SQLException { @@ -351,26 +345,6 @@ private List> getTablesData(String catalog, String schemaPattern, String @Override public ResultSet getTypeInfo() throws SQLException { - List columns = Arrays.asList( - QueryResult.Column.builder().name(TYPE_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(PRECISION).type(INTEGER).build(), - QueryResult.Column.builder().name(LITERAL_PREFIX).type(TEXT).build(), - QueryResult.Column.builder().name(LITERAL_SUFFIX).type(TEXT).build(), - QueryResult.Column.builder().name(CREATE_PARAMS).type(TEXT).build(), - QueryResult.Column.builder().name(NULLABLE).type(INTEGER).build(), - QueryResult.Column.builder().name(CASE_SENSITIVE).type(BOOLEAN).build(), - QueryResult.Column.builder().name(SEARCHABLE).type(INTEGER).build(), - QueryResult.Column.builder().name(UNSIGNED_ATTRIBUTE).type(BOOLEAN).build(), - QueryResult.Column.builder().name(FIXED_PREC_SCALE).type(BOOLEAN).build(), - QueryResult.Column.builder().name(AUTO_INCREMENT).type(BOOLEAN).build(), - QueryResult.Column.builder().name(LOCAL_TYPE_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(MINIMUM_SCALE).type(INTEGER).build(), - QueryResult.Column.builder().name(MAXIMUM_SCALE).type(INTEGER).build(), - QueryResult.Column.builder().name(SQL_DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(SQL_DATETIME_SUB).type(INTEGER).build(), - QueryResult.Column.builder().name(NUM_PREC_RADIX).type(INTEGER).build()); - List usableTypes = Arrays.asList(INTEGER, BIG_INT, REAL, DOUBLE_PRECISION, TEXT, DATE, TIMESTAMP, NUMERIC, ARRAY, TUPLE, BYTEA, BOOLEAN); List> rows = usableTypes.stream().map(type -> @@ -398,7 +372,27 @@ public ResultSet getTypeInfo() throws SQLException { COMMON_RADIX)) .collect(toList()); - return FireboltResultSet.of(QueryResult.builder().columns(columns).rows(rows).build()); + return createResultSet( + Stream.of( + entry(TYPE_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(PRECISION, INTEGER), + entry(LITERAL_PREFIX, TEXT), + entry(LITERAL_SUFFIX, TEXT), + entry(CREATE_PARAMS, TEXT), + entry(NULLABLE, INTEGER), + entry(CASE_SENSITIVE, BOOLEAN), + entry(SEARCHABLE, INTEGER), + entry(UNSIGNED_ATTRIBUTE, BOOLEAN), + entry(FIXED_PREC_SCALE, BOOLEAN), + entry(AUTO_INCREMENT, BOOLEAN), + entry(LOCAL_TYPE_NAME, TEXT), + entry(MINIMUM_SCALE, INTEGER), + entry(MAXIMUM_SCALE, INTEGER), + entry(SQL_DATA_TYPE, INTEGER), + entry(SQL_DATETIME_SUB, INTEGER), + entry(NUM_PREC_RADIX, INTEGER)), + rows); } @Override @@ -432,45 +426,32 @@ public int getDatabaseMinorVersion() throws SQLException { } @Override - public int getJDBCMajorVersion() throws SQLException { + public int getJDBCMajorVersion() { return VersionUtil.extractMajorVersion(VersionUtil.getSpecificationVersion()); } @Override - public int getJDBCMinorVersion() throws SQLException { + public int getJDBCMinorVersion() { return VersionUtil.extractMinorVersion(VersionUtil.getSpecificationVersion()); } @Override - public String getDriverVersion() throws SQLException { + public String getDriverVersion() { return VersionUtil.getDriverVersion(); } @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isAssignableFrom(getClass()); - } - - @Override - public T unwrap(Class iface) throws SQLException { - if (isWrapperFor(iface)) { - return iface.cast(this); - } - throw new SQLException("Cannot unwrap to " + iface.getName()); - } - - @Override - public boolean allProceduresAreCallable() throws SQLException { + public boolean allProceduresAreCallable() { return false; } @Override - public boolean allTablesAreSelectable() throws SQLException { + public boolean allTablesAreSelectable() { return true; } @Override - public String getUserName() throws SQLException { + public String getUserName() { return connection.getSessionProperties().getPrincipal(); } @@ -480,77 +461,77 @@ public boolean isReadOnly() throws SQLException { } @Override - public boolean nullsAreSortedHigh() throws SQLException { + public boolean nullsAreSortedHigh() { return false; } @Override - public boolean nullsAreSortedLow() throws SQLException { + public boolean nullsAreSortedLow() { return !nullsAreSortedHigh(); } @Override - public boolean nullsAreSortedAtStart() throws SQLException { + public boolean nullsAreSortedAtStart() { return false; } @Override - public boolean nullsAreSortedAtEnd() throws SQLException { + public boolean nullsAreSortedAtEnd() { return !nullsAreSortedAtStart(); } @Override - public boolean usesLocalFiles() throws SQLException { + public boolean usesLocalFiles() { return false; } @Override - public boolean usesLocalFilePerTable() throws SQLException { + public boolean usesLocalFilePerTable() { return false; } @Override - public boolean supportsMixedCaseIdentifiers() throws SQLException { + public boolean supportsMixedCaseIdentifiers() { return false; } @Override - public boolean storesUpperCaseIdentifiers() throws SQLException { + public boolean storesUpperCaseIdentifiers() { return false; } @Override - public boolean storesLowerCaseIdentifiers() throws SQLException { + public boolean storesLowerCaseIdentifiers() { return true; } @Override - public boolean storesMixedCaseIdentifiers() throws SQLException { + public boolean storesMixedCaseIdentifiers() { return false; } @Override - public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + public boolean supportsMixedCaseQuotedIdentifiers() { return true; } @Override - public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + public boolean storesUpperCaseQuotedIdentifiers() { return false; } @Override - public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + public boolean storesLowerCaseQuotedIdentifiers() { return false; } @Override - public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + public boolean storesMixedCaseQuotedIdentifiers() { return true; } @Override - public String getIdentifierQuoteString() throws SQLException { + public String getIdentifierQuoteString() { return "\""; } @@ -585,102 +566,101 @@ public String getTimeDateFunctions() { } @Override - public String getSearchStringEscape() throws SQLException { + public String getSearchStringEscape() { return "\\"; } /** * Returns empty string for compatibility with PostgreSQL. * @return empty string - * @throws SQLException - if fact does not throw exception because the implementation is trivial */ @Override - public String getExtraNameCharacters() throws SQLException { + public String getExtraNameCharacters() { return ""; } @Override - public boolean supportsAlterTableWithAddColumn() throws SQLException { + public boolean supportsAlterTableWithAddColumn() { return false; } @Override - public boolean supportsAlterTableWithDropColumn() throws SQLException { + public boolean supportsAlterTableWithDropColumn() { return false; } @Override - public boolean supportsColumnAliasing() throws SQLException { + public boolean supportsColumnAliasing() { return true; } @Override - public boolean nullPlusNonNullIsNull() throws SQLException { + public boolean nullPlusNonNullIsNull() { return true; } @Override - public boolean supportsConvert() throws SQLException { + public boolean supportsConvert() { return false; } @Override - public boolean supportsConvert(int fromType, int toType) throws SQLException { + public boolean supportsConvert(int fromType, int toType) { return false; } @Override - public boolean supportsTableCorrelationNames() throws SQLException { + public boolean supportsTableCorrelationNames() { return true; } @Override - public boolean supportsDifferentTableCorrelationNames() throws SQLException { + public boolean supportsDifferentTableCorrelationNames() { return false; } @Override - public boolean supportsExpressionsInOrderBy() throws SQLException { + public boolean supportsExpressionsInOrderBy() { return true; } @Override - public boolean supportsOrderByUnrelated() throws SQLException { + public boolean supportsOrderByUnrelated() { return true; } @Override - public boolean supportsGroupBy() throws SQLException { + public boolean supportsGroupBy() { return true; } @Override - public boolean supportsGroupByUnrelated() throws SQLException { + public boolean supportsGroupByUnrelated() { return false; } @Override - public boolean supportsGroupByBeyondSelect() throws SQLException { + public boolean supportsGroupByBeyondSelect() { return false; } @Override - public boolean supportsLikeEscapeClause() throws SQLException { + public boolean supportsLikeEscapeClause() { return false; } @Override - public boolean supportsMultipleResultSets() throws SQLException { + public boolean supportsMultipleResultSets() { return false; } @Override - public boolean supportsMultipleTransactions() throws SQLException { + public boolean supportsMultipleTransactions() { return false; } @Override - public boolean supportsNonNullableColumns() throws SQLException { + public boolean supportsNonNullableColumns() { return true; } @@ -692,7 +672,7 @@ public boolean supportsNonNullableColumns() throws SQLException { * @throws SQLException - actually never throws */ @Override - public boolean supportsMinimumSQLGrammar() throws SQLException { + public boolean supportsMinimumSQLGrammar() { return true; } @@ -700,363 +680,362 @@ public boolean supportsMinimumSQLGrammar() throws SQLException { * Does this driver support the Core ODBC SQL grammar. We need SQL-92 conformance for this. * * @return false - * @throws SQLException if a database access error occurs */ @Override - public boolean supportsCoreSQLGrammar() throws SQLException { + public boolean supportsCoreSQLGrammar() { return false; } @Override - public boolean supportsExtendedSQLGrammar() throws SQLException { + public boolean supportsExtendedSQLGrammar() { return false; } @Override - public boolean supportsANSI92EntryLevelSQL() throws SQLException { + public boolean supportsANSI92EntryLevelSQL() { // We do not support it (eg: we would need to be compliant with JDBC and support 'schema') return false; } @Override - public boolean supportsANSI92IntermediateSQL() throws SQLException { + public boolean supportsANSI92IntermediateSQL() { return false; } @Override - public boolean supportsANSI92FullSQL() throws SQLException { + public boolean supportsANSI92FullSQL() { return false; } @Override - public boolean supportsIntegrityEnhancementFacility() throws SQLException { + public boolean supportsIntegrityEnhancementFacility() { // Similar approach as pgjdbc: we assume it means supported constraints return false; } @Override - public boolean supportsOuterJoins() throws SQLException { + public boolean supportsOuterJoins() { return true; } @Override - public boolean supportsFullOuterJoins() throws SQLException { + public boolean supportsFullOuterJoins() { return true; } @Override - public boolean supportsLimitedOuterJoins() throws SQLException { + public boolean supportsLimitedOuterJoins() { return true; } @Override - public String getSchemaTerm() throws SQLException { + public String getSchemaTerm() { return "schema"; } @Override - public String getProcedureTerm() throws SQLException { + public String getProcedureTerm() { return "procedure"; } @Override - public String getCatalogTerm() throws SQLException { + public String getCatalogTerm() { return "database"; } @Override - public boolean isCatalogAtStart() throws SQLException { + public boolean isCatalogAtStart() { // it is currently not supported but it will be soon return false; } @Override - public String getCatalogSeparator() throws SQLException { + public String getCatalogSeparator() { return "."; } @Override - public boolean supportsSchemasInDataManipulation() throws SQLException { + public boolean supportsSchemasInDataManipulation() { return false; } @Override - public boolean supportsSchemasInProcedureCalls() throws SQLException { + public boolean supportsSchemasInProcedureCalls() { return false; } @Override - public boolean supportsSchemasInTableDefinitions() throws SQLException { + public boolean supportsSchemasInTableDefinitions() { return false; } @Override - public boolean supportsSchemasInIndexDefinitions() throws SQLException { + public boolean supportsSchemasInIndexDefinitions() { return false; } @Override - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + public boolean supportsSchemasInPrivilegeDefinitions() { return false; } @Override - public boolean supportsCatalogsInDataManipulation() throws SQLException { + public boolean supportsCatalogsInDataManipulation() { return false; } @Override - public boolean supportsCatalogsInProcedureCalls() throws SQLException { + public boolean supportsCatalogsInProcedureCalls() { return false; } @Override - public boolean supportsCatalogsInTableDefinitions() throws SQLException { + public boolean supportsCatalogsInTableDefinitions() { return false; } @Override - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + public boolean supportsCatalogsInIndexDefinitions() { return false; } @Override - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + public boolean supportsCatalogsInPrivilegeDefinitions() { return false; } @Override - public boolean supportsPositionedDelete() throws SQLException { + public boolean supportsPositionedDelete() { return false; } @Override - public boolean supportsPositionedUpdate() throws SQLException { + public boolean supportsPositionedUpdate() { return false; } @Override - public boolean supportsSelectForUpdate() throws SQLException { + public boolean supportsSelectForUpdate() { return false; } @Override - public boolean supportsStoredProcedures() throws SQLException { + public boolean supportsStoredProcedures() { return false; } @Override - public boolean supportsSubqueriesInComparisons() throws SQLException { + public boolean supportsSubqueriesInComparisons() { return true; } @Override - public boolean supportsSubqueriesInExists() throws SQLException { + public boolean supportsSubqueriesInExists() { return true; } @Override - public boolean supportsSubqueriesInIns() throws SQLException { + public boolean supportsSubqueriesInIns() { return true; } @Override - public boolean supportsSubqueriesInQuantifieds() throws SQLException { + public boolean supportsSubqueriesInQuantifieds() { return false; } @Override - public boolean supportsCorrelatedSubqueries() throws SQLException { + public boolean supportsCorrelatedSubqueries() { return true; } @Override - public boolean supportsUnion() throws SQLException { + public boolean supportsUnion() { return true; } @Override - public boolean supportsUnionAll() throws SQLException { + public boolean supportsUnionAll() { return true; } @Override - public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + public boolean supportsOpenCursorsAcrossCommit() { return false; } @Override - public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + public boolean supportsOpenCursorsAcrossRollback() { return false; } @Override - public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + public boolean supportsOpenStatementsAcrossCommit() { return false; } @Override - public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + public boolean supportsOpenStatementsAcrossRollback() { return false; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxBinaryLiteralLength() throws SQLException { + public int getMaxBinaryLiteralLength() { return MAX_LITERAL_LENGTH; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxCharLiteralLength() throws SQLException { + public int getMaxCharLiteralLength() { return MAX_LITERAL_LENGTH; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxColumnNameLength() throws SQLException { + public int getMaxColumnNameLength() { return MAX_IDENTIFIER_LENGTH; } @Override - public int getMaxColumnsInGroupBy() throws SQLException { + public int getMaxColumnsInGroupBy() { return 0x10000; //65536 } /** * Indexes are not supported, so the value is irrelevant. * @return 0 - * @throws SQLException never thrown */ - public int getMaxColumnsInIndex() throws SQLException { + public int getMaxColumnsInIndex() { return 0; } @Override - public int getMaxColumnsInOrderBy() throws SQLException { + public int getMaxColumnsInOrderBy() { return 16384; } @Override - public int getMaxColumnsInSelect() throws SQLException { + public int getMaxColumnsInSelect() { return 8192; } @Override - public int getMaxColumnsInTable() throws SQLException { + public int getMaxColumnsInTable() { return 1000; } @Override - public int getMaxConnections() throws SQLException { + public int getMaxConnections() { return 0; } @Override - public int getMaxCursorNameLength() throws SQLException { + public int getMaxCursorNameLength() { return 0; } @Override - public int getMaxIndexLength() throws SQLException { + public int getMaxIndexLength() { return 0; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxSchemaNameLength() throws SQLException { + public int getMaxSchemaNameLength() { return MAX_IDENTIFIER_LENGTH; } @Override - public int getMaxProcedureNameLength() throws SQLException { + public int getMaxProcedureNameLength() { return 0; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxCatalogNameLength() throws SQLException { + public int getMaxCatalogNameLength() { return MAX_IDENTIFIER_LENGTH; } @Override @ExcludeFromJacocoGeneratedReport @NotImplemented - public int getMaxRowSize() throws SQLException { + public int getMaxRowSize() { return 0; } @Override @ExcludeFromJacocoGeneratedReport - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + public boolean doesMaxRowSizeIncludeBlobs() { return false; } @Override @ExcludeFromJacocoGeneratedReport @NotImplemented - public int getMaxStatementLength() throws SQLException { + public int getMaxStatementLength() { return 0; } @Override - public int getMaxStatements() throws SQLException { + public int getMaxStatements() { return 0; } @Override @SuppressWarnings("java:S4144") // identical implementation - public int getMaxTableNameLength() throws SQLException { + public int getMaxTableNameLength() { return MAX_IDENTIFIER_LENGTH; } @Override - public int getMaxTablesInSelect() throws SQLException { + public int getMaxTablesInSelect() { return 0; } @Override - public int getMaxUserNameLength() throws SQLException { + @SuppressWarnings("java:S4144") // identical implementation + public int getMaxUserNameLength() { return MAX_IDENTIFIER_LENGTH; } @Override - public int getDefaultTransactionIsolation() throws SQLException { + public int getDefaultTransactionIsolation() { return Connection.TRANSACTION_NONE; } @Override - public boolean supportsTransactions() throws SQLException { + public boolean supportsTransactions() { return false; } @Override - public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + public boolean supportsDataDefinitionAndDataManipulationTransactions() { return false; } @Override - public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + public boolean supportsDataManipulationTransactionsOnly() { return false; } @Override - public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + public boolean dataDefinitionCausesTransactionCommit() { return false; } @Override - public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + public boolean dataDefinitionIgnoredInTransactions() { return false; } @Override - public boolean supportsResultSetType(int type) throws SQLException { + public boolean supportsResultSetType(int type) { return TYPE_FORWARD_ONLY == type; } @Override - public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + public boolean supportsResultSetConcurrency(int type, int concurrency) { return type == ResultSet.TYPE_FORWARD_ONLY && concurrency == ResultSet.CONCUR_READ_ONLY; } @@ -1065,79 +1044,79 @@ public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQ * since we do not support updating ResultSet objects */ @Override - public boolean ownUpdatesAreVisible(int type) throws SQLException { + public boolean ownUpdatesAreVisible(int type) { return false; } @Override - public boolean ownDeletesAreVisible(int type) throws SQLException { + public boolean ownDeletesAreVisible(int type) { return false; } @Override - public boolean ownInsertsAreVisible(int type) throws SQLException { + public boolean ownInsertsAreVisible(int type) { return false; } @Override - public boolean othersUpdatesAreVisible(int type) throws SQLException { + public boolean othersUpdatesAreVisible(int type) { return false; } @Override - public boolean othersDeletesAreVisible(int type) throws SQLException { + public boolean othersDeletesAreVisible(int type) { return false; } @Override - public boolean othersInsertsAreVisible(int type) throws SQLException { + public boolean othersInsertsAreVisible(int type) { return false; } @Override - public boolean updatesAreDetected(int type) throws SQLException { + public boolean updatesAreDetected(int type) { return false; } @Override - public boolean deletesAreDetected(int type) throws SQLException { + public boolean deletesAreDetected(int type) { return false; } @Override - public boolean insertsAreDetected(int type) throws SQLException { + public boolean insertsAreDetected(int type) { return false; } @Override - public boolean supportsBatchUpdates() throws SQLException { + public boolean supportsBatchUpdates() { // We support it partially (via FireboltPreparedStatement but not with the // 'basic' FireboltStatement ) return false; } @Override - public boolean supportsSavepoints() throws SQLException { + public boolean supportsSavepoints() { return false; } @Override - public boolean supportsNamedParameters() throws SQLException { + public boolean supportsNamedParameters() { return false; } @Override - public boolean supportsMultipleOpenResults() throws SQLException { + public boolean supportsMultipleOpenResults() { return false; } @Override - public boolean supportsGetGeneratedKeys() throws SQLException { + public boolean supportsGetGeneratedKeys() { return false; } @Override - public boolean supportsResultSetHoldability(int holdability) throws SQLException { + public boolean supportsResultSetHoldability(int holdability) { return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT; } @@ -1145,174 +1124,144 @@ public boolean supportsResultSetHoldability(int holdability) throws SQLException * Since Firebolt does not support transactions commit does not affect the existing {@code ResultSet} and therefore * it behaves as if it is held between transaction. Therefore, it returns {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} * @return {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} - * @throws SQLException if something is going wrong */ @Override - public int getResultSetHoldability() throws SQLException { + public int getResultSetHoldability() { return ResultSet.HOLD_CURSORS_OVER_COMMIT; } @Override - public int getSQLStateType() throws SQLException { + public int getSQLStateType() { return sqlStateSQL; } @Override - public boolean locatorsUpdateCopy() throws SQLException { + public boolean locatorsUpdateCopy() { return false; } @Override - public boolean supportsStatementPooling() throws SQLException { + public boolean supportsStatementPooling() { return false; } @Override - public RowIdLifetime getRowIdLifetime() throws SQLException { + public RowIdLifetime getRowIdLifetime() { return RowIdLifetime.ROWID_UNSUPPORTED; } @Override - public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + public boolean supportsStoredFunctionsUsingCallSyntax() { return false; } @Override - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + public boolean autoCommitFailureClosesAllResultSets() { return false; } @Override public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(PROCEDURE_CAT, TEXT), - entry(PROCEDURE_SCHEM, TEXT), - entry(PROCEDURE_NAME, TEXT), - entry(COLUMN_NAME, TEXT), - entry(COLUMN_TYPE, INTEGER), // Short - entry(DATA_TYPE, INTEGER), - entry(TYPE_NAME, TEXT), - entry(PRECISION, INTEGER), - entry(LENGTH, INTEGER), - entry(SCALE, INTEGER), // short - entry(RADIX, INTEGER), // short - entry(NULLABLE, INTEGER), // short - entry(REMARKS, TEXT), - entry(COLUMN_DEF, TEXT), - entry(SQL_DATA_TYPE, INTEGER), - entry(SQL_DATETIME_SUB, INTEGER), - entry(CHAR_OCTET_LENGTH, INTEGER), - entry(ORDINAL_POSITION, INTEGER), - entry(IS_NULLABLE, TEXT), - entry(SPECIFIC_NAME, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(PROCEDURE_CAT, TEXT), + entry(PROCEDURE_SCHEM, TEXT), + entry(PROCEDURE_NAME, TEXT), + entry(COLUMN_NAME, TEXT), + entry(COLUMN_TYPE, INTEGER), // Short + entry(DATA_TYPE, INTEGER), + entry(TYPE_NAME, TEXT), + entry(PRECISION, INTEGER), + entry(LENGTH, INTEGER), + entry(SCALE, INTEGER), // short + entry(RADIX, INTEGER), // short + entry(NULLABLE, INTEGER), // short + entry(REMARKS, TEXT), + entry(COLUMN_DEF, TEXT), + entry(SQL_DATA_TYPE, INTEGER), + entry(SQL_DATETIME_SUB, INTEGER), + entry(CHAR_OCTET_LENGTH, INTEGER), + entry(ORDINAL_POSITION, INTEGER), + entry(IS_NULLABLE, TEXT), + entry(SPECIFIC_NAME, TEXT) + )); } @Override public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TYPE_CAT, TEXT), - entry(TYPE_SCHEM, TEXT), - entry(TYPE_NAME, TEXT), - entry(CLASS_NAME, TEXT), - entry(DATA_TYPE, INTEGER), - entry(REMARKS, TEXT), - entry(BASE_TYPE, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TYPE_CAT, TEXT), + entry(TYPE_SCHEM, TEXT), + entry(TYPE_NAME, TEXT), + entry(CLASS_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(REMARKS, TEXT), + entry(BASE_TYPE, INTEGER) // short + )); } @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TYPE_CAT, TEXT), - entry(TYPE_SCHEM, TEXT), - entry(TYPE_NAME, TEXT), - entry(SUPERTYPE_CAT, TEXT), - entry(SUPERTYPE_SCHEM, TEXT), - entry(SUPERTYPE_NAME, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TYPE_CAT, TEXT), + entry(TYPE_SCHEM, TEXT), + entry(TYPE_NAME, TEXT), + entry(SUPERTYPE_CAT, TEXT), + entry(SUPERTYPE_SCHEM, TEXT), + entry(SUPERTYPE_NAME, TEXT) + )); } @Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TYPE_CAT, TEXT), - entry(TYPE_SCHEM, TEXT), - entry(TYPE_NAME, TEXT), - entry(SUPERTABLE_NAME, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TYPE_CAT, TEXT), + entry(TYPE_SCHEM, TEXT), + entry(TYPE_NAME, TEXT), + entry(SUPERTABLE_NAME, TEXT) + )); } @Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TYPE_CAT, TEXT), - entry(TYPE_SCHEM, TEXT), - entry(TYPE_NAME, TEXT), - entry(ATTR_NAME, TEXT), - entry(DATA_TYPE, INTEGER), - entry(ATTR_TYPE_NAME, TEXT), - entry(ATTR_SIZE, INTEGER), - entry(DECIMAL_DIGITS, INTEGER), - entry(NUM_PREC_RADIX, INTEGER), - entry(NULLABLE, INTEGER), - entry(REMARKS, TEXT), - entry(ATTR_DEF, TEXT), - entry(SQL_DATA_TYPE, INTEGER), - entry(SQL_DATETIME_SUB, INTEGER), - entry(CHAR_OCTET_LENGTH, INTEGER), - entry(ORDINAL_POSITION, INTEGER), - entry(IS_NULLABLE, TEXT), - entry(SCOPE_CATALOG, TEXT), - entry(SCOPE_SCHEMA, TEXT), - entry(SCOPE_TABLE, TEXT), - entry(SOURCE_DATA_TYPE, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TYPE_CAT, TEXT), + entry(TYPE_SCHEM, TEXT), + entry(TYPE_NAME, TEXT), + entry(ATTR_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(ATTR_TYPE_NAME, TEXT), + entry(ATTR_SIZE, INTEGER), + entry(DECIMAL_DIGITS, INTEGER), + entry(NUM_PREC_RADIX, INTEGER), + entry(NULLABLE, INTEGER), + entry(REMARKS, TEXT), + entry(ATTR_DEF, TEXT), + entry(SQL_DATA_TYPE, INTEGER), + entry(SQL_DATETIME_SUB, INTEGER), + entry(CHAR_OCTET_LENGTH, INTEGER), + entry(ORDINAL_POSITION, INTEGER), + entry(IS_NULLABLE, TEXT), + entry(SCOPE_CATALOG, TEXT), + entry(SCOPE_SCHEMA, TEXT), + entry(SCOPE_TABLE, TEXT), + entry(SOURCE_DATA_TYPE, INTEGER) // short + )); } @Override public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(PROCEDURE_CAT, TEXT), - entry(PROCEDURE_SCHEM, TEXT), - entry(PROCEDURE_NAME, TEXT), - entry(REMARKS, TEXT), - entry(PROCEDURE_TYPE, INTEGER), // short - entry(SPECIFIC_NAME, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(PROCEDURE_CAT, TEXT), + entry(PROCEDURE_SCHEM, TEXT), + entry(PROCEDURE_NAME, TEXT), + entry(REMARKS, TEXT), + entry(PROCEDURE_TYPE, INTEGER), // short + entry(SPECIFIC_NAME, TEXT) + )); } @Override public ResultSet getColumnPrivileges(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { - List columns = Stream.of( - entry(TABLE_CAT, TEXT), - entry(TABLE_SCHEM, TEXT), - entry(TABLE_NAME, TEXT), - entry(COLUMN_NAME, TEXT), - entry(GRANTOR, TEXT), - entry(GRANTEE, TEXT), - entry(PRIVILEGE, TEXT), - entry(IS_GRANTABLE, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList()); - List> rows = new ArrayList<>(); String query = MetadataUtil.getColumnsQuery(schemaPattern, tableNamePattern, columnNamePattern); try (Statement statement = connection.createStatement(); @@ -1328,21 +1277,20 @@ public ResultSet getColumnPrivileges(String catalog, String schemaPattern, Strin "NO")); // is_grantable } } - return FireboltResultSet.of(QueryResult.builder().columns(columns).rows(rows).build()); - } - - @Override - public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - List columns = Stream.of( + return createResultSet(Stream.of( entry(TABLE_CAT, TEXT), entry(TABLE_SCHEM, TEXT), entry(TABLE_NAME, TEXT), + entry(COLUMN_NAME, TEXT), entry(GRANTOR, TEXT), entry(GRANTEE, TEXT), entry(PRIVILEGE, TEXT), entry(IS_GRANTABLE, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList()); + ), rows); + } + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { List> rows = new ArrayList<>(); String query = MetadataUtil.getTablesQuery(catalog, schemaPattern, tableNamePattern, new String[] {"BASE TABLE", "DIMENSION", "FACT"}); try (Statement statement = connection.createStatement(); @@ -1357,172 +1305,122 @@ public ResultSet getTablePrivileges(String catalog, String schemaPattern, String "NO")); // is_grantable } } - return FireboltResultSet.of(QueryResult.builder().columns(columns).rows(rows).build()); + return createResultSet(Stream.of( + entry(TABLE_CAT, TEXT), + entry(TABLE_SCHEM, TEXT), + entry(TABLE_NAME, TEXT), + entry(GRANTOR, TEXT), + entry(GRANTEE, TEXT), + entry(PRIVILEGE, TEXT), + entry(IS_GRANTABLE, TEXT) + ), rows); } @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(SCOPE, INTEGER), // short - entry(COLUMN_NAME, TEXT), - entry(DATA_TYPE, INTEGER), - entry(TYPE_NAME, TEXT), - entry(COLUMN_SIZE, INTEGER), - entry(BUFFER_LENGTH, INTEGER), - entry(DECIMAL_DIGITS, INTEGER), // short - entry(PSEUDO_COLUMN, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(SCOPE, INTEGER), // short + entry(COLUMN_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(TYPE_NAME, TEXT), + entry(COLUMN_SIZE, INTEGER), + entry(BUFFER_LENGTH, INTEGER), + entry(DECIMAL_DIGITS, INTEGER), // short + entry(PSEUDO_COLUMN, INTEGER) // short + )); } @Override public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(SCOPE, INTEGER), // short - entry(COLUMN_NAME, TEXT), - entry(DATA_TYPE, INTEGER), - entry(TYPE_NAME, TEXT), - entry(COLUMN_SIZE, INTEGER), - entry(BUFFER_LENGTH, INTEGER), - entry(DECIMAL_DIGITS, INTEGER), // short - entry(PSEUDO_COLUMN, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(SCOPE, INTEGER), // short + entry(COLUMN_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(TYPE_NAME, TEXT), + entry(COLUMN_SIZE, INTEGER), + entry(BUFFER_LENGTH, INTEGER), + entry(DECIMAL_DIGITS, INTEGER), // short + entry(PSEUDO_COLUMN, INTEGER) // short + )); } @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TABLE_CAT, TEXT), - entry(TABLE_SCHEM, TEXT), - entry(TABLE_NAME, TEXT), - entry(COLUMN_NAME, TEXT), - entry(KEY_SEQ, INTEGER), // short - entry(PK_NAME, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TABLE_CAT, TEXT), + entry(TABLE_SCHEM, TEXT), + entry(TABLE_NAME, TEXT), + entry(COLUMN_NAME, TEXT), + entry(KEY_SEQ, INTEGER), // short + entry(PK_NAME, TEXT) + )); } @Override public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(PKTABLE_CAT, TEXT), - entry(PKTABLE_SCHEM, TEXT), - entry(PKTABLE_NAME, TEXT), - entry(PKCOLUMN_NAME, TEXT), - entry(FKTABLE_CAT, TEXT), - entry(FKTABLE_SCHEM, TEXT), - entry(FKTABLE_NAME, TEXT), - entry(FKCOLUMN_NAME, TEXT), - entry(KEY_SEQ, INTEGER), // short - entry(UPDATE_RULE, INTEGER), // short - entry(DELETE_RULE, INTEGER), // short - entry(FK_NAME, TEXT), - entry(PK_NAME, TEXT), - entry(DEFERRABILITY, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return getKeys(); } @Override public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(PKTABLE_CAT, TEXT), - entry(PKTABLE_SCHEM, TEXT), - entry(PKTABLE_NAME, TEXT), - entry(PKCOLUMN_NAME, TEXT), - entry(FKTABLE_CAT, TEXT), - entry(FKTABLE_SCHEM, TEXT), - entry(FKTABLE_NAME, TEXT), - entry(FKCOLUMN_NAME, TEXT), - entry(KEY_SEQ, INTEGER), // short - entry(UPDATE_RULE, INTEGER), // short - entry(DELETE_RULE, INTEGER), // short - entry(FK_NAME, TEXT), - entry(PK_NAME, TEXT), - entry(DEFERRABILITY, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return getKeys(); } - @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(PKTABLE_CAT, TEXT), - entry(PKTABLE_SCHEM, TEXT), - entry(PKTABLE_NAME, TEXT), - entry(PKCOLUMN_NAME, TEXT), - entry(FKTABLE_CAT, TEXT), - entry(FKTABLE_SCHEM, TEXT), - entry(FKTABLE_NAME, TEXT), - entry(FKCOLUMN_NAME, TEXT), - entry(KEY_SEQ, INTEGER), // short - entry(UPDATE_RULE, INTEGER), // short - entry(DELETE_RULE, INTEGER), // short - entry(FK_NAME, TEXT), - entry(PK_NAME, TEXT), - entry(DEFERRABILITY, INTEGER) // short - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return getKeys(); + } + + private ResultSet getKeys() throws SQLException { + return createEmptyResultSet(Stream.of( + entry(PKTABLE_CAT, TEXT), + entry(PKTABLE_SCHEM, TEXT), + entry(PKTABLE_NAME, TEXT), + entry(PKCOLUMN_NAME, TEXT), + entry(FKTABLE_CAT, TEXT), + entry(FKTABLE_SCHEM, TEXT), + entry(FKTABLE_NAME, TEXT), + entry(FKCOLUMN_NAME, TEXT), + entry(KEY_SEQ, INTEGER), // short + entry(UPDATE_RULE, INTEGER), // short + entry(DELETE_RULE, INTEGER), // short + entry(FK_NAME, TEXT), + entry(PK_NAME, TEXT), + entry(DEFERRABILITY, INTEGER) // short + )); } @Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TABLE_CAT, TEXT), - entry(TABLE_SCHEM, TEXT), - entry(TABLE_NAME, TEXT), - entry(NON_UNIQUE, BOOLEAN), - entry(INDEX_QUALIFIER, TEXT), - entry(INDEX_NAME, TEXT), - entry(TYPE, INTEGER), // short - entry(ORDINAL_POSITION, INTEGER), // short - entry(COLUMN_NAME, TEXT), - entry(ASC_OR_DESC, TEXT), - entry(CARDINALITY, BIG_INT), // long - entry(PAGES, BIG_INT), // long - entry(FILTER_CONDITION, INTEGER) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TABLE_CAT, TEXT), + entry(TABLE_SCHEM, TEXT), + entry(TABLE_NAME, TEXT), + entry(NON_UNIQUE, BOOLEAN), + entry(INDEX_QUALIFIER, TEXT), + entry(INDEX_NAME, TEXT), + entry(TYPE, INTEGER), // short + entry(ORDINAL_POSITION, INTEGER), // short + entry(COLUMN_NAME, TEXT), + entry(ASC_OR_DESC, TEXT), + entry(CARDINALITY, BIG_INT), // long + entry(PAGES, BIG_INT), // long + entry(FILTER_CONDITION, INTEGER) + )); } @Override public ResultSet getClientInfoProperties() throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(NAME, TEXT), - entry(MAX_LEN, INTEGER), - entry(DEFAULT_VALUE, TEXT), - entry(DESCRIPTION, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(NAME, TEXT), + entry(MAX_LEN, INTEGER), + entry(DEFAULT_VALUE, TEXT), + entry(DESCRIPTION, TEXT) + )); } @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { - List columns = Arrays.asList( - QueryResult.Column.builder().name(FUNCTION_CAT).type(TEXT).build(), - QueryResult.Column.builder().name(FUNCTION_SCHEM).type(TEXT).build(), - QueryResult.Column.builder().name(FUNCTION_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(REMARKS).type(TEXT).build(), - QueryResult.Column.builder().name(FUNCTION_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(SPECIFIC_NAME).type(TEXT).build()); Predicate functionFilter = functionNamePattern == null ? f -> true : compile(functionNamePattern, CASE_INSENSITIVE).asPredicate(); List> rows = Arrays.stream(String.join(",", getStringFunctions(), getNumericFunctions(), getTimeDateFunctions(), getSystemFunctions()).split(",")) @@ -1532,31 +1430,17 @@ public ResultSet getFunctions(String catalog, String schemaPattern, String funct .distinct() // some functions belong to different categories, e.g. TO_DATE is both date-time and string function .map(function -> Arrays.asList(null, null, function, null, functionNoTable, function)) .collect(toList()); - return FireboltResultSet.of(QueryResult.builder().columns(columns).rows(rows).build()); + return createResultSet(Stream.of( + entry(FUNCTION_CAT, TEXT), + entry(FUNCTION_SCHEM, TEXT), + entry(FUNCTION_NAME, TEXT), + entry(REMARKS, TEXT), + entry(FUNCTION_TYPE, INTEGER), + entry(SPECIFIC_NAME, TEXT)), rows); } @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { - - List columns = Arrays.asList( - QueryResult.Column.builder().name(FUNCTION_CAT).type(TEXT).build(), - QueryResult.Column.builder().name(FUNCTION_SCHEM).type(TEXT).build(), - QueryResult.Column.builder().name(FUNCTION_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(COLUMN_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(COLUMN_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(DATA_TYPE).type(INTEGER).build(), - QueryResult.Column.builder().name(TYPE_NAME).type(TEXT).build(), - QueryResult.Column.builder().name(PRECISION).type(INTEGER).build(), - QueryResult.Column.builder().name(LENGTH).type(INTEGER).build(), - QueryResult.Column.builder().name(SCALE).type(INTEGER).build(), - QueryResult.Column.builder().name(RADIX).type(INTEGER).build(), - QueryResult.Column.builder().name(NULLABLE).type(INTEGER).build(), - QueryResult.Column.builder().name(REMARKS).type(TEXT).build(), - QueryResult.Column.builder().name(CHAR_OCTET_LENGTH).type(INTEGER).build(), - QueryResult.Column.builder().name(ORDINAL_POSITION).type(INTEGER).build(), - QueryResult.Column.builder().name(IS_NULLABLE).type(TEXT).build(), - QueryResult.Column.builder().name(SPECIFIC_NAME).type(TEXT).build() - ); Predicate functionFilter = functionNamePattern == null ? f -> true : compile(functionNamePattern, CASE_INSENSITIVE).asPredicate(); List> stringFunctions = Arrays.stream(String.join(",", getStringFunctions()).split(",")).map(String::trim).filter(functionFilter) @@ -1592,31 +1476,56 @@ public ResultSet getFunctionColumns(String catalog, String schemaPattern, String }; List> allFunctions = Stream.of(stringFunctions, numericFunctions, timeDateFunctions, systemFunctions).flatMap(Collection::stream).sorted(comparator).collect(toList()); - return FireboltResultSet.of(QueryResult.builder().columns(columns).rows(allFunctions).build()); + return createResultSet(Stream.of( + entry(FUNCTION_CAT, TEXT), + entry(FUNCTION_SCHEM, TEXT), + entry(FUNCTION_NAME, TEXT), + entry(COLUMN_NAME, TEXT), + entry(COLUMN_TYPE, INTEGER), + entry(DATA_TYPE, INTEGER), + entry(TYPE_NAME, TEXT), + entry(PRECISION, INTEGER), + entry(LENGTH, INTEGER), + entry(SCALE, INTEGER), + entry(RADIX, INTEGER), + entry(NULLABLE, INTEGER), + entry(REMARKS, TEXT), + entry(CHAR_OCTET_LENGTH, INTEGER), + entry(ORDINAL_POSITION, INTEGER), + entry(IS_NULLABLE, TEXT), + entry(SPECIFIC_NAME, TEXT)), allFunctions); } @Override public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { - return FireboltResultSet.of(QueryResult.builder() - .columns(Stream.of( - entry(TABLE_CAT, TEXT), - entry(TABLE_SCHEM, TEXT), - entry(TABLE_NAME, TEXT), - entry(COLUMN_NAME, TEXT), - entry(DATA_TYPE, INTEGER), - entry(COLUMN_SIZE, INTEGER), - entry(DECIMAL_DIGITS, INTEGER), - entry(NUM_PREC_RADIX, INTEGER), - entry(COLUMN_USAGE, TEXT), - entry(REMARKS, TEXT), - entry(CHAR_OCTET_LENGTH, INTEGER), - entry(IS_NULLABLE, TEXT) - ).map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) - .rows(List.of()) - .build()); + return createEmptyResultSet(Stream.of( + entry(TABLE_CAT, TEXT), + entry(TABLE_SCHEM, TEXT), + entry(TABLE_NAME, TEXT), + entry(COLUMN_NAME, TEXT), + entry(DATA_TYPE, INTEGER), + entry(COLUMN_SIZE, INTEGER), + entry(DECIMAL_DIGITS, INTEGER), + entry(NUM_PREC_RADIX, INTEGER), + entry(COLUMN_USAGE, TEXT), + entry(REMARKS, TEXT), + entry(CHAR_OCTET_LENGTH, INTEGER), + entry(IS_NULLABLE, TEXT) + )); } @Override - public boolean generatedKeyAlwaysReturned() throws SQLException { + public boolean generatedKeyAlwaysReturned() { return false; } + + private ResultSet createEmptyResultSet(Stream> columns) throws SQLException { + return createResultSet(columns, List.of()); + } + + private ResultSet createResultSet(Stream> columns, List> rows) throws SQLException { + return FireboltResultSet.of(QueryResult.builder() + .columns(columns.map(e -> QueryResult.Column.builder().name(e.getKey()).type(e.getValue()).build()).collect(toList())) + .rows(rows) + .build()); + } } diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index ece748fc0..3077f6808 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -444,10 +444,11 @@ public boolean isBeforeFirst() throws SQLException { } @Override - public boolean isAfterLast() throws SQLException { + public boolean isAfterLast() { return !hasNext() && currentLine == null; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean hasNext() { return reader.lines().iterator().hasNext(); } @@ -459,7 +460,7 @@ public boolean isFirst() throws SQLException { } @Override - public boolean isLast() throws SQLException { + public boolean isLast() { return !hasNext() && currentLine != null; } @@ -542,19 +543,6 @@ public int findColumn(String columnName) throws SQLException { return index; } - @Override - public boolean isWrapperFor(Class iface) { - return iface.isAssignableFrom(getClass()); - } - - @Override - public T unwrap(Class iface) throws SQLException { - if (iface.isAssignableFrom(getClass())) { - return iface.cast(this); - } - throw new SQLException("Cannot unwrap to " + iface.getName()); - } - @Override public InputStream getAsciiStream(int columnIndex) throws SQLException { return getTextStream(columnIndex, StandardCharsets.US_ASCII); @@ -632,7 +620,7 @@ public boolean previous() throws SQLException { } @Override - public int getFetchDirection() throws SQLException { + public int getFetchDirection() { return ResultSet.FETCH_FORWARD; } @@ -644,7 +632,8 @@ public void setFetchDirection(int direction) throws SQLException { } @Override - public int getFetchSize() throws SQLException { + @SuppressWarnings("SpellCheckingInspection") + public int getFetchSize() { return 0; // fetch size is not supported; 0 means unlimited like in PostgreSQL and MySQL } @@ -658,7 +647,7 @@ public void setFetchSize(int rows) throws SQLException { } @Override - public int getConcurrency() throws SQLException { + public int getConcurrency() { return ResultSet.CONCUR_READ_ONLY; } @@ -957,7 +946,7 @@ public void moveToCurrentRow() throws SQLException { } @Override - public Statement getStatement() throws SQLException { + public Statement getStatement() { return statement; } @@ -1104,7 +1093,7 @@ public void updateRowId(String columnLabel, RowId x) throws SQLException { } @Override - public int getHoldability() throws SQLException { + public int getHoldability() { return ResultSet.HOLD_CURSORS_OVER_COMMIT; } diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSetMetaData.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSetMetaData.java index 64a95df5f..ae7449ea1 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSetMetaData.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSetMetaData.java @@ -1,6 +1,6 @@ package com.firebolt.jdbc.resultset; -import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.GenericWrapper; import com.firebolt.jdbc.resultset.column.Column; import java.sql.ResultSetMetaData; @@ -11,7 +11,7 @@ import static java.lang.String.format; @SuppressWarnings("java:S4144") // Methods should not have identical implementations - many methods here have trivial identical implementation -public class FireboltResultSetMetaData implements ResultSetMetaData { +public class FireboltResultSetMetaData implements ResultSetMetaData, GenericWrapper { private final String dbName; private final String tableName; private final List columns; @@ -89,20 +89,6 @@ Column getColumn(int column) throws SQLException { return columns.get(column - 1); } - @Override - @SuppressWarnings("unchecked") - public T unwrap(Class interfaceName) throws SQLException { - if (isWrapperFor(interfaceName)) { - return (T) this; - } - throw new FireboltException("Unable unwrap to " + interfaceName); - } - - @Override - public boolean isWrapperFor(Class interfaceName) throws SQLException { - return interfaceName != null && interfaceName.isAssignableFrom(getClass()); - } - @Override public boolean isCaseSensitive(int column) throws SQLException { return getColumn(column).getType().getDataType().isCaseSensitive(); diff --git a/src/main/java/com/firebolt/jdbc/statement/ParamMarker.java b/src/main/java/com/firebolt/jdbc/statement/ParamMarker.java index 93b011a3a..f3063583c 100644 --- a/src/main/java/com/firebolt/jdbc/statement/ParamMarker.java +++ b/src/main/java/com/firebolt/jdbc/statement/ParamMarker.java @@ -6,6 +6,6 @@ @AllArgsConstructor @Value public class ParamMarker { - int id; // Id / index of the param marker in the SQL statement + int id; // ID / index of the param marker in the SQL statement int position; // Position in the SQL subStatement } \ No newline at end of file diff --git a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java index fca7e8bee..256dfc1e3 100644 --- a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java +++ b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java @@ -67,7 +67,7 @@ public List parseToStatementInfoWrappers(String sql) { /** * Parse sql statement to a {@link RawStatementWrapper}. The method construct * the {@link RawStatementWrapper} by splitting it in a list of sub-statements - * (supports multistatements) + * (supports multi-statements) * * @param sql the sql statement * @return a list of {@link StatementInfoWrapper} @@ -88,7 +88,7 @@ public RawStatementWrapper parseToRawStatementWrapper(String sql) { boolean isInSingleLineComment = false; boolean isInMultipleLinesComment = false; boolean isInComment = false; - boolean foundSubqueryEndingSemicolon = false; + boolean foundSubQueryEndingSemicolon = false; char previousChar; int subQueryParamsCount = 0; boolean isPreviousCharInComment; @@ -103,16 +103,16 @@ public RawStatementWrapper parseToRawStatementWrapper(String sql) { isInComment = isInSingleLineComment || isInMultipleLinesComment; if (!isInComment) { // Although the ending semicolon may have been found, we need to include any - // potential comments to the subquery + // potential comments to the sub-query if (!isCurrentSubstringBetweenQuotes && isEndingSemicolon(currentChar, previousChar, - foundSubqueryEndingSemicolon, isPreviousCharInComment)) { - foundSubqueryEndingSemicolon = true; - if (isEndOfSubquery(currentChar)) { + foundSubQueryEndingSemicolon, isPreviousCharInComment)) { + foundSubQueryEndingSemicolon = true; + if (isEndOfSubQuery(currentChar)) { subStatements.add(RawStatement.of(sql.substring(subQueryStart, currentIndex), subStatementParamMarkersPositions, cleanedSubQuery.toString().trim())); subStatementParamMarkersPositions = new ArrayList<>(); subQueryStart = currentIndex; - foundSubqueryEndingSemicolon = false; + foundSubQueryEndingSemicolon = false; cleanedSubQuery = new StringBuilder(); } } else if (currentChar == '?' && !isCurrentSubstringBetweenQuotes @@ -134,15 +134,15 @@ public RawStatementWrapper parseToRawStatementWrapper(String sql) { return new RawStatementWrapper(subStatements); } - private boolean isEndingSemicolon(char currentChar, char previousChar, boolean foundSubqueryEndingSemicolon, + private boolean isEndingSemicolon(char currentChar, char previousChar, boolean foundSubQueryEndingSemicolon, boolean isPreviousCharInComment) { - if (foundSubqueryEndingSemicolon) { + if (foundSubQueryEndingSemicolon) { return true; } return (';' == previousChar && currentChar != ';' && !isPreviousCharInComment); } - private boolean isEndOfSubquery(char currentChar) { + private boolean isEndOfSubQuery(char currentChar) { return currentChar != '-' && currentChar != '/' && currentChar != ' ' && currentChar != '\n'; } @@ -226,14 +226,14 @@ public static List replaceParameterMarksWithValues(@NonNul public List replaceParameterMarksWithValues(@NonNull Map params, @NonNull RawStatementWrapper rawStatement) { List subQueries = new ArrayList<>(); - for (int subqueryIndex = 0; subqueryIndex < rawStatement.getSubStatements().size(); subqueryIndex++) { + for (int subQueryIndex = 0; subQueryIndex < rawStatement.getSubStatements().size(); subQueryIndex++) { int currentPos; /* * As the parameter markers are being placed then the statement sql keeps * getting bigger, which is why we need to keep track of the offset */ int offset = 0; - RawStatement subQuery = rawStatement.getSubStatements().get(subqueryIndex); + RawStatement subQuery = rawStatement.getSubStatements().get(subQueryIndex); String subQueryWithParams = subQuery.getSql(); if (params.size() != rawStatement.getTotalParams()) { diff --git a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java index aa5911fe5..e7f20b89b 100644 --- a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java @@ -188,7 +188,7 @@ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { } @Override - public void clearParameters() throws SQLException { + public void clearParameters() { providedParameters.clear(); rows.clear(); } @@ -221,7 +221,7 @@ public boolean execute() throws SQLException { } @Override - public void addBatch() throws SQLException { + public void addBatch() { rows.add(providedParameters); providedParameters = new HashMap<>(); } diff --git a/src/main/java/com/firebolt/jdbc/statement/rawstatement/QueryRawStatement.java b/src/main/java/com/firebolt/jdbc/statement/rawstatement/QueryRawStatement.java index 5ca71042a..2456edb3a 100644 --- a/src/main/java/com/firebolt/jdbc/statement/rawstatement/QueryRawStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/rawstatement/QueryRawStatement.java @@ -14,7 +14,7 @@ /** * A query statement is a statement that returns data (Typically starts with - * SELECT, SHOW, etc) + * SELECT, SHOW, etc.) */ @Getter @EqualsAndHashCode(callSuper = true) diff --git a/src/main/java/com/firebolt/jdbc/type/BaseType.java b/src/main/java/com/firebolt/jdbc/type/BaseType.java index 9bd68af54..b46c2b09d 100644 --- a/src/main/java/com/firebolt/jdbc/type/BaseType.java +++ b/src/main/java/com/firebolt/jdbc/type/BaseType.java @@ -26,7 +26,7 @@ import static com.firebolt.jdbc.type.array.SqlArrayUtil.BYTE_ARRAY_PREFIX; import static com.firebolt.jdbc.type.array.SqlArrayUtil.hexStringToByteArray; -/** This class contains the java types the Firebolt datatypes are mapped to */ +/** This class contains the java types the Firebolt data types are mapped to */ public enum BaseType { LONG(TypePredicate.mayBeFloatingNumber, Long.class, conversion -> Long.parseLong(checkInfinity(conversion.getValue())), conversion -> Double.valueOf(conversion.getValue()).longValue()), INTEGER(TypePredicate.mayBeFloatingNumber, Integer.class, conversion -> Integer.parseInt(checkInfinity(conversion.getValue())), conversion -> Integer.parseInt(Long.toString(Double.valueOf(conversion.getValue()).longValue()))), diff --git a/src/main/java/com/firebolt/jdbc/type/FireboltDataType.java b/src/main/java/com/firebolt/jdbc/type/FireboltDataType.java index f2d4b36df..e1a9b6307 100644 --- a/src/main/java/com/firebolt/jdbc/type/FireboltDataType.java +++ b/src/main/java/com/firebolt/jdbc/type/FireboltDataType.java @@ -34,7 +34,7 @@ public enum FireboltDataType { DATE_32(Types.DATE, FireboltDataTypeDisplayNames.PGDATE, BaseType.DATE, false, false, 10, 0, 0, true,"Date32", "PGDate"), DATE_TIME_64(Types.TIMESTAMP, FireboltDataTypeDisplayNames.TIMESTAMP, BaseType.TIMESTAMP, false, false, 19, 0, 6, true, "DateTime64", "TIMESTAMP"), TIMESTAMP(Types.TIMESTAMP, FireboltDataTypeDisplayNames.TIMESTAMP, BaseType.TIMESTAMP, false, false, 6, 0, 0, true,"DateTime", "TIMESTAMP", "TimestampNtz"), - TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE, FireboltDataTypeDisplayNames.TIMESTAMPTZ, BaseType.TIMESTAMP_WITH_TIMEZONE, false, false, 6, 0, 0, true,"Timestamptz"), + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE, FireboltDataTypeDisplayNames.TIMESTAMPTZ, BaseType.TIMESTAMP_WITH_TIMEZONE, false, false, 6, 0, 0, true,"TimestampTz"), NOTHING(Types.NULL, FireboltDataTypeDisplayNames.NULL, BaseType.NULL, false, false, 0, 0, 0, false,"Nothing", "NULL"), UNKNOWN(Types.OTHER, FireboltDataTypeDisplayNames.UNKNOWN, BaseType.OTHER, false, false, 0, 0, 0, false,"Unknown"), NUMERIC(Types.NUMERIC, FireboltDataTypeDisplayNames.NUMERIC, BaseType.NUMERIC, true, false, 38, 0, 37, false, "Decimal", "DEC", "NUMERIC"), diff --git a/src/main/java/com/firebolt/jdbc/type/FireboltDataTypeDisplayNames.java b/src/main/java/com/firebolt/jdbc/type/FireboltDataTypeDisplayNames.java index c063c5f54..a404d02bd 100644 --- a/src/main/java/com/firebolt/jdbc/type/FireboltDataTypeDisplayNames.java +++ b/src/main/java/com/firebolt/jdbc/type/FireboltDataTypeDisplayNames.java @@ -2,6 +2,7 @@ import lombok.experimental.UtilityClass; +@SuppressWarnings("SpellCheckingInspection") @UtilityClass public class FireboltDataTypeDisplayNames { static final String INTEGER = "integer"; diff --git a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java index 0eb54c568..2229f622a 100644 --- a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java +++ b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java @@ -143,10 +143,6 @@ private static CheckedFunction getSQLStringValueOfString() { }; } - public Class getSourceType() { - return sourceType; - } - public String transform(Object object, Object ... more) throws SQLException { if (object == null) { return NULL_VALUE; diff --git a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java index 54b8979ca..3aea5e03b 100644 --- a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java @@ -43,6 +43,7 @@ public static Logger getRootLogger() { * @return a copy of the {@link InputStream} provided */ public InputStream logInputStream(InputStream is) { + @SuppressWarnings("SpellCheckingInspection") // BAOS means byte array output stream ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024]; diff --git a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java index 5e9b1c979..dbf9fc04d 100644 --- a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java @@ -69,8 +69,8 @@ private static void retrieveVersionInfo() throws IOException { if (retrieveVersionInfoFromManifest(VersionUtil.class.getResourceAsStream("/META-INF/MANIFEST.MF"))) { return; } - for(Enumeration eurl = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF"); eurl.hasMoreElements();) { - try (InputStream in = eurl.nextElement().openStream()) { + for(Enumeration eUrl = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF"); eUrl.hasMoreElements();) { + try (InputStream in = eUrl.nextElement().openStream()) { if (retrieveVersionInfoFromManifest(in)) { return; } From e2d8fd0950a1b87550edba0b85de5535f870250a Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Mon, 27 May 2024 15:01:14 +0300 Subject: [PATCH 09/52] =?UTF-8?q?FIR-33270:=20implemented=20execute=20and?= =?UTF-8?q?=20executeUpdate=20with=20column=20indexes=20=E2=80=A6=20(#416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...reboltSQLFeatureNotSupportedException.java | 4 +++ .../jdbc/statement/FireboltStatement.java | 29 +++++++++------ .../jdbc/statement/FireboltStatementTest.java | 35 +++++++++++++++---- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/exception/FireboltSQLFeatureNotSupportedException.java b/src/main/java/com/firebolt/jdbc/exception/FireboltSQLFeatureNotSupportedException.java index 994681926..66b61f0b5 100644 --- a/src/main/java/com/firebolt/jdbc/exception/FireboltSQLFeatureNotSupportedException.java +++ b/src/main/java/com/firebolt/jdbc/exception/FireboltSQLFeatureNotSupportedException.java @@ -10,4 +10,8 @@ public FireboltSQLFeatureNotSupportedException() { super(String.format(FEATURE_NOT_SUPPORTED, Thread.currentThread().getStackTrace()[2].getMethodName(), Thread.currentThread().getStackTrace()[2].getLineNumber())); } + + public FireboltSQLFeatureNotSupportedException(String message) { + super(message); + } } diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index 7af1f96db..cfd544a5b 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -454,15 +454,19 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException } @Override - @NotImplemented public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + if (columnIndexes == null || columnIndexes.length == 0) { + return executeUpdate(sql); + } + throw new FireboltSQLFeatureNotSupportedException("Returning autogenerated keys by column index is not supported."); } @Override - @NotImplemented public int executeUpdate(String sql, String[] columnNames) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + if (columnNames == null || columnNames.length == 0) { + return executeUpdate(sql); + } + throw new FireboltSQLFeatureNotSupportedException("Returning autogenerated keys by column name is not supported."); } @Override @@ -474,26 +478,29 @@ public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { } @Override - @NotImplemented public boolean execute(String sql, int[] columnIndexes) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + if (columnIndexes == null || columnIndexes.length == 0) { + return execute(sql); + } + throw new FireboltSQLFeatureNotSupportedException("Returning autogenerated keys by column index is not supported."); } @Override - @NotImplemented public boolean execute(String sql, String[] columnNames) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + if (columnNames == null || columnNames.length == 0) { + return execute(sql); + } + throw new FireboltSQLFeatureNotSupportedException("Returning autogenerated keys by column name is not supported."); } @Override - @NotImplemented - public int getResultSetHoldability() throws SQLException { + public int getResultSetHoldability() { // N/A applicable as we do not support transactions => commits do not affect anything => kind of hold cursors over commit return ResultSet.HOLD_CURSORS_OVER_COMMIT; } @Override - public boolean isPoolable() throws SQLException { + public boolean isPoolable() { return false; } diff --git a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java index 4a23ef853..0c8d366ea 100644 --- a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java @@ -85,12 +85,12 @@ private static Stream unsupported() { return Stream.of( Arguments.of("setCursorName", (Executable) () -> statement.setCursorName("my_cursor")), Arguments.of("getGeneratedKeys", (Executable) () -> statement.getGeneratedKeys()), - Arguments.of("executeUpdate(auto generated keys)", (Executable) () -> statement.executeUpdate("insert", Statement.RETURN_GENERATED_KEYS)), - Arguments.of("executeUpdate(column indexes)", (Executable) () -> statement.executeUpdate("insert", new int[0])), - Arguments.of("executeUpdate(column names)", (Executable) () -> statement.executeUpdate("insert", new String[0])), + Arguments.of("executeUpdate(column indexes)", (Executable) () -> statement.executeUpdate("insert", new int[] {1})), + Arguments.of("executeUpdate(column names)", (Executable) () -> statement.executeUpdate("insert", new String[] {"foo"})), + Arguments.of("execute(auto generated keys)", (Executable) () -> statement.execute("insert", Statement.RETURN_GENERATED_KEYS)), + Arguments.of("execute(column indexes)", (Executable) () -> statement.execute("insert", new int[] {1})), + Arguments.of("execute(column names)", (Executable) () -> statement.execute("insert", new String[] {"foo"})), Arguments.of("execute(auto generated keys)", (Executable) () -> statement.execute("insert", Statement.RETURN_GENERATED_KEYS)), - Arguments.of("execute(column indexes)", (Executable) () -> statement.execute("insert", new int[0])), - Arguments.of("execute(column names)", (Executable) () -> statement.execute("insert", new String[0])), Arguments.of("setPoolable(true)", (Executable) () -> statement.setPoolable(true)) ); } @@ -156,7 +156,17 @@ void shouldExecuteIfUpdateStatementWouldNotReturnAResultSet() throws SQLExceptio @Test void shouldExecuteIfUpdateStatementWouldNotReturnAResultSetNoGeneratedKeys() throws SQLException { - shouldExecuteIfUpdateStatementWouldNotReturnAResultSet((statement, sql) -> statement.executeUpdate(sql, Statement.NO_GENERATED_KEYS)); + shouldExecuteIfUpdateStatementWouldNotReturnAResultSet((fireboltStatement, sql) -> fireboltStatement.executeUpdate(sql, Statement.NO_GENERATED_KEYS)); + } + + @Test + void shouldExecuteIfUpdateStatementWithIndexesWouldNotReturnAResultSet() throws SQLException { + shouldExecuteIfUpdateStatementWouldNotReturnAResultSet((fireboltStatement, sql) -> fireboltStatement.executeUpdate(sql, new int[0])); + } + + @Test + void shouldExecuteIfUpdateStatementWithNamesWouldNotReturnAResultSet() throws SQLException { + shouldExecuteIfUpdateStatementWouldNotReturnAResultSet((fireboltStatement, sql) -> fireboltStatement.executeUpdate(sql, new String[0])); } private void shouldExecuteIfUpdateStatementWouldNotReturnAResultSet(CheckedBiFunction executor) throws SQLException { @@ -177,9 +187,20 @@ void shouldExecuteStatementThatReturnsResultSet() throws SQLException { @Test void shouldExecuteStatementNoGeneratedKeysThatReturnsResultSet() throws SQLException { - shouldExecuteStatementThatReturnsResultSet((statement, sql) -> statement.execute(sql, Statement.NO_GENERATED_KEYS)); + shouldExecuteStatementThatReturnsResultSet((fireboltStatement, sql) -> fireboltStatement.execute(sql, Statement.NO_GENERATED_KEYS)); } + @Test + void shouldExecuteStatementWithIndexesWouldNotReturnAResultSet() throws SQLException { + shouldExecuteStatementThatReturnsResultSet((fireboltStatement, sql) -> fireboltStatement.execute(sql, new int[0])); + } + + @Test + void shouldExecuteStatementWithNamesWouldNotReturnAResultSet() throws SQLException { + shouldExecuteStatementThatReturnsResultSet((fireboltStatement, sql) -> fireboltStatement.execute(sql, new String[0])); + } + + private void shouldExecuteStatementThatReturnsResultSet(CheckedBiFunction executor) throws SQLException { ResultSet rs = mock(FireboltResultSet.class); FireboltConnection connection = mock(FireboltConnection.class); From 1cd9cf44e10e2effeae1accc9997d831dcb32c6a Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 28 May 2024 13:29:39 +0300 Subject: [PATCH 10/52] =?UTF-8?q?Fixed=20expected=20exception=20in=20tests?= =?UTF-8?q?=20that=20validate=20wrong=20special=20numeric=E2=80=A6=20(#418?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/integration/tests/SpecialValuesTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/integrationTest/java/integration/tests/SpecialValuesTest.java b/src/integrationTest/java/integration/tests/SpecialValuesTest.java index 3411a8cd3..589c42bf9 100644 --- a/src/integrationTest/java/integration/tests/SpecialValuesTest.java +++ b/src/integrationTest/java/integration/tests/SpecialValuesTest.java @@ -190,9 +190,9 @@ void nanDoubleUserEngine(String query) throws SQLException { private void specialSelect(Connection connection, String query, Number floatGetObjectValue, Number doubleGetObjectValue, Number expectedGetObjectValue) throws SQLException { try (Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query)) { resultSet.next(); - assertThrows(IllegalArgumentException.class, () -> resultSet.getShort(1)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getInt(1)); - assertThrows(IllegalArgumentException.class, () -> resultSet.getLong(1)); + assertThrows(SQLException.class, () -> resultSet.getShort(1)); + assertThrows(SQLException.class, () -> resultSet.getInt(1)); + assertThrows(SQLException.class, () -> resultSet.getLong(1)); assertEquals(floatGetObjectValue, resultSet.getFloat(1)); assertEquals(doubleGetObjectValue, resultSet.getDouble(1)); assertEquals(expectedGetObjectValue, resultSet.getObject(1)); From cc48926f22e733e37e664ae5708ff91b37e405ea Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 28 May 2024 16:26:41 +0300 Subject: [PATCH 11/52] FIR-33118: implemented blob and clob (#414) --- .../tests/PreparedStatementTest.java | 24 +- .../jdbc/connection/FireboltConnection.java | 17 +- .../jdbc/resultset/FireboltResultSet.java | 17 +- .../firebolt/jdbc/type/lob/FireboltBlob.java | 83 +++++++ .../firebolt/jdbc/type/lob/FireboltClob.java | 101 +++++++++ .../firebolt/jdbc/type/lob/FireboltLob.java | 148 ++++++++++++ .../connection/FireboltConnectionTest.java | 26 ++- .../FireboltPreparedStatementTest.java | 17 +- .../jdbc/type/lob/FireboltBlobTest.java | 192 ++++++++++++++++ .../jdbc/type/lob/FireboltClobTest.java | 211 ++++++++++++++++++ .../jdbc/type/lob/FireboltLobTest.java | 79 +++++++ 11 files changed, 873 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/type/lob/FireboltBlob.java create mode 100644 src/main/java/com/firebolt/jdbc/type/lob/FireboltClob.java create mode 100644 src/main/java/com/firebolt/jdbc/type/lob/FireboltLob.java create mode 100644 src/test/java/com/firebolt/jdbc/type/lob/FireboltBlobTest.java create mode 100644 src/test/java/com/firebolt/jdbc/type/lob/FireboltClobTest.java create mode 100644 src/test/java/com/firebolt/jdbc/type/lob/FireboltLobTest.java diff --git a/src/integrationTest/java/integration/tests/PreparedStatementTest.java b/src/integrationTest/java/integration/tests/PreparedStatementTest.java index 306335dc8..44eed8c61 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementTest.java @@ -18,14 +18,14 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import javax.sql.rowset.serial.SerialBlob; -import javax.sql.rowset.serial.SerialClob; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; import java.net.MalformedURLException; import java.net.URL; +import java.sql.Blob; +import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; @@ -279,12 +279,12 @@ void shouldInsertAndSelectBlobClob() throws SQLException, IOException { try (PreparedStatement statement = connection .prepareStatement("INSERT INTO prepared_statement_test (sales, make, signature) VALUES (?,?,?)")) { statement.setLong(1, car1.getSales()); - statement.setClob(2, new SerialClob(car1.getMake().toCharArray())); - statement.setBlob(3, new SerialBlob(car1.getSignature())); + statement.setClob(2, clob(connection, car1.getMake())); + statement.setBlob(3, blob(connection, car1.getSignature())); statement.addBatch(); statement.setLong(1, car2.getSales()); - statement.setClob(2, new SerialClob(car2.getMake().toCharArray())); - statement.setBlob(3, new SerialBlob(car2.getSignature())); + statement.setClob(2, clob(connection, car2.getMake())); + statement.setBlob(3, blob(connection, car2.getSignature())); statement.addBatch(); int[] result = statement.executeBatch(); assertArrayEquals(new int[] { SUCCESS_NO_INFO, SUCCESS_NO_INFO }, result); @@ -305,6 +305,18 @@ void shouldInsertAndSelectBlobClob() throws SQLException, IOException { } } + private Blob blob(Connection connection, byte[] bytes) throws SQLException { + Blob blob = connection.createBlob(); + blob.setBytes(1, bytes); + return blob; + } + + private Clob clob(Connection connection, String text) throws SQLException { + Clob clob = connection.createClob(); + clob.setString(1, text); + return clob; + } + @Test void shouldInsertAndSelectStreams() throws SQLException, IOException { Car car1 = Car.builder().make("Ford").sales(12345).signature("Henry Ford".getBytes()).build(); diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 5445347bb..95165979c 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -19,6 +19,8 @@ import com.firebolt.jdbc.statement.preparedstatement.FireboltPreparedStatement; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; +import com.firebolt.jdbc.type.lob.FireboltBlob; +import com.firebolt.jdbc.type.lob.FireboltClob; import com.firebolt.jdbc.util.PropertyUtil; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -603,21 +605,18 @@ public CallableStatement prepareCall(String sql, int resultSetType, int resultSe } @Override - @NotImplemented - public Clob createClob() throws SQLException { - throw new SQLFeatureNotSupportedException(); + public Clob createClob() { + return new FireboltClob(); } @Override - @NotImplemented - public Blob createBlob() throws SQLException { - throw new SQLFeatureNotSupportedException(); + public Blob createBlob() { + return new FireboltBlob(); } @Override - @NotImplemented - public NClob createNClob() throws SQLException { - throw new SQLFeatureNotSupportedException(); + public NClob createNClob() { + return new FireboltClob(); } @Override diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index 3077f6808..324df5beb 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -15,11 +15,11 @@ import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; import com.firebolt.jdbc.type.array.SqlArrayUtil; +import com.firebolt.jdbc.type.lob.FireboltBlob; +import com.firebolt.jdbc.type.lob.FireboltClob; import com.firebolt.jdbc.util.LoggerUtil; import org.apache.commons.text.StringEscapeUtils; -import javax.sql.rowset.serial.SerialBlob; -import javax.sql.rowset.serial.SerialClob; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -966,14 +966,12 @@ public Ref getRef(int columnIndex) throws SQLException { @Override public Blob getBlob(int columnIndex) throws SQLException { - byte[] bytes = getBytes(columnIndex); - return bytes == null ? null : new SerialBlob(bytes); + return Optional.ofNullable(getBytes(columnIndex)).map(FireboltBlob::new).orElse(null); } @Override public Clob getClob(int columnIndex) throws SQLException { - String str = getString(columnIndex); - return str == null ? null : new SerialClob(str.toCharArray()); + return Optional.ofNullable(getString(columnIndex)).map(String::toCharArray).map(FireboltClob::new).orElse(null); } @Override @@ -1124,12 +1122,7 @@ public void updateNClob(String columnLabel, NClob nClob) throws SQLException { @Override public NClob getNClob(int columnIndex) throws SQLException { String str = getString(columnIndex); - class FireboltNClob extends SerialClob implements NClob { - public FireboltNClob(char[] ch) throws SQLException { - super(ch); - } - } - return str == null ? null : new FireboltNClob(str.toCharArray()); + return str == null ? null : new FireboltClob(str.toCharArray()); } @Override diff --git a/src/main/java/com/firebolt/jdbc/type/lob/FireboltBlob.java b/src/main/java/com/firebolt/jdbc/type/lob/FireboltBlob.java new file mode 100644 index 000000000..83b27524f --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/type/lob/FireboltBlob.java @@ -0,0 +1,83 @@ +package com.firebolt.jdbc.type.lob; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.sql.Blob; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.LinkedList; + +public class FireboltBlob extends FireboltLob implements Blob { + public FireboltBlob() { + this(new byte[0]); + } + + public FireboltBlob(byte[] buf) { + super(buf, (a, i) -> a[i], Integer::byteValue, n -> (byte[])Array.newInstance(byte.class, n)); + } + + @Override + public byte[] getBytes(long pos, int length) throws SQLException { + isValid(buf); + validateGetRange(pos, length, buf.length); + int from = (int)pos - 1; + byte[] bytes = new byte[length]; + System.arraycopy(buf, from, bytes, 0, bytes.length); + return bytes; + } + + @Override + public InputStream getBinaryStream() throws SQLException { + isValid(buf); + return new ByteArrayInputStream(buf); + } + + @Override + public long position(byte[] pattern, long start) throws SQLException { + return super.position(pattern, start); + } + + @Override + public long position(Blob pattern, long start) throws SQLException { + return position(pattern.getBytes(1, (int)(pattern.length())), start); + } + + @Override + public int setBytes(long pos, byte[] bytes) throws SQLException { + return setBytes(pos, bytes, 0, bytes.length); + } + + @Override + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { + return setData(pos, bytes, offset, len); + } + + @Override + public OutputStream setBinaryStream(long pos) throws SQLException { + return setStream(pos, new LinkedList<>()); + } + + @Override + public void truncate(long length) throws SQLException { + isValid(buf); + buf = length == 0 ? new byte[0] : getBytes(1, (int)length); + } + + @Override + public InputStream getBinaryStream(long pos, long length) throws SQLException { + return new ByteArrayInputStream(getBytes(pos, (int)length)); + } + + @Override + @SuppressWarnings("java:S6201") // Pattern Matching for "instanceof" was introduced in java 16 while we still try to be compliant with java 11 + public boolean equals(Object obj) { + return this == obj || (obj instanceof FireboltBlob && Arrays.equals(buf, ((FireboltBlob)obj).buf)); + } + + @Override + public int hashCode() { + return 31 * FireboltBlob.class.hashCode() + Arrays.hashCode(buf); + } +} diff --git a/src/main/java/com/firebolt/jdbc/type/lob/FireboltClob.java b/src/main/java/com/firebolt/jdbc/type/lob/FireboltClob.java new file mode 100644 index 000000000..c310afc21 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/type/lob/FireboltClob.java @@ -0,0 +1,101 @@ +package com.firebolt.jdbc.type.lob; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import java.lang.reflect.Array; +import java.sql.Clob; +import java.sql.NClob; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.LinkedList; + +public class FireboltClob extends FireboltLob implements NClob { + public FireboltClob() { + this(new char[0]); + } + + public FireboltClob(char[] buf) { + super(buf, (a, i) -> a[i], i -> (char)i.intValue(), n -> (char[])Array.newInstance(char.class, n)); + } + + @Override + public String getSubString(long pos, int length) throws SQLException { + isValid(buf); + validateGetRange(pos, length, buf.length); + int from = (int)(pos - 1); + return new String(buf, from, Math.min(buf.length - from, length)); + } + + @Override + public Reader getCharacterStream() throws SQLException { + isValid(buf); + return new StringReader(new String(buf)); + } + + @Override + public InputStream getAsciiStream() throws SQLException { + isValid(buf); + return new ByteArrayInputStream(new String(buf).getBytes()); + } + + @Override + public long position(String searchStr, long start) throws SQLException { + return position(searchStr.toCharArray(), start); + } + + @Override + public long position(Clob searchStr, long start) throws SQLException { + return position(searchStr.getSubString(1, (int)searchStr.length()), start); + } + + @Override + public int setString(long pos, String str) throws SQLException { + return setString(pos, str, 0, str.length()); + } + + @Override + public int setString(long pos, String str, int offset, int len) throws SQLException { + return setChars(pos, str.toCharArray(), offset, len); + } + + private int setChars(long pos, char[] chars, int offset, int len) throws SQLException { + return setData(pos, chars, offset, len); + } + + @Override + public OutputStream setAsciiStream(long pos) throws SQLException { + return setStream(pos, new LinkedList<>()); + } + + @Override + public Writer setCharacterStream(long pos) throws SQLException { + return new OutputStreamWriter(setAsciiStream(pos)); + } + + @Override + public void truncate(long length) throws SQLException { + isValid(buf); + buf = length == 0 ? new char[0] : getSubString(1, (int)length).toCharArray(); + } + + @Override + public Reader getCharacterStream(long pos, long length) throws SQLException { + return new StringReader(getSubString(pos, (int)length)); + } + + @Override + @SuppressWarnings("java:S6201") // Pattern Matching for "instanceof" was introduced in java 16 while we still try to be compliant with java 11 + public boolean equals(Object obj) { + return this == obj || (obj instanceof FireboltClob && Arrays.equals(buf, ((FireboltClob)obj).buf)); + } + + @Override + public int hashCode() { + return 31 * FireboltClob.class.hashCode() + Arrays.hashCode(buf); + } +} diff --git a/src/main/java/com/firebolt/jdbc/type/lob/FireboltLob.java b/src/main/java/com/firebolt/jdbc/type/lob/FireboltLob.java new file mode 100644 index 000000000..7df29a0e3 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/type/lob/FireboltLob.java @@ -0,0 +1,148 @@ +package com.firebolt.jdbc.type.lob; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.sql.SQLException; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Base class for implementations of Blob and Clob. It operates with primitive arrays (byte[] for Blob and char[] for Clob) + * and is optimized for better performance using lower level APIs like {@link System#arraycopy(Object, int, Object, int, int)} + * and minimizes primitive-to-wrapper and back conversions. This is the reason that this class has 2 generic parameters: + * the array of primitives {@code T} and the element type {@link E}. + */ +abstract class FireboltLob { + private final BiFunction elementGetter; + private final Function castor; + private final Function bufferFactory; + protected T buf; + + protected FireboltLob(T buf, BiFunction elementGetter, Function castor, Function bufferFactory) { + this.buf = buf; + this.elementGetter = elementGetter; + this.castor = castor; + this.bufferFactory = bufferFactory; + } + + + protected void validateGetRange(long pos, int length, int bufferLength) throws SQLException { + int from = (int)(pos - 1); + if (from < 0 || from > bufferLength) { + throw new SQLException("Invalid position in Clob object set"); + } + if (length < 0 || from + length > bufferLength) { + throw new SQLException("Invalid position and substring length"); + } + } + + protected void isValid(Object buf) throws SQLException { + if (buf == null) { + throw new SQLException("Error: You cannot call a method on a Blob instance once free() has been called."); + } + } + + protected void validateSetRange(long pos, int fragmentLength, int offset, int len) throws SQLException { + if (offset < 0 || offset + len > fragmentLength) { + throw new SQLException("Invalid offset in byte array set"); + } + if (pos < 1) { + throw new SQLException("Invalid position in Clob object set"); + } + } + + public long length() throws SQLException { + isValid(buf); + return Array.getLength(buf); + } + + @SuppressWarnings("SuspiciousSystemArraycopy") // guaranteed by subclass + protected int setData(long pos, T data, int offset, int len) throws SQLException { + isValid(buf); + validateSetRange(pos, Array.getLength(data), offset, len); + int index = (int)(pos - 1); + int bufLength = Array.getLength(buf); + int newLength = Math.max(bufLength, index + len); + @SuppressWarnings("unchecked") + T buffer = (T)Array.newInstance(buf.getClass().getComponentType(), newLength); + System.arraycopy(buf, 0, buffer, 0, bufLength); + System.arraycopy(data, offset, buffer, index, len); + buf = buffer; + return len; + } + + public void free() throws SQLException { + isValid(buf); + buf = null; + } + + @SuppressWarnings({"StatementWithEmptyBody", "java:S3776", "java:S127"}) + protected long position(T pattern, long start) throws SQLException { + isValid(buf); + int bufLength = Array.getLength(buf); + if (start < 1 || start > bufLength || bufLength == 0) { + return -1; + } + int patternLength = Array.getLength(pattern); + if (patternLength == 0) { + return 1; + } + int fromIndex = (int)(start - 1L); + int max = bufLength - patternLength; + for (int i = fromIndex; i <= max; i++) { + if (elementGetter.apply(buf, i) != elementGetter.apply(pattern, 0)) { + for (i++; i < max && elementGetter.apply(buf, i) != elementGetter.apply(pattern, 0); i++); + } + if (i <= max) { + int j = i + 1; + int end = j + patternLength - 1; + for (int k = 1; j < end && elementGetter.apply(buf, j) == elementGetter.apply(pattern, k); j++, k++); + if (j == end) { + return i + 1L; + } + } + } + return -1; + } + + protected OutputStream setStream(long pos, List temp) throws SQLException { + isValid(buf); + return new OutputStream() { + private int from = (int)(pos - 1); + private volatile boolean closed = false; + + @Override + public void write(int b) throws IOException { + if (closed) { + throw new IOException("Stream is closed"); + } + temp.add(castor.apply(b)); + } + + @Override + @SuppressWarnings("SuspiciousSystemArraycopy") // guaranteed by subclass + public void flush() { + int length = temp.size(); + int bufLength = Array.getLength(buf); + int newLength = Math.max(bufLength, length + from); + if (newLength > bufLength) { + T newBuf = bufferFactory.apply(newLength); + System.arraycopy(buf, 0, newBuf, 0, bufLength); + buf = newBuf; + } + for (E b : temp) { + Array.set(buf, from++, b); + } + temp.clear(); + } + + @Override + public void close() { + flush(); + closed = true; + } + }; + } +} diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index ba305b594..c77710523 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -27,7 +27,10 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import java.io.IOException; import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -110,9 +113,6 @@ protected FireboltConnectionTest(String url) { private static Stream unsupported() { return Stream.of( - Arguments.of("createClob", (Executable) () -> connection.createClob()), - Arguments.of("createNClob", (Executable) () -> connection.createNClob()), - Arguments.of("createBlob", (Executable) () -> connection.createBlob()), Arguments.of("createSQLXML", (Executable) () -> connection.createSQLXML()), Arguments.of("createStruct", (Executable) () -> connection.createStruct("text", new Object[] {"name"})), @@ -611,6 +611,26 @@ void createArray() throws SQLException { } } + @Test + void createBlob() throws SQLException, IOException { + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + Blob blob = fireboltConnection.createBlob(); + String str = "hello"; + blob.setBytes(1, str.getBytes()); + assertEquals(str, new String(blob.getBinaryStream().readAllBytes())); + } + } + + @Test + void createClob() throws SQLException, IOException { + try (Connection fireboltConnection = createConnection(URL, connectionProperties)) { + Clob clob = fireboltConnection.createClob(); + String str = "hello"; + clob.setString(1, str); + assertEquals(str, new String(clob.getAsciiStream().readAllBytes())); + } + } + @ParameterizedTest(name = "{0}") @MethodSource("unsupported") void shouldThrowSQLFeatureNotSupportedException(String name, Executable function) throws SQLException { diff --git a/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java index 8d488714a..09f3418ca 100644 --- a/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatementTest.java @@ -8,6 +8,8 @@ import com.firebolt.jdbc.statement.StatementInfoWrapper; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; +import com.firebolt.jdbc.type.lob.FireboltBlob; +import com.firebolt.jdbc.type.lob.FireboltClob; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,8 +27,6 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import javax.sql.rowset.serial.SerialBlob; -import javax.sql.rowset.serial.SerialClob; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -90,13 +90,6 @@ private interface ParameterizedSetter { void set(PreparedStatement statement, int index, T value) throws SQLException; } - private static class SerialNClob extends SerialClob implements NClob { - public SerialNClob(char[] ch) throws SQLException { - super(ch); - } - } - - private static Stream unsupported() { return Stream.of( Arguments.of("setRef", (Executable) () -> statement.setRef(1, mock(Ref.class))), @@ -115,7 +108,7 @@ private static Stream buffers() { Arguments.of("setClob((Clob)null)", (Setter) statement -> statement.setClob(1, (Clob)null), "NULL"), Arguments.of("setClob((Reader)null)", (Setter) statement -> statement.setClob(1, (Reader)null), "NULL"), Arguments.of("setClob((Reader)null, length)", (Setter) statement -> statement.setClob(1, null, 1L), "NULL"), - Arguments.of("setClob(Reader)", (Setter) statement -> statement.setClob(1, new SerialClob("hello".toCharArray())), "'hello'"), + Arguments.of("setClob(Reader)", (Setter) statement -> statement.setClob(1, new FireboltClob("hello".toCharArray())), "'hello'"), Arguments.of("setClob(Reader, length=)", (Setter) statement -> statement.setClob(1, new StringReader("hello"), 5), "'hello'"), Arguments.of("setClob(Reader, length-1)", (Setter) statement -> statement.setClob(1, new StringReader("hello"), 4), "'hell'"), Arguments.of("setClob(Reader, length+1)", (Setter) statement -> statement.setClob(1, new StringReader("hello"), 6), "'hello'"), @@ -126,7 +119,7 @@ private static Stream buffers() { Arguments.of("setNClob((NClob)null)", (Setter) statement -> statement.setNClob(1, (NClob)null), "NULL"), Arguments.of("setNClob((Reader)null)", (Setter) statement -> statement.setNClob(1, (Reader)null), "NULL"), Arguments.of("setNClob((Reader)null, length)", (Setter) statement -> statement.setNClob(1, null, 1L), "NULL"), - Arguments.of("setClob(Reader)", (Setter) statement -> statement.setNClob(1, new SerialNClob("hello".toCharArray())), "'hello'"), + Arguments.of("setClob(Reader)", (Setter) statement -> statement.setNClob(1, new FireboltClob("hello".toCharArray())), "'hello'"), Arguments.of("setNClob(Reader, length=)", (Setter) statement -> statement.setNClob(1, new StringReader("hello"), 5), "'hello'"), Arguments.of("setNClob(Reader, length-1)", (Setter) statement -> statement.setNClob(1, new StringReader("hello"), 4), "'hell'"), Arguments.of("setNClob(Reader, length+1)", (Setter) statement -> statement.setNClob(1, new StringReader("hello"), 6), "'hello'"), @@ -137,7 +130,7 @@ private static Stream buffers() { Arguments.of("setBlob((Blob)null)", (Setter) statement -> statement.setBlob(1, (Blob)null), "NULL"), Arguments.of("setBClob((InputStream)null)", (Setter) statement -> statement.setBlob(1, (InputStream)null), "NULL"), Arguments.of("setBClob((InputStream)null, length)", (Setter) statement -> statement.setBlob(1, null, 1L), "NULL"), - Arguments.of("setBlob((Clob)null)", (Setter) statement -> statement.setBlob(1, new SerialBlob("hello".getBytes())), "E'\\x68\\x65\\x6c\\x6c\\x6f'::BYTEA"), + Arguments.of("setBlob((Clob)null)", (Setter) statement -> statement.setBlob(1, new FireboltBlob("hello".getBytes())), "E'\\x68\\x65\\x6c\\x6c\\x6f'::BYTEA"), Arguments.of("setCharacterStream(null)", (Setter) statement -> statement.setCharacterStream(1, null), "NULL"), Arguments.of("setCharacterStream(null, int)", (Setter) statement -> statement.setCharacterStream(1, null, 1), "NULL"), diff --git a/src/test/java/com/firebolt/jdbc/type/lob/FireboltBlobTest.java b/src/test/java/com/firebolt/jdbc/type/lob/FireboltBlobTest.java new file mode 100644 index 000000000..fbfdd3e31 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/type/lob/FireboltBlobTest.java @@ -0,0 +1,192 @@ +package com.firebolt.jdbc.type.lob; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.io.OutputStream; +import java.sql.Blob; +import java.sql.SQLException; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class FireboltBlobTest extends FireboltLobTest { + @Test + void empty() throws SQLException, IOException { + Blob blob = new FireboltBlob(); + assertEquals(0, blob.length()); + + assertEquals(0, blob.getBytes(1, 0).length); + assertThrows(SQLException.class, () -> blob.getBytes(1, 1)); + assertThrows(SQLException.class, () -> blob.getBytes(1, 123)); + assertThrows(SQLException.class, () -> blob.getBytes(0, 123)); + assertThrows(SQLException.class, () -> blob.getBytes(0, 1)); + assertThrows(SQLException.class, () -> blob.getBytes(1, -1)); + + assertEquals(-1, blob.getBinaryStream(1, 0).read()); + assertThrows(SQLException.class, () -> blob.getBinaryStream(1, 1)); + assertThrows(SQLException.class, () -> blob.getBinaryStream(1, 123)); + assertThrows(SQLException.class, () -> blob.getBinaryStream(1, -1)); + + assertEquals(-1, blob.getBinaryStream().read()); + assertArrayEquals(new byte[0], blob.getBinaryStream().readAllBytes()); + } + + @Test + void preInitialized() throws SQLException, IOException { + String str = "hello, world!"; + Blob blob = new FireboltBlob(str.getBytes()); + + assertEquals(str.length(), blob.length()); + + assertEquals("", new String(blob.getBytes(1, 0))); + assertEquals("h", new String(blob.getBytes(1, 1))); + assertEquals(str, new String(blob.getBytes(1, str.length()))); + assertEquals("hello", new String(blob.getBytes(1, 5))); + assertEquals("world", new String(blob.getBytes(8, 5))); + assertEquals("world!", new String(blob.getBytes(8, 6))); + assertThrows(SQLException.class, () -> blob.getBinaryStream(1, str.length() + 1)); + assertThrows(SQLException.class, () -> blob.getBinaryStream(0, str.length())); + assertThrows(SQLException.class, () -> blob.getBinaryStream(0, str.length() + 1)); + + assertEquals(str, new String(blob.getBinaryStream().readAllBytes())); + } + + @Test + void binaryStreamToEmptyBlob() throws SQLException, IOException { + String str = "hello, world!"; + Blob blob = new FireboltBlob(); + try (OutputStream os = blob.setBinaryStream(1)) { + os.write(str.getBytes()); + } + assertEquals(str, new String(blob.getBinaryStream().readAllBytes())); + } + + @Test + void characterStreamWithFlush() throws SQLException, IOException { + String str = "hello, world!"; + Blob blob = new FireboltBlob(str.getBytes()); + try (OutputStream os = blob.setBinaryStream(8)) { + os.write("all".getBytes()); + assertEquals(str, new String(blob.getBinaryStream().readAllBytes())); + os.flush(); + assertEquals("hello, allld!", new String(blob.getBinaryStream().readAllBytes())); + os.write(" ".getBytes()); + os.write("people".getBytes()); + os.write("!".getBytes()); + assertEquals("hello, allld!", new String(blob.getBinaryStream().readAllBytes())); + } + // the rest is flushed automatically when writer is closed + assertEquals("hello, all people!", new String(blob.getBinaryStream().readAllBytes())); + } + + @Test + void failedToWriteToClosedWriter() throws SQLException, IOException { + Blob blob = new FireboltBlob(); + OutputStream os = blob.setBinaryStream(1); + os.close(); + assertThrows(IOException.class, () -> os.write(1)); + } + + @ParameterizedTest + @MethodSource("replace") + void binaryStreamReplace(String initial, String replacement, int pos, String expected) throws SQLException, IOException { + Blob blob = new FireboltBlob(initial.getBytes()); + try (OutputStream os = blob.setBinaryStream(pos)) { + os.write(replacement.getBytes()); + } + assertEquals(expected, new String(blob.getBinaryStream().readAllBytes())); + } + + @Test + void setStringToEmptyBlob() throws SQLException { + String str = "hello, world!"; + Blob blob = new FireboltBlob(); + blob.setBytes(1, str.getBytes()); + assertEquals(str, new String(blob.getBytes(1, str.length()))); + } + + @ParameterizedTest + @MethodSource("replace") + void stringReplace(String initial, String replacement, int pos, String expected) throws SQLException { + Blob blob = new FireboltBlob(initial.getBytes()); + assertEquals(initial, new String(blob.getBytes(1, initial.length()))); + blob.setBytes(pos, replacement.getBytes()); + assertEquals(expected, new String(blob.getBytes(1, expected.length()))); + } + + @ParameterizedTest + @MethodSource("partialReplace") + void partialStringReplace(String initial, String replacement, int pos, int offset, int length, String expected) throws SQLException { + Blob blob = new FireboltBlob(initial.getBytes()); + assertEquals(initial, new String(blob.getBytes(1, initial.length()))); + blob.setBytes(pos, replacement.getBytes(), offset, length); + assertEquals(expected, new String(blob.getBytes(1, expected.length()))); + } + + @ParameterizedTest + @MethodSource("wrongReplace") + void wrongReplace(String initial, String replacement, int pos, int offset, int length) throws SQLException { + Blob blob = new FireboltBlob(initial.getBytes()); + assertEquals(initial, new String(blob.getBytes(1, initial.length()))); + assertThrows(SQLException.class, () -> blob.setBytes(pos, replacement.getBytes(), offset, length)); + } + + @ParameterizedTest + @MethodSource("truncate") + void truncate(String str, int length, String expected) throws SQLException, IOException { + Blob blob = new FireboltBlob(str.getBytes()); + blob.truncate(length); + assertEquals(expected, new String(blob.getBinaryStream().readAllBytes())); + } + + @ParameterizedTest + @ValueSource(longs = {14L, -1L}) + void truncateWrongNumber(long length) { + String str = "hello, world!"; + Blob blob = new FireboltBlob(str.getBytes()); + assertThrows(SQLException.class, () -> blob.truncate(length)); + } + + @Test + void invalid() throws SQLException, IOException { + Blob blob = new FireboltBlob("".getBytes()); + assertEquals("", new String(blob.getBinaryStream().readAllBytes())); + blob.free(); + assertThrows(SQLException.class, blob::getBinaryStream); + } + + @ParameterizedTest + @MethodSource("position") + void position(String str, String search, int start, int expected) throws SQLException { + Blob blob = new FireboltBlob(str.getBytes()); + assertEquals(expected, blob.position(search.getBytes(), start)); + assertEquals(expected, blob.position(new FireboltBlob(search.getBytes()), start)); + } + + @ParameterizedTest + @MethodSource("equalsAndHashCode") + void equalsAndHashCode(String s1, String s2, boolean expectedEquals) { + Blob blob1 = new FireboltBlob(s1.getBytes()); + Blob blob2 = new FireboltBlob(s2.getBytes()); + if (expectedEquals) { + assertEquals(blob1, blob2); + assertEquals(blob1.hashCode(), blob2.hashCode()); + } else { + assertNotEquals(blob1, blob2); + assertNotEquals(blob1.hashCode(), blob2.hashCode()); + } + } + + @Test + void equalsNotCompatibleObject() { + String text = "hello"; + Blob blob = new FireboltBlob(text.getBytes()); + assertNotEquals(blob, text); + } +} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/type/lob/FireboltClobTest.java b/src/test/java/com/firebolt/jdbc/type/lob/FireboltClobTest.java new file mode 100644 index 000000000..38f509074 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/type/lob/FireboltClobTest.java @@ -0,0 +1,211 @@ +package com.firebolt.jdbc.type.lob; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.sql.Clob; +import java.sql.SQLException; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class FireboltClobTest extends FireboltLobTest { + @Test + void empty() throws SQLException, IOException { + Clob clob = new FireboltClob(); + assertEquals(0, clob.length()); + + assertEquals(0, clob.getSubString(1, 0).length()); + assertThrows(SQLException.class, () -> clob.getSubString(1, 1)); + assertThrows(SQLException.class, () -> clob.getSubString(1, 123)); + assertThrows(SQLException.class, () -> clob.getSubString(0, 123)); + assertThrows(SQLException.class, () -> clob.getSubString(0, 1)); + assertThrows(SQLException.class, () -> clob.getSubString(1, -1)); + + assertEquals(-1, clob.getCharacterStream(1, 0).read()); + assertThrows(SQLException.class, () -> clob.getCharacterStream(1, 1)); + assertThrows(SQLException.class, () -> clob.getCharacterStream(1, 123)); + assertThrows(SQLException.class, () -> clob.getCharacterStream(1, -1)); + + assertEquals(-1, clob.getAsciiStream().read()); + assertEquals("", readAll(clob.getCharacterStream())); + } + + @Test + void preInitialized() throws SQLException, IOException { + String str = "hello, world!"; + Clob clob = new FireboltClob(str.toCharArray()); + + assertEquals(str.length(), clob.length()); + + assertEquals("", clob.getSubString(1, 0)); + assertEquals("h", clob.getSubString(1, 1)); + assertEquals(str, clob.getSubString(1, str.length())); + assertEquals("hello", clob.getSubString(1, 5)); + assertEquals("world", clob.getSubString(8, 5)); + assertEquals("world!", clob.getSubString(8, 6)); + assertThrows(SQLException.class, () -> clob.getCharacterStream(1, str.length() + 1)); + assertThrows(SQLException.class, () -> clob.getCharacterStream(0, str.length())); + assertThrows(SQLException.class, () -> clob.getCharacterStream(0, str.length() + 1)); + + assertEquals(str, new String(clob.getAsciiStream().readAllBytes())); + + assertEquals(str, readAll(clob.getCharacterStream())); + } + + @Test + void asciiStream() throws SQLException, IOException { + String str = "hello, world!"; + Clob clob = new FireboltClob(); + try (OutputStream os = clob.setAsciiStream(1)) { + os.write(str.getBytes()); + } + assertEquals(str, new String(clob.getAsciiStream().readAllBytes())); + } + + @Test + void characterStream() throws SQLException, IOException { + String str = "hello, world!"; + Clob clob = new FireboltClob(); + try (Writer writer = clob.setCharacterStream(1)) { + writer.write(str); + } + assertEquals(str, readAll(clob.getCharacterStream())); + } + + @Test + void characterStreamWithFlush() throws SQLException, IOException { + String str = "hello, world!"; + Clob clob = new FireboltClob(str.toCharArray()); + try (Writer writer = clob.setCharacterStream(8)) { + writer.write("all"); + assertEquals(str, readAll(clob.getCharacterStream())); + writer.flush(); + assertEquals("hello, allld!", readAll(clob.getCharacterStream())); + writer.write(" "); + writer.write("people"); + writer.write("!"); + assertEquals("hello, allld!", readAll(clob.getCharacterStream())); + } + // the rest is flushed automatically when writer is closed + assertEquals("hello, all people!", readAll(clob.getCharacterStream())); + } + + @Test + void failedToWriteToClosedWriter() throws SQLException, IOException { + Clob clob = new FireboltClob(); + Writer writer = clob.setCharacterStream(1); + writer.close(); + assertThrows(IOException.class, () -> writer.write("x")); + } + + @ParameterizedTest + @MethodSource("replace") + void binaryStreamReplace(String initial, String replacement, int pos, String expected) throws SQLException, IOException { + Clob clob = new FireboltClob(initial.toCharArray()); + try (Writer writer = clob.setCharacterStream(pos)) { + writer.write(replacement); + } + assertEquals(expected, readAll(clob.getCharacterStream())); + } + + @ParameterizedTest + @MethodSource("replace") + void stringReplaceCharacters(String initial, String replacement, int pos, String expected) throws SQLException { + Clob clob = new FireboltClob(initial.toCharArray()); + assertEquals(initial, clob.getSubString(1, initial.length())); + clob.setString(pos, replacement); + assertEquals(expected, clob.getSubString(1, expected.length())); + } + + @ParameterizedTest + @MethodSource("partialReplace") + void partialStringReplace(String initial, String replacement, int pos, int offset, int length, String expected) throws SQLException { + Clob clob = new FireboltClob(initial.toCharArray()); + assertEquals(initial, clob.getSubString(1, initial.length())); + clob.setString(pos, replacement, offset, length); + assertEquals(expected, clob.getSubString(1, expected.length())); + } + + @ParameterizedTest + @MethodSource("wrongReplace") + void wrongReplace(String initial, String replacement, int pos, int offset, int length) throws SQLException { + Clob clob = new FireboltClob(initial.toCharArray()); + assertEquals(initial, clob.getSubString(1, initial.length())); + assertThrows(SQLException.class, () -> clob.setString(pos, replacement, offset, length)); + } + + @Test + void setStringToEmptyClob() throws SQLException { + String str = "hello, world!"; + Clob clob = new FireboltClob(); + clob.setString(1, str); + assertEquals(str, clob.getSubString(1, str.length())); + } + + @ParameterizedTest + @MethodSource("truncate") + void truncate(String str, int length, String expected) throws SQLException, IOException { + Clob clob = new FireboltClob(str.toCharArray()); + clob.truncate(length); + assertEquals(expected, new String(clob.getAsciiStream().readAllBytes())); + } + + @ParameterizedTest + @ValueSource(longs = {14L, -1L}) + void truncateWrongNumber(long length) { + String str = "hello, world!"; + Clob clob = new FireboltClob(str.toCharArray()); + assertThrows(SQLException.class, () -> clob.truncate(length)); + } + + @Test + void invalid() throws SQLException, IOException { + Clob clob = new FireboltClob("".toCharArray()); + assertEquals("", new String(clob.getAsciiStream().readAllBytes())); + clob.free(); + assertThrows(SQLException.class, clob::getAsciiStream); + } + + @ParameterizedTest + @MethodSource("position") + void position(String str, String search, int start, int expected) throws SQLException { + Clob clob = new FireboltClob(str.toCharArray()); + assertEquals(expected, clob.position(search, start)); + assertEquals(expected, clob.position(new FireboltClob(search.toCharArray()), start)); + } + + @ParameterizedTest + @MethodSource("equalsAndHashCode") + void equalsAndHashCode(String s1, String s2, boolean expectedEquals) { + Clob clob1 = new FireboltClob(s1.toCharArray()); + Clob clob2 = new FireboltClob(s2.toCharArray()); + if (expectedEquals) { + assertEquals(clob1, clob2); + assertEquals(clob1.hashCode(), clob2.hashCode()); + } else { + assertNotEquals(clob1, clob2); + assertNotEquals(clob1.hashCode(), clob2.hashCode()); + } + } + + @Test + void equalsNotCompatibleObject() { + String text = "hello"; + Clob clob = new FireboltClob(text.toCharArray()); + assertNotEquals(clob, text); + } + + private String readAll(Reader reader) { + return new BufferedReader(reader).lines().collect(Collectors.joining(System.lineSeparator())); + } +} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/type/lob/FireboltLobTest.java b/src/test/java/com/firebolt/jdbc/type/lob/FireboltLobTest.java new file mode 100644 index 000000000..27b8a0ad7 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/type/lob/FireboltLobTest.java @@ -0,0 +1,79 @@ +package com.firebolt.jdbc.type.lob; + +import org.junit.jupiter.params.provider.Arguments; + +import java.util.stream.Stream; + +abstract class FireboltLobTest { + protected static Stream replace() { + return Stream.of( + Arguments.of("hey, world!", "bye", 1, "bye, world!"), + Arguments.of("hello, all!", "world!", 8, "hello, world!"), + Arguments.of("hello, world!", "hello, world?", 1, "hello, world?"), + Arguments.of("hello, world!", "!", 6, "hello! world!"), + Arguments.of("hello, world!", "", 5, "hello, world!") + ); + } + + protected static Stream partialReplace() { + return Stream.of( + Arguments.of("hey, world!", "bye", 1, 0, 3, "bye, world!"), + Arguments.of("hello, all!", "world!", 8, 0, 6, "hello, world!"), + Arguments.of("hello, world!", "hello, world?", 1, 0, 13, "hello, world?"), + Arguments.of("hello, world!", "!", 6, 0, 1, "hello! world!"), + Arguments.of("hello, world!", "", 5, 0, 0, "hello, world!"), + + Arguments.of("hello, world!", "world!", 8, 0, 5, "hello, world"), + Arguments.of("hello, world!", "all people", 8, 4, 6, "hello, people"), + Arguments.of("hello, all!", "bye people", 7, 3, 7, "hello, people") + ); + } + + protected static Stream wrongReplace() { + return Stream.of( + Arguments.of("hello, all!", "people", -1, 0, 6), + Arguments.of("hello, all!", "people", 1, -1, 6), + Arguments.of("hello, all!", "people", 1, 0, 7), + Arguments.of("hello, all!", "people", 1, 7, 0), + Arguments.of("hello, all!", "people", 1, 5, 2) + ); + } + + protected static Stream truncate() { + return Stream.of( + Arguments.of("hello, world!", 5, "hello"), + Arguments.of("hello, world!", 13, "hello, world!"), + Arguments.of("hello, world!", 0, ""), + Arguments.of("hello, world!", 1, "h") + ); + } + + protected static Stream position() { + return Stream.of( + Arguments.of("hello, world!", "hello", 1, 1), + Arguments.of("hello, world!", "world", 1, 8), + Arguments.of("hello, world!", "world", 3, 8), + Arguments.of("hello, world!", "world", 8, 8), + Arguments.of("hello, world!", "world", 9, -1), + Arguments.of("hello, world!", "world", 0, -1), + Arguments.of("hello, world!", "world", 14, -1), + Arguments.of("hello, world!", "bye", 1, -1), + Arguments.of("hello, world!", "hello", 5, -1), + Arguments.of("1212", "112", 1, -1), + Arguments.of("", "", 1, -1), + Arguments.of("hello", "h", 0, -1), + Arguments.of("hello", "", 1, 1) + ); + } + + protected static Stream equalsAndHashCode() { + return Stream.of( + Arguments.of("one", "one", true), + Arguments.of("one", "two", false), + Arguments.of("two", "one", false), + Arguments.of("", "", true), + Arguments.of("something", "", false), + Arguments.of("", "anything", false) + ); + } +} From 905a037f80e3ec14b1777fc4f4041d4f1faa2a48 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 28 May 2024 18:37:21 +0300 Subject: [PATCH 12/52] FIR-33264: quoted engine and DB names (#417) --- .../integration/tests/ConnectionTest.java | 2 +- .../integration/tests/SystemEngineTest.java | 99 +++++++++++++------ .../FireboltEngineVersion2Service.java | 2 +- 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/integrationTest/java/integration/tests/ConnectionTest.java b/src/integrationTest/java/integration/tests/ConnectionTest.java index c0d96d049..2dd2289a9 100644 --- a/src/integrationTest/java/integration/tests/ConnectionTest.java +++ b/src/integrationTest/java/integration/tests/ConnectionTest.java @@ -76,7 +76,7 @@ void connectToWrongDbNotAttachedToEngine() throws SQLException { String enginelessDb = "engineless_db" + System.currentTimeMillis(); try (Connection systemConnection = createConnection(null)) { try { - systemConnection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS %s", enginelessDb)); + systemConnection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS \"%s\"", enginelessDb)); String url = format("jdbc:firebolt:%s?env=%s&account=%s&engine=%s", enginelessDb, params.getEnv(), params.getAccount(), params.getEngine()); String errorMessage = format("The engine with the name %s is not attached to database %s", params.getEngine(), enginelessDb); assertEquals(errorMessage, assertThrows(FireboltException.class, () -> DriverManager.getConnection(url, params.getPrincipal(), params.getSecret())).getMessage()); diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 29bbc30ff..9eab35764 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -36,6 +36,7 @@ import java.util.logging.Logger; import java.util.stream.Stream; +import static com.firebolt.jdbc.connection.FireboltConnectionUserPassword.SYSTEM_ENGINE_NAME; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Map.entry; @@ -134,23 +135,23 @@ void useDatabase(String entityType) throws SQLException { ConnectionInfo current = integration.ConnectionInfo.getInstance(); try (Connection connection = createConnection(getSystemEngineName())) { try { - connection.createStatement().executeUpdate(format("USE %s %s", entityType, current.getDatabase())); // use current DB; shouldn't have any effect + connection.createStatement().executeUpdate(format("USE %s \"%s\"", entityType, current.getDatabase())); // use current DB; shouldn't have any effect assertNull(getTableDbName(connection, TABLE1)); // the table does not exist yet - connection.createStatement().executeUpdate(format("CREATE TABLE %s ( id LONG)", TABLE1)); // create table1 in current DB + connection.createStatement().executeUpdate(format("CREATE TABLE \"%s\" ( id LONG)", TABLE1)); // create table1 in current DB assertEquals(current.getDatabase(), getTableDbName(connection, TABLE1)); // now table t1 exists Assert.assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("USE %s %s", entityType, USE_DATABASE_NAME))); // DB does not exist - connection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS %s", USE_DATABASE_NAME)); // create DB + connection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS \"%s\"", USE_DATABASE_NAME)); // create DB connection.createStatement().executeUpdate(format("USE %s %s", entityType, USE_DATABASE_NAME)); // Now this should succeed - connection.createStatement().executeUpdate(format("CREATE TABLE %s ( id LONG)", TABLE2)); // create table2 in other DB + connection.createStatement().executeUpdate(format("CREATE TABLE \"%s\" ( id LONG)", TABLE2)); // create table2 in other DB assertNull(getTableDbName(connection, TABLE1)); // table1 does not exist here assertEquals(USE_DATABASE_NAME, getTableDbName(connection, TABLE2)); // but table2 does exist } finally { // now clean up everything for (String query : new String[] { - format("USE %s %s", entityType, USE_DATABASE_NAME), // switch to DB that should be current just in case because the previous code can fail at any phase + format("USE %s \"%s\"", entityType, USE_DATABASE_NAME), // switch to DB that should be current just in case because the previous code can fail at any phase format("DROP TABLE %s", TABLE2), - format("DROP DATABASE %s", USE_DATABASE_NAME), - format("USE %s %s", entityType, current.getDatabase()), // now switch back + format("DROP DATABASE \"%s\"", USE_DATABASE_NAME), + format("USE %s \"%s\"", entityType, current.getDatabase()), // now switch back format("DROP TABLE %s", TABLE1)}) { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); @@ -169,23 +170,65 @@ void useDatabase(String entityType) throws SQLException { void useEngine() throws SQLException { try (Connection connection = createConnection(getSystemEngineName())) { try { - connection.createStatement().executeUpdate("USE ENGINE SYSTEM"); - assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("USE ENGINE %s", ENGINE_NAME))); - connection.createStatement().executeUpdate(format("CREATE ENGINE %s", ENGINE_NAME)); - connection.createStatement().executeUpdate(format("USE ENGINE %s", ENGINE_NAME)); - connection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS %s", USE_DATABASE_NAME)); - connection.createStatement().executeUpdate(format("USE DATABASE %s", USE_DATABASE_NAME)); - connection.createStatement().executeUpdate(format("CREATE TABLE %s ( id LONG)", TABLE1)); + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); + assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", ENGINE_NAME))); + connection.createStatement().executeUpdate(format("CREATE ENGINE \"%s\"", ENGINE_NAME)); + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", ENGINE_NAME)); + connection.createStatement().executeUpdate(format("CREATE DATABASE IF NOT EXISTS \"%s\"", USE_DATABASE_NAME)); + connection.createStatement().executeUpdate(format("USE DATABASE \"%s\"", USE_DATABASE_NAME)); + connection.createStatement().executeUpdate(format("CREATE TABLE \"%s\" ( id LONG)", TABLE1)); connection.createStatement().executeUpdate(format("INSERT INTO %s (id) VALUES (1)", TABLE1)); // should succeed using user engine // switch back to the system engine - connection.createStatement().executeUpdate("USE ENGINE SYSTEM"); + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("INSERT INTO %s (id) VALUES (1)", TABLE1))); // system engine cannot insert data } finally { - connection.createStatement().executeUpdate(format("USE DATABASE %s", USE_DATABASE_NAME)); + connection.createStatement().executeUpdate(format("USE DATABASE \"%s\"", USE_DATABASE_NAME)); connection.createStatement().executeUpdate(format("DROP TABLE %s", TABLE1)); - connection.createStatement().executeUpdate(format("DROP DATABASE %s", USE_DATABASE_NAME)); - connection.createStatement().executeUpdate(format("STOP ENGINE %s", ENGINE_NAME)); - connection.createStatement().executeUpdate(format("DROP ENGINE %s", ENGINE_NAME)); + connection.createStatement().executeUpdate(format("DROP DATABASE \"%s\"", USE_DATABASE_NAME)); + connection.createStatement().executeUpdate(format("STOP ENGINE \"%s\"", ENGINE_NAME)); + connection.createStatement().executeUpdate(format("DROP ENGINE \"%s\"", ENGINE_NAME)); + } + } + } + + @Test + @Tag("v2") + @Tag("slow") + @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) + void useEngineMixedCase() throws SQLException { + String mixedCaseEngineName = "JavaIntegrationTestMixedCase" + ID; + try (Connection connection = createConnection(getSystemEngineName())) { + try { + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); + connection.createStatement().executeUpdate(format("CREATE ENGINE \"%s\"", mixedCaseEngineName)); + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", mixedCaseEngineName)); + assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("USE ENGINE %s", mixedCaseEngineName))); + } finally { + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); + connection.createStatement().executeUpdate(format("STOP ENGINE \"%s\"", mixedCaseEngineName)); + connection.createStatement().executeUpdate(format("DROP ENGINE \"%s\"", mixedCaseEngineName)); + } + } + } + + @Test + @Tag("v2") + @Tag("slow") + @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) + void useEngineMixedCaseToLowerCase() throws SQLException { + String mixedCaseEngineName = "JavaIntegrationTestToLowerCase" + ID; + try (Connection connection = createConnection(getSystemEngineName())) { + try { + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); + // engine name is lower cased because it is not quoted + connection.createStatement().executeUpdate(format("CREATE ENGINE %s", mixedCaseEngineName)); + connection.createStatement().executeUpdate(format("USE ENGINE %s", mixedCaseEngineName)); + // engine name remains mixed case and statement fails because engine name was not quoted when we created the engine + assertThrows(SQLException.class, () -> connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", mixedCaseEngineName))); + } finally { + connection.createStatement().executeUpdate(format("USE ENGINE \"%s\"", SYSTEM_ENGINE_NAME)); + connection.createStatement().executeUpdate(format("STOP ENGINE %s", mixedCaseEngineName)); + connection.createStatement().executeUpdate(format("DROP ENGINE %s", mixedCaseEngineName)); } } } @@ -259,20 +302,20 @@ void shouldExecuteEngineManagementQueries() throws SQLException { try { boolean attachEngineToDb = ((FireboltConnection)connection).getInfraVersion() < 2; List queries = Stream.of( - entry(true, format("CREATE DATABASE IF NOT EXISTS %s", SECOND_DATABASE_NAME)), - entry(true, format("CREATE ENGINE %s", ENGINE_NAME)), - entry(attachEngineToDb, format("ATTACH ENGINE %s TO %s;", ENGINE_NAME, SECOND_DATABASE_NAME)), - entry(true, format("ALTER DATABASE %s SET DESCRIPTION = 'JDBC Integration test'", SECOND_DATABASE_NAME)), - entry(true, format("ALTER ENGINE %s RENAME TO %s", ENGINE_NAME, ENGINE_NEW_NAME)), - entry(true, format("START ENGINE %s", ENGINE_NEW_NAME))) + entry(true, format("CREATE DATABASE IF NOT EXISTS \"%s\"", SECOND_DATABASE_NAME)), + entry(true, format("CREATE ENGINE \"%s\"", ENGINE_NAME)), + entry(attachEngineToDb, format("ATTACH ENGINE \"%s\" TO \"%s\";", ENGINE_NAME, SECOND_DATABASE_NAME)), + entry(true, format("ALTER DATABASE \"%s\" SET DESCRIPTION = 'JDBC Integration test'", SECOND_DATABASE_NAME)), + entry(true, format("ALTER ENGINE \"%s\" RENAME TO \"%s\"", ENGINE_NAME, ENGINE_NEW_NAME)), + entry(true, format("START ENGINE \"%s\"", ENGINE_NEW_NAME))) .filter(Map.Entry::getKey).map(Map.Entry::getValue).collect(toList()); executeAll(connection, queries); } finally { // now clean up everything for (String query : new String[]{ - format("STOP ENGINE %s", ENGINE_NEW_NAME), - format("DROP ENGINE %s", ENGINE_NEW_NAME), - format("DROP DATABASE %s", SECOND_DATABASE_NAME)}) { + format("STOP ENGINE \"%s\"", ENGINE_NEW_NAME), + format("DROP ENGINE \"%s\"", ENGINE_NEW_NAME), + format("DROP DATABASE \"%s\"", SECOND_DATABASE_NAME)}) { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); } catch (SQLException e) { // catch just in case to do our best to clean everything even if test has failed diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineVersion2Service.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineVersion2Service.java index 7aa97fc31..db15c1994 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineVersion2Service.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineVersion2Service.java @@ -31,6 +31,6 @@ public Engine getEngine(FireboltProperties properties) throws SQLException { } private String use(String entity, String name) { - return format("USE %s %s", entity, name); + return format("USE %s \"%s\"", entity, name); } } From 908125bbc06473d2fcdeef799183b194857de049 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 29 May 2024 17:49:50 +0300 Subject: [PATCH 13/52] Cache accountId and system engine URL (#419) --- .../integration/tests/SystemEngineTest.java | 2 ++ .../firebolt/jdbc/client/FireboltClient.java | 8 +++++++- .../client/account/FireboltAccountClient.java | 15 +++++++++++++- .../account/FireboltAccountRetriever.java | 20 +++++++++++++++++-- .../jdbc/connection/CacheListener.java | 7 +++++++ .../jdbc/connection/FireboltConnection.java | 15 +++++++++++++- .../account/FireboltAccountClientTest.java | 9 +++++++++ .../gateway/FireboltGatewayUrlClientTest.java | 10 ++++++++++ 8 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/connection/CacheListener.java diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 9eab35764..31a6e200c 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -1,5 +1,6 @@ package integration.tests; +import com.firebolt.jdbc.connection.CacheListener; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; @@ -257,6 +258,7 @@ void connectToAccountWithoutUser() throws SQLException, IOException { // } String jdbcUrl = format("jdbc:firebolt:%s?env=%s&account=%s&engine=%s", database, current.getEnv(), current.getAccount(), current.getEngine()); + ((CacheListener)connection).cleanup(); SQLException e = assertThrows(SQLException.class, () -> DriverManager.getConnection(jdbcUrl, clientId, clientSecret)); assertTrue(e.getMessage().matches(format("Account '%s' does not exist in this organization or is not authorized.+RBAC.+", current.getAccount())), "Unexpected exception message: " + e.getMessage()); } finally { diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index 8f3657071..29c9e93d0 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.client; +import com.firebolt.jdbc.connection.CacheListener; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.compress.LZ4InputStream; @@ -38,7 +39,7 @@ import static java.util.Optional.ofNullable; @Getter -public abstract class FireboltClient { +public abstract class FireboltClient implements CacheListener { private static final String HEADER_AUTHORIZATION = "Authorization"; private static final String HEADER_AUTHORIZATION_BEARER_PREFIX_VALUE = "Bearer "; @@ -54,6 +55,7 @@ protected FireboltClient(OkHttpClient httpClient, FireboltConnection connection, this.connection = connection; this.headerUserAgentValue = UsageTrackerUtil.getUserAgentString(customDrivers != null ? customDrivers : "", customClients != null ? customClients : ""); + connection.register(this); } protected T getResource(String uri, String accessToken, Class valueType) @@ -208,4 +210,8 @@ private String getInternalErrorWithHeadersText(Response response) { return response.toString() + "\n" + response.headers(); } + @Override + public void cleanup() { + // empty default implementation + } } diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java index 69096c918..eb0ff73d5 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java @@ -12,6 +12,8 @@ import java.io.IOException; import java.sql.SQLException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import static java.lang.String.format; @@ -23,6 +25,7 @@ public class FireboltAccountClient extends FireboltClient { private static final String URI_SUFFIX_DATABASE_INFO_URL = "engines:getURLByDatabaseName?databaseName="; private static final String URI_PREFIX_WITH_ACCOUNT_RESOURCE = "%s/core/v1/accounts/%s/%s"; private static final String URI_PREFIX_WITHOUT_ACCOUNT_RESOURCE = "%s/core/v1/account/%s"; + private static final Map resourceCache = new ConcurrentHashMap<>(); public FireboltAccountClient(OkHttpClient httpClient, FireboltConnection fireboltConnection, String customDrivers, String customClients) { super(httpClient, fireboltConnection, customDrivers, customClients); @@ -36,9 +39,15 @@ public FireboltAccountClient(OkHttpClient httpClient, FireboltConnection firebol * @param accessToken the access token * @return the account */ + @SuppressWarnings("java:S3824") // cannot use computeIfAbsent() because getResource() throws checked exceptions public FireboltAccountResponse getAccount(String host, String account, String accessToken) throws SQLException, IOException { String uri = format(GET_ACCOUNT_ID_URI, host, account); - return getResource(uri, host, accessToken, FireboltAccountResponse.class); + FireboltAccountResponse accountResponse = (FireboltAccountResponse)resourceCache.get(uri); + if (accountResponse == null) { + accountResponse = getResource(uri, host, accessToken, FireboltAccountResponse.class); + resourceCache.put(uri, accountResponse); + } + return accountResponse; } /** @@ -101,4 +110,8 @@ private String createAccountUri(String account, String host, String suffix) { return account == null || account.isEmpty() ? format(URI_PREFIX_WITHOUT_ACCOUNT_RESOURCE, host, suffix) : format(URI_PREFIX_WITH_ACCOUNT_RESOURCE, host, account, suffix); } + @Override + public void cleanup() { + resourceCache.clear(); + } } \ No newline at end of file diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java index 11a55e1fb..8b4876af4 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java @@ -1,21 +1,25 @@ package com.firebolt.jdbc.client.account; import com.firebolt.jdbc.client.FireboltClient; +import com.firebolt.jdbc.connection.CacheListener; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.FireboltException; import okhttp3.OkHttpClient; import java.io.IOException; import java.sql.SQLException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; -public class FireboltAccountRetriever extends FireboltClient { +public class FireboltAccountRetriever extends FireboltClient implements CacheListener { private static final String URL = "https://%s/web/v3/account/%s/%s"; private final String host; private final String path; private final Class type; + private static final Map valueCache = new ConcurrentHashMap<>(); public FireboltAccountRetriever(OkHttpClient httpClient, FireboltConnection connection, String customDrivers, String customClients, String host, String path, Class type) { super(httpClient, connection, customDrivers, customClients); @@ -26,7 +30,14 @@ public FireboltAccountRetriever(OkHttpClient httpClient, FireboltConnection conn public T retrieve(String accessToken, String accountName) throws SQLException { try { - return getResource(format(URL, host, accountName, path), accessToken, type); + String url = format(URL, host, accountName, path); + @SuppressWarnings("unchecked") + T value = (T)valueCache.get(url); + if (value == null) { + value = getResource(url, accessToken, type); + valueCache.put(url, value); + } + return value; } catch (IOException e) { throw new FireboltException(String.format("Failed to get %s url for account %s: %s", path, accountName, e.getMessage()), e); } @@ -46,4 +57,9 @@ protected void validateResponse(String host, int statusCode, String errorMessage statusCode, errorMessageFromServer); } } + + @Override + public void cleanup() { + valueCache.clear(); + } } diff --git a/src/main/java/com/firebolt/jdbc/connection/CacheListener.java b/src/main/java/com/firebolt/jdbc/connection/CacheListener.java new file mode 100644 index 000000000..7090712a3 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/connection/CacheListener.java @@ -0,0 +1,7 @@ +package com.firebolt.jdbc.connection; + +import java.util.EventListener; + +public interface CacheListener extends EventListener { + void cleanup(); +} diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 95165979c..439cf859a 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -45,6 +45,9 @@ import java.sql.Statement; import java.sql.Struct; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -63,7 +66,7 @@ import static java.sql.ResultSet.TYPE_FORWARD_ONLY; import static java.util.stream.Collectors.toMap; -public abstract class FireboltConnection extends JdbcBase implements Connection { +public abstract class FireboltConnection extends JdbcBase implements Connection, CacheListener { private static final Logger log = Logger.getLogger(FireboltConnection.class.getName()); private final FireboltAuthenticationService fireboltAuthenticationService; @@ -80,6 +83,7 @@ public abstract class FireboltConnection extends JdbcBase implements Connection //Properties that are used at the beginning of the connection for authentication protected final FireboltProperties loginProperties; + private final Collection cacheListeners = Collections.newSetFromMap(new IdentityHashMap<>()); protected FireboltConnection(@NonNull String url, Properties connectionSettings, @@ -668,4 +672,13 @@ public String getProtocolVersion() { public int getInfraVersion() { return infraVersion; } + + public void register(CacheListener listener) { + cacheListeners.add(listener); + } + + @Override + public void cleanup() { + cacheListeners.forEach(CacheListener::cleanup); + } } diff --git a/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java b/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java index bcc5cf36c..6ceb74830 100644 --- a/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/account/FireboltAccountClientTest.java @@ -28,6 +28,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -45,9 +47,16 @@ void setUp() { @Test void getAccount() throws SQLException, IOException { + client.cleanup(); String accountId = "123"; injectMockedResponse(httpClient, HTTP_OK, format("{\"account_id\":\"%s\"}", accountId)); // FireboltAccountResponse assertEquals(accountId, client.getAccount("http://host", "account", "token").getAccountId()); + verify(httpClient, times(1)).newCall(any()); + assertEquals(accountId, client.getAccount("http://host", "account", "token").getAccountId()); + verify(httpClient, times(1)).newCall(any()); + client.cleanup(); + assertEquals(accountId, client.getAccount("http://host", "account", "token").getAccountId()); + verify(httpClient, times(2)).newCall(any()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java index ebab5e97b..83e6b0160 100644 --- a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; @@ -50,6 +51,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -81,9 +83,17 @@ void shouldGetGatewayUrlWhenResponseIsOk() throws SQLException, IOException { @Test void shouldGetAccountId() throws SQLException, IOException { + fireboltAccountIdResolver.cleanup(); FireboltAccount account = new FireboltAccount("12345", "central", 2); injectMockedResponse(httpClient, HTTP_OK, "{\"id\": \"12345\", \"region\":\"central\", \"infraVersion\":2}"); assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); + Mockito.verify(httpClient, times(1)).newCall(any()); + // Do this again. The response is cached, so the invocation count will remain 1 + assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); + // now clean the cache and call resolve() again. The invocation counter will be incremented. + fireboltAccountIdResolver.cleanup(); + assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); + Mockito.verify(httpClient, times(2)).newCall(any()); } @Test From f8a80745fe91a68395774a5fea456d15404112da Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 4 Jun 2024 17:42:26 +0300 Subject: [PATCH 14/52] FIR-32120: removed redundant throws SQLException (#420) --- .../client/config/OkHttpClientCreator.java | 2 +- .../jdbc/connection/FireboltConnection.java | 14 +++++------ .../FireboltConnectionServiceSecret.java | 2 -- .../service/FireboltGatewayUrlService.java | 1 - .../jdbc/statement/FireboltStatement.java | 24 +++++++++---------- .../jdbc/type/array/SqlArrayUtil.java | 2 +- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java index e45870b9e..532475f0f 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java +++ b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java @@ -93,7 +93,7 @@ private static Optional getHostnameVerifier(FireboltProperties } private static Optional getSSLConfig(FireboltProperties fireboltProperties) throws CertificateException, - NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { + NoSuchAlgorithmException, KeyStoreException, IOException { if (!fireboltProperties.isSsl()) { return Optional.empty(); } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 439cf859a..e010c7284 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -234,7 +234,7 @@ public boolean getAutoCommit() throws SQLException { @Override @ExcludeFromJacocoGeneratedReport @NotImplemented - public void setAutoCommit(boolean autoCommit) throws SQLException { + public void setAutoCommit(boolean autoCommit) { // No-op as Firebolt does not support transactions } @@ -265,7 +265,7 @@ public String getCatalog() throws SQLException { @Override @NotImplemented - public void setCatalog(String catalog) throws SQLException { + public void setCatalog(String catalog) { // no-op as catalogs are not supported } @@ -490,7 +490,7 @@ public String getEndpoint() { @Override @NotImplemented - public void commit() throws SQLException { + public void commit() { // no-op as transactions are not supported } @@ -539,7 +539,7 @@ public boolean isReadOnly() throws SQLException { @Override @ExcludeFromJacocoGeneratedReport @NotImplemented - public void setReadOnly(boolean readOnly) throws SQLException { + public void setReadOnly(boolean readOnly) { // no-op } @@ -551,7 +551,7 @@ public CallableStatement prepareCall(String sql, int resultSetType, int resultSe @Override @NotImplemented - public Map> getTypeMap() throws SQLException { + public Map> getTypeMap() { // Since setTypeMap is currently not supported, an empty map is returned (refer to the doc for more info) return Map.of(); } @@ -570,7 +570,7 @@ public int getHoldability() throws SQLException { @Override @ExcludeFromJacocoGeneratedReport @NotImplemented - public void setHoldability(int holdability) throws SQLException { + public void setHoldability(int holdability) { // No support for transaction } @@ -636,7 +636,7 @@ public void setClientInfo(String name, String value) throws SQLClientInfoExcepti } @Override - public String getClientInfo(String name) throws SQLException { + public String getClientInfo(String name) { return Optional.ofNullable(FireboltSessionProperty.byAlias(name.toUpperCase()).getValue(sessionProperties)).map(Object::toString).orElse(null); } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index cbe98c27e..e61092786 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -8,7 +8,6 @@ import com.firebolt.jdbc.client.authentication.ServiceAccountAuthenticationRequest; import com.firebolt.jdbc.client.gateway.GatewayUrlResponse; import com.firebolt.jdbc.connection.settings.FireboltProperties; -import com.firebolt.jdbc.connection.settings.FireboltQueryParameterKey; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.service.FireboltAccountIdService; import com.firebolt.jdbc.service.FireboltAuthenticationService; @@ -21,7 +20,6 @@ import lombok.NonNull; import okhttp3.OkHttpClient; -import java.net.URI; import java.net.URL; import java.sql.SQLException; import java.util.Map; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java b/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java index 6e9846597..fef97d4bf 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltGatewayUrlService.java @@ -2,7 +2,6 @@ import com.firebolt.jdbc.client.account.FireboltAccountRetriever; import com.firebolt.jdbc.client.gateway.GatewayUrlResponse; -import com.firebolt.jdbc.exception.FireboltException; import lombok.RequiredArgsConstructor; import java.sql.SQLException; diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index cfd544a5b..dcf04d9b5 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -247,7 +247,7 @@ private synchronized void closeUnclosedProcessedResults() throws SQLException { } @Override - public int getMaxRows() throws SQLException { + public int getMaxRows() { return maxRows; } @@ -290,12 +290,12 @@ public void close(boolean removeFromConnection) throws SQLException { } @Override - public boolean isClosed() throws SQLException { + public boolean isClosed() { return isClosed; } @Override - public synchronized ResultSet getResultSet() throws SQLException { + public synchronized ResultSet getResultSet() { return firstUnclosedStatementResult != null ? firstUnclosedStatementResult.getResultSet() : null; } @@ -309,27 +309,27 @@ public boolean getMoreResults() throws SQLException { } @Override - public int getUpdateCount() throws SQLException { + public int getUpdateCount() { return currentUpdateCount; } @Override - public void closeOnCompletion() throws SQLException { + public void closeOnCompletion() { closeOnCompletion = true; } @Override - public boolean isCloseOnCompletion() throws SQLException { + public boolean isCloseOnCompletion() { return closeOnCompletion; } @Override - public int getQueryTimeout() throws SQLException { + public int getQueryTimeout() { return queryTimeout; } @Override - public void setQueryTimeout(int seconds) throws SQLException { + public void setQueryTimeout(int seconds) { queryTimeout = seconds; } @@ -358,12 +358,12 @@ public boolean isStatementRunning() { } @Override - public int getMaxFieldSize() throws SQLException { + public int getMaxFieldSize() { return maxFieldSize; } @Override - public void setMaxFieldSize(int max) throws SQLException { + public void setMaxFieldSize(int max) { maxFieldSize = max; } @@ -417,12 +417,12 @@ public int getResultSetType() { } @Override - public void addBatch(String sql) throws SQLException { + public void addBatch(String sql) { batchStatements.add(sql); } @Override - public void clearBatch() throws SQLException { + public void clearBatch() { batchStatements.clear(); } diff --git a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java index 2ef60ffc1..03f1b01e7 100644 --- a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java @@ -47,7 +47,7 @@ public Markers(char leftArrayBracket, char rightArrayBracket, char literalQuote, } } - public SqlArrayUtil(ColumnType columnType, Markers markers) { + private SqlArrayUtil(ColumnType columnType, Markers markers) { this.columnType = columnType; this.markers = markers; } From ae8f237b868b1f3419f376805027731512879894 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 4 Jun 2024 17:42:45 +0300 Subject: [PATCH 15/52] FIR-33431: implemented getObject with type map (#421) --- .../tests/PreparedStatementTest.java | 14 ++++++++++- .../jdbc/resultset/FireboltResultSet.java | 24 ++++++++++++++----- .../jdbc/resultset/FireboltResultSetTest.java | 11 ++++++++- .../jdbc/type/FireboltDataTypeTest.java | 22 +++++++++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/firebolt/jdbc/type/FireboltDataTypeTest.java diff --git a/src/integrationTest/java/integration/tests/PreparedStatementTest.java b/src/integrationTest/java/integration/tests/PreparedStatementTest.java index 44eed8c61..090788c2c 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementTest.java @@ -118,7 +118,19 @@ Stream numericTypes() { (CheckedTriFunction) (s, i, v) -> { s.setLong(i, v.longValue()); return null; - }, (CheckedBiFunction) (rs, i) -> (int) rs.getLong(i)) + }, (CheckedBiFunction) (rs, i) -> (int) rs.getLong(i)), + + Arguments.of("getObject(Long.class)", + (CheckedTriFunction) (s, i, v) -> { + s.setLong(i, v.longValue()); + return null; + }, (CheckedBiFunction) (rs, i) -> rs.getObject(i, Long.class).intValue()), + + Arguments.of("getObject(i, java.util.Map.of(\"long\", Integer.class)", + (CheckedTriFunction) (s, i, v) -> { + s.setLong(i, v.longValue()); + return null; + }, (CheckedBiFunction) (rs, i) -> (int) rs.getObject(i, java.util.Map.of("long", Integer.class))) ); } diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index 324df5beb..af94336d0 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -36,6 +36,7 @@ import java.sql.Blob; import java.sql.Clob; import java.sql.Date; +import java.sql.JDBCType; import java.sql.NClob; import java.sql.Ref; import java.sql.ResultSet; @@ -50,6 +51,7 @@ import java.util.Calendar; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.TimeZone; import java.util.TreeMap; @@ -57,6 +59,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; import static com.firebolt.jdbc.type.BaseType.isNull; import static com.firebolt.jdbc.util.StringUtil.splitAll; @@ -951,10 +954,21 @@ public Statement getStatement() { } @Override - @NotImplemented - @ExcludeFromJacocoGeneratedReport public Object getObject(int columnIndex, Map> map) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + FireboltDataType dataType = resultSetMetaData.getColumn(columnIndex).getType().getDataType(); + Map> caseInsensitiveMap = new TreeMap<>(CASE_INSENSITIVE_ORDER); + caseInsensitiveMap.putAll(map); + Class type = getAllNames(dataType).map(caseInsensitiveMap::get).filter(Objects::nonNull).findFirst() + .orElseThrow(() -> new FireboltException(format("Cannot find type %s in provided types map", dataType))); + return getObject(columnIndex, type); + } + + private Stream getAllNames(FireboltDataType dataType) { + return Stream.concat(Stream.of(dataType.getDisplayName(), getJdbcType(dataType)).filter(Objects::nonNull), Stream.of(dataType.getAliases())); + } + + private String getJdbcType(FireboltDataType dataType) { + return JDBCType.valueOf(dataType.getSqlType()).getName(); } @Override @@ -975,10 +989,8 @@ public Clob getClob(int columnIndex) throws SQLException { } @Override - @NotImplemented - @ExcludeFromJacocoGeneratedReport public Object getObject(String columnLabel, Map> map) throws SQLException { - throw new FireboltSQLFeatureNotSupportedException(); + return getObject(findColumn(columnLabel), map); } @Override diff --git a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java index c7255c483..5d3c7e3e2 100644 --- a/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java +++ b/src/test/java/com/firebolt/jdbc/resultset/FireboltResultSetTest.java @@ -44,6 +44,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Calendar; +import java.util.Map; import java.util.TimeZone; import java.util.concurrent.Callable; @@ -192,7 +193,7 @@ void unsupported() throws SQLException { assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateFloat("label", 0.0f)); assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateDouble("label", 0.0)); assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateBigDecimal("label", new BigDecimal(0))); - ; + assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateString("label", "")); assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateBytes("label", new byte[0])); assertThrows(SQLFeatureNotSupportedException.class, () -> resultSet.updateDate("label", new Date(0))); @@ -428,6 +429,11 @@ void shouldReturnInt() throws SQLException { assertEquals(1, resultSet.getInt(1)); assertEquals(1, resultSet.getInt("id")); assertEquals(1, resultSet.getObject(1, Long.class)); + assertEquals(1L, resultSet.getObject(1, Map.of("int", Long.class))); + assertEquals(1L, resultSet.getObject("id", Map.of("INTEGER", Long.class))); + assertEquals(1., resultSet.getObject(1, Map.of("int32", Double.class))); + assertThrows(SQLException.class, () -> resultSet.getObject(1, Map.of("real", Double.class))); // exising type that does not match column type + assertThrows(SQLException.class, () -> resultSet.getObject(1, Map.of("notatype", Double.class))); // type alias that does not exist resultSet.next(); assertEquals(2, resultSet.getInt(1)); @@ -446,6 +452,8 @@ void shouldReturnFloat() throws SQLException { assertEquals(14.6f, resultSet.getFloat(6)); assertEquals(14.6f, resultSet.getFloat("a_double")); assertEquals(14.6f, resultSet.getObject(6, Float.class)); + assertEquals(14.6, resultSet.getObject(6, Map.of("Float32", Double.class))); + assertEquals((short)14, resultSet.getObject(6, Map.of("Float32", Short.class))); resultSet.next(); assertEquals(0, resultSet.getFloat(6)); @@ -1209,6 +1217,7 @@ void shouldGetDouble() throws SQLException { assertEquals(1.23, resultSet.getDouble(3)); assertEquals(1.23456789012, resultSet.getObject(4, Double.class)); + assertEquals(1.23456789012, (double)resultSet.getObject(4, Map.of("double precision", Double.class)), 0.01); assertEquals(new BigDecimal("1.23456789012"), resultSet.getBigDecimal(4)); assertEquals(1231232.123459999990457054844258706536, resultSet.getObject(5, Double.class), 0.01); diff --git a/src/test/java/com/firebolt/jdbc/type/FireboltDataTypeTest.java b/src/test/java/com/firebolt/jdbc/type/FireboltDataTypeTest.java new file mode 100644 index 000000000..a5c68d9e8 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/type/FireboltDataTypeTest.java @@ -0,0 +1,22 @@ +package com.firebolt.jdbc.type; + + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import java.sql.JDBCType; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class FireboltDataTypeTest { + /** + * This test validates that {@link FireboltDataType#getSqlType()} return standard type defined in {@link java.sql.Types} and {@link JDBCType}. + * @param type - the type + */ + @ParameterizedTest + @EnumSource(FireboltDataType.class) + void sqlType(FireboltDataType type) { + // assert here is just to satisfy static code analysis. valueOf() either succeeds or throws IllegalArgumentException + assertNotNull(JDBCType.valueOf(type.getSqlType())); + } +} \ No newline at end of file From 4696472092457d73f8c1887142402fbb4d203464 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 4 Jun 2024 17:43:08 +0300 Subject: [PATCH 16/52] =?UTF-8?q?added=20tests=20of=20getMaxStatementLengt?= =?UTF-8?q?h()=20and=20getMaxRowSize()=20that=20retur=E2=80=A6=20(#423)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../firebolt/jdbc/metadata/FireboltDatabaseMetadata.java | 9 +-------- .../jdbc/metadata/FireboltDatabaseMetadataTest.java | 3 +++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java index f40348576..5a7abbac9 100644 --- a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java +++ b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java @@ -2,8 +2,6 @@ import com.firebolt.jdbc.GenericWrapper; import com.firebolt.jdbc.QueryResult; -import com.firebolt.jdbc.annotation.ExcludeFromJacocoGeneratedReport; -import com.firebolt.jdbc.annotation.NotImplemented; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.resultset.FireboltResultSet; import com.firebolt.jdbc.resultset.column.Column; @@ -958,21 +956,16 @@ public int getMaxCatalogNameLength() { } @Override - @ExcludeFromJacocoGeneratedReport - @NotImplemented public int getMaxRowSize() { return 0; } @Override - @ExcludeFromJacocoGeneratedReport public boolean doesMaxRowSizeIncludeBlobs() { - return false; + return true; } @Override - @ExcludeFromJacocoGeneratedReport - @NotImplemented public int getMaxStatementLength() { return 0; } diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 6180df11b..806a25c7f 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -630,6 +630,9 @@ void checkLimits() throws SQLException { assertEquals(0, fireboltDatabaseMetadata.getMaxStatements()); assertEquals(63, fireboltDatabaseMetadata.getMaxUserNameLength()); assertEquals(0, fireboltDatabaseMetadata.getMaxTablesInSelect()); + assertEquals(0, fireboltDatabaseMetadata.getMaxRowSize()); + assertEquals(0, fireboltDatabaseMetadata.getMaxStatementLength()); + assertTrue(fireboltDatabaseMetadata.doesMaxRowSizeIncludeBlobs()); } @Test From b207197be0b4aa86621efaee15ef39f6ce98a137 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 5 Jun 2024 18:07:28 +0300 Subject: [PATCH 17/52] Fir 32732 remove environment manager (#402) --- .github/workflows/integration-test-v2.yml | 19 +----- .github/workflows/integration-test.yml | 28 -------- build.gradle | 22 ------- .../java/integration/EnvironmentManager.java | 65 ------------------- 4 files changed, 2 insertions(+), 132 deletions(-) delete mode 100644 src/integrationTest/java/integration/EnvironmentManager.java diff --git a/.github/workflows/integration-test-v2.yml b/.github/workflows/integration-test-v2.yml index a2a168513..1f0a1920f 100644 --- a/.github/workflows/integration-test-v2.yml +++ b/.github/workflows/integration-test-v2.yml @@ -16,11 +16,6 @@ on: description: 'Account' required: true type: string - run_setup: - description: 'Run setup database and engine using GitHub action' - required: true - type: boolean - default: true secrets: FIREBOLT_CLIENT_ID_STG_NEW_IDN: required: true @@ -50,14 +45,13 @@ jobs: - name: Setup database and engine id: setup - if: ${{ (inputs.database == '') && (inputs.run_setup == true) }} + if: ${{ inputs.database == '' }} uses: firebolt-db/integration-testing-setup@v2 with: firebolt-client-id: ${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }} firebolt-client-secret: ${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }} account: ${{ inputs.account }} api-endpoint: "api.staging.firebolt.io" - instance-type: "B2" - name: Determine database name id: find-database-name @@ -77,14 +71,5 @@ jobs: echo "engine_name=${{ steps.setup.outputs.engine_name }}" >> $GITHUB_OUTPUT fi - - name: Setup env by build - id: setup-env - run: | - if [ ${{ inputs.run_setup }} == true ]; then - echo "run_setup=false" >> $GITHUB_OUTPUT - else - echo "run_setup=true" >> $GITHUB_OUTPUT - fi - - name: Run integration tests - run: ./gradlew integrationTest -Ddb=${{ steps.find-database-name.outputs.database_name }} -Denv=staging -Dclient_secret="${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }}" -Dclient_id="${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }}" -Daccount="${{ inputs.account }}" -Dengine="${{ steps.find-engine-name.outputs.engine_name }}" -DexcludeTags=v1 -Drun_setup="${{ steps.setup-env.outputs.run_setup }}" + run: ./gradlew integrationTest -Ddb=${{ steps.find-database-name.outputs.database_name }} -Denv=staging -Dclient_secret="${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }}" -Dclient_id="${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }}" -Daccount="${{ inputs.account }}" -Dengine="${{ steps.find-engine-name.outputs.engine_name }}" -DexcludeTags=v1 diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 66cd26165..9c99320bc 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -7,10 +7,6 @@ on: description: 'Database (v1) - a new one will be created if not provided' required: false default: '' - database2: - description: 'Database (v2) - a new one will be created if not provided' - required: false - default: '' database-with-engine-v2: description: 'Database (v2) for Firebolt v2 - a new one will be created if not provided' required: false @@ -18,9 +14,6 @@ on: engine1: description: 'Engine (v1) - a new one will be created if not provided' required: false - engine2: - description: 'Engine (v2) - a new one will be created if not provided' - required: false engine_v2_fb_2_0: description: 'Engine (v2) for Firebolt v2 - a new one will be created if not provided' required: false @@ -32,14 +25,6 @@ on: options: - 'true' - 'false' - run-v2: - description: 'Run tests against Firebolt DB v2' - required: true - default: true - type: choice - options: - - 'true' - - 'false' run-database-with-engine-v2: description: 'Run tests against Firebolt DB v2 and Engine V2' required: true @@ -60,18 +45,6 @@ jobs: FIREBOLT_STG_USERNAME: ${{ secrets.FIREBOLT_STG_USERNAME }} FIREBOLT_STG_PASSWORD: ${{ secrets.FIREBOLT_STG_PASSWORD }} - run-integration-tests2: - if: ${{ inputs.run-v2 == 'true' }} - uses: ./.github/workflows/integration-test-v2.yml - with: - database: ${{ inputs.database2 }} - engine: ${{ inputs.engine2 }} - account: ${{ vars.FIREBOLT_ACCOUNT_V1 }} - run_setup: true - secrets: - FIREBOLT_CLIENT_ID_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }} - FIREBOLT_CLIENT_SECRET_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }} - run-integration-tests-engine2: if: ${{ inputs.run-database-with-engine-v2 == 'true' }} uses: ./.github/workflows/integration-test-v2.yml @@ -79,7 +52,6 @@ jobs: database: ${{ inputs.database-with-engine-v2 }} engine: ${{ inputs.engine_v2_fb_2_0 }} account: ${{ vars.FIREBOLT_ACCOUNT_V2 }} - run_setup: false secrets: FIREBOLT_CLIENT_ID_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }} FIREBOLT_CLIENT_SECRET_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }} diff --git a/build.gradle b/build.gradle index 066ca2b14..c034379e5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,4 @@ import java.util.jar.JarFile -import java.util.stream.Stream - -import static java.util.stream.Collectors.toList plugins { id 'java' @@ -116,25 +113,6 @@ test { } tasks.register('integrationTest', Test) { - doFirst { - if (Boolean.parseBoolean(System.getProperty("run_setup", "false"))) { - URL[] urls = Stream.concat(sourceSets.integrationTest.output.getFiles().stream(), sourceSets.integrationTest.compileClasspath.getFiles().stream()) - .map(f -> f.toURI().toURL()).collect(toList()).toArray() - ClassLoader classLoader = new URLClassLoader(urls) - def mgr = classLoader.loadClass("integration.EnvironmentManager").newInstance(new Object[0]); - ext.environmentManager = mgr - Properties props = mgr.create() - props.each { - systemProperty it.key, it.value - } - } - } - doLast { - if (Boolean.parseBoolean(System.getProperty("run_setup", "false"))) { - def mgr = ext.environmentManager - mgr.cleanup() - } - } description = 'Runs integration tests.' useJUnitPlatform() { includeTags(System.getProperty("includeTags", "common").split(",")) diff --git a/src/integrationTest/java/integration/EnvironmentManager.java b/src/integrationTest/java/integration/EnvironmentManager.java deleted file mode 100644 index 5a71912a6..000000000 --- a/src/integrationTest/java/integration/EnvironmentManager.java +++ /dev/null @@ -1,65 +0,0 @@ -package integration; - -import com.firebolt.FireboltDriver; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Properties; - -public class EnvironmentManager { - private final String name = "integration_testing__" + System.currentTimeMillis(); - private Connection connection; - - enum Action { - CREATE, START, STOP, DROP - } - - enum Entity { - ENGINE("engine"), DATABASE("db"); - private final String property; - - Entity(String property) { - this.property = property; - } - } - - public Properties create() throws SQLException, ClassNotFoundException { - connection = createDbConnection(); - Properties props = new Properties(); - perform(props, Entity.ENGINE, name, Action.CREATE); - perform(props, Entity.DATABASE, name, Action.CREATE); - return props; - } - - public void cleanup() throws SQLException { - perform(System.getProperties(), Entity.ENGINE, name, Action.STOP, Action.DROP); - perform(System.getProperties(), Entity.DATABASE, name, Action.DROP); - connection.close(); - } - - private Connection createDbConnection() throws SQLException, ClassNotFoundException { - Class.forName(FireboltDriver.class.getName()); - Properties props = new Properties(); - props.setProperty("env", System.getProperty("env", "staging")); - props.setProperty("account", System.getProperty("account", "infra-engines-v2")); - props.setProperty("client_id", System.getProperty("client_id", System.getProperty("user"))); - props.setProperty("client_secret", System.getProperty("client_secret", System.getProperty("password"))); - return DriverManager.getConnection("jdbc:firebolt:" + name, props); - } - - private void perform(Properties props, Entity entity, String entityName, Action ... actions) throws SQLException { - if (System.getProperty(entity.property, "").isBlank()) { - for (Action action : actions) { - executeSql(String.format("%s %s %s", action, entity, entityName)); - if (Action.CREATE.equals(action)) { - props.setProperty(entity.property, entityName); - } - } - } - } - - private void executeSql(String sql) throws SQLException { - connection.createStatement().executeUpdate(sql); - } -} From 4a64ce5b171050ee8b6c05e68d8aa1b0147540c4 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Tue, 11 Jun 2024 10:14:27 +0300 Subject: [PATCH 18/52] fixed integration tests broken by the server side changes (#425) --- .../tests/DatabaseMetaDataTest.java | 22 ++++++++-------- .../integration/tests/SpecialValuesTest.java | 26 ------------------- .../SystemEngineDatabaseMetaDataTest.java | 5 ++++ .../integration/tests/SystemEngineTest.java | 6 +++-- .../jdbc/statement/FireboltStatement.java | 2 +- 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java b/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java index c65b1b493..ba83a7d50 100644 --- a/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java +++ b/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java @@ -136,24 +136,24 @@ void shouldReturnTable() throws SQLException { @ParameterizedTest @CsvSource({ // table types - ",,,,tables;databases;integration_test,", - ",,,TABLE;VIEW,tables;databases;integration_test,", - ",,,VIEW;TABLE,integration_test;tables;databases,", - ",,,TABLE,integration_test,databases;tables", - ",,,VIEW,databases;tables,integration_test", + ",,,,tables;views;integration_test,", + ",,,TABLE;VIEW,tables;views;integration_test,", + ",,,VIEW;TABLE,integration_test;tables;views,", + ",,,TABLE,integration_test,views;tables", + ",,,VIEW,views;tables,integration_test", // table name pattern - ",,%account%,,service_account_users;service_accounts,tables;columns;databases", - ",,%test,,integration_test,tables;columns;databases", + ",,%account%,,service_account_users;service_accounts,tables;columns;views", + ",,%test,,integration_test,tables;columns;views", // schema name pattern - ",public,,,integration_test,tables;columns;databases", + ",public,,,integration_test,tables;columns;views", ",information_schema,,,tables;columns,integration_test", // schema name pattern and table types - ",public,,TABLE,integration_test,tables;columns;databases", - ",public,,TABLE;VIEW,integration_test,tables;columns;databases", - ",public,,VIEW,,tables;columns;databases", + ",public,,TABLE,integration_test,tables;columns;views", + ",public,,TABLE;VIEW,integration_test,tables;columns;views", + ",public,,VIEW,,tables;columns;views", ",information_schema,,TABLE,,integration_test", ",information_schema,,TABLE;VIEW,tables;columns,integration_test", ",information_schema,,VIEW,tables;columns,", diff --git a/src/integrationTest/java/integration/tests/SpecialValuesTest.java b/src/integrationTest/java/integration/tests/SpecialValuesTest.java index 589c42bf9..823110219 100644 --- a/src/integrationTest/java/integration/tests/SpecialValuesTest.java +++ b/src/integrationTest/java/integration/tests/SpecialValuesTest.java @@ -59,18 +59,10 @@ void infFloatAsDoubleUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select 'inf'::float", "select '+inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) void infFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); } - @ParameterizedTest - @ValueSource(strings = {"select 'inf'::float", "select '+inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) - void infFloatSystemEngine(String query) throws SQLException { - specialSelect(systemConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); - } - @ParameterizedTest @ValueSource(strings = {"select 'inf'::double", "select '+inf'::double"}) void infDoubleSystemEngine(String query) throws SQLException { @@ -111,18 +103,10 @@ void minusInfRealSystemEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select '-inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) void minusInfFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); } - @ParameterizedTest - @ValueSource(strings = {"select '-inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) - void minusInfSystemEngine(String query) throws SQLException { - specialSelect(systemConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); - } - @ParameterizedTest @ValueSource(strings = {"select '-inf'::double"}) void minusInfDoubleUserEngine(String query) throws SQLException { @@ -167,20 +151,10 @@ void nanDoubleSystemEngine(String query) throws SQLException { @ValueSource(strings = { "select 'nan'::float", "select '+nan'::float", "select '-nan'::float", }) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) void nanFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NaN, Double.NaN, Double.NaN); } - @ParameterizedTest - @ValueSource(strings = { - "select 'nan'::float", "select '+nan'::float", "select '-nan'::float", - }) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) - void nanFloatSystemEngine(String query) throws SQLException { - specialSelect(systemConnection, query, Float.NaN, Double.NaN, Float.NaN); - } - @ParameterizedTest @ValueSource(strings = {"select 'nan'::double", "select '+nan'::double", "select '-nan'::double"}) void nanDoubleUserEngine(String query) throws SQLException { diff --git a/src/integrationTest/java/integration/tests/SystemEngineDatabaseMetaDataTest.java b/src/integrationTest/java/integration/tests/SystemEngineDatabaseMetaDataTest.java index aa5bfc5e1..92751b576 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineDatabaseMetaDataTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineDatabaseMetaDataTest.java @@ -4,6 +4,7 @@ import integration.IntegrationTest; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -47,6 +48,7 @@ void readOnly() throws SQLException { } @Test + @Tag("v2") void getSchemas() throws SQLException { String database = integration.ConnectionInfo.getInstance().getDatabase(); assertEquals(List.of(List.of("information_schema", database)), getSchemas(DatabaseMetaData::getSchemas)); @@ -65,6 +67,7 @@ void getSchemas() throws SQLException { "{database},%schema", "{database},%form%", }) + @Tag("v2") void getSchemasInformationSchema(String catalog, String schemaPattern) throws SQLException { String database = integration.ConnectionInfo.getInstance().getDatabase(); String cat = catalog == null ? null : catalog.replace("{database}", database); @@ -110,6 +113,7 @@ void getSchemasInformationSchema(String catalog, String schemaPattern) throws SQ ",,%in%,VIEW;TABLE,engines,tables", ",,,TABLE,,", }) + @Tag("v2") void getTables(String catalog, String schemaPattern, String tableNamePattern, String types, String requiredTableName, String forbiddenTableName) throws SQLException { String database = integration.ConnectionInfo.getInstance().getDatabase(); String requiredCatalog = catalog == null ? null : catalog.replace("{database}", database); @@ -173,6 +177,7 @@ void getTables(String catalog, String schemaPattern, String tableNamePattern, St ",,%in%,no-one,,information_schema.columns.column_name", ",,,does-not-exist,,information_schema.columns.column_name", }) + @Tag("v2") void getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern, String requiredColumn, String forbiddenColumn) throws SQLException { String database = integration.ConnectionInfo.getInstance().getDatabase(); String requiredCatalog = catalog == null ? null : catalog.replace("{database}", database); diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 31a6e200c..614b0ab03 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -102,7 +102,8 @@ void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { String secret = current.getSecret(); Collection expectedErrorMessages = Set.of( "Queries against table dummy require a user engine", - "The system engine doesn't support queries against table dummy. Run this query on a user engine."); + "The system engine doesn't support queries against table dummy. Run this query on a user engine.", + "Line 1, Column 22: relation \"dummy\" does not exist"); try (Connection systemConnection = DriverManager.getConnection(systemEngineJdbcUrl, principal, secret); Connection customConnection = DriverManager.getConnection(customEngineJdbcUrl, principal, secret)) { @@ -116,7 +117,7 @@ void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { } FireboltException e = assertThrows(FireboltException.class, () -> systemConnection.createStatement().executeQuery("select count(*) from dummy")); String actualErrorMessage = e.getErrorMessageFromServer().replaceAll("\r?\n", ""); - assertTrue(expectedErrorMessages.contains(actualErrorMessage)); + assertTrue(expectedErrorMessages.contains(actualErrorMessage), "Unexpected error message: " + actualErrorMessage); } finally { try { customConnection.createStatement().executeUpdate("DROP TABLE dummy"); @@ -299,6 +300,7 @@ private String getTableDbName(Connection connection, String table) throws SQLExc @Test @Tag("slow") + @Tag("v2") // does not work on new V1 - DB cannot be managed by system engine void shouldExecuteEngineManagementQueries() throws SQLException { try (Connection connection = createConnection(getSystemEngineName())) { try { diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index dcf04d9b5..caec200c1 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -110,7 +110,7 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper) t } InputStream inputStream = null; try { - log.log(Level.INFO, "Executing the statement with label {0} : {1}", new Object[] {statementInfoWrapper.getLabel(), statementInfoWrapper.getSql()}); + log.log(Level.FINE, "Executing the statement with label {0} : {1}", new Object[] {statementInfoWrapper.getLabel(), statementInfoWrapper.getSql()}); if (statementInfoWrapper.getType() == StatementType.PARAM_SETTING) { connection.addProperty(statementInfoWrapper.getParam()); log.log(Level.FINE, "The property from the query {0} was stored", runningStatementLabel); From 07a4dc5ef44a6ba701efeb05303af1dc19d0691a Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Mon, 17 Jun 2024 19:05:56 +0300 Subject: [PATCH 19/52] fix: FIR-33214: fixed service account name to follow new rules (#427) --- .../java/integration/tests/SystemEngineTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 614b0ab03..6ba024310 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -240,7 +240,7 @@ void useEngineMixedCaseToLowerCase() throws SQLException { void connectToAccountWithoutUser() throws SQLException, IOException { ConnectionInfo current = integration.ConnectionInfo.getInstance(); String database = current.getDatabase(); - String serviceAccountName = format("%s_sa_no_user_%d", database, System.currentTimeMillis()); + String serviceAccountName = format("%s_%d_sa_no_user", database, System.currentTimeMillis()); try (Connection connection = createConnection(getSystemEngineName())) { try { connection.createStatement().executeUpdate(format("CREATE SERVICE ACCOUNT \"%s\" WITH DESCRIPTION = 'Ecosytem test with no user'", serviceAccountName)); From 21e5f3c795679d10b78b1bc9aae2647b6915d37e Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 19 Jun 2024 18:24:36 +0300 Subject: [PATCH 20/52] feat: FIR-33601: use catalogs table instead of databases table if exists (#424) --- .../FireboltConnectionServiceSecret.java | 2 +- ...ireboltEngineInformationSchemaService.java | 32 ++++++++++------ ...oltEngineInformationSchemaServiceTest.java | 38 ++++++++++--------- ...onSchemaServiceUsingCatalogsTableTest.java | 33 ++++++++++++++++ ...nSchemaServiceUsingDatabasesTableTest.java | 7 ++++ 5 files changed, 81 insertions(+), 31 deletions(-) create mode 100644 src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingCatalogsTableTest.java create mode 100644 src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingDatabasesTableTest.java diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index e61092786..ab08eb342 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -122,7 +122,7 @@ private FireboltProperties getSessionPropertiesForSystemEngine(String accessToke - private FireboltEngineService getFireboltEngineService() { + private FireboltEngineService getFireboltEngineService() throws SQLException { if (fireboltEngineService == null) { int currentInfraVersion = Optional.ofNullable(loginProperties.getAdditionalProperties().get("infraVersion")).map(Integer::parseInt).orElse(infraVersion); fireboltEngineService = currentInfraVersion >= 2 ? new FireboltEngineVersion2Service(this) : new FireboltEngineInformationSchemaService(this); diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java index 9791628bb..731663a0a 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java @@ -4,7 +4,6 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; -import lombok.RequiredArgsConstructor; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -17,29 +16,38 @@ import static java.lang.String.format; import static java.util.stream.Collectors.toCollection; -@RequiredArgsConstructor public class FireboltEngineInformationSchemaService implements FireboltEngineService { private static final String ENGINE_URL = "url"; private static final String STATUS_FIELD = "status"; private static final String ENGINE_NAME_FIELD = "engine_name"; private static final Collection RUNNING_STATUSES = Stream.of("running", "ENGINE_STATE_RUNNING").collect(toCollection(() -> new TreeSet<>(CASE_INSENSITIVE_ORDER))); private static final String ENGINE_QUERY = - "SELECT engs.url, engs.attached_to, dbs.database_name, engs.status, engs.engine_name " + + "SELECT engs.url, engs.attached_to, dbs.%1$s_name, engs.status, engs.engine_name " + "FROM information_schema.engines as engs " + - "LEFT JOIN information_schema.databases as dbs ON engs.attached_to = dbs.database_name " + + "LEFT JOIN information_schema.%1$ss as dbs ON engs.attached_to = dbs.%1$s_name " + "WHERE engs.engine_name = ?"; - private static final String DATABASE_QUERY = "SELECT database_name FROM information_schema.databases WHERE database_name=?"; + private static final String INVENTORY_QUERY = "SELECT %1$s_name FROM information_schema.%1$ss WHERE %1$s_name=?"; private final FireboltConnection fireboltConnection; + private final String dbTerm; + + public FireboltEngineInformationSchemaService(FireboltConnection fireboltConnection) throws SQLException { + this.fireboltConnection = fireboltConnection; + dbTerm = doesRecordExist(format(INVENTORY_QUERY, "table"), "catalogs") ? "catalog" : "database"; + } @Override public boolean doesDatabaseExist(String database) throws SQLException { - try (PreparedStatement ps = fireboltConnection.prepareStatement(DATABASE_QUERY)) { - ps.setString(1, database); - try (ResultSet rs = ps.executeQuery()) { - return rs.next(); - } - } + return doesRecordExist(format(INVENTORY_QUERY, dbTerm), database); + } + + private boolean doesRecordExist(String query, String param) throws SQLException { + try (PreparedStatement ps = fireboltConnection.prepareStatement(query)) { + ps.setString(1, param); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + } } @Override @@ -49,7 +57,7 @@ public Engine getEngine(FireboltProperties properties) throws SQLException { if (engine == null) { throw new IllegalArgumentException("Cannot retrieve engine parameters because its name is null"); } - try (PreparedStatement ps = fireboltConnection.prepareStatement(ENGINE_QUERY)) { + try (PreparedStatement ps = fireboltConnection.prepareStatement(format(ENGINE_QUERY, dbTerm))) { ps.setString(1, engine); try (ResultSet rs = ps.executeQuery()) { if (!rs.next()) { diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceTest.java index 412a50f4a..d4ab80fb9 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceTest.java @@ -4,11 +4,11 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -30,13 +30,27 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class FireboltEngineInformationSchemaServiceTest { +abstract class FireboltEngineInformationSchemaServiceTest { - @InjectMocks - private FireboltEngineInformationSchemaService fireboltEngineService; + protected FireboltEngineInformationSchemaService fireboltEngineService; @Mock - private FireboltConnection fireboltConnection; + protected FireboltConnection fireboltConnection; + private final boolean useCatalogTable; + + FireboltEngineInformationSchemaServiceTest(boolean useCatalogTable) { + this.useCatalogTable = useCatalogTable; + } + + @BeforeEach + void init() throws SQLException { + PreparedStatement catalogsStatement = mock(PreparedStatement.class); + Map catalogsRsData = useCatalogTable ? Map.of("table_name", "catalogs") : Map.of(); + ResultSet catalogsResultSet = mockedResultSet(catalogsRsData); + when(fireboltConnection.prepareStatement("SELECT table_name FROM information_schema.tables WHERE table_name=?")).thenReturn(catalogsStatement); + when(catalogsStatement.executeQuery()).thenReturn(catalogsResultSet); + fireboltEngineService = new FireboltEngineInformationSchemaService(fireboltConnection); + } @Test void shouldThrowExceptionEngineWhenEngineNameIsNotProvided() { @@ -86,18 +100,6 @@ void shouldThrowExceptionWhenSomethingIsWrong(String engineName, String db, Stri Mockito.verify(statement, Mockito.times(1)).setString(1, engineName); } - @ParameterizedTest - @CsvSource(value = {"mydb;'';false", "other_db;'database_name,other_db';true"}, delimiter = ';') - void doesDatabaseExist(String db, String row, boolean expected) throws SQLException { - PreparedStatement statement = mock(PreparedStatement.class); - Map rowData = row == null || row.isEmpty() ? Map.of() : Map.of(row.split(",")[0], row.split(",")[1]); - ResultSet resultSet = mockedResultSet(rowData); - when(fireboltConnection.prepareStatement("SELECT database_name FROM information_schema.databases WHERE database_name=?")).thenReturn(statement); - when(statement.executeQuery()).thenReturn(resultSet); - assertEquals(expected, fireboltEngineService.doesDatabaseExist(db)); - Mockito.verify(statement, Mockito.times(1)).setString(1, db); - } - private PreparedStatement mockedEntityStatement(String entity, String row) throws SQLException { if (row == null) { return null; @@ -109,7 +111,7 @@ private PreparedStatement mockedEntityStatement(String entity, String row) throw return statement; } - private ResultSet mockedResultSet(Map values) throws SQLException { + protected ResultSet mockedResultSet(Map values) throws SQLException { ResultSet resultSet = mock(ResultSet.class); if (values == null || values.isEmpty()) { when(resultSet.next()).thenReturn(false); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingCatalogsTableTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingCatalogsTableTest.java new file mode 100644 index 000000000..bd8670407 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingCatalogsTableTest.java @@ -0,0 +1,33 @@ +package com.firebolt.jdbc.service; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mockito; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class FireboltEngineInformationSchemaServiceUsingCatalogsTableTest extends FireboltEngineInformationSchemaServiceTest{ + FireboltEngineInformationSchemaServiceUsingCatalogsTableTest() { + super(true); + } + + @ParameterizedTest + @CsvSource(value = {"mydb;'';false", "other_db;'database_name,other_db';true"}, delimiter = ';') + void doesDatabaseExist(String db, String row, boolean expected) throws SQLException { + PreparedStatement statement = mock(PreparedStatement.class); + Map rowData = row == null || row.isEmpty() ? Map.of() : Map.of(row.split(",")[0], row.split(",")[1]); + ResultSet resultSet = mockedResultSet(rowData); + when(fireboltConnection.prepareStatement("SELECT catalog_name FROM information_schema.catalogs WHERE catalog_name=?")).thenReturn(statement); + when(statement.executeQuery()).thenReturn(resultSet); + assertEquals(expected, fireboltEngineService.doesDatabaseExist(db)); + Mockito.verify(statement, Mockito.times(1)).setString(1, db); + } + +} diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingDatabasesTableTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingDatabasesTableTest.java new file mode 100644 index 000000000..aebc6412a --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaServiceUsingDatabasesTableTest.java @@ -0,0 +1,7 @@ +package com.firebolt.jdbc.service; + +class FireboltEngineInformationSchemaServiceUsingDatabasesTableTest extends FireboltEngineInformationSchemaServiceTest{ + FireboltEngineInformationSchemaServiceUsingDatabasesTableTest() { + super(false); + } +} From bb2e0d8a136769838a43a3bb55bfaf83735a4615 Mon Sep 17 00:00:00 2001 From: Alexander Radzin Date: Wed, 19 Jun 2024 23:05:50 +0300 Subject: [PATCH 21/52] FIR-33627: json formatted server error (#426) --- .../java/integration/tests/StatementTest.java | 20 ++ .../integration/tests/SystemEngineTest.java | 22 +- .../firebolt/jdbc/client/FireboltClient.java | 62 +++++- .../firebolt/jdbc/exception/ServerError.java | 210 ++++++++++++++++++ .../jdbc/client/FireboltClientTest.java | 19 +- .../jdbc/exception/ServerErrorTest.java | 34 +++ 6 files changed, 358 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/exception/ServerError.java create mode 100644 src/test/java/com/firebolt/jdbc/exception/ServerErrorTest.java diff --git a/src/integrationTest/java/integration/tests/StatementTest.java b/src/integrationTest/java/integration/tests/StatementTest.java index 05331d865..2ed7ccc51 100644 --- a/src/integrationTest/java/integration/tests/StatementTest.java +++ b/src/integrationTest/java/integration/tests/StatementTest.java @@ -3,6 +3,7 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.FireboltException; import integration.ConnectionInfo; +import integration.EnvironmentCondition; import integration.IntegrationTest; import kotlin.collections.ArrayDeque; import org.hamcrest.Matchers; @@ -99,6 +100,25 @@ void shouldThrowExceptionWhenTryingToReuseStatementClosedOnCompletion() throws S } } + @Test + void shouldThrowExceptionWhenExecutingWrongQuery() throws SQLException { + try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { + String errorMessage = assertThrows(FireboltException.class, () -> statement.executeQuery("select wrong query")).getMessage(); + assertTrue(errorMessage.contains("Column 'wrong' does not exist.")); + } + } + + @Test + @EnvironmentCondition(value = "4.2.0", comparison = EnvironmentCondition.Comparison.GE) + void shouldThrowExceptionWhenExecutingWrongQueryWithJsonError() throws SQLException { + try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { + statement.execute("set advanced_mode=1"); + statement.execute("set enable_json_error_output_format=true"); + String errorMessage = assertThrows(FireboltException.class, () -> statement.executeQuery("select wrong query")).getMessage(); + assertTrue(errorMessage.contains("Column 'wrong' does not exist.")); + } + } + @Test void shouldReturnTrueWhenExecutingAStatementThatReturnsAResultSet() throws SQLException { try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 6ba024310..7b40c7293 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -38,6 +38,7 @@ import java.util.stream.Stream; import static com.firebolt.jdbc.connection.FireboltConnectionUserPassword.SYSTEM_ENGINE_NAME; +import static integration.EnvironmentCondition.Attribute.fireboltVersion; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Map.entry; @@ -91,6 +92,25 @@ void shouldSelect1() throws SQLException { } } + @Test + void shouldThrowExceptionWhenExecutingWrongQuery() throws SQLException { + try (Connection connection = createConnection(getSystemEngineName()); Statement statement = connection.createStatement()) { + String errorMessage = assertThrows(FireboltException.class, () -> statement.executeQuery("select wrong query")).getMessage(); + assertTrue(errorMessage.contains("Column 'wrong' does not exist.")); + } + } + + @Test + @EnvironmentCondition(value = "4.2.0", attribute = fireboltVersion, comparison = EnvironmentCondition.Comparison.GE) + void shouldThrowExceptionWhenExecutingWrongQueryWithJsonError() throws SQLException { + try (Connection connection = createConnection(getSystemEngineName()); Statement statement = connection.createStatement()) { + statement.execute("set advanced_mode=1"); + statement.execute("set enable_json_error_output_format=true"); + String errorMessage = assertThrows(FireboltException.class, () -> statement.executeQuery("select wrong query")).getMessage(); + assertTrue(errorMessage.contains("Column 'wrong' does not exist.")); + } + } + @Test void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { ConnectionInfo current = integration.ConnectionInfo.getInstance(); @@ -103,7 +123,7 @@ void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { Collection expectedErrorMessages = Set.of( "Queries against table dummy require a user engine", "The system engine doesn't support queries against table dummy. Run this query on a user engine.", - "Line 1, Column 22: relation \"dummy\" does not exist"); + "relation \"dummy\" does not exist"); try (Connection systemConnection = DriverManager.getConnection(systemEngineJdbcUrl, principal, secret); Connection customConnection = DriverManager.getConnection(customEngineJdbcUrl, principal, secret)) { diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index 29c9e93d0..f7b597846 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -3,6 +3,8 @@ import com.firebolt.jdbc.connection.CacheListener; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.exception.ServerError; +import com.firebolt.jdbc.exception.ServerError.Error.Location; import com.firebolt.jdbc.resultset.compress.LZ4InputStream; import com.firebolt.jdbc.util.CloseableUtil; import lombok.Getter; @@ -13,6 +15,7 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; @@ -24,13 +27,17 @@ import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.lang.String.format; @@ -46,6 +53,7 @@ public abstract class FireboltClient implements CacheListener { private static final String HEADER_USER_AGENT = "User-Agent"; private static final String HEADER_PROTOCOL_VERSION = "Firebolt-Protocol-Version"; private static final Logger log = Logger.getLogger(FireboltClient.class.getName()); + private static final Pattern plainErrorPattern = Pattern.compile("Line (\\d+), Column (\\d+): (.*)$", Pattern.MULTILINE); private final OkHttpClient httpClient; private final String headerUserAgentValue; protected final FireboltConnection connection; @@ -142,17 +150,19 @@ protected void validateResponse(String host, Response response, Boolean isCompre throw new FireboltException(format("Could not query Firebolt at %s. The engine is not running.", host), statusCode); } String errorMessageFromServer = extractErrorMessage(response, isCompress); - validateResponse(host, statusCode, errorMessageFromServer); + ServerError serverError = parseServerError(errorMessageFromServer); + String processedErrorMessage = serverError.getErrorMessage(); + validateResponse(host, statusCode, processedErrorMessage); String errorResponseMessage = format( "Server failed to execute query with the following error:%n%s%ninternal error:%n%s", - errorMessageFromServer, getInternalErrorWithHeadersText(response)); + processedErrorMessage, getInternalErrorWithHeadersText(response)); if (statusCode == HTTP_UNAUTHORIZED) { getConnection().removeExpiredTokens(); throw new FireboltException(format( "Could not query Firebolt at %s. The operation is not authorized or the token is expired and has been cleared from the cache.%n%s", - host, errorResponseMessage), statusCode, errorMessageFromServer); + host, errorResponseMessage), statusCode, processedErrorMessage); } - throw new FireboltException(errorResponseMessage, statusCode, errorMessageFromServer); + throw new FireboltException(errorResponseMessage, statusCode, processedErrorMessage); } } @@ -194,6 +204,50 @@ private String extractErrorMessage(Response response, boolean isCompress) throws return new String(entityBytes, StandardCharsets.UTF_8); } + private ServerError parseServerError(String responseText) { + try { + if (responseText == null) { + return new ServerError(null, null); + } + ServerError serverError = new ServerError(new JSONObject(responseText)); + ServerError.Error[] errors = serverError.getErrors() == null ? null : Arrays.stream(serverError.getErrors()).map(this::updateError).toArray(ServerError.Error[]::new); + return new ServerError(serverError.getQuery(), errors); + } catch (JSONException e) { + String message = responseText; + Location location = null; + Entry locationAndText = getLocationFromMessage(responseText); + if (locationAndText != null) { + location = locationAndText.getKey(); + message = locationAndText.getValue(); + } + return new ServerError(null, new ServerError.Error[] {new ServerError.Error(null, message, null, null, null, null, null, location)}); + } + } + + private ServerError.Error updateError(ServerError.Error error) { + if (error == null || error.getDescription() == null) { + return error; + } + Entry locationAndText = getLocationFromMessage(error.getDescription()); + if (locationAndText == null) { + return error; + } + Location location = Objects.requireNonNullElse(error.getLocation(), locationAndText.getKey()); + return new ServerError.Error(error.getCode(), error.getName(), error.getSeverity(), error.getSource(), + locationAndText.getValue(), error.getResolution(), error.getHelpLink(), location); + } + + private Entry getLocationFromMessage(String responseText) { + Matcher m = plainErrorPattern.matcher(responseText); + if (m.find()) { + int line = Integer.parseInt(m.group(1)); + int column = Integer.parseInt(m.group(2)); + String message = m.group(3); + return Map.entry(new Location(line, column, column), message); + } + return null; + } + protected boolean isCallSuccessful(int statusCode) { return statusCode >= 200 && statusCode <= 299; // Call is considered successful when the status code is 2XX } diff --git a/src/main/java/com/firebolt/jdbc/exception/ServerError.java b/src/main/java/com/firebolt/jdbc/exception/ServerError.java new file mode 100644 index 000000000..80e756984 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/exception/ServerError.java @@ -0,0 +1,210 @@ +package com.firebolt.jdbc.exception; + +import lombok.Getter; +import lombok.ToString; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toUnmodifiableMap; + +@Getter +@ToString +public class ServerError { + private final Query query; + private final Error[] errors; + + public ServerError(Query query, Error[] errors) { + this.query = query; + this.errors = errors; + } + + public ServerError(JSONObject json) { + this(fromJson(json.optJSONObject("query"), Query::new), fromJson(json.optJSONArray("errors"), Error::new, Error[]::new)); + } + + private static T[] fromJson(JSONArray jsonArray, Function factory, IntFunction arrayFactory) { + return jsonArray == null ? null : IntStream.range(0, jsonArray.length()).boxed().map(jsonArray::getJSONObject).map(factory).toArray(arrayFactory); + } + + private static T fromJson(JSONObject json, Function factory) { + return ofNullable(json).map(factory).orElse(null); + } + + public String getErrorMessage() { + return errors == null ? + null + : + Arrays.stream(errors) + .filter(Objects::nonNull) + .map(e -> Stream.of(e.severity, e.source, e.code, e.name, e.description).filter(Objects::nonNull).map(Object::toString).collect(joining(" "))) + .collect(joining("; ")); + } + + public Query getQuery() { + return query; + } + + public Error[] getErrors() { + return errors; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ServerError that = (ServerError) o; + return Objects.equals(query, that.query) && Objects.deepEquals(errors, that.errors); + } + + @Override + public int hashCode() { + return Objects.hash(query, Arrays.hashCode(errors)); + } + + @Getter + @ToString + public static class Query { + private final String queryId; + private final String requestId; + private final String queryLabel; + + public Query(String queryId, String requestId, String queryLabel) { + this.queryId = queryId; + this.requestId = requestId; + this.queryLabel = queryLabel; + } + + Query(JSONObject json) { + this(json.optString("query_id", null), json.optString("request_id", null), json.optString("query_label", null)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Query query = (Query) o; + return Objects.equals(queryId, query.queryId) && Objects.equals(requestId, query.requestId) && Objects.equals(queryLabel, query.queryLabel); + } + + @Override + public int hashCode() { + return Objects.hash(queryId, requestId, queryLabel); + } + } + + @Getter + @ToString + public static class Error { + private final String code; + private final String name; + private final Severity severity; + private final Source source; + private final String description; + private final String resolution; + private final String helpLink; + private final Location location; + + @SuppressWarnings("java:S107") // the price of the immutability + public Error(String code, String name, Severity severity, Source source, String description, String resolution, String helpLink, Location location) { + this.code = code; + this.name = name; + this.severity = severity; + this.source = source; + this.description = description; + this.resolution = resolution; + this.helpLink = helpLink; + this.location = location; + } + + Error(JSONObject json) { + this(json.optString("code", null), json.optString("name", null), + json.optEnum(Severity.class, "severity"), + ofNullable(json.optString("source", null)).map(Source::fromText).orElse(Source.UNKNOWN), + json.optString("description", null), json.optString("resolution", null), json.optString("helpLink", null), + ofNullable(json.optJSONObject("location", null)).map(Location::new).orElse(null)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Error error = (Error) o; + return Objects.equals(code, error.code) && Objects.equals(name, error.name) && severity == error.severity && source == error.source && Objects.equals(description, error.description) && Objects.equals(resolution, error.resolution) && Objects.equals(helpLink, error.helpLink) && Objects.equals(location, error.location); + } + + @Override + public int hashCode() { + return Objects.hash(code, name, severity, source, description, resolution, helpLink, location); + } + + public enum Severity { + ERROR, WARNING, + } + + public enum Source { + SYSTEM_ERROR("System Error"), + USER_ERROR("User Error"), + UNKNOWN("Unknown"), + USER_WARNING("User Warning"), + SYSTEM_WARNING("System Warning"), + SYSTEM_SEVIER_WARNING("System Sevier Warning"), + ; + private final String text; + private static final Map textToSource = Arrays.stream(values()).collect(toUnmodifiableMap(e -> e.text, e -> e)); + + Source(String text) { + this.text = text; + } + + public static Source fromText(String text) { + return textToSource.get(text); + } + + @Override + public String toString() { + return text; + } + } + + @Getter + @ToString + public static class Location { + private final int failingLine; + private final int startOffset; + private final int endOffset; + + public Location(int failingLine, int startOffset, int endOffset) { + this.failingLine = failingLine; + this.startOffset = startOffset; + this.endOffset = endOffset; + } + + Location(JSONObject json) { + this(json.optInt("failingLine"), json.optInt("startOffset"), json.optInt("endOffset")); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Location location = (Location) o; + return failingLine == location.failingLine && startOffset == location.startOffset && endOffset == location.endOffset; + } + + @Override + public int hashCode() { + return Objects.hash(failingLine, startOffset, endOffset); + } + } + } +} diff --git a/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java b/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java index b5ff5cc9d..fa0212048 100644 --- a/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/FireboltClientTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; @@ -104,8 +105,18 @@ void cannotExtractCompressedErrorMessage() throws IOException { } } - @Test - void canExtractErrorMessage() throws IOException { + // FIR-33934: This test does not validate the fields of ServerError except error message including Location because this information is not exposed to FireboltException + @ParameterizedTest + @CsvSource(value = { + "Error happened; Error happened", + "Error happened on server: Line 16, Column 64: Something bad happened; Something bad happened", + "{}; null", + "{\"errors:\": [null]}; null", + "{errors: [{\"name\": \"Something wrong happened\"}]}; Something wrong happened", + "{errors: [{\"description\": \"Error happened on server: Line 16, Column 64: Something bad happened\"}]}; Something bad happened", + "{errors: [{\"description\": \"Error happened on server: Line 16, Column 64: Something bad happened\", \"location\": {\"failingLine\": 20, \"startOffset\": 30, \"endOffset\": 40}}]}; Something bad happened" + }, delimiter = ';') + void canExtractErrorMessage(String rawMessage, String expectedMessage) throws IOException { try (Response response = mock(Response.class)) { when(response.code()).thenReturn(HTTP_NOT_FOUND); ResponseBody responseBody = mock(ResponseBody.class); @@ -113,7 +124,7 @@ void canExtractErrorMessage() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream compressedStream = new LZ4OutputStream(baos, 100); - compressedStream.write("Error happened".getBytes()); + compressedStream.write(rawMessage.getBytes()); compressedStream.flush(); compressedStream.close(); when(responseBody.bytes()).thenReturn(baos.toByteArray()); // compressed error message @@ -121,7 +132,7 @@ void canExtractErrorMessage() throws IOException { FireboltClient client = Mockito.mock(FireboltClient.class, Mockito.CALLS_REAL_METHODS); FireboltException e = assertThrows(FireboltException.class, () -> client.validateResponse("the_host", response, true)); assertEquals(ExceptionType.RESOURCE_NOT_FOUND, e.getType()); - assertTrue(e.getMessage().contains("Error happened")); // compressed error message is used as-is + assertTrue(e.getMessage().contains(expectedMessage)); // compressed error message is used as-is } } diff --git a/src/test/java/com/firebolt/jdbc/exception/ServerErrorTest.java b/src/test/java/com/firebolt/jdbc/exception/ServerErrorTest.java new file mode 100644 index 000000000..dc01ab015 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/exception/ServerErrorTest.java @@ -0,0 +1,34 @@ +package com.firebolt.jdbc.exception; + +import org.json.JSONObject; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static com.firebolt.jdbc.exception.ServerError.Error; +import static com.firebolt.jdbc.exception.ServerError.Error.Location; +import static com.firebolt.jdbc.exception.ServerError.Error.Severity; +import static com.firebolt.jdbc.exception.ServerError.Error.Source; +import static com.firebolt.jdbc.exception.ServerError.Query; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ServerErrorTest { + protected static Stream parse() { + return Stream.of( + Arguments.of("{}", new ServerError(null, null)), + Arguments.of("{\"query\": {}, \"errors\": []}", new ServerError(new Query(null, null, null), new Error[0])), + Arguments.of("{\"query\": {\"query_id\": \"qid\", \"request_id\": \"rid\", \"query_label\": \"ql\"}, \"errors\": []}", new ServerError(new Query("qid", "rid", "ql"), new Error[0])), + Arguments.of("{\"errors\": [{}]}", new ServerError(null, new Error[] {new Error(null, null, null, Source.UNKNOWN, null, null, null, null)})), + Arguments.of("{\"errors\": [{\"code\": \"c1\", \"name\": \"name1\", \"severity\": \"ERROR\", \"source\": \"System Error\", \"description\": \"description1\", \"resolution\": \"resolution1\", \"helpLink\": \"http://help1.com\", \"location\": {\"failingLine\": 1, \"startOffset\": 10, \"endOffset\": 100}}]}", + new ServerError(null, new Error[] {new Error("c1", "name1", Severity.ERROR, Source.SYSTEM_ERROR, "description1", "resolution1", "http://help1.com", new Location(1, 10, 100))})) + ); + } + + @ParameterizedTest + @MethodSource("parse") + void parse(String json, ServerError expected) { + assertEquals(expected, new ServerError(new JSONObject(json))); + } +} From 59750f751101ea02f480afc7d22db2c5f88a7076 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:28:49 +0100 Subject: [PATCH 22/52] feat(FIR-34158): populating SQLState in firebolt errors (#432) --- .../firebolt/jdbc/client/FireboltClient.java | 10 +- .../jdbc/exception/FireboltException.java | 22 +++ .../com/firebolt/jdbc/exception/SQLState.java | 131 ++++++++++++++++++ .../FireboltAuthenticationService.java | 7 +- .../FireboltAuthenticationClientTest.java | 19 ++- .../gateway/FireboltGatewayUrlClientTest.java | 9 +- .../FireboltAuthenticationServiceTest.java | 18 +++ 7 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/exception/SQLState.java diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index f7b597846..042d32afc 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -3,6 +3,7 @@ import com.firebolt.jdbc.connection.CacheListener; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.exception.SQLState; import com.firebolt.jdbc.exception.ServerError; import com.firebolt.jdbc.exception.ServerError.Error.Location; import com.firebolt.jdbc.resultset.compress.LZ4InputStream; @@ -41,6 +42,7 @@ import java.util.stream.Collectors; import static java.lang.String.format; +import static java.net.HttpURLConnection.HTTP_FORBIDDEN; import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; import static java.util.Optional.ofNullable; @@ -147,7 +149,8 @@ protected void validateResponse(String host, Response response, Boolean isCompre int statusCode = response.code(); if (!isCallSuccessful(statusCode)) { if (statusCode == HTTP_UNAVAILABLE) { - throw new FireboltException(format("Could not query Firebolt at %s. The engine is not running.", host), statusCode); + throw new FireboltException(format("Could not query Firebolt at %s. The engine is not running.", host), + statusCode, SQLState.CONNECTION_FAILURE); } String errorMessageFromServer = extractErrorMessage(response, isCompress); ServerError serverError = parseServerError(errorMessageFromServer); @@ -156,11 +159,12 @@ protected void validateResponse(String host, Response response, Boolean isCompre String errorResponseMessage = format( "Server failed to execute query with the following error:%n%s%ninternal error:%n%s", processedErrorMessage, getInternalErrorWithHeadersText(response)); - if (statusCode == HTTP_UNAUTHORIZED) { + if (statusCode == HTTP_UNAUTHORIZED || statusCode == HTTP_FORBIDDEN) { getConnection().removeExpiredTokens(); throw new FireboltException(format( "Could not query Firebolt at %s. The operation is not authorized or the token is expired and has been cleared from the cache.%n%s", - host, errorResponseMessage), statusCode, processedErrorMessage); + host, errorResponseMessage), statusCode, processedErrorMessage, + SQLState.INVALID_AUTHORIZATION_SPECIFICATION); } throw new FireboltException(errorResponseMessage, statusCode, processedErrorMessage); } diff --git a/src/main/java/com/firebolt/jdbc/exception/FireboltException.java b/src/main/java/com/firebolt/jdbc/exception/FireboltException.java index 4c0ead1de..ede3445a9 100644 --- a/src/main/java/com/firebolt/jdbc/exception/FireboltException.java +++ b/src/main/java/com/firebolt/jdbc/exception/FireboltException.java @@ -39,10 +39,20 @@ public FireboltException(String message, Integer httpStatusCode, String errorMes this.errorMessageFromServer = errorMessageFromServer; } + public FireboltException(String message, Integer httpStatusCode, String errorMessageFromServer, SQLState state) { + super(message, state.getCode()); + type = getExceptionType(httpStatusCode); + this.errorMessageFromServer = errorMessageFromServer; + } + public FireboltException(String message, Throwable cause) { this(message, cause, ExceptionType.ERROR); } + public FireboltException(String message, Throwable cause, SQLState state) { + this(message, cause, ExceptionType.ERROR, state); + } + public FireboltException(String message, ExceptionType type) { super(message); this.type = type; @@ -59,6 +69,18 @@ public FireboltException(String message, Throwable cause, ExceptionType type) { errorMessageFromServer = null; } + public FireboltException(String message, Throwable cause, ExceptionType type, SQLState state) { + super(message, state.getCode(), cause); + this.type = type; + errorMessageFromServer = null; + } + + public FireboltException(String message, int httpStatusCode, SQLState state) { + super(message, state.getCode()); + type = getExceptionType(httpStatusCode); + errorMessageFromServer = null; + } + private static ExceptionType getExceptionType(Integer httpStatusCode) { if (httpStatusCode == null) { return ERROR; diff --git a/src/main/java/com/firebolt/jdbc/exception/SQLState.java b/src/main/java/com/firebolt/jdbc/exception/SQLState.java new file mode 100644 index 000000000..620118566 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/exception/SQLState.java @@ -0,0 +1,131 @@ +package com.firebolt.jdbc.exception; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +// https://en.wikipedia.org/wiki/SQLSTATE +public enum SQLState { + SUCCESS("00000"), + WARNING("01000"), + NO_DATA("02000"), + STATEMENT_STRING_DATA_RIGHT_TRUNCATION("01004"), + NULL_VALUE_NO_INDICATOR_PARAMETER("22002"), + CONNECTION_EXCEPTION("08001"), + CONNECTION_DOES_NOT_EXIST("08003"), + CONNECTION_FAILURE("08006"), + TRANSACTION_RESOLUTION_UNKNOWN("08007"), + SQL_SYNTAX_ERROR("42000"), + SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION("42601"), + DUPLICATE_KEY_VALUE("23505"), + DATA_EXCEPTION("22000"), + CHARACTER_NOT_IN_REPERTOIRE("22021"), + STRING_DATA_RIGHT_TRUNCATION("22001"), + NUMERIC_VALUE_OUT_OF_RANGE("22003"), + INVALID_DATETIME_FORMAT("22007"), + INVALID_TIME_ZONE_DISPLACEMENT_VALUE("22009"), + INVALID_ESCAPE_CHARACTER("22019"), + INVALID_PARAMETER_VALUE("22023"), + INVALID_CURSOR_STATE("24000"), + INVALID_TRANSACTION_STATE("25000"), + INVALID_AUTHORIZATION_SPECIFICATION("28000"), + INVALID_SQL_STATEMENT_NAME("26000"), + INVALID_CURSOR_NAME("34000"), + INVALID_SCHEMA_NAME("3F000"), + TRANSACTION_ROLLBACK("40000"), + SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION_IN_DIRECT_STATEMENT("2F000"), + INVALID_SQL_DESCRIPTOR_NAME("33000"), + INVALID_CURSOR_POSITION("34000"), + INVALID_CONDITION_NUMBER("35000"), + INVALID_TRANSACTION_TERMINATION("2D000"), + INVALID_CONNECTION_NAME("2E000"), + INVALID_AUTHORIZATION_NAME("28000"), + INVALID_COLUMN_NAME("42703"), + INVALID_COLUMN_DEFINITION("42P16"), + INVALID_CURSOR_DEFINITION("42P11"), + INVALID_DATABASE_DEFINITION("42P15"), + INVALID_FUNCTION_DEFINITION("42P13"), + INVALID_PREPARED_STATEMENT_DEFINITION("42P12"), + INVALID_SCHEMA_DEFINITION("42P14"), + INVALID_TABLE_DEFINITION("42P01"), + INVALID_OBJECT_DEFINITION("42P17"), + WITH_CHECK_OPTION_VIOLATION("44000"), + INSUFFICIENT_RESOURCES("53000"), + DISK_FULL("53100"), + OUT_OF_MEMORY("53200"), + TOO_MANY_CONNECTIONS("53300"), + CONFIGURATION_LIMIT_EXCEEDED("53400"), + PROGRAM_LIMIT_EXCEEDED("54000"), + OBJECT_NOT_IN_PREREQUISITE_STATE("55000"), + OBJECT_IN_USE("55006"), + CANT_CHANGE_RUNTIME_PARAM("55P02"), + LOCK_NOT_AVAILABLE("55P03"), + OPERATOR_INTERVENTION("57000"), + QUERY_CANCELED("57014"), + ADMIN_SHUTDOWN("57P01"), + CRASH_SHUTDOWN("57P02"), + CANNOT_CONNECT_NOW("57P03"), + DATABASE_DROPPED("57P04"), + SYSTEM_ERROR("58000"), + IO_ERROR("58030"), + UNDEFINED_FILE("58P01"), + DUPLICATE_FILE("58P02"), + SNAPSHOT_TOO_OLD("72000"), + CONFIGURATION_FILE_ERROR("F0000"), + LOCK_FILE_EXISTS("F0001"), + FDW_ERROR("HV000"), + FDW_COLUMN_NAME_NOT_FOUND("HV005"), + FDW_DYNAMIC_PARAMETER_VALUE_NEEDED("HV002"), + FDW_FUNCTION_SEQUENCE_ERROR("HV010"), + FDW_INCONSISTENT_DESCRIPTOR_INFORMATION("HV021"), + FDW_INVALID_ATTRIBUTE_VALUE("HV024"), + FDW_INVALID_COLUMN_NAME("HV007"), + FDW_INVALID_COLUMN_NUMBER("HV008"), + FDW_INVALID_DATA_TYPE("HV004"), + FDW_INVALID_DATA_TYPE_DESCRIPTORS("HV006"), + FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER("HV091"), + FDW_INVALID_HANDLE("HV00B"), + FDW_INVALID_OPTION_INDEX("HV00C"), + FDW_INVALID_OPTION_NAME("HV00D"), + FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH("HV090"), + FDW_INVALID_STRING_FORMAT("HV00A"), + FDW_INVALID_USE_OF_NULL_POINTER("HV009"), + FDW_TOO_MANY_HANDLES("HV014"), + FDW_OUT_OF_MEMORY("HV001"), + FDW_NO_SCHEMAS("HV00P"), + FDW_OPTION_NAME_NOT_FOUND("HV00J"), + FDW_REPLY_HANDLE("HV00K"), + FDW_SCHEMA_NOT_FOUND("HV00Q"), + FDW_TABLE_NOT_FOUND("HV00R"), + FDW_UNABLE_TO_CREATE_EXECUTION("HV00L"), + FDW_UNABLE_TO_CREATE_REPLY("HV00M"), + FDW_UNABLE_TO_ESTABLISH_CONNECTION("HV00N"), + PLPGSQL_ERROR("P0000"), + RAISE_EXCEPTION("P0001"), + NO_DATA_FOUND("P0002"), + TOO_MANY_ROWS("P0003"), + ASSERT_FAILURE("P0004"), + INTERNAL_ERROR("XX000"), + DATA_CORRUPTED("XX001"), + INDEX_CORRUPTED("XX002"), + STATE_NOT_DEFINED(null); + + private final String code; + private static final Map codeMap = new HashMap<>(); + static { + for (SQLState s : EnumSet.allOf(SQLState.class)) + codeMap.put(s.getCode(), s); + } + + SQLState(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static SQLState fromCode(String sqlState) { + return codeMap.get(sqlState); + } +} diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java index a540a1153..a03c27867 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java @@ -4,6 +4,8 @@ import com.firebolt.jdbc.connection.FireboltConnectionTokens; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.exception.SQLState; + import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import net.jodah.expiringmap.ExpiringMap; @@ -51,7 +53,8 @@ public FireboltConnectionTokens getConnectionTokens(String host, FireboltPropert } catch (FireboltException e) { log.log(Level.SEVERE, "Failed to connect to Firebolt", e); String msg = ofNullable(e.getErrorMessageFromServer()).map(m -> format(ERROR_MESSAGE_FROM_SERVER, m)).orElse(format(ERROR_MESSAGE, e.getMessage())); - throw new FireboltException(msg, e); + SQLState sqlState = SQLState.fromCode(e.getSQLState()); + throw new FireboltException(msg, e, sqlState); } catch (Exception e) { log.log(Level.SEVERE, "Failed to connect to Firebolt", e); throw new FireboltException(format(ERROR_MESSAGE, e.getMessage()), e); @@ -69,7 +72,7 @@ private long getCachingDurationInSeconds(long expireInSeconds) { /** * Removes connection tokens from the cache. - * + * * @param host host * @param loginProperties the login properties linked to the tokens */ diff --git a/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java b/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java index c120e3378..a65a1ae27 100644 --- a/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClientTest.java @@ -3,6 +3,8 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.FireboltConnectionTokens; import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.exception.SQLState; + import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -24,6 +26,7 @@ import static java.net.HttpURLConnection.HTTP_FORBIDDEN; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -118,7 +121,21 @@ void shouldThrowExceptionWhenStatusCodeIsForbidden() throws Exception { when(response.code()).thenReturn(HTTP_FORBIDDEN); when(httpClient.newCall(any())).thenReturn(call); - assertThrows(FireboltException.class, + FireboltException ex = assertThrows(FireboltException.class, + () -> fireboltAuthenticationClient.postConnectionTokens(HOST, USER, PASSWORD, ENV)); + assertEquals(SQLState.INVALID_AUTHORIZATION_SPECIFICATION.getCode(), ex.getSQLState()); + } + + @Test + void shouldThrowExceptionWhenStatusCodeIsUnavailable() throws Exception { + Response response = mock(Response.class); + Call call = mock(Call.class); + when(call.execute()).thenReturn(response); + when(response.code()).thenReturn(HTTP_UNAVAILABLE); + when(httpClient.newCall(any())).thenReturn(call); + + FireboltException ex = assertThrows(FireboltException.class, () -> fireboltAuthenticationClient.postConnectionTokens(HOST, USER, PASSWORD, ENV)); + assertEquals(SQLState.CONNECTION_FAILURE.getCode(), ex.getSQLState()); } } diff --git a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java index 83e6b0160..360eac32b 100644 --- a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java @@ -138,7 +138,6 @@ private FireboltAccountRetriever mockAccountRetriever(String path, Class< @CsvSource({ HTTP_BAD_REQUEST + "," + GENERIC_ERROR_MESSAGE, HTTP_PAYMENT_REQUIRED + "," + GENERIC_ERROR_MESSAGE, - HTTP_FORBIDDEN + "," + GENERIC_ERROR_MESSAGE, HTTP_BAD_METHOD + "," + GENERIC_ERROR_MESSAGE, HTTP_NOT_ACCEPTABLE + "," + GENERIC_ERROR_MESSAGE, HTTP_PROXY_AUTH + "," + GENERIC_ERROR_MESSAGE, @@ -157,8 +156,12 @@ private FireboltAccountRetriever mockAccountRetriever(String path, Class< HTTP_VERSION + "," + GENERIC_ERROR_MESSAGE, HTTP_NOT_FOUND + "," + "Account '%s' does not exist", - HTTP_UNAVAILABLE + "," + "Could not query Firebolt at https://test-firebolt.io/web/v3/account/%s/%s. The engine is not running.", - HTTP_UNAUTHORIZED + "," + "Could not query Firebolt at https://test-firebolt.io/web/v3/account/%s/%s. The operation is not authorized" + HTTP_UNAVAILABLE + "," + + "Could not query Firebolt at https://test-firebolt.io/web/v3/account/%s/%s. The engine is not running.", + HTTP_FORBIDDEN + "," + + "Could not query Firebolt at https://test-firebolt.io/web/v3/account/%s/%s. The operation is not authorized", + HTTP_UNAUTHORIZED + "," + + "Could not query Firebolt at https://test-firebolt.io/web/v3/account/%s/%s. The operation is not authorized" }) void testFailedAccountDataRetrieving(int statusCode, String errorMessageTemplate) throws IOException { injectMockedResponse(httpClient, statusCode, null); diff --git a/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java b/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java index 38d638603..6c05ae6ed 100644 --- a/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java +++ b/src/test/java/com/firebolt/jdbc/service/FireboltAuthenticationServiceTest.java @@ -20,6 +20,7 @@ import com.firebolt.jdbc.connection.FireboltConnectionTokens; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; +import com.firebolt.jdbc.exception.SQLState; @ExtendWith(MockitoExtension.class) class FireboltAuthenticationServiceTest { @@ -80,6 +81,21 @@ void shouldGetConnectionTokenAfterRemoving() throws SQLException, IOException { @Test void shouldThrowExceptionWithServerResponseWhenAResponseIsAvailable() throws SQLException, IOException { + String randomHost = UUID.randomUUID().toString(); + Mockito.when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)) + .thenThrow(new FireboltException("An error happened during authentication", 403, "INVALID PASSWORD", + SQLState.INVALID_AUTHORIZATION_SPECIFICATION)); + + FireboltException ex = assertThrows(FireboltException.class, + () -> fireboltAuthenticationService.getConnectionTokens(randomHost, PROPERTIES)); + assertEquals( + "Failed to connect to Firebolt with the error from the server: INVALID PASSWORD, see logs for more info.", + ex.getMessage()); + assertEquals(SQLState.INVALID_AUTHORIZATION_SPECIFICATION.getCode(), ex.getSQLState()); + } + + @Test + void shouldThrowExceptionNoSQLStateWithServerResponseWhenAResponseIsAvailable() throws SQLException, IOException { String randomHost = UUID.randomUUID().toString(); Mockito.when(fireboltAuthenticationClient.postConnectionTokens(randomHost, USER, PASSWORD, ENV)) .thenThrow(new FireboltException("An error happened during authentication", 403, "INVALID PASSWORD")); @@ -89,6 +105,7 @@ void shouldThrowExceptionWithServerResponseWhenAResponseIsAvailable() throws SQL assertEquals( "Failed to connect to Firebolt with the error from the server: INVALID PASSWORD, see logs for more info.", ex.getMessage()); + assertEquals(null, ex.getSQLState()); } @Test @@ -100,6 +117,7 @@ void shouldThrowExceptionWithExceptionMessageWhenAResponseIsNotAvailable() throw FireboltException ex = assertThrows(FireboltException.class, () -> fireboltAuthenticationService.getConnectionTokens(randomHost, PROPERTIES)); assertEquals("Failed to connect to Firebolt with the error: NULL!, see logs for more info.", ex.getMessage()); + assertEquals(null, ex.getSQLState()); } } From b0bfc2d7dc136e62189ec4ebf0de03d469bc359b Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 10:48:13 +0300 Subject: [PATCH 23/52] ci: fix publishing action (#434) --- .github/workflows/release.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aa1e1b9df..e632b014e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,11 @@ name: Release new version on: release: types: [published] + workflow_dispatch: + inputs: + tag_name: + description: 'Tag name to publish' + required: true jobs: build: @@ -15,7 +20,7 @@ jobs: - name: Check out code uses: actions/checkout@v3 with: - ref: ${{ github.event.release.tag_name }} + ref: ${{ github.event.release.tag_name || github.event.inputs.tag_name}} - name: Download uber-jar uses: actions/download-artifact@v3 with: From 939e8009b20d0cd36f28488f45140278044d8766 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 11:08:40 +0300 Subject: [PATCH 24/52] build: migrate to yumi licenser (#435) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c034379e5..8b6e7f300 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "org.sonarqube" version "5.0.0.4638" id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.0.0' - id 'org.quiltmc.gradle.licenser' version '2.0.2' + id 'dev.yumi.gradle.licenser' version '1.2.0' id 'signing' } From 3f9974ca6928069bfddfcc9c7c52a336149cbd50 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 12:09:32 +0300 Subject: [PATCH 25/52] build: Update compilation version compatibility (#436) --- .github/workflows/release.yml | 2 +- build.gradle | 4 ++-- gradle.properties | 2 +- src/test/java/com/firebolt/FireboltDriverTest.java | 2 +- .../jdbc/metadata/FireboltDatabaseMetadataTest.java | 4 ++-- src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java | 6 ++---- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e632b014e..54570a393 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: file: ${{ needs.build.outputs.uber-jar }} tags: true draft: false - - name: Deploy to Repsy repository + - name: Deploy to Maven Central repository run: ./gradlew publish env: MAVEN_REPO_USERNAME: ${{ secrets.MAVEN_REPO_USERNAME }} diff --git a/build.gradle b/build.gradle index 8b6e7f300..721ce6a69 100644 --- a/build.gradle +++ b/build.gradle @@ -28,8 +28,8 @@ java { } compileJava { - sourceCompatibility = '11' - targetCompatibility = '11' + sourceCompatibility = '17' + targetCompatibility = '17' } configurations { diff --git a/gradle.properties b/gradle.properties index 749134fd2..79bf72343 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=3.0.4-SNAPSHOT +version=3.1.1 jdbcVersion=4.3 \ No newline at end of file diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index 7808418f4..4f3096780 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -93,7 +93,7 @@ void jdbcCompliant() { void version() { FireboltDriver fireboltDriver = new FireboltDriver(); assertEquals(3, fireboltDriver.getMajorVersion()); - assertEquals(0, fireboltDriver.getMinorVersion()); + assertEquals(1, fireboltDriver.getMinorVersion()); } @ParameterizedTest diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 806a25c7f..6825e1976 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -348,12 +348,12 @@ void shouldGetDriverMajorVersion() { @Test void shouldGetDriverMinorVersion() { - assertEquals(0, fireboltDatabaseMetadata.getDriverMinorVersion()); + assertEquals(1, fireboltDatabaseMetadata.getDriverMinorVersion()); } @Test void shouldGetDriverVersion() throws SQLException { - assertEquals("3.0.4-SNAPSHOT", fireboltDatabaseMetadata.getDriverVersion()); + assertEquals("3.1.1", fireboltDatabaseMetadata.getDriverVersion()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java index dbb4257e5..ae4a27381 100644 --- a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java @@ -13,13 +13,11 @@ void shouldGetDriverMajorVersion() { @Test void shouldGetDriverMinorVersion() { - assertEquals(0, VersionUtil.getDriverMinorVersion()); + assertEquals(1, VersionUtil.getDriverMinorVersion()); } @Test - void shouldGetProjectVersion() { - assertEquals("3.0.4-SNAPSHOT", VersionUtil.getDriverVersion()); - } + void shouldGetProjectVersion() { assertEquals("3.1.1", VersionUtil.getDriverVersion()); } @Test void shouldGetMinorVersionFromString() { From a671bfa4c18333f9444c7efeb9174f0d86a5b45b Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 12:20:03 +0300 Subject: [PATCH 26/52] build: reduce version (#437) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 79bf72343..9ffbf99dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=3.1.1 +version=3.1.0 jdbcVersion=4.3 \ No newline at end of file From 8ce630317712022742a651270f55291b13eae883 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 12:32:18 +0300 Subject: [PATCH 27/52] test: fix unit tests (#438) --- .../firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java | 2 +- src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 6825e1976..61789090b 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -353,7 +353,7 @@ void shouldGetDriverMinorVersion() { @Test void shouldGetDriverVersion() throws SQLException { - assertEquals("3.1.1", fireboltDatabaseMetadata.getDriverVersion()); + assertEquals("3.1.0", fireboltDatabaseMetadata.getDriverVersion()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java index ae4a27381..d4821cd04 100644 --- a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java @@ -17,7 +17,7 @@ void shouldGetDriverMinorVersion() { } @Test - void shouldGetProjectVersion() { assertEquals("3.1.1", VersionUtil.getDriverVersion()); } + void shouldGetProjectVersion() { assertEquals("3.1.0", VersionUtil.getDriverVersion()); } @Test void shouldGetMinorVersionFromString() { From ad60bfdfc1f8b85990fb7d8ebb36d4754037559b Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 12:52:27 +0300 Subject: [PATCH 28/52] build: remove redundant plugin (#439) --- build.gradle | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 721ce6a69..0ec9fd58f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ plugins { id "org.sonarqube" version "5.0.0.4638" id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.0.0' - id 'dev.yumi.gradle.licenser' version '1.2.0' id 'signing' } @@ -28,8 +27,8 @@ java { } compileJava { - sourceCompatibility = '17' - targetCompatibility = '17' + sourceCompatibility = '11' + targetCompatibility = '11' } configurations { From 805056a2b367360a5381a26f59ede600caa61994 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 13:37:48 +0300 Subject: [PATCH 29/52] build: remove signing of a build artifact (#440) --- build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build.gradle b/build.gradle index 0ec9fd58f..bb29269f4 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ plugins { id "org.sonarqube" version "5.0.0.4638" id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.0.0' - id 'signing' } group 'io.firebolt' @@ -335,11 +334,6 @@ task generateJavadoc(type: Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') } - -signing { - sign publishing.publications -} - if (hasProperty('buildScan')) { buildScan { termsOfServiceUrl = 'https://gradle.com/terms-of-service' From ec13fb5ad705f7b6ad1ecc475e130f38b6020ffa Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 17:25:06 +0300 Subject: [PATCH 30/52] build: add artifact signing (#441) --- build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.gradle b/build.gradle index bb29269f4..7c332e1e5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ plugins { id "org.sonarqube" version "5.0.0.4638" id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.0.0' + id 'signing' } group 'io.firebolt' @@ -334,6 +335,14 @@ task generateJavadoc(type: Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') } +signing { + def signingKey = System.getenv("GRADLE_SIGNING_KEY") + def signingPassword = System.getenv("GRADLE_SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKey, signingPassword) + + sign publishing.publications +} + if (hasProperty('buildScan')) { buildScan { termsOfServiceUrl = 'https://gradle.com/terms-of-service' From 164dc2e6701909f4112abd242d036f7d19260058 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 3 Jul 2024 17:26:57 +0300 Subject: [PATCH 31/52] ci: add missing secrets (#442) --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 54570a393..c51f547bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,3 +41,5 @@ jobs: env: MAVEN_REPO_USERNAME: ${{ secrets.MAVEN_REPO_USERNAME }} MAVEN_REPO_PASSWORD: ${{ secrets.MAVEN_REPO_PASSWORD }} + GRADLE_SIGNING_KEY: ${{ secrets.GRADLE_SIGNING_KEY }} + GRADLE_SIGNING_PASSWORD: ${{ secrets.GRADLE_SIGNING_PASSWORD }} From 2ca83fe0d20512a87a5697f09de8c05cb0f1ef18 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Thu, 18 Jul 2024 13:52:54 +0300 Subject: [PATCH 32/52] Revert "FIR-32836: log is simplified now - no lombok in log (#405)" (#444) Co-authored-by: ptiurin --- build.gradle | 1 - lombok.config | 1 + .../java/integration/IntegrationTest.java | 2 + .../tests/PreparedStatementArrayTest.java | 2 + .../tests/PreparedStatementTest.java | 3 + .../tests/StatementCancelTest.java | 11 +- .../java/integration/tests/StatementTest.java | 2 + .../integration/tests/SystemEngineTest.java | 18 +-- .../java/integration/tests/TimeoutTest.java | 7 +- .../java/integration/tests/TimestampTest.java | 2 + .../java/com/firebolt/FireboltDriver.java | 13 +- .../firebolt/jdbc/client/FireboltClient.java | 9 +- .../jdbc/client/HttpClientConfig.java | 14 ++- .../jdbc/client/UsageTrackerUtil.java | 13 +- .../client/account/FireboltAccountClient.java | 2 + .../FireboltAuthenticationClient.java | 12 +- .../client/config/OkHttpClientCreator.java | 2 + .../jdbc/client/config/RetryInterceptor.java | 7 +- .../socket/FireboltSSLSocketFactory.java | 10 +- .../config/socket/FireboltSocketFactory.java | 10 +- .../jdbc/client/config/socket/SocketUtil.java | 19 +-- .../client/query/StatementClientImpl.java | 11 +- .../jdbc/connection/FireboltConnection.java | 17 ++- .../com/firebolt/jdbc/connection/UrlUtil.java | 7 +- .../settings/FireboltProperties.java | 2 + .../com/firebolt/jdbc/log/FireboltLogger.java | 35 ++++++ .../java/com/firebolt/jdbc/log/JDKLogger.java | 111 ++++++++++++++++++ .../com/firebolt/jdbc/log/SLF4JLogger.java | 89 ++++++++++++++ .../metadata/FireboltDatabaseMetadata.java | 2 + .../jdbc/resultset/FireboltResultSet.java | 14 +-- .../jdbc/resultset/column/Column.java | 9 +- .../jdbc/resultset/column/ColumnType.java | 7 +- .../FireboltAuthenticationService.java | 15 ++- .../service/FireboltEngineApiService.java | 2 + ...ireboltEngineInformationSchemaService.java | 3 + .../service/FireboltStatementService.java | 2 + .../jdbc/statement/FireboltStatement.java | 29 ++--- .../statement/StatementResultWrapper.java | 14 +-- .../jdbc/statement/StatementUtil.java | 9 +- .../FireboltPreparedStatement.java | 10 +- .../rawstatement/RawStatementWrapper.java | 2 + .../java/com/firebolt/jdbc/type/BaseType.java | 2 + .../jdbc/type/array/SqlArrayUtil.java | 10 +- .../firebolt/jdbc/type/date/SqlDateUtil.java | 2 + .../com/firebolt/jdbc/util/CloseableUtil.java | 11 +- .../firebolt/jdbc/util/InputStreamUtil.java | 7 +- .../com/firebolt/jdbc/util/LoggerUtil.java | 51 ++++---- .../com/firebolt/jdbc/util/PropertyUtil.java | 2 + .../com/firebolt/jdbc/util/VersionUtil.java | 9 +- .../java/com/firebolt/FireboltDriverTest.java | 6 +- .../com/firebolt/jdbc/log/JDKLoggerTest.java | 68 +++++++++++ .../firebolt/jdbc/log/LogLevelExample.java | 0 .../firebolt/jdbc/log/SLF4JLoggerTest.java | 68 +++++++++++ .../jdbc/statement/FireboltStatementTest.java | 3 +- .../firebolt/jdbc/util/LoggerUtilTest.java | 16 +-- 55 files changed, 602 insertions(+), 203 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/log/FireboltLogger.java create mode 100644 src/main/java/com/firebolt/jdbc/log/JDKLogger.java create mode 100644 src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java create mode 100644 src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java create mode 100644 src/test/java/com/firebolt/jdbc/log/LogLevelExample.java create mode 100644 src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java diff --git a/build.gradle b/build.gradle index 7c332e1e5..5078fcf3d 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,6 @@ dependencies { implementation 'net.jodah:expiringmap:0.5.11' implementation 'org.apache.commons:commons-text:1.12.0' implementation 'org.lz4:lz4-java:1.8.0' - implementation 'org.slf4j:jul-to-slf4j:2.0.13' implementation fileTree(dir: 'libs', includes: ['*.jar']) diff --git a/lombok.config b/lombok.config index 9ab6f2abe..86058d25d 100644 --- a/lombok.config +++ b/lombok.config @@ -1,3 +1,4 @@ lombok.anyConstructor.addConstructorProperties = true config.stopBubbling = true lombok.addLombokGeneratedAnnotation = true +lombok.log.custom.declaration = com.firebolt.jdbc.log.FireboltLogger com.firebolt.jdbc.util.LoggerUtil.getLogger(NAME) \ No newline at end of file diff --git a/src/integrationTest/java/integration/IntegrationTest.java b/src/integrationTest/java/integration/IntegrationTest.java index 06549081c..d51246930 100644 --- a/src/integrationTest/java/integration/IntegrationTest.java +++ b/src/integrationTest/java/integration/IntegrationTest.java @@ -1,6 +1,7 @@ package integration; import com.firebolt.jdbc.client.HttpClientConfig; +import lombok.CustomLog; import lombok.SneakyThrows; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestInstance; @@ -16,6 +17,7 @@ import static com.firebolt.jdbc.connection.FireboltConnectionUserPassword.SYSTEM_ENGINE_NAME; import static org.junit.jupiter.api.Assertions.assertNotNull; +@CustomLog @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Tag("common") public abstract class IntegrationTest { diff --git a/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java b/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java index 7a39e693c..c0d08f173 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementArrayTest.java @@ -3,6 +3,7 @@ import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.array.FireboltArray; import integration.IntegrationTest; +import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; +@CustomLog class PreparedStatementArrayTest extends IntegrationTest { enum PreparedStatementValueSetter { ARRAY { diff --git a/src/integrationTest/java/integration/tests/PreparedStatementTest.java b/src/integrationTest/java/integration/tests/PreparedStatementTest.java index 090788c2c..779ab50a9 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementTest.java @@ -9,6 +9,7 @@ import integration.ConnectionInfo; import integration.IntegrationTest; import lombok.Builder; +import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Value; import org.junit.jupiter.api.AfterEach; @@ -32,6 +33,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; @@ -49,6 +51,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +@CustomLog class PreparedStatementTest extends IntegrationTest { @BeforeEach diff --git a/src/integrationTest/java/integration/tests/StatementCancelTest.java b/src/integrationTest/java/integration/tests/StatementCancelTest.java index 83a01c732..a2538307b 100644 --- a/src/integrationTest/java/integration/tests/StatementCancelTest.java +++ b/src/integrationTest/java/integration/tests/StatementCancelTest.java @@ -5,6 +5,7 @@ import com.firebolt.jdbc.statement.FireboltStatement; import integration.EnvironmentCondition; import integration.IntegrationTest; +import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -16,15 +17,13 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; import static integration.EnvironmentCondition.Attribute.databaseVersion; import static integration.EnvironmentCondition.Comparison.GE; import static org.junit.jupiter.api.Assertions.assertEquals; +@CustomLog class StatementCancelTest extends IntegrationTest { - private static final Logger log = Logger.getLogger(StatementCancelTest.class.getName()); @BeforeEach void beforeEach() { @@ -92,11 +91,11 @@ private void verifyThatNoMoreRecordsAreAdded(Connection connection, String table // data is available. long waitForResultTime = insertTime / 2; long waitForResultDelay = waitForResultTime / 10; - log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded insertTime={0}, waitForResultTime={0}", new Object[] {insertTime, waitForResultTime}); + log.info("verifyThatNoMoreRecordsAreAdded insertTime={}, waitForResultTime={}", insertTime, waitForResultTime); int count0; int i = 0; for (count0 = count(connection, tableName); i < 10; count0 = count(connection, tableName), i++) { - log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded count0={0}", count0); + log.info("verifyThatNoMoreRecordsAreAdded count0={}", count0); if (count0 > 0) { break; } @@ -109,7 +108,7 @@ private void verifyThatNoMoreRecordsAreAdded(Connection connection, String table int count1 = count(connection, tableName); Thread.sleep(insertTime); // waiting to see if more records are being added int count2 = count(connection, tableName); - log.log(Level.INFO, "verifyThatNoMoreRecordsAreAdded count1={0}, count2={1}", new Object[] {count1, count2}); + log.info("verifyThatNoMoreRecordsAreAdded count1={}, count2={}", count1, count2); assertEquals(count1, count2); } diff --git a/src/integrationTest/java/integration/tests/StatementTest.java b/src/integrationTest/java/integration/tests/StatementTest.java index 2ed7ccc51..054177107 100644 --- a/src/integrationTest/java/integration/tests/StatementTest.java +++ b/src/integrationTest/java/integration/tests/StatementTest.java @@ -6,6 +6,7 @@ import integration.EnvironmentCondition; import integration.IntegrationTest; import kotlin.collections.ArrayDeque; +import lombok.CustomLog; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -42,6 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +@CustomLog class StatementTest extends IntegrationTest { @BeforeEach diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 7b40c7293..549d22db9 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -7,6 +7,7 @@ import integration.ConnectionInfo; import integration.EnvironmentCondition; import integration.IntegrationTest; +import lombok.CustomLog; import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -33,8 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; import static com.firebolt.jdbc.connection.FireboltConnectionUserPassword.SYSTEM_ENGINE_NAME; @@ -49,6 +48,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +@CustomLog @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class SystemEngineTest extends IntegrationTest { @@ -62,14 +62,12 @@ public class SystemEngineTest extends IntegrationTest { private static final String TABLE1 = TABLE + "_1"; private static final String TABLE2 = TABLE + "_2"; - private static final Logger log = Logger.getLogger(SystemEngineTest.class.getName()); - @BeforeAll void beforeAll() { try { executeStatementFromFile("/statements/system/ddl.sql", getSystemEngineName()); } catch (Exception e) { - log.log(Level.WARNING, "Could not execute statement", e); + log.warn("Could not execute statement", e); } } @@ -78,7 +76,7 @@ void afterAll() { try { executeStatementFromFile("/statements/system/cleanup.sql", getSystemEngineName()); } catch (Exception e) { - log.log(Level.WARNING, "Could not execute statement", e); + log.warn("Could not execute statement", e); } } @@ -112,6 +110,7 @@ void shouldThrowExceptionWhenExecutingWrongQueryWithJsonError() throws SQLExcept } @Test + @Tag("v2") void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { ConnectionInfo current = integration.ConnectionInfo.getInstance(); String systemEngineJdbcUrl = new ConnectionInfo(current.getPrincipal(), current.getSecret(), @@ -178,7 +177,7 @@ void useDatabase(String entityType) throws SQLException { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); } catch (SQLException e) { // catch just in case to do our best to clean everything even if test has failed - log.log(Level.WARNING, "Cannot perform query " + query, e); + log.warn("Cannot perform query {}", query, e); } } } @@ -342,8 +341,9 @@ void shouldExecuteEngineManagementQueries() throws SQLException { format("DROP DATABASE \"%s\"", SECOND_DATABASE_NAME)}) { try (Statement statement = connection.createStatement()) { statement.executeUpdate(query); - } catch (SQLException e) { // catch just in case to do our best to clean everything even if test has failed - log.log(Level.WARNING, "Cannot perform query " + query, e); + } catch ( + SQLException e) { // catch just in case to do our best to clean everything even if test has failed + log.warn("Cannot perform query {}", query, e); } } } diff --git a/src/integrationTest/java/integration/tests/TimeoutTest.java b/src/integrationTest/java/integration/tests/TimeoutTest.java index ac3e14b2e..54fa6cd28 100644 --- a/src/integrationTest/java/integration/tests/TimeoutTest.java +++ b/src/integrationTest/java/integration/tests/TimeoutTest.java @@ -3,6 +3,7 @@ import com.firebolt.jdbc.connection.FireboltConnection; import integration.EnvironmentCondition; import integration.IntegrationTest; +import lombok.CustomLog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -14,18 +15,16 @@ import java.sql.Statement; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; import static integration.EnvironmentCondition.Attribute.databaseVersion; import static integration.EnvironmentCondition.Comparison.GE; import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertTrue; +@CustomLog class TimeoutTest extends IntegrationTest { private static final int MIN_TIME_SECONDS = 350; private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 180000000000L); - private static final Logger log = Logger.getLogger(TimeoutTest.class.getName()); private long startTime; @BeforeEach @@ -37,7 +36,7 @@ void before() { void after() { long endTime = System.nanoTime(); long elapsedTimeSeconds = (endTime - startTime) / 1_000_000_000; - log.log(Level.INFO, "Time elapsed: {0} seconds", elapsedTimeSeconds); + log.info("Time elapsed: {} seconds", elapsedTimeSeconds); assertTrue(elapsedTimeSeconds > MIN_TIME_SECONDS, format("Test is too short. It took %d but should take at least %d seconds", elapsedTimeSeconds, MIN_TIME_SECONDS)); } diff --git a/src/integrationTest/java/integration/tests/TimestampTest.java b/src/integrationTest/java/integration/tests/TimestampTest.java index 99732ea0e..bfc0e4487 100644 --- a/src/integrationTest/java/integration/tests/TimestampTest.java +++ b/src/integrationTest/java/integration/tests/TimestampTest.java @@ -3,6 +3,7 @@ import com.firebolt.jdbc.testutils.AssertionUtil; import integration.IntegrationTest; import io.zonky.test.db.postgres.embedded.EmbeddedPostgres; +import lombok.CustomLog; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -36,6 +37,7 @@ import static java.sql.Types.TIMESTAMP_WITH_TIMEZONE; import static org.junit.jupiter.api.Assertions.assertEquals; +@CustomLog @DefaultTimeZone("UTC") class TimestampTest extends IntegrationTest { private static final TimeZone UTC_TZ = TimeZone.getTimeZone("UTC"); diff --git a/src/main/java/com/firebolt/FireboltDriver.java b/src/main/java/com/firebolt/FireboltDriver.java index d8537117d..96b759a7e 100644 --- a/src/main/java/com/firebolt/FireboltDriver.java +++ b/src/main/java/com/firebolt/FireboltDriver.java @@ -1,28 +1,27 @@ package com.firebolt; import com.firebolt.jdbc.connection.FireboltConnection; -import com.firebolt.jdbc.util.LoggerUtil; +import com.firebolt.jdbc.exception.FireboltSQLFeatureNotSupportedException; import com.firebolt.jdbc.util.PropertyUtil; import com.firebolt.jdbc.util.VersionUtil; +import lombok.CustomLog; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverPropertyInfo; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; +@CustomLog public class FireboltDriver implements Driver { public static final String JDBC_FIREBOLT = "jdbc:firebolt:"; - private static final Logger rootLog; - private static final Logger log; static { try { java.sql.DriverManager.registerDriver(new FireboltDriver()); - rootLog = LoggerUtil.getRootLogger(); - log = Logger.getLogger(FireboltDriver.class.getName()); log.info("Firebolt Driver registered"); } catch (SQLException ex) { throw new RuntimeException("Cannot register the driver"); @@ -60,7 +59,7 @@ public boolean jdbcCompliant() { } @Override - public Logger getParentLogger() { - return rootLog; + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new FireboltSQLFeatureNotSupportedException(); } } diff --git a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java index 042d32afc..c48f13746 100644 --- a/src/main/java/com/firebolt/jdbc/client/FireboltClient.java +++ b/src/main/java/com/firebolt/jdbc/client/FireboltClient.java @@ -8,6 +8,7 @@ import com.firebolt.jdbc.exception.ServerError.Error.Location; import com.firebolt.jdbc.resultset.compress.LZ4InputStream; import com.firebolt.jdbc.util.CloseableUtil; +import lombok.CustomLog; import lombok.Getter; import lombok.NonNull; import okhttp3.Call; @@ -48,13 +49,12 @@ import static java.util.Optional.ofNullable; @Getter +@CustomLog public abstract class FireboltClient implements CacheListener { - private static final String HEADER_AUTHORIZATION = "Authorization"; private static final String HEADER_AUTHORIZATION_BEARER_PREFIX_VALUE = "Bearer "; private static final String HEADER_USER_AGENT = "User-Agent"; private static final String HEADER_PROTOCOL_VERSION = "Firebolt-Protocol-Version"; - private static final Logger log = Logger.getLogger(FireboltClient.class.getName()); private static final Pattern plainErrorPattern = Pattern.compile("Line (\\d+), Column (\\d+): (.*)$", Pattern.MULTILINE); private final OkHttpClient httpClient; private final String headerUserAgentValue; @@ -181,13 +181,12 @@ protected String getResponseAsString(Response response) throws SQLException, IOE return response.body().string(); } - @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both private String extractErrorMessage(Response response, boolean isCompress) throws SQLException { byte[] entityBytes; try { entityBytes = response.body() != null ? response.body().bytes() : null; } catch (IOException e) { - log.log(Level.WARNING, "Could not parse response containing the error message from Firebolt", e); + log.warn("Could not parse response containing the error message from Firebolt", e); String errorResponseMessage = format("Server failed to execute query%ninternal error:%n%s", getInternalErrorWithHeadersText(response)); throw new FireboltException(errorResponseMessage, response.code(), e); @@ -202,7 +201,7 @@ private String extractErrorMessage(Response response, boolean isCompress) throws return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)).lines() .collect(Collectors.joining("\n")) + "\n"; } catch (Exception e) { - log.log(Level.WARNING, "Could not decompress error from server"); + log.warn("Could not decompress error from server"); } } return new String(entityBytes, StandardCharsets.UTF_8); diff --git a/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java b/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java index 557b0746f..7849c65a8 100644 --- a/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java +++ b/src/main/java/com/firebolt/jdbc/client/HttpClientConfig.java @@ -1,18 +1,20 @@ package com.firebolt.jdbc.client; -import com.firebolt.jdbc.client.config.OkHttpClientCreator; -import com.firebolt.jdbc.connection.settings.FireboltProperties; -import okhttp3.OkHttpClient; - import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; -import java.util.logging.Logger; +import com.firebolt.jdbc.client.config.OkHttpClientCreator; +import com.firebolt.jdbc.connection.settings.FireboltProperties; + +import lombok.CustomLog; +import okhttp3.OkHttpClient; + +@CustomLog public class HttpClientConfig { - private static final Logger log = Logger.getLogger(HttpClientConfig.class.getName()); + private static OkHttpClient instance; private HttpClientConfig() { diff --git a/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java b/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java index 409c07ddd..55aaa8eca 100644 --- a/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java +++ b/src/main/java/com/firebolt/jdbc/client/UsageTrackerUtil.java @@ -1,17 +1,16 @@ package com.firebolt.jdbc.client; import com.firebolt.jdbc.util.VersionUtil; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.util.HashMap; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; +@CustomLog @UtilityClass public class UsageTrackerUtil { - private static final Logger log = Logger.getLogger(UsageTrackerUtil.class.getName()); public static final Map CLIENT_MAP = Map.of( "Tableau", "com.tableau", "Looker", "com.looker", @@ -25,7 +24,7 @@ private static String getVersionForClass(String name) { Class c = Class.forName(name); return c.getPackage().getImplementationVersion(); } catch (ClassNotFoundException e) { - log.log(Level.FINE, "Unable to get version for class {0}", name); + log.debug("Unable to get version for class " + name); return ""; } } @@ -39,13 +38,13 @@ public Map getClients(StackTraceElement[] stack, Map connectorEntry : clientMap.entrySet()) { if (s.getClassName().contains(connectorEntry.getValue())) { String version = getVersionForClass(s.getClassName()); - log.log(Level.FINE, "Detected running from {0} Version {1}", new Object[] {connectorEntry.getKey(), version}); + log.debug("Detected running from " + connectorEntry.getKey() + " Version " + version); clients.put(connectorEntry.getKey(), version); } } } if (clients.isEmpty()) { - log.log(Level.FINE, "No clients detected for tracking"); + log.debug("No clients detected for tracking"); } return clients; } @@ -60,7 +59,7 @@ private static Map extractNameToVersion(String namesAndVersions) nameToVersion.put(connectorInfo[0], connectorInfo[1]); } } else { - log.log(Level.FINE, "Incorrect connector format is provided: {0}, Expected: ConnA:1.0.2,ConnB:2.9.3", namesAndVersions); + log.debug(String.format("Incorrect connector format is provided: %s, Expected: ConnA:1.0.2,ConnB:2.9.3", namesAndVersions)); } return nameToVersion; } diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java index eb0ff73d5..2acd545a6 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountClient.java @@ -8,6 +8,7 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.exception.ExceptionType; import com.firebolt.jdbc.exception.FireboltException; +import lombok.CustomLog; import okhttp3.OkHttpClient; import java.io.IOException; @@ -17,6 +18,7 @@ import static java.lang.String.format; +@CustomLog public class FireboltAccountClient extends FireboltClient { private static final String GET_ACCOUNT_ID_URI = "%s/iam/v2/accounts:getIdByName?accountName=%s"; diff --git a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java index 3c28151b5..d65b313ec 100644 --- a/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java +++ b/src/main/java/com/firebolt/jdbc/client/authentication/FireboltAuthenticationClient.java @@ -3,17 +3,17 @@ import com.firebolt.jdbc.client.FireboltClient; import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.FireboltConnectionTokens; +import com.firebolt.jdbc.exception.FireboltException; +import lombok.CustomLog; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; +@CustomLog public abstract class FireboltAuthenticationClient extends FireboltClient { - private static final Logger log = Logger.getLogger(FireboltAuthenticationClient.class.getName()); protected FireboltAuthenticationClient(OkHttpClient httpClient, FireboltConnection connection, String customDrivers, String customClients) { @@ -33,7 +33,7 @@ public FireboltConnectionTokens postConnectionTokens(String host, String user, S throws SQLException, IOException { AuthenticationRequest authenticationRequest = getAuthenticationRequest(user, password, host, environment); String uri = authenticationRequest.getUri(); - log.log(Level.FINE, "Creating connection with url {0}", uri); + log.debug("Creating connection with url {}", uri); Request request = createPostRequest(uri, null, authenticationRequest.getRequestBody(), null); try (Response response = execute(request, host)) { String responseString = getResponseAsString(response); @@ -47,13 +47,13 @@ public FireboltConnectionTokens postConnectionTokens(String host, String user, S private void logToken(FireboltConnectionTokens connectionTokens) { logIfPresent(connectionTokens.getAccessToken(), "Retrieved access_token"); if (connectionTokens.getExpiresInSeconds() >=- 0) { - log.log(Level.FINE, "Retrieved expires_in"); + log.debug("Retrieved expires_in"); } } private void logIfPresent(String token, String message) { if (token != null && !token.isEmpty()) { - log.log(Level.FINE, message); + log.debug(message); } } diff --git a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java index 532475f0f..ec5a7deb6 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java +++ b/src/main/java/com/firebolt/jdbc/client/config/OkHttpClientCreator.java @@ -4,6 +4,7 @@ import com.firebolt.jdbc.client.config.socket.FireboltSocketFactory; import com.firebolt.jdbc.connection.settings.FireboltProperties; import lombok.Builder; +import lombok.CustomLog; import lombok.Value; import lombok.experimental.UtilityClass; import okhttp3.ConnectionPool; @@ -35,6 +36,7 @@ * Class to configure the http client using the session settings */ @UtilityClass +@CustomLog public class OkHttpClientCreator { private static final String SSL_STRICT_MODE = "strict"; diff --git a/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java b/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java index 8959d5681..9ab7c6864 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java +++ b/src/main/java/com/firebolt/jdbc/client/config/RetryInterceptor.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.client.config; +import lombok.CustomLog; import lombok.NonNull; import lombok.RequiredArgsConstructor; import okhttp3.Interceptor; @@ -10,8 +11,6 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import static java.net.HttpURLConnection.HTTP_BAD_GATEWAY; import static java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT; @@ -19,11 +18,11 @@ import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; @RequiredArgsConstructor +@CustomLog public class RetryInterceptor implements Interceptor { private static final Set RETRYABLE_RESPONSE_CODES = new HashSet<>( Arrays.asList(HTTP_CLIENT_TIMEOUT, HTTP_BAD_GATEWAY, HTTP_UNAVAILABLE, HTTP_GATEWAY_TIMEOUT)); - private static final Logger log = Logger.getLogger(RetryInterceptor.class.getName()); private final int maxRetries; @@ -45,7 +44,7 @@ public Response intercept(@NonNull Chain chain) throws IOException { failureInfo = String.format("Failure #%d - Response code: %d. Retrying to send the request.", tryCount, response.code()); } - log.log(Level.WARNING, failureInfo); + log.warn(failureInfo); // retry the request response.close(); diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java index c1f3b06a5..5a6fe7e45 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSSLSocketFactory.java @@ -1,14 +1,18 @@ package com.firebolt.jdbc.client.config.socket; -import com.firebolt.jdbc.connection.settings.FireboltProperties; +import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; -import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; +import javax.net.ssl.SSLSocketFactory; + +import com.firebolt.jdbc.connection.settings.FireboltProperties; + +import lombok.CustomLog; +@CustomLog public class FireboltSSLSocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; private final FireboltProperties fireboltProperties; diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java index e424c41b0..299715bda 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/FireboltSocketFactory.java @@ -1,14 +1,18 @@ package com.firebolt.jdbc.client.config.socket; -import com.firebolt.jdbc.connection.settings.FireboltProperties; +import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; -import javax.net.SocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import static com.firebolt.jdbc.client.config.socket.SocketUtil.wrap; +import javax.net.SocketFactory; + +import com.firebolt.jdbc.connection.settings.FireboltProperties; + +import lombok.CustomLog; +@CustomLog public class FireboltSocketFactory extends SocketFactory { private static final javax.net.SocketFactory delegate = SocketFactory.getDefault(); private final FireboltProperties fireboltProperties; diff --git a/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java b/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java index 61b080b25..cd70d43ab 100644 --- a/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java +++ b/src/main/java/com/firebolt/jdbc/client/config/socket/SocketUtil.java @@ -1,19 +1,19 @@ package com.firebolt.jdbc.client.config.socket; +import java.io.IOException; +import java.net.Socket; +import java.net.SocketOption; + import com.firebolt.jdbc.connection.settings.FireboltProperties; + import jdk.net.ExtendedSocketOptions; import jdk.net.Sockets; +import lombok.CustomLog; import lombok.experimental.UtilityClass; -import java.io.IOException; -import java.net.Socket; -import java.net.SocketOption; -import java.util.logging.Level; -import java.util.logging.Logger; - @UtilityClass +@CustomLog public class SocketUtil { - private static final Logger log = Logger.getLogger(SocketUtil.class.getName()); public static Socket wrap(Socket s, FireboltProperties fireboltProperties) throws IOException { s.setKeepAlive(true); @@ -23,7 +23,7 @@ public static Socket wrap(Socket s, FireboltProperties fireboltProperties) throw setSocketOption(s, ExtendedSocketOptions.TCP_KEEPCOUNT, fireboltProperties.getTcpKeepCount()); setSocketOption(s, ExtendedSocketOptions.TCP_KEEPINTERVAL, fireboltProperties.getTcpKeepInterval()); } catch (Error | Exception e) { - log.log(Level.FINE, "Could not set socket options", e); + log.debug("Could not set socket options", e); } return s; } @@ -32,7 +32,8 @@ private void setSocketOption(Socket socket, SocketOption option, int va try { Sockets.setOption(socket, option, value); } catch (Exception e) { - log.log(Level.FINE, "Could not set the socket option {0}. The operation is not supported: {1}", new Object[] {option.name(), e.getMessage()}); + log.debug("Could not set the socket option {}. The operation is not supported: {}", option.name(), + e.getMessage()); } } } diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java index 61d22e9f6..5fb4a3fa4 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java @@ -11,6 +11,7 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatement; import com.firebolt.jdbc.util.CloseableUtil; import com.firebolt.jdbc.util.PropertyUtil; +import lombok.CustomLog; import lombok.NonNull; import okhttp3.Call; import okhttp3.Dispatcher; @@ -37,8 +38,6 @@ import java.util.Optional; import java.util.function.BiPredicate; import java.util.function.Function; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Pattern; import static com.firebolt.jdbc.connection.settings.FireboltQueryParameterKey.DEFAULT_FORMAT; @@ -50,6 +49,7 @@ import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import static java.util.Optional.ofNullable; +@CustomLog public class StatementClientImpl extends FireboltClient implements StatementClient { private static final String TAB_SEPARATED_WITH_NAMES_AND_TYPES_FORMAT = "TabSeparatedWithNamesAndTypes"; @@ -57,7 +57,6 @@ public class StatementClientImpl extends FireboltClient implements StatementClie Pattern.compile("HTTP status code: 401"), "Please associate user with your service account.", Pattern.compile("Engine .+? does not exist or not authorized"), "Please grant at least one role to user associated your service account." ); - private static final Logger log = Logger.getLogger(StatementClientImpl.class.getName()); private final BiPredicate isCallWithLabel = (call, label) -> call.request().tag() instanceof String && Objects.equals(call.request().tag(), label); // visible for testing @@ -157,11 +156,11 @@ public InputStream executeSqlStatement(@NonNull StatementInfoWrapper statementIn private InputStream executeSqlStatementWithRetryOnUnauthorized(String label, @NonNull FireboltProperties connectionProperties, String formattedStatement, String uri) throws SQLException, IOException { try { - log.log(Level.FINE, "Posting statement with label {0} to URI: {1}", new Object[] {label, uri}); + log.debug("Posting statement with label {} to URI: {}", label, uri); return postSqlStatement(connectionProperties, formattedStatement, uri, label); } catch (FireboltException exception) { if (exception.getType() == UNAUTHORIZED) { - log.log(Level.FINE, "Retrying to post statement with label {0} following a 401 status code to URI: {1}", new Object[] {label, uri}); + log.debug("Retrying to post statement with label {} following a 401 status code to URI: {}",label, uri); return postSqlStatement(connectionProperties, formattedStatement, uri, label); } else { throw exception; @@ -222,7 +221,7 @@ private void abortRunningDbStatement(String label, FireboltProperties fireboltPr if (e.getType() == ExceptionType.INVALID_REQUEST || e.getType() == ExceptionType.RESOURCE_NOT_FOUND) { // 400 on that request indicates that the statement does not exist // 404 - the same when working against "real" v2 engine - log.warning(e.getMessage()); + log.warn(e.getMessage()); } else { throw e; } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index e010c7284..14cfd8096 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -22,6 +22,7 @@ import com.firebolt.jdbc.type.lob.FireboltBlob; import com.firebolt.jdbc.type.lob.FireboltClob; import com.firebolt.jdbc.util.PropertyUtil; +import lombok.CustomLog; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -56,8 +57,6 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Pattern; import static com.firebolt.jdbc.connection.settings.FireboltSessionProperty.getNonDeprecatedProperties; @@ -66,9 +65,9 @@ import static java.sql.ResultSet.TYPE_FORWARD_ONLY; import static java.util.stream.Collectors.toMap; +@CustomLog public abstract class FireboltConnection extends JdbcBase implements Connection, CacheListener { - private static final Logger log = Logger.getLogger(FireboltConnection.class.getName()); private final FireboltAuthenticationService fireboltAuthenticationService; private final FireboltStatementService fireboltStatementService; protected String httpConnectionUrl; @@ -171,7 +170,7 @@ protected void connect() throws SQLException { } databaseMetaData = retrieveMetaData(); - log.fine("Connection opened"); + log.debug("Connection opened"); } protected abstract void authenticate() throws SQLException; @@ -319,7 +318,7 @@ public void abort(Executor executor) throws SQLException { @Override public void close() { - log.fine("Closing connection"); + log.debug("Closing connection"); synchronized (this) { if (isClosed()) { return; @@ -332,13 +331,13 @@ public void close() { try { statement.close(false); } catch (Exception e) { - log.log(Level.WARNING, "Could not close statement", e); + log.warn("Could not close statement", e); } } statements.clear(); } databaseMetaData = null; - log.warning("Connection closed"); + log.debug("Connection closed"); } protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) { @@ -435,9 +434,9 @@ private void validateConnection(FireboltProperties fireboltProperties, boolean i // This error cannot be ignored when testing the connection to validate a param. if (ignoreToManyRequestsError && e instanceof FireboltException && ((FireboltException) e).getType() == ExceptionType.TOO_MANY_REQUESTS) { - log.log(Level.WARNING, "Too many requests are being sent to the server", e); + log.warn("Too many requests are being sent to the server", e); } else { - log.log(Level.WARNING, "Connection is not valid", e); + log.warn("Connection is not valid", e); throw e; } } diff --git a/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java b/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java index 1142403e2..1ceecc168 100644 --- a/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java +++ b/src/main/java/com/firebolt/jdbc/connection/UrlUtil.java @@ -1,6 +1,7 @@ package com.firebolt.jdbc.connection; import com.firebolt.jdbc.connection.settings.FireboltSessionProperty; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.net.MalformedURLException; @@ -11,17 +12,15 @@ import java.util.Optional; import java.util.Properties; import java.util.TreeMap; -import java.util.logging.Level; -import java.util.logging.Logger; import static java.lang.String.CASE_INSENSITIVE_ORDER; import static java.util.stream.Collectors.toMap; +@CustomLog @UtilityClass public class UrlUtil { public static final String JDBC_PREFIX = "jdbc:firebolt:"; - private static final Logger log = Logger.getLogger(UrlUtil.class.getName()); public static Properties extractProperties(String jdbcUrl) { return parseUriQueryPart(jdbcUrl); @@ -40,7 +39,7 @@ private static Properties parseUriQueryPart(String jdbcConnectionString) { if (keyValueTokens.length == 2) { uriProperties.put(keyValueTokens[0], keyValueTokens[1]); } else { - log.log(Level.WARNING, "Cannot parse key-pair: {0}", keyValue); + log.warn("Cannot parse key-pair: {}", keyValue); } } } diff --git a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java index e3ddc9de0..7c8266863 100644 --- a/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java +++ b/src/main/java/com/firebolt/jdbc/connection/settings/FireboltProperties.java @@ -2,6 +2,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -31,6 +32,7 @@ @AllArgsConstructor @EqualsAndHashCode @Builder(toBuilder = true) +@CustomLog public class FireboltProperties { private static final Pattern DB_PATH_PATTERN = Pattern.compile("/?([a-zA-Z0-9_*\\-]+)"); diff --git a/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java b/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java new file mode 100644 index 000000000..478c4548a --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/log/FireboltLogger.java @@ -0,0 +1,35 @@ +package com.firebolt.jdbc.log; + +public interface FireboltLogger { + + void trace(String message); + + void trace(String message, Object... arguments); + + void trace(String message, Throwable t); + + void debug(String message); + + void debug(String message, Object... arguments); + + void debug(String message, Throwable t); + + void info(String message); + + void info(String message, Object... arguments); + + void info(String message, Throwable t); + + void warn(String message); + + void warn(String message, Object... arguments); + + void warn(String message, Throwable t); + + void error(String message); + + void error(String message, Object... arguments); + + void error(String message, Throwable t); + +} diff --git a/src/main/java/com/firebolt/jdbc/log/JDKLogger.java b/src/main/java/com/firebolt/jdbc/log/JDKLogger.java new file mode 100644 index 000000000..ad19f26d5 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/log/JDKLogger.java @@ -0,0 +1,111 @@ +package com.firebolt.jdbc.log; + +import java.util.logging.Level; + +public class JDKLogger implements FireboltLogger { + + private final java.util.logging.Logger logger; + + public JDKLogger(String name) { + this.logger = java.util.logging.Logger.getLogger(name); + } + + @Override + public void trace(String message) { + logger.log(Level.FINEST, message); + } + + @Override + public void trace(String message, Object... arguments) { + logger.log(Level.FINEST, addMissingArgumentsIndexes(message), arguments); + } + + @Override + public void trace(String message, Throwable t) { + logger.log(Level.FINEST, message, t); + } + + @Override + public void debug(String message) { + logger.log(Level.FINE, message); + } + + @Override + public void debug(String message, Object... arguments) { + logger.log(Level.FINE, addMissingArgumentsIndexes(message), arguments); + } + + @Override + public void debug(String message, Throwable t) { + logger.log(Level.FINE, message, t); + } + + @Override + public void info(String message) { + logger.log(Level.INFO, message); + } + + @Override + public void info(String message, Object... arguments) { + logger.log(Level.INFO, addMissingArgumentsIndexes(message), arguments); + } + + @Override + public void info(String message, Throwable t) { + logger.log(Level.INFO, message, t); + } + + @Override + public void warn(String message) { + logger.log(Level.WARNING, message); + } + + @Override + public void warn(String message, Object... arguments) { + logger.log(Level.WARNING, addMissingArgumentsIndexes(message), arguments); + } + + @Override + public void warn(String message, Throwable t) { + logger.log(Level.WARNING, message, t); + + } + + @Override + public void error(String message) { + logger.log(Level.SEVERE, message); + } + + @Override + public void error(String message, Object... arguments) { + logger.log(Level.SEVERE, addMissingArgumentsIndexes(message), arguments); + } + + @Override + public void error(String message, Throwable t) { + logger.log(Level.SEVERE, message, t); + } + + /** + * SLF4J and java.util.logging use a different log format. With SLF4J it is not + * required to have argument indexes in the logs (eg: "log.info("hello {}", + * "world");), but it is required for java.util.logging (eg: "log.info("hello + * {1}", "world");) In this project we use the SLF4J way of logging, which is + * why we need to add the missing indexes. + */ + private String addMissingArgumentsIndexes(String message) { + StringBuilder result = new StringBuilder(); + int argumentIndex = 0; + int i = 0; + while (i < message.length()) { + if (message.charAt(i) == '{' && i < message.length() - 1 && message.charAt(i + 1) == '}') { + result.append(String.format("{%d}", argumentIndex++)); + i++; + } else { + result.append(message.charAt(i)); + } + i++; + } + return result.toString(); + } +} diff --git a/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java b/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java new file mode 100644 index 000000000..ba769bbfc --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/log/SLF4JLogger.java @@ -0,0 +1,89 @@ +package com.firebolt.jdbc.log; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SLF4JLogger implements FireboltLogger { + + private final Logger logger; + + public SLF4JLogger(String name) { + logger = LoggerFactory.getLogger(name); + } + + @Override + public void trace(String message) { + logger.trace(message); + } + + @Override + public void trace(String message, Object... arguments) { + logger.trace(message, arguments); + } + + @Override + public void trace(String message, Throwable t) { + logger.trace(message, t); + } + + @Override + public void debug(String message) { + logger.debug(message); + } + + @Override + public void debug(String message, Object... arguments) { + logger.debug(message, arguments); + + } + + @Override + public void debug(String message, Throwable t) { + logger.debug(message, t); + } + + @Override + public void info(String message) { + logger.info(message); + } + + @Override + public void info(String message, Object... arguments) { + logger.info(message, arguments); + } + + @Override + public void info(String message, Throwable t) { + logger.info(message, t); + } + + @Override + public void warn(String message) { + logger.warn(message); + } + + @Override + public void warn(String message, Object... arguments) { + logger.warn(message, arguments); + } + + @Override + public void warn(String message, Throwable t) { + logger.warn(message, t); + } + + @Override + public void error(String message) { + logger.error(message); + } + + @Override + public void error(String message, Object... arguments) { + logger.error(message, arguments); + } + + @Override + public void error(String message, Throwable t) { + logger.error(message, t); + } +} diff --git a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java index 5a7abbac9..abb1c703d 100644 --- a/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java +++ b/src/main/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadata.java @@ -7,6 +7,7 @@ import com.firebolt.jdbc.resultset.column.Column; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.util.VersionUtil; +import lombok.CustomLog; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -147,6 +148,7 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +@CustomLog @SuppressWarnings("java:S6204") // compatibility with JDK 11 public class FireboltDatabaseMetadata implements DatabaseMetaData, GenericWrapper { diff --git a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java index af94336d0..df09da038 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java +++ b/src/main/java/com/firebolt/jdbc/resultset/FireboltResultSet.java @@ -18,6 +18,7 @@ import com.firebolt.jdbc.type.lob.FireboltBlob; import com.firebolt.jdbc.type.lob.FireboltClob; import com.firebolt.jdbc.util.LoggerUtil; +import lombok.CustomLog; import org.apache.commons.text.StringEscapeUtils; import java.io.BufferedReader; @@ -55,8 +56,6 @@ import java.util.Optional; import java.util.TimeZone; import java.util.TreeMap; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -71,10 +70,10 @@ /** * ResultSet for InputStream using the format "TabSeparatedWithNamesAndTypes" */ +@CustomLog public class FireboltResultSet extends JdbcBase implements ResultSet { private static final String FORWARD_ONLY_ERROR = "Cannot call %s() for ResultSet of type TYPE_FORWARD_ONLY"; private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192; // the default of BufferedReader - private static final Logger log = Logger.getLogger(FireboltResultSet.class.getName()); private final BufferedReader reader; private final Map columnNameToColumnNumber; private final FireboltResultSetMetaData resultSetMetaData; @@ -90,10 +89,9 @@ public class FireboltResultSet extends JdbcBase implements ResultSet { private String lastReadValue = null; - @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both public FireboltResultSet(InputStream is, String tableName, String dbName, int bufferSize, boolean isCompressed, FireboltStatement statement, boolean logResultSet) throws SQLException { - log.fine("Creating resultSet..."); + log.debug("Creating resultSet..."); this.statement = statement; if (logResultSet) { is = LoggerUtil.logInputStream(is); @@ -115,10 +113,10 @@ public FireboltResultSet(InputStream is, String tableName, String dbName, int bu columns = next() ? getColumns(fields, currentLine) : new ArrayList<>(); resultSetMetaData = new FireboltResultSetMetaData(dbName, tableName, columns); } catch (Exception e) { - log.log(Level.SEVERE, e, () -> "Could not create ResultSet: " + e.getMessage()); - throw new FireboltException("Cannot read response from DB: error while creating ResultSet", e); + log.error("Could not create ResultSet: {}", e.getMessage(), e); + throw new FireboltException("Cannot read response from DB: error while creating ResultSet ", e); } - log.fine("ResultSet created"); + log.debug("ResultSet created"); } public static FireboltResultSet of(QueryResult queryResult) throws SQLException { diff --git a/src/main/java/com/firebolt/jdbc/resultset/column/Column.java b/src/main/java/com/firebolt/jdbc/resultset/column/Column.java index 8797c5e60..d0cae2425 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/column/Column.java +++ b/src/main/java/com/firebolt/jdbc/resultset/column/Column.java @@ -1,24 +1,23 @@ package com.firebolt.jdbc.resultset.column; import lombok.Builder; +import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; -import java.util.logging.Level; -import java.util.logging.Logger; - @Builder @Getter @EqualsAndHashCode @ToString +@CustomLog public final class Column { - private static final Logger log = Logger.getLogger(Column.class.getName()); + private final ColumnType type; private final String columnName; public static Column of(String columnType, String columnName) { - log.log(Level.FINE, "Creating column info for column: {0} of type: {1}", new Object[] {columnName, columnType}); + log.debug("Creating column info for column: {} of type: {}", columnName, columnType); return Column.builder().columnName(columnName).type(ColumnType.of(columnType)).build(); } } diff --git a/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java b/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java index c8ddf6737..4e1d23a21 100644 --- a/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java +++ b/src/main/java/com/firebolt/jdbc/resultset/column/ColumnType.java @@ -2,6 +2,7 @@ import com.firebolt.jdbc.type.FireboltDataType; import lombok.Builder; +import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; @@ -16,8 +17,6 @@ import java.util.Optional; import java.util.Set; import java.util.TimeZone; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -28,6 +27,7 @@ /** * This class represents a Column type returned by the server */ +@CustomLog @Builder @Value @EqualsAndHashCode @@ -40,7 +40,6 @@ public class ColumnType { private static final Set TIMEZONES = Arrays.stream(TimeZone.getAvailableIDs()) .collect(Collectors.toCollection(HashSet::new)); private static final Pattern COMMA_WITH_SPACES = Pattern.compile("\\s*,\\s*"); - private static final Logger log = Logger.getLogger(ColumnType.class.getName()); @EqualsAndHashCode.Exclude String name; FireboltDataType dataType; @@ -167,7 +166,7 @@ private static TimeZone getTimeZoneFromArguments(@NonNull String[] arguments) { if (TIMEZONES.contains(id)) { timeZone = TimeZone.getTimeZone(timeZoneArgument.replace("\\'", "")); } else { - log.log(Level.FINE, "Could not use the timezone returned by the server with the id {0} as it is not supported.", id); + log.warn("Could not use the timezone returned by the server with the id {} as it is not supported.", id); } } return timeZone; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java index a03c27867..0bd2d4f39 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltAuthenticationService.java @@ -6,6 +6,8 @@ import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.exception.SQLState; + +import lombok.CustomLog; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import net.jodah.expiringmap.ExpiringMap; @@ -14,8 +16,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; import static java.lang.String.format; import static java.util.Optional.ofNullable; @@ -23,9 +23,9 @@ import static net.jodah.expiringmap.ExpirationPolicy.CREATED; @RequiredArgsConstructor +@CustomLog public class FireboltAuthenticationService { - private static final Logger log = Logger.getLogger(FireboltAuthenticationService.class.getName()); private static final ExpiringMap tokensMap = ExpiringMap.builder() .variableExpiration().build(); private static final long TOKEN_EXPIRATION_OFFSET = 5L; @@ -34,14 +34,13 @@ public class FireboltAuthenticationService { private static final String ERROR_MESSAGE_FROM_SERVER = "Failed to connect to Firebolt with the error from the server: %s, see logs for more info."; private final FireboltAuthenticationClient fireboltAuthenticationClient; - @SuppressWarnings("java:S2139") // TODO: Exceptions should be either logged or rethrown but not both public FireboltConnectionTokens getConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); synchronized (this) { FireboltConnectionTokens foundToken = tokensMap.get(connectionParams); if (foundToken != null) { - log.log(Level.FINE, "Using the token of {} from the cache", host); + log.debug("Using the token of {} from the cache", host); return foundToken; } FireboltConnectionTokens fireboltConnectionTokens = fireboltAuthenticationClient @@ -51,12 +50,12 @@ public FireboltConnectionTokens getConnectionTokens(String host, FireboltPropert return fireboltConnectionTokens; } } catch (FireboltException e) { - log.log(Level.SEVERE, "Failed to connect to Firebolt", e); + log.error("Failed to connect to Firebolt", e); String msg = ofNullable(e.getErrorMessageFromServer()).map(m -> format(ERROR_MESSAGE_FROM_SERVER, m)).orElse(format(ERROR_MESSAGE, e.getMessage())); SQLState sqlState = SQLState.fromCode(e.getSQLState()); throw new FireboltException(msg, e, sqlState); } catch (Exception e) { - log.log(Level.SEVERE, "Failed to connect to Firebolt", e); + log.error("Failed to connect to Firebolt", e); throw new FireboltException(format(ERROR_MESSAGE, e.getMessage()), e); } } @@ -78,7 +77,7 @@ private long getCachingDurationInSeconds(long expireInSeconds) { */ public void removeConnectionTokens(String host, FireboltProperties loginProperties) throws SQLException { try { - log.log(Level.FINE, "Removing connection token for host {0}", host); + log.debug("Removing connection token for host {}", host); ConnectParams connectionParams = new ConnectParams(host, loginProperties.getPrincipal(), loginProperties.getSecret()); tokensMap.remove(connectionParams); } catch (NoSuchAlgorithmException e) { diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java index 4c2be433b..9a947f2a4 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java @@ -8,6 +8,7 @@ import com.firebolt.jdbc.connection.Engine; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; +import lombok.CustomLog; import lombok.RequiredArgsConstructor; import java.io.IOException; @@ -19,6 +20,7 @@ import static java.util.Optional.ofNullable; @RequiredArgsConstructor +@CustomLog public class FireboltEngineApiService implements FireboltEngineService { private static final Set ENGINE_NOT_READY_STATUSES = Set.of( "ENGINE_STATUS_PROVISIONING_STARTED", "ENGINE_STATUS_PROVISIONING_PENDING", diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java index 731663a0a..d4c223990 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltEngineInformationSchemaService.java @@ -4,10 +4,12 @@ import com.firebolt.jdbc.connection.FireboltConnection; import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; +import lombok.CustomLog; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collection; import java.util.TreeSet; import java.util.stream.Stream; @@ -16,6 +18,7 @@ import static java.lang.String.format; import static java.util.stream.Collectors.toCollection; +@CustomLog public class FireboltEngineInformationSchemaService implements FireboltEngineService { private static final String ENGINE_URL = "url"; private static final String STATUS_FIELD = "status"; diff --git a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java index 67d783006..832d43dda 100644 --- a/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java +++ b/src/main/java/com/firebolt/jdbc/service/FireboltStatementService.java @@ -9,6 +9,7 @@ import com.firebolt.jdbc.statement.rawstatement.QueryRawStatement; import com.firebolt.jdbc.util.CloseableUtil; import com.firebolt.jdbc.util.InputStreamUtil; +import lombok.CustomLog; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -20,6 +21,7 @@ import static java.util.Optional.ofNullable; @RequiredArgsConstructor +@CustomLog public class FireboltStatementService { private static final String UNKNOWN_TABLE_NAME = "unknown"; diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index caec200c1..be2f49949 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -10,6 +10,7 @@ import com.firebolt.jdbc.exception.FireboltUnsupportedOperationException; import com.firebolt.jdbc.service.FireboltStatementService; import com.firebolt.jdbc.util.CloseableUtil; +import lombok.CustomLog; import java.io.InputStream; import java.sql.Connection; @@ -25,16 +26,13 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import static com.firebolt.jdbc.statement.rawstatement.StatementValidatorFactory.createValidator; -import static java.lang.String.format; import static java.util.stream.Collectors.toCollection; +@CustomLog public class FireboltStatement extends JdbcBase implements Statement { - private static final Logger log = Logger.getLogger(FireboltStatement.class.getName()); private final FireboltStatementService statementService; private final FireboltProperties sessionProperties; private final FireboltConnection connection; @@ -55,7 +53,7 @@ public FireboltStatement(FireboltStatementService statementService, FireboltProp this.statementService = statementService; this.sessionProperties = sessionProperties; this.connection = connection; - log.fine("Created Statement"); + log.debug("Created Statement"); } @Override @@ -110,10 +108,12 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper) t } InputStream inputStream = null; try { - log.log(Level.FINE, "Executing the statement with label {0} : {1}", new Object[] {statementInfoWrapper.getLabel(), statementInfoWrapper.getSql()}); + + log.info("Executing the statement with label {} : {}", statementInfoWrapper.getLabel(), + statementInfoWrapper.getSql()); if (statementInfoWrapper.getType() == StatementType.PARAM_SETTING) { connection.addProperty(statementInfoWrapper.getParam()); - log.log(Level.FINE, "The property from the query {0} was stored", runningStatementLabel); + log.debug("The property from the query {} was stored", runningStatementLabel); } else { Optional currentRs = statementService.execute(statementInfoWrapper, sessionProperties, this); if (currentRs.isPresent()) { @@ -122,11 +122,12 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper) t } else { currentUpdateCount = 0; } - log.log(Level.INFO, "The query with the label {0} was executed with success", runningStatementLabel); + log.info("The query with the label {} was executed with success", runningStatementLabel); } } catch (Exception ex) { CloseableUtil.close(inputStream); - log.log(Level.SEVERE, ex, () -> format("An error happened while executing the statement with the id %s", runningStatementLabel)); + log.error(String.format("An error happened while executing the statement with the id %s", + runningStatementLabel), ex); throw ex; } finally { runningStatementLabel = null; @@ -139,7 +140,7 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper) t } } } else { - log.log(Level.FINE, "Aborted query with id {0}", statementInfoWrapper.getLabel()); + log.warn("Aborted query with id {}", statementInfoWrapper.getLabel()); } return Optional.ofNullable(resultSet); } @@ -166,7 +167,7 @@ public void cancel() throws SQLException { } String statementLabel = runningStatementLabel; if (statementLabel != null) { - log.log(Level.INFO, "Cancelling statement with label {0}", statementLabel); + log.info("Cancelling statement with label " + statementLabel); abortStatementRunningOnFirebolt(statementLabel); } } @@ -174,7 +175,7 @@ public void cancel() throws SQLException { private void abortStatementRunningOnFirebolt(String statementLabel) throws SQLException { try { statementService.abortStatement(statementLabel, sessionProperties); - log.log(Level.FINE, "Statement with label {0} was aborted", statementLabel); + log.debug("Statement with label {} was aborted", statementLabel); } catch (Exception e) { throw new FireboltException("Could not abort statement", e); } finally { @@ -254,7 +255,7 @@ public int getMaxRows() { @Override public void setMaxRows(int max) throws SQLException { if (max < 0) { - throw new FireboltException(format("Illegal maxRows value: %d", max)); + throw new FireboltException(String.format("Illegal maxRows value: %d", max)); } maxRows = max; } @@ -286,7 +287,7 @@ public void close(boolean removeFromConnection) throws SQLException { connection.removeClosedStatement(this); } cancel(); - log.fine("Statement closed"); + log.debug("Statement closed"); } @Override diff --git a/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java b/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java index a67cbd1d6..c82031324 100644 --- a/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java +++ b/src/main/java/com/firebolt/jdbc/statement/StatementResultWrapper.java @@ -1,16 +1,16 @@ package com.firebolt.jdbc.statement; -import lombok.Data; - -import javax.annotation.Nullable; import java.io.Closeable; import java.sql.ResultSet; -import java.util.logging.Level; -import java.util.logging.Logger; + +import javax.annotation.Nullable; + +import lombok.CustomLog; +import lombok.Data; @Data +@CustomLog public class StatementResultWrapper implements Closeable { - private static final Logger log = Logger.getLogger(StatementResultWrapper.class.getName()); private ResultSet resultSet; private int updateCount; private StatementInfoWrapper statementInfoWrapper; @@ -29,7 +29,7 @@ public void close() { resultSet.close(); } } catch (Exception e) { - log.log(Level.WARNING, "Could not close ResultSet", e); + log.warn("Could not close ResultSet", e); } if (next != null) { next.close(); diff --git a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java index 256dfc1e3..b7a719722 100644 --- a/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java +++ b/src/main/java/com/firebolt/jdbc/statement/StatementUtil.java @@ -4,6 +4,7 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatementWrapper; import com.firebolt.jdbc.statement.rawstatement.SetParamRawStatement; import com.firebolt.jdbc.util.StringUtil; +import lombok.CustomLog; import lombok.NonNull; import lombok.experimental.UtilityClass; @@ -14,19 +15,17 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; @UtilityClass +@CustomLog public class StatementUtil { private static final String SET_PREFIX = "set"; private static final Pattern SET_WITH_SPACE_REGEX = Pattern.compile(SET_PREFIX + " ", Pattern.CASE_INSENSITIVE); private static final String[] SELECT_KEYWORDS = new String[] { "show", "select", "describe", "exists", "explain", "with", "call" }; - private static final Logger log = Logger.getLogger(StatementUtil.class.getName()); /** * Returns true if the statement is a query (eg: SELECT, SHOW). @@ -181,7 +180,7 @@ public Map getParamMarketsPositions(String sql) { public Entry, Optional> extractDbNameAndTableNamePairFromCleanQuery(String cleanSql) { Optional from = Optional.empty(); if (isQuery(cleanSql)) { - log.log(Level.FINE, "Extracting DB and Table name for SELECT: {0}", cleanSql); + log.debug("Extracting DB and Table name for SELECT: {}", cleanSql); String withoutQuotes = cleanSql.replace("'", "").trim(); String withoutQuotesUpperCase = withoutQuotes.toUpperCase(); if (withoutQuotesUpperCase.startsWith("SELECT")) { @@ -194,7 +193,7 @@ public Entry, Optional> extractDbNameAndTableNamePairFr } else if (withoutQuotesUpperCase.startsWith("SHOW")) { from = Optional.empty(); // Depends on the information requested } else { - log.log(Level.FINE, "Could not find table name for query {0}. This may happen when there is no table.", cleanSql); + log.debug("Could not find table name for query {}. This may happen when there is no table.", cleanSql); } } return Map.entry(extractDbNameFromFromPartOfTheQuery(from.orElse(null)), diff --git a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java index e7f20b89b..41ce33462 100644 --- a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java @@ -14,6 +14,7 @@ import com.firebolt.jdbc.statement.rawstatement.RawStatementWrapper; import com.firebolt.jdbc.type.JavaTypeToFireboltSQLString; import com.firebolt.jdbc.util.InputStreamUtil; +import lombok.CustomLog; import lombok.NonNull; import java.io.IOException; @@ -42,8 +43,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import static com.firebolt.jdbc.statement.StatementUtil.replaceParameterMarksWithValues; import static com.firebolt.jdbc.statement.rawstatement.StatementValidatorFactory.createValidator; @@ -52,8 +51,9 @@ import static java.sql.Types.NUMERIC; import static java.sql.Types.VARBINARY; +@CustomLog public class FireboltPreparedStatement extends FireboltStatement implements PreparedStatement { - private static final Logger log = Logger.getLogger(FireboltPreparedStatement.class.getName()); + private final RawStatementWrapper rawStatement; private final List> rows; private Map providedParameters; @@ -65,7 +65,7 @@ public FireboltPreparedStatement(FireboltStatementService statementService, Fire public FireboltPreparedStatement(FireboltStatementService statementService, FireboltProperties sessionProperties, FireboltConnection connection, String sql) { super(statementService, sessionProperties, connection); - log.log(Level.FINE, "Populating PreparedStatement object for SQL: {0}", sql); + log.debug("Populating PreparedStatement object for SQL: {}", sql); this.providedParameters = new HashMap<>(); this.rawStatement = StatementUtil.parseToRawStatementWrapper(sql); rawStatement.getSubStatements().forEach(statement -> createValidator(statement, connection).validate(statement)); @@ -261,7 +261,7 @@ public void setArray(int parameterIndex, Array x) throws SQLException { @Override public int[] executeBatch() throws SQLException { validateStatementIsNotClosed(); - log.log(Level.FINE, "Executing batch for statement: {0}", rawStatement); + log.debug("Executing batch for statement: {}", rawStatement); List inserts = new ArrayList<>(); int[] result = new int[rows.size()]; for (Map row : rows) { diff --git a/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java b/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java index 75e967dfb..656f26381 100644 --- a/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java +++ b/src/main/java/com/firebolt/jdbc/statement/rawstatement/RawStatementWrapper.java @@ -1,11 +1,13 @@ package com.firebolt.jdbc.statement.rawstatement; +import lombok.CustomLog; import lombok.Value; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +@CustomLog @Value public class RawStatementWrapper { diff --git a/src/main/java/com/firebolt/jdbc/type/BaseType.java b/src/main/java/com/firebolt/jdbc/type/BaseType.java index b46c2b09d..c2b4caf97 100644 --- a/src/main/java/com/firebolt/jdbc/type/BaseType.java +++ b/src/main/java/com/firebolt/jdbc/type/BaseType.java @@ -6,6 +6,7 @@ import com.firebolt.jdbc.type.array.SqlArrayUtil; import com.firebolt.jdbc.type.date.SqlDateUtil; import lombok.Builder; +import lombok.CustomLog; import lombok.Value; import org.apache.commons.text.StringEscapeUtils; @@ -27,6 +28,7 @@ import static com.firebolt.jdbc.type.array.SqlArrayUtil.hexStringToByteArray; /** This class contains the java types the Firebolt data types are mapped to */ +@CustomLog public enum BaseType { LONG(TypePredicate.mayBeFloatingNumber, Long.class, conversion -> Long.parseLong(checkInfinity(conversion.getValue())), conversion -> Double.valueOf(conversion.getValue()).longValue()), INTEGER(TypePredicate.mayBeFloatingNumber, Integer.class, conversion -> Integer.parseInt(checkInfinity(conversion.getValue())), conversion -> Integer.parseInt(Long.toString(Double.valueOf(conversion.getValue()).longValue()))), diff --git a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java index 03f1b01e7..82d9d5619 100644 --- a/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/array/SqlArrayUtil.java @@ -1,9 +1,11 @@ package com.firebolt.jdbc.type.array; +import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.resultset.column.ColumnType; import com.firebolt.jdbc.type.FireboltDataType; import com.firebolt.jdbc.type.JavaTypeToFireboltSQLString; import com.firebolt.jdbc.util.StringUtil; +import lombok.CustomLog; import lombok.NonNull; import javax.annotation.Nullable; @@ -13,8 +15,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; import static java.lang.String.format; @@ -23,15 +23,15 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +@CustomLog public class SqlArrayUtil { private static final Map formatMarkers = Map.of( '[', new Markers('[', ']', '\'', '\''), '{', new Markers('{', '}', '"', '\'') ); - public static final String BYTE_ARRAY_PREFIX = "\\x"; - private static final Logger log = Logger.getLogger(SqlArrayUtil.class.getName()); private final ColumnType columnType; private final Markers markers; + public static final String BYTE_ARRAY_PREFIX = "\\x"; private static final class Markers { private final char leftArrayBracket; @@ -53,7 +53,7 @@ private SqlArrayUtil(ColumnType columnType, Markers markers) { } public static FireboltArray transformToSqlArray(String value, ColumnType columnType) throws SQLException { - log.log(Level.FINE, "Transformer array with value {0} and type {1}", new Object[] {value, columnType}); + log.debug("Transformer array with value {} and type {}", value, columnType); if (isNullValue(value)) { return null; } diff --git a/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java b/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java index d6d8b1347..5a77bfb10 100644 --- a/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java +++ b/src/main/java/com/firebolt/jdbc/type/date/SqlDateUtil.java @@ -1,6 +1,7 @@ package com.firebolt.jdbc.type.date; import com.firebolt.jdbc.CheckedBiFunction; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.sql.Date; @@ -16,6 +17,7 @@ import java.util.function.Function; @UtilityClass +@CustomLog public class SqlDateUtil { public static final long ONE_DAY_MILLIS = 86400000L; diff --git a/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java b/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java index c09886fda..660576645 100644 --- a/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/CloseableUtil.java @@ -1,15 +1,14 @@ package com.firebolt.jdbc.util; -import lombok.experimental.UtilityClass; - import java.io.Closeable; import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; +import lombok.CustomLog; +import lombok.experimental.UtilityClass; + +@CustomLog @UtilityClass public class CloseableUtil { - private static final Logger log = Logger.getLogger(CloseableUtil.class.getName()); /** * Closes the {@link Closeable} and log any potential {@link IOException} @@ -21,7 +20,7 @@ public void close(Closeable closeable) { try { closeable.close(); } catch (IOException e) { - log.log(Level.SEVERE, "An error happened while closing the closeable: {0}", e.getMessage()); + log.error("An error happened while closing the closeable: {}", e.getMessage()); } } } diff --git a/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java b/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java index a1e66e03c..8518f4a37 100644 --- a/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/InputStreamUtil.java @@ -1,19 +1,18 @@ package com.firebolt.jdbc.util; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import java.util.logging.Level; -import java.util.logging.Logger; @UtilityClass +@CustomLog public class InputStreamUtil { private static final int K_BYTE = 1024; private static final int BUFFER_SIZE = 8 * K_BYTE; - private static final Logger log = Logger.getLogger(InputStreamUtil.class.getName()); /** * Read all bytes from the input stream if the stream is not null @@ -26,7 +25,7 @@ public void readAllBytes(@Nullable InputStream is) { try { if (is.read() == -1) break; } catch (IOException e) { - log.log(Level.WARNING, "Could not read entire input stream for non query statement", e); + log.warn("Could not read entire input stream for non query statement", e); } } } diff --git a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java index 3aea5e03b..3e5f52b4c 100644 --- a/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/LoggerUtil.java @@ -1,39 +1,38 @@ package com.firebolt.jdbc.util; -import com.firebolt.FireboltDriver; -import lombok.experimental.UtilityClass; -import org.slf4j.bridge.SLF4JBridgeHandler; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Collectors; +import com.firebolt.jdbc.log.FireboltLogger; +import com.firebolt.jdbc.log.JDKLogger; +import com.firebolt.jdbc.log.SLF4JLogger; + +import lombok.CustomLog; +import lombok.experimental.UtilityClass; + @UtilityClass +@CustomLog public class LoggerUtil { - private static final boolean SLF4J_AVAILABLE = isSlf4jJAvailable(); - private static final Logger root = initRootLogger(); - private static final Logger log = Logger.getLogger(LoggerUtil.class.getName()); + private static Boolean slf4jAvailable; - private Logger initRootLogger() { - Logger parent = Logger.getLogger(FireboltDriver.class.getPackageName()); - if (SLF4J_AVAILABLE) { - synchronized (LoggerUtil.class) { - parent.addHandler(new SLF4JBridgeHandler()); - parent.setLevel(Level.ALL); - } + /** + * Provides a {@link FireboltLogger} based on whether SLF4J is available or not. + * + * @param name logger name + * @return a {@link FireboltLogger} + */ + public static FireboltLogger getLogger(String name) { + if (slf4jAvailable == null) { + slf4jAvailable = isSlf4jJAvailable(); } - return parent; - } - public static Logger getRootLogger() { - return root; + if (slf4jAvailable) { + return new SLF4JLogger(name); + } else { + return new JDKLogger(name); + } } /** @@ -60,7 +59,7 @@ public InputStream logInputStream(InputStream is) { log.info("======================================"); return new ByteArrayInputStream(baos.toByteArray()); } catch (Exception ex) { - log.log(Level.WARNING, "Could not log the stream", ex); + log.warn("Could not log the stream", ex); } return new ByteArrayInputStream(baos.toByteArray()); } diff --git a/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java b/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java index bf6a382dd..ae1c90df5 100644 --- a/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/PropertyUtil.java @@ -2,6 +2,7 @@ import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.connection.settings.FireboltSessionProperty; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.sql.DriverPropertyInfo; @@ -17,6 +18,7 @@ import static com.firebolt.jdbc.connection.UrlUtil.extractProperties; import static com.firebolt.jdbc.connection.settings.FireboltSessionProperty.getNonDeprecatedProperties; +@CustomLog @UtilityClass public class PropertyUtil { diff --git a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java index dbf9fc04d..8b11df99d 100644 --- a/src/main/java/com/firebolt/jdbc/util/VersionUtil.java +++ b/src/main/java/com/firebolt/jdbc/util/VersionUtil.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.util; +import lombok.CustomLog; import lombok.experimental.UtilityClass; import java.io.File; @@ -11,12 +12,11 @@ import java.util.Properties; import java.util.jar.Attributes.Name; import java.util.jar.Manifest; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @UtilityClass +@CustomLog public class VersionUtil { private static final Pattern VERSION_PATTERN = Pattern.compile("^\\s*(\\d+)\\.(\\d+).*"); @@ -27,14 +27,13 @@ public class VersionUtil { private static String driverVersion = "3.0.4"; private static String specificationVersion = "4.3"; - private static final Logger log = Logger.getLogger(VersionUtil.class.getName()); static { try { retrieveVersionInfo(); - log.log(Level.INFO, "Firebolt driver version used: {0}", driverVersion); + log.info("Firebolt driver version used: {}", driverVersion); } catch (IOException e) { - log.log(Level.SEVERE, "Could not get Project Version defined in the build.gradle file", e); + log.error("Could not get Project Version defined in the build.gradle file", e); } } diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index 4f3096780..0f72b83d5 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -12,12 +12,12 @@ import java.sql.Connection; import java.sql.DriverPropertyInfo; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.logging.Logger; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mockConstruction; class FireboltDriverTest { @@ -80,8 +81,7 @@ void acceptsURL(String url, boolean expected) { @Test void getParentLogger() { - Logger logger = new FireboltDriver().getParentLogger(); - assertNotNull(logger); + assertThrows(SQLFeatureNotSupportedException.class, () -> new FireboltDriver().getParentLogger()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java b/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java new file mode 100644 index 000000000..a9ba09cc6 --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/log/JDKLoggerTest.java @@ -0,0 +1,68 @@ +package com.firebolt.jdbc.log; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +class JDKLoggerTest { + + @Test + void shouldLogWithCorrectLevel() { + try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { + Logger logger = mock(Logger.class); + mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); + JDKLogger jdkLogger = new JDKLogger("myTest"); + jdkLogger.debug("This is a debug log"); + jdkLogger.warn("This is a warning log"); + jdkLogger.error("This is an error log"); + jdkLogger.trace("This is a trace log"); + verify(logger).log(Level.FINE, "This is a debug log"); + verify(logger).log(Level.WARNING, "This is a warning log"); + verify(logger).log(Level.SEVERE, "This is an error log"); + verify(logger).log(Level.FINEST, "This is a trace log"); + } + } + + @Test + void shouldLogWithCorrectArgumentIndexes() { + try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { + Logger logger = mock(Logger.class); + mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); + JDKLogger jdkLogger = new JDKLogger("myTest"); + jdkLogger.debug("This debug log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + jdkLogger.warn("This warning log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + jdkLogger.error("This error log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + jdkLogger.trace("This trace log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + Object[] args = new Object[] { "arg1", "arg2", "arg3" }; + verify(logger).log(Level.FINE, "This debug log has some arguments: {0}, {1}, {2}", args); + verify(logger).log(Level.WARNING, "This warning log has some arguments: {0}, {1}, {2}", args); + verify(logger).log(Level.SEVERE, "This error log has some arguments: {0}, {1}, {2}", args); + verify(logger).log(Level.FINEST, "This trace log has some arguments: {0}, {1}, {2}", args); + } + } + + @Test + void shouldLogWithThrowable() { + try (MockedStatic mockedLogger = Mockito.mockStatic(Logger.class)) { + Logger logger = mock(Logger.class); + mockedLogger.when(() -> java.util.logging.Logger.getLogger(any())).thenReturn(logger); + JDKLogger jdkLogger = new JDKLogger("myTest"); + IllegalArgumentException illegalArgumentException = new IllegalArgumentException(); + jdkLogger.debug("This debug log has an exception", illegalArgumentException); + jdkLogger.warn("This warning log has an exception", illegalArgumentException); + jdkLogger.error("This error log has an exception", illegalArgumentException); + jdkLogger.trace("This trace log has an exception", illegalArgumentException); + verify(logger).log(Level.FINE, "This debug log has an exception", illegalArgumentException); + verify(logger).log(Level.WARNING, "This warning log has an exception", illegalArgumentException); + verify(logger).log(Level.SEVERE, "This error log has an exception", illegalArgumentException); + verify(logger).log(Level.FINEST, "This trace log has an exception", illegalArgumentException); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/log/LogLevelExample.java b/src/test/java/com/firebolt/jdbc/log/LogLevelExample.java new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java b/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java new file mode 100644 index 000000000..6b51d0beb --- /dev/null +++ b/src/test/java/com/firebolt/jdbc/log/SLF4JLoggerTest.java @@ -0,0 +1,68 @@ +package com.firebolt.jdbc.log; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class SLF4JLoggerTest { + + @Test + void shouldLogWithCorrectLevel() { + try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { + Logger logger = mock(Logger.class); + mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); + SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); + slf4JLogger.debug("This is a debug log"); + slf4JLogger.warn("This is a warning log"); + slf4JLogger.error("This is an error log"); + slf4JLogger.trace("This is a trace log"); + verify(logger).debug("This is a debug log"); + verify(logger).warn("This is a warning log"); + verify(logger).error("This is an error log"); + verify(logger).trace("This is a trace log"); + } + } + + @Test + void shouldLogWithArguments() { + try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { + Logger logger = mock(Logger.class); + mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); + SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); + slf4JLogger.debug("This debug log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + slf4JLogger.warn("This warning log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + slf4JLogger.error("This error log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + slf4JLogger.trace("This trace log has some arguments: {}, {}, {}", "arg1", "arg2", "arg3"); + Object[] args = new Object[] { "arg1", "arg2", "arg3" }; + verify(logger).debug("This debug log has some arguments: {}, {}, {}", args); + verify(logger).warn("This warning log has some arguments: {}, {}, {}", args); + verify(logger).error("This error log has some arguments: {}, {}, {}", args); + verify(logger).trace("This trace log has some arguments: {}, {}, {}", args); + } + } + + @Test + void shouldLogWithThrowable() { + try (MockedStatic mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) { + Logger logger = mock(Logger.class); + mockedLoggerFactory.when(() -> LoggerFactory.getLogger(anyString())).thenReturn(logger); + SLF4JLogger slf4JLogger = new SLF4JLogger("logger"); + IllegalArgumentException illegalArgumentException = new IllegalArgumentException(); + slf4JLogger.debug("This debug log has an exception", illegalArgumentException); + slf4JLogger.warn("This warning log has an exception", illegalArgumentException); + slf4JLogger.error("This error log has an exception", illegalArgumentException); + slf4JLogger.trace("This trace log has an exception", illegalArgumentException); + verify(logger).debug("This debug log has an exception", illegalArgumentException); + verify(logger).warn("This warning log has an exception", illegalArgumentException); + verify(logger).error("This error log has an exception", illegalArgumentException); + verify(logger).trace("This trace log has an exception", illegalArgumentException); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java index 0c8d366ea..b42a68b0c 100644 --- a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java @@ -281,7 +281,8 @@ public String getLabel() { assertNull(fireboltStatement.getResultSet()); fireboltStatement.getMoreResults(CLOSE_CURRENT_RESULT); verify(fireboltStatementService, times(0)).execute(any(), any(), any()); - assertTrue(logMessages.contains("Aborted query with id other label"), "Expected log message is not found"); + // TODO: fix logging here, since we've reverted logging to lombok it doesn't catch log messages properly anymore + // assertTrue(logMessages.contains("Aborted query with id other label"), "Expected log message is not found"); } diff --git a/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java b/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java index 245198ee8..7b334070e 100644 --- a/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/LoggerUtilTest.java @@ -1,23 +1,23 @@ package com.firebolt.jdbc.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; -import org.slf4j.bridge.SLF4JBridgeHandler; + +import com.firebolt.jdbc.log.FireboltLogger; +import com.firebolt.jdbc.log.SLF4JLogger; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Logger; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; class LoggerUtilTest { @Test void shouldGetSLF4JLoggerWhenAvailable() { - Logger fireboltLogger = LoggerUtil.getRootLogger(); + FireboltLogger fireboltLogger = LoggerUtil.getLogger("myLogger"); // Should be true since SLF4J is available - assertTrue(Arrays.stream(fireboltLogger.getHandlers()).anyMatch(handler -> handler instanceof SLF4JBridgeHandler)); + assertTrue(fireboltLogger instanceof SLF4JLogger); } @Test From 51862371cb1385551de2bc5295a6db4f2986fa98 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:59:04 +0100 Subject: [PATCH 33/52] chore: Bump version to 3.1.1 (#445) --- gradle.properties | 4 ++-- .../firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java | 2 +- src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9ffbf99dc..3aa759746 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=3.1.0 -jdbcVersion=4.3 \ No newline at end of file +version=3.1.1 +jdbcVersion=4.3 diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 61789090b..6825e1976 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -353,7 +353,7 @@ void shouldGetDriverMinorVersion() { @Test void shouldGetDriverVersion() throws SQLException { - assertEquals("3.1.0", fireboltDatabaseMetadata.getDriverVersion()); + assertEquals("3.1.1", fireboltDatabaseMetadata.getDriverVersion()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java index d4821cd04..ae4a27381 100644 --- a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java @@ -17,7 +17,7 @@ void shouldGetDriverMinorVersion() { } @Test - void shouldGetProjectVersion() { assertEquals("3.1.0", VersionUtil.getDriverVersion()); } + void shouldGetProjectVersion() { assertEquals("3.1.1", VersionUtil.getDriverVersion()); } @Test void shouldGetMinorVersionFromString() { From 4e47282c688ea8e4145cf376ea2efe8ebe4c85ff Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:41:51 +0100 Subject: [PATCH 34/52] ci: Simplify integration test workflows (#446) --- .github/workflows/integration-test-v1.yml | 13 +++++-- .github/workflows/integration-test-v2.yml | 36 ++++++++++++++++---- .github/workflows/integration-test.yml | 41 +---------------------- 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/.github/workflows/integration-test-v1.yml b/.github/workflows/integration-test-v1.yml index 7a5dcc33c..caa03e314 100644 --- a/.github/workflows/integration-test-v1.yml +++ b/.github/workflows/integration-test-v1.yml @@ -1,15 +1,24 @@ name: Run integration tests v1 on: + workflow_dispatch: + inputs: + database: + description: 'Database override' + required: false + default: '' + engine: + description: 'Engine override' + required: false workflow_call: inputs: database: - description: 'Database - a new one will be created if not provided' + description: 'Database override' required: false default: '' type: string engine: - description: 'Engine - a new one will be created if not provided' + description: 'Engine override' required: false type: string secrets: diff --git a/.github/workflows/integration-test-v2.yml b/.github/workflows/integration-test-v2.yml index 1f0a1920f..f8dda8e19 100644 --- a/.github/workflows/integration-test-v2.yml +++ b/.github/workflows/integration-test-v2.yml @@ -1,20 +1,33 @@ name: Run integration tests v2 on: + workflow_dispatch: + inputs: + database: + description: 'Database override' + required: false + default: '' + engine: + description: 'Engine override' + required: false + account: + description: 'Account override' + required: false + type: string workflow_call: inputs: database: - description: 'Database - a new one will be created if not provided' + description: 'Database override' required: false default: '' type: string engine: - description: 'Engine - a new one will be created if not provided' + description: 'Engine override' required: false type: string account: - description: 'Account' - required: true + description: 'Account override' + required: false type: string secrets: FIREBOLT_CLIENT_ID_STG_NEW_IDN: @@ -34,6 +47,17 @@ jobs: script: | core.setFailed("Database and Engine parameters should be provided simultaneously") + - name: Resolve account + id: set-account + run: | + if ! [[ -z "${{ inputs.account }}" ]]; then + echo "account=${{ inputs.account }}" >> $GITHUB_OUTPUT + echo "account=${{ inputs.account }}" + else + echo "account=${{ vars.FIREBOLT_ACCOUNT }}" >> $GITHUB_OUTPUT + echo "account=${{ vars.FIREBOLT_ACCOUNT }}" + fi + - name: Check out code uses: actions/checkout@v3 @@ -50,7 +74,7 @@ jobs: with: firebolt-client-id: ${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }} firebolt-client-secret: ${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }} - account: ${{ inputs.account }} + account: ${{ steps.set-account.outputs.account }} api-endpoint: "api.staging.firebolt.io" - name: Determine database name @@ -72,4 +96,4 @@ jobs: fi - name: Run integration tests - run: ./gradlew integrationTest -Ddb=${{ steps.find-database-name.outputs.database_name }} -Denv=staging -Dclient_secret="${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }}" -Dclient_id="${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }}" -Daccount="${{ inputs.account }}" -Dengine="${{ steps.find-engine-name.outputs.engine_name }}" -DexcludeTags=v1 + run: ./gradlew integrationTest -Ddb=${{ steps.find-database-name.outputs.database_name }} -Denv=staging -Dclient_secret="${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }}" -Dclient_id="${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }}" -Daccount="${{ steps.set-account.outputs.account }}" -Dengine="${{ steps.find-engine-name.outputs.engine_name }}" -DexcludeTags=v1 diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 9c99320bc..7be2cef70 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -2,56 +2,17 @@ name: Run integration tests on: workflow_dispatch: - inputs: - database1: - description: 'Database (v1) - a new one will be created if not provided' - required: false - default: '' - database-with-engine-v2: - description: 'Database (v2) for Firebolt v2 - a new one will be created if not provided' - required: false - default: '' - engine1: - description: 'Engine (v1) - a new one will be created if not provided' - required: false - engine_v2_fb_2_0: - description: 'Engine (v2) for Firebolt v2 - a new one will be created if not provided' - required: false - run-v1: - description: 'Run tests against Firebolt DB v1' - required: true - default: true - type: choice - options: - - 'true' - - 'false' - run-database-with-engine-v2: - description: 'Run tests against Firebolt DB v2 and Engine V2' - required: true - default: true - type: choice - options: - - 'true' - - 'false' + workflow_call: jobs: run-integration-tests1: - if: ${{ inputs.run-v1 == 'true' }} uses: ./.github/workflows/integration-test-v1.yml - with: - database: ${{ inputs.database1 }} - engine: ${{ inputs.engine1 }} secrets: FIREBOLT_STG_USERNAME: ${{ secrets.FIREBOLT_STG_USERNAME }} FIREBOLT_STG_PASSWORD: ${{ secrets.FIREBOLT_STG_PASSWORD }} run-integration-tests-engine2: - if: ${{ inputs.run-database-with-engine-v2 == 'true' }} uses: ./.github/workflows/integration-test-v2.yml - with: - database: ${{ inputs.database-with-engine-v2 }} - engine: ${{ inputs.engine_v2_fb_2_0 }} - account: ${{ vars.FIREBOLT_ACCOUNT_V2 }} secrets: FIREBOLT_CLIENT_ID_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_ID_STG_NEW_IDN }} FIREBOLT_CLIENT_SECRET_STG_NEW_IDN: ${{ secrets.FIREBOLT_CLIENT_SECRET_STG_NEW_IDN }} From e967a62d020a3e1bb528c7ab7a243d33dc6d7c7c Mon Sep 17 00:00:00 2001 From: Mosha Pasumansky <93998884+moshap-firebolt@users.noreply.github.com> Date: Tue, 23 Jul 2024 07:34:41 -0700 Subject: [PATCH 35/52] refactor: Remove deprecated firebolt_enable_beta_functions (#447) --- .../com/firebolt/jdbc/connection/FireboltConnectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index c77710523..7428a4db5 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -85,7 +85,7 @@ @ExtendWith(MockitoExtension.class) abstract class FireboltConnectionTest { - private static final String LOCAL_URL = "jdbc:firebolt:local_dev_db?account=dev&ssl=false&max_query_size=10000000&mask_internal_errors=0&firebolt_enable_beta_functions=1&firebolt_case_insensitive_identifiers=1&rest_api_pull_timeout_sec=3600&rest_api_pull_interval_millisec=5000&rest_api_retry_times=10&host=localhost"; + private static final String LOCAL_URL = "jdbc:firebolt:local_dev_db?account=dev&ssl=false&max_query_size=10000000&mask_internal_errors=0&firebolt_case_insensitive_identifiers=1&rest_api_pull_timeout_sec=3600&rest_api_pull_interval_millisec=5000&rest_api_retry_times=10&host=localhost"; private final FireboltConnectionTokens fireboltConnectionTokens = new FireboltConnectionTokens(null, 0); @Captor private ArgumentCaptor propertiesArgumentCaptor; From 9daa67fc6274e339e6941438202af12412374044 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Tue, 30 Jul 2024 15:01:26 +0300 Subject: [PATCH 36/52] fix: Fir 35049 dont reset engine autostop with service queries in drivers for jdbc (#448) --- .../firebolt/jdbc/connection/FireboltConnection.java | 12 ++++++++---- .../jdbc/connection/FireboltConnectionTest.java | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 14cfd8096..1129935f8 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -417,7 +417,7 @@ public boolean isValid(int timeout) throws SQLException { } try { if (!loginProperties.isSystemEngine()) { - validateConnection(getSessionProperties(), true); + validateConnection(getSessionProperties(), true, true); } return true; } catch (Exception e) { @@ -425,9 +425,13 @@ public boolean isValid(int timeout) throws SQLException { } } - private void validateConnection(FireboltProperties fireboltProperties, boolean ignoreToManyRequestsError) + private void validateConnection(FireboltProperties fireboltProperties, boolean ignoreToManyRequestsError, boolean isInternalRequest) throws SQLException { - try (Statement s = createStatement(fireboltProperties)) { + FireboltProperties propertiesCopy = FireboltProperties.copy(fireboltProperties); + if (isInternalRequest) { + propertiesCopy.addProperty("auto_start_stop_control", "ignore"); + } + try (Statement s = createStatement(propertiesCopy)) { s.execute("SELECT 1"); } catch (Exception e) { // A connection is not invalid when too many requests are being sent. @@ -470,7 +474,7 @@ private synchronized void changeProperty(Consumer properties try { FireboltProperties tmpProperties = FireboltProperties.copy(sessionProperties); propertiesEditor.accept(tmpProperties); - validateConnection(tmpProperties, false); + validateConnection(tmpProperties, false, false); propertiesEditor.accept(sessionProperties); } catch (FireboltException e) { throw e; diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index 7428a4db5..a372e3b98 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -336,6 +336,7 @@ void shouldValidateConnectionWhenCallingIsValid() throws SQLException { verify(fireboltStatementService).execute(queryInfoWrapperArgumentCaptor.capture(), propertiesArgumentCaptor.capture(), any()); assertEquals(List.of("SELECT 1"), queryInfoWrapperArgumentCaptor.getAllValues().stream().map(StatementInfoWrapper::getSql).collect(toList())); + assertEquals(Map.of("auto_start_stop_control", "ignore"), propertiesArgumentCaptor.getValue().getAdditionalProperties()); } } From 741ccc533a12036ad26acc14bd61a0714f728970 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 09:40:10 +0100 Subject: [PATCH 37/52] Bump actions/download-artifact from 3 to 4.1.7 in /.github/workflows (#453) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/performance-test.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index 31973ef9d..e8b908a42 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -30,7 +30,7 @@ jobs: mkdir dependencies - name: Download uber-jar id: download-jar - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.7 with: name: ${{ needs.build.outputs.uber-jar }} path: dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c51f547bf..4faa50464 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,11 +22,11 @@ jobs: with: ref: ${{ github.event.release.tag_name || github.event.inputs.tag_name}} - name: Download uber-jar - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.7 with: name: ${{ needs.build.outputs.uber-jar }} - name: Download sources-jar - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4.1.7 with: name: ${{ needs.build.outputs.sources-jar }} - uses: xresloader/upload-to-github-release@v1 From b97c8bbc03ea36f6ef81c22ed04708fbbb5d6929 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Mon, 9 Sep 2024 13:19:18 +0300 Subject: [PATCH 38/52] refactor: FIR-35469 remove account resolve endpoint from jdbc (#452) --- .../integration/tests/SystemEngineTest.java | 5 +-- .../java/integration/tests/TimeoutTest.java | 2 +- .../account/FireboltAccountRetriever.java | 10 +++--- .../client/query/StatementClientImpl.java | 5 ++- .../FireboltConnectionServiceSecret.java | 14 +++----- .../gateway/FireboltGatewayUrlClientTest.java | 35 +++++-------------- 6 files changed, 24 insertions(+), 47 deletions(-) diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 549d22db9..6e400ca16 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -136,7 +136,8 @@ void shouldFailToSelectFromCustomDbUsingSystemEngine() throws SQLException { } FireboltException e = assertThrows(FireboltException.class, () -> systemConnection.createStatement().executeQuery("select count(*) from dummy")); String actualErrorMessage = e.getErrorMessageFromServer().replaceAll("\r?\n", ""); - assertTrue(expectedErrorMessages.contains(actualErrorMessage), "Unexpected error message: " + actualErrorMessage); + // Check that at least one error message from expectedErrorMessages is contained in the actual error message + assertTrue(expectedErrorMessages.stream().anyMatch(actualErrorMessage::contains), "Unexpected error message: " + actualErrorMessage); } finally { try { customConnection.createStatement().executeUpdate("DROP TABLE dummy"); @@ -292,7 +293,7 @@ private String getClientSecret(Connection connection, String serviceAccountName, FireboltConnection fbConn = (FireboltConnection)connection; String accessToken = fbConn.getAccessToken().orElseThrow(() -> new IllegalStateException("access token is not found")); FireboltProperties fbProps = fbConn.getSessionProperties(); - URL url = new URL(format("%s/query?output_format=TabSeparatedWithNamesAndTypes&database=%s&account_id=%s", fbProps.getHttpConnectionUrl(), database, fbProps.getAccountId())); + URL url = new URL(format("%s/query?output_format=TabSeparatedWithNamesAndTypes&database=%s", fbProps.getHttpConnectionUrl(), database)); HttpURLConnection con = (HttpURLConnection)url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); diff --git a/src/integrationTest/java/integration/tests/TimeoutTest.java b/src/integrationTest/java/integration/tests/TimeoutTest.java index 54fa6cd28..0a8b281b6 100644 --- a/src/integrationTest/java/integration/tests/TimeoutTest.java +++ b/src/integrationTest/java/integration/tests/TimeoutTest.java @@ -24,7 +24,7 @@ @CustomLog class TimeoutTest extends IntegrationTest { private static final int MIN_TIME_SECONDS = 350; - private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 180000000000L); + private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 600000000000L); private long startTime; @BeforeEach diff --git a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java index 8b4876af4..3e578829f 100644 --- a/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java +++ b/src/main/java/com/firebolt/jdbc/client/account/FireboltAccountRetriever.java @@ -15,22 +15,20 @@ import static java.net.HttpURLConnection.HTTP_NOT_FOUND; public class FireboltAccountRetriever extends FireboltClient implements CacheListener { - private static final String URL = "https://%s/web/v3/account/%s/%s"; + private static final String URL = "https://%s/web/v3/account/%s/engineUrl"; private final String host; - private final String path; private final Class type; private static final Map valueCache = new ConcurrentHashMap<>(); - public FireboltAccountRetriever(OkHttpClient httpClient, FireboltConnection connection, String customDrivers, String customClients, String host, String path, Class type) { + public FireboltAccountRetriever(OkHttpClient httpClient, FireboltConnection connection, String customDrivers, String customClients, String host, Class type) { super(httpClient, connection, customDrivers, customClients); this.host = host; - this.path = path; this.type = type; } public T retrieve(String accessToken, String accountName) throws SQLException { try { - String url = format(URL, host, accountName, path); + String url = format(URL, host, accountName); @SuppressWarnings("unchecked") T value = (T)valueCache.get(url); if (value == null) { @@ -39,7 +37,7 @@ public T retrieve(String accessToken, String accountName) throws SQLException { } return value; } catch (IOException e) { - throw new FireboltException(String.format("Failed to get %s url for account %s: %s", path, accountName, e.getMessage()), e); + throw new FireboltException(String.format("Failed to get engine url for account %s: %s", accountName, e.getMessage()), e); } } diff --git a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java index 5fb4a3fa4..8e37b9b3c 100644 --- a/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java +++ b/src/main/java/com/firebolt/jdbc/client/query/StatementClientImpl.java @@ -314,9 +314,12 @@ private Map getAllParameters(FireboltProperties fireboltProperti } } else { if (connection.getInfraVersion() >= 2) { + String engine = fireboltProperties.getEngine(); if (accountId != null) { params.put(FireboltQueryParameterKey.ACCOUNT_ID.getKey(), accountId); - params.put(FireboltQueryParameterKey.ENGINE.getKey(), fireboltProperties.getEngine()); + } + if (engine != null) { + params.put(FireboltQueryParameterKey.ENGINE.getKey(), engine); } params.put(FireboltQueryParameterKey.QUERY_LABEL.getKey(), statementInfoWrapper.getLabel()); //QUERY_LABEL } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index ab08eb342..72122f9a4 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -34,7 +34,6 @@ public class FireboltConnectionServiceSecret extends FireboltConnection { private static final String PROTOCOL_VERSION = "2.1"; private final FireboltGatewayUrlService fireboltGatewayUrlService; - private final FireboltAccountIdService fireboltAccountIdService; private FireboltEngineService fireboltEngineService; // depends on infra version and is discovered during authentication FireboltConnectionServiceSecret(@NonNull String url, @@ -46,7 +45,6 @@ public class FireboltConnectionServiceSecret extends FireboltConnection { FireboltAccountIdService fireboltAccountIdService) throws SQLException { super(url, connectionSettings, fireboltAuthenticationService, fireboltStatementService, PROTOCOL_VERSION); this.fireboltGatewayUrlService = fireboltGatewayUrlService; - this.fireboltAccountIdService = fireboltAccountIdService; this.fireboltEngineService = fireboltEngineService; connect(); } @@ -55,14 +53,13 @@ public class FireboltConnectionServiceSecret extends FireboltConnection { FireboltConnectionServiceSecret(@NonNull String url, Properties connectionSettings) throws SQLException { super(url, connectionSettings, PROTOCOL_VERSION); OkHttpClient httpClient = getHttpClient(loginProperties); - this.fireboltGatewayUrlService = new FireboltGatewayUrlService(createFireboltAccountRetriever(httpClient,"engineUrl", GatewayUrlResponse.class)); - this.fireboltAccountIdService = new FireboltAccountIdService(createFireboltAccountRetriever(httpClient,"resolve", FireboltAccount.class)); + this.fireboltGatewayUrlService = new FireboltGatewayUrlService(createFireboltAccountRetriever(httpClient, GatewayUrlResponse.class)); // initialization of fireboltEngineService depends on the infraVersion (the version of engine) connect(); } - private FireboltAccountRetriever createFireboltAccountRetriever(OkHttpClient httpClient, String path, Class type) { - return new FireboltAccountRetriever<>(httpClient, this, loginProperties.getUserDrivers(), loginProperties.getUserClients(), loginProperties.getHost(), path, type); + private FireboltAccountRetriever createFireboltAccountRetriever(OkHttpClient httpClient, Class type) { + return new FireboltAccountRetriever<>(httpClient, this, loginProperties.getUserDrivers(), loginProperties.getUserClients(), loginProperties.getHost(), type); } @Override @@ -102,11 +99,9 @@ protected void assertDatabaseExisting(String database) throws SQLException { private FireboltProperties getSessionPropertiesForSystemEngine(String accessToken, String accountName) throws SQLException { String systemEngineEndpoint = fireboltGatewayUrlService.getUrl(accessToken, accountName); - FireboltAccount account = fireboltAccountIdService.getValue(accessToken, accountName); - infraVersion = account.getInfraVersion(); + infraVersion = 2; URL systemEngienUrl = UrlUtil.createUrl(systemEngineEndpoint); Map systemEngineUrlUrlParams = UrlUtil.getQueryParameters(systemEngienUrl); - String accountId = systemEngineUrlUrlParams.getOrDefault(ACCOUNT_ID.getKey(), account.getId()); for (Entry e : systemEngineUrlUrlParams.entrySet()) { loginProperties.addProperty(e); } @@ -114,7 +109,6 @@ private FireboltProperties getSessionPropertiesForSystemEngine(String accessToke .toBuilder() .systemEngine(true) .compress(false) - .accountId(accountId) .host(systemEngienUrl.getHost()) .build(); } diff --git a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java index 360eac32b..c0aa7d13d 100644 --- a/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java +++ b/src/test/java/com/firebolt/jdbc/client/gateway/FireboltGatewayUrlClientTest.java @@ -65,13 +65,11 @@ class FireboltAccountRetrieverTest { private FireboltConnection fireboltConnection; private FireboltAccountRetriever fireboltGatewayUrlClient; - private FireboltAccountRetriever fireboltAccountIdResolver; @BeforeEach void setUp() { - fireboltGatewayUrlClient = new FireboltAccountRetriever<>(httpClient, fireboltConnection, null, null, "test-firebolt.io", "engineUrl", GatewayUrlResponse.class); - fireboltAccountIdResolver = new FireboltAccountRetriever<>(httpClient, fireboltConnection, null, null, "test-firebolt.io", "resolve", FireboltAccount.class); + fireboltGatewayUrlClient = new FireboltAccountRetriever<>(httpClient, fireboltConnection, null, null, "test-firebolt.io", GatewayUrlResponse.class); } @Test @@ -81,21 +79,6 @@ void shouldGetGatewayUrlWhenResponseIsOk() throws SQLException, IOException { assertEquals(engineUrl, fireboltGatewayUrlClient.retrieve("access_token", "account").getEngineUrl()); } - @Test - void shouldGetAccountId() throws SQLException, IOException { - fireboltAccountIdResolver.cleanup(); - FireboltAccount account = new FireboltAccount("12345", "central", 2); - injectMockedResponse(httpClient, HTTP_OK, "{\"id\": \"12345\", \"region\":\"central\", \"infraVersion\":2}"); - assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); - Mockito.verify(httpClient, times(1)).newCall(any()); - // Do this again. The response is cached, so the invocation count will remain 1 - assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); - // now clean the cache and call resolve() again. The invocation counter will be incremented. - fireboltAccountIdResolver.cleanup(); - assertEquals(account, fireboltAccountIdResolver.retrieve("access_token", "account")); - Mockito.verify(httpClient, times(2)).newCall(any()); - } - @Test void shouldRuntimeExceptionUponRuntimeException() { when(httpClient.newCall(any())).thenThrow(new IllegalArgumentException("ex")); @@ -107,20 +90,19 @@ void shouldThrowFireboltExceptionUponIOException() throws IOException { Call call = mock(Call.class); when(httpClient.newCall(any())).thenReturn(call); when(call.execute()).thenThrow(new IOException("io error")); - assertEquals("Failed to get engineUrl url for account acc: io error", assertThrows(FireboltException.class, () -> fireboltGatewayUrlClient.retrieve("token", "acc")).getMessage()); + assertEquals("Failed to get engine url for account acc: io error", assertThrows(FireboltException.class, () -> fireboltGatewayUrlClient.retrieve("token", "acc")).getMessage()); } @ParameterizedTest(name = "{0}:{1}") @CsvSource({ - "resolve, com.firebolt.jdbc.client.account.FireboltAccount, {}, JSONObject[\"id\"] not found.", - "engineUrl, com.firebolt.jdbc.client.gateway.GatewayUrlResponse, {}, JSONObject[\"engineUrl\"] not found." + "com.firebolt.jdbc.client.gateway.GatewayUrlResponse, {}, JSONObject[\"engineUrl\"] not found." }) - void shouldThrowFireboltExceptionUponWrongJsonFormat(String path, Class clazz, String json, String expectedErrorMessage) throws IOException { - FireboltAccountRetriever fireboltAccountIdResolver = mockAccountRetriever(path, clazz, json); - assertEquals(format("Failed to get %s url for account acc: %s", path, expectedErrorMessage), assertThrows(FireboltException.class, () -> fireboltAccountIdResolver.retrieve("token", "acc")).getMessage()); + void shouldThrowFireboltExceptionUponWrongJsonFormat(Class clazz, String json, String expectedErrorMessage) throws IOException { + FireboltAccountRetriever fireboltAccountIdResolver = mockAccountRetriever(clazz, json); + assertEquals(format("Failed to get engine url for account acc: %s", expectedErrorMessage), assertThrows(FireboltException.class, () -> fireboltAccountIdResolver.retrieve("token", "acc")).getMessage()); } - private FireboltAccountRetriever mockAccountRetriever(String path, Class clazz, String json) throws IOException { + private FireboltAccountRetriever mockAccountRetriever(Class clazz, String json) throws IOException { try (Response response = mock(Response.class)) { when(response.code()).thenReturn(200); ResponseBody responseBody = mock(ResponseBody.class); @@ -130,7 +112,7 @@ private FireboltAccountRetriever mockAccountRetriever(String path, Class< Call call = mock(); when(call.execute()).thenReturn(response); when(okHttpClient.newCall(any())).thenReturn(call); - return new FireboltAccountRetriever<>(okHttpClient, mock(), null, null, "test-firebolt.io", path, clazz); + return new FireboltAccountRetriever<>(okHttpClient, mock(), null, null, "test-firebolt.io", clazz); } } @@ -165,7 +147,6 @@ private FireboltAccountRetriever mockAccountRetriever(String path, Class< }) void testFailedAccountDataRetrieving(int statusCode, String errorMessageTemplate) throws IOException { injectMockedResponse(httpClient, statusCode, null); - assertErrorMessage(fireboltAccountIdResolver, "one", format(errorMessageTemplate, "one", "resolve")); assertErrorMessage(fireboltGatewayUrlClient, "two", format(errorMessageTemplate, "two", "engineUrl")); } From 487ec3d409f2608b7129d3a14c0589ca09cc5328 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:53:37 +0100 Subject: [PATCH 39/52] fix(FIR-35270): Avoid printing secrets in logs (#454) --- .../jdbc/statement/FireboltStatement.java | 12 +++- .../jdbc/statement/FireboltStatementTest.java | 69 ++++++++++++------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java index be2f49949..3e2a35549 100644 --- a/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/FireboltStatement.java @@ -108,9 +108,8 @@ private Optional execute(StatementInfoWrapper statementInfoWrapper) t } InputStream inputStream = null; try { - - log.info("Executing the statement with label {} : {}", statementInfoWrapper.getLabel(), - statementInfoWrapper.getSql()); + log.debug("Executing the statement with label {} : {}", statementInfoWrapper.getLabel(), + sanitizeSql(statementInfoWrapper.getSql())); if (statementInfoWrapper.getType() == StatementType.PARAM_SETTING) { connection.addProperty(statementInfoWrapper.getParam()); log.debug("The property from the query {} was stored", runningStatementLabel); @@ -519,4 +518,11 @@ public void setPoolable(boolean poolable) throws SQLException { public boolean hasMoreResults() { return currentStatementResult.getNext() != null; } + + private String sanitizeSql(String sql) { + // Replace any occurrence of secrets with *** + return sql.replaceAll("AWS_KEY_ID\\s*=\\s*[\\S]*", "AWS_KEY_ID=***") + .replaceAll("AWS_SECRET_KEY\\s*=\\s*[\\S]*", + "AWS_SECRET_KEY=***"); + } } diff --git a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java index b42a68b0c..eb76e027d 100644 --- a/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java +++ b/src/test/java/com/firebolt/jdbc/statement/FireboltStatementTest.java @@ -33,17 +33,16 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.sql.Wrapper; -import java.text.MessageFormat; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; import java.util.stream.Stream; +import org.slf4j.LoggerFactory; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import static java.lang.String.format; import static java.sql.Statement.CLOSE_CURRENT_RESULT; @@ -241,23 +240,13 @@ void test() throws SQLException { FireboltConnection connection = mock(FireboltConnection.class); FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, connection); - List logMessages = new ArrayList<>(); - Logger log = Logger.getLogger(FireboltStatement.class.getName()); - log.setLevel(Level.ALL); - log.addHandler(new Handler() { - @Override - public void publish(LogRecord record) { - logMessages.add(new MessageFormat(record.getMessage()).format(record.getParameters())); - } + Logger fooLogger = (Logger) LoggerFactory.getLogger(FireboltStatement.class); - @Override - public void flush() { - } + fooLogger.setLevel(Level.ALL); + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); - @Override - public void close() throws SecurityException { - } - }); + fooLogger.addAppender(listAppender); String query = "SELECT 1"; // This trick simulates cancelled statement. getLabel() called first time returns the initial label generated @@ -281,8 +270,9 @@ public String getLabel() { assertNull(fireboltStatement.getResultSet()); fireboltStatement.getMoreResults(CLOSE_CURRENT_RESULT); verify(fireboltStatementService, times(0)).execute(any(), any(), any()); - // TODO: fix logging here, since we've reverted logging to lombok it doesn't catch log messages properly anymore - // assertTrue(logMessages.contains("Aborted query with id other label"), "Expected log message is not found"); + + List logsList = listAppender.list; + assertTrue(logsList.stream().anyMatch(event -> event.getFormattedMessage().contains("Aborted query with id other label"))); } @@ -579,4 +569,37 @@ void shouldClearBatch() throws SQLException { assertArrayEquals(new int[] {SUCCESS_NO_INFO, SUCCESS_NO_INFO}, fireboltStatement.executeBatch()); } + + @ParameterizedTest + @CsvSource(value = { + "CREATE EXTERNAL TABLE x WITH CREDENTIALS = (AWS_KEY_ID='123', AWS_SECRET_KEY='4%5-6');", + "CREATE EXTERNAL TABLE x WITH CREDENTIALS = (AWS_KEY_ID ='123', AWS_SECRET_KEY= '4%5-6');", + "CREATE EXTERNAL TABLE x WITH CREDENTIALS = (AWS_KEY_ID = '123', AWS_SECRET_KEY = '4%5-6');", + "COPY INTO x FROM s3 WITH CREDENTIALS = (AWS_KEY_ID = '123' AWS_SECRET_KEY = '4%5-6');", + "COPY INTO x FROM s3 WITH CREDENTIALS = (AWS_KEY_ID = '123', AWS_SECRET_KEY = '4%5-6') ERROR_FILE_CREDENTIALS = AWS_KEY_ID = '123' AWS_SECRET_KEY = '4%5-6';", + "COPY INTO x FROM s3 WITH ERROR_FILE_CREDENTIALS = AWS_KEY_ID = '123' AWS_SECRET_KEY = '4%5-6';" + }, delimiter = ';') + void shouldNotOutputAWSKeyIdInDebugLogs(String query) throws SQLException { + + Logger fooLogger = (Logger) LoggerFactory.getLogger(FireboltStatement.class); + + fooLogger.setLevel(Level.ALL); + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + + fooLogger.addAppender(listAppender); + + FireboltConnection connection = mock(FireboltConnection.class); + FireboltStatement fireboltStatement = new FireboltStatement(fireboltStatementService, fireboltProperties, + connection); + fireboltStatement.execute(query); + + List logsList = listAppender.list; + assertTrue(logsList.stream().noneMatch(event -> event.getFormattedMessage().contains("123"))); + assertTrue(logsList.stream().noneMatch(event -> event.getFormattedMessage().contains("4%5-6"))); + // Make sure the query is not lost + assertTrue(logsList.stream().anyMatch(event -> event.getFormattedMessage().contains("WITH"))); + assertTrue(logsList.stream().anyMatch(event -> event.getFormattedMessage().contains("AWS_KEY_ID"))); + assertTrue(logsList.stream().anyMatch(event -> event.getFormattedMessage().contains("AWS_SECRET_KEY"))); + } } \ No newline at end of file From b521ce2ae225597ce6d85a9ddb2a6606dd910cbd Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:00:25 +0200 Subject: [PATCH 40/52] ci: Bump upload artifact action version (#455) --- .github/workflows/build.yml | 4 ++-- .github/workflows/performance-test.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a3c56966a..5c03d7e59 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,12 +45,12 @@ jobs: run: | echo "PROJECT_VERSION=$(./gradlew printVersion |grep 'PROJECT_VERSION=' | cut -d= -f2)" >> $GITHUB_OUTPUT - name: Upload uber-jar - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: firebolt-jdbc-${{ steps.project-version.outputs.PROJECT_VERSION }}.jar path: build/libs/firebolt-jdbc-${{ steps.project-version.outputs.PROJECT_VERSION }}.jar - name: Upload sources-jar - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: firebolt-jdbc-${{ steps.project-version.outputs.PROJECT_VERSION }}-sources.jar path: build/libs/firebolt-jdbc-${{ steps.project-version.outputs.PROJECT_VERSION }}-sources.jar diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index e8b908a42..2216a720f 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -63,12 +63,12 @@ jobs: outputReportsFolder: reports/ args: -Jdatabase=${{ steps.find-database-name.outputs.database_name }} -Jpassword=${{ secrets.SERVICE_ACCOUNT_SECRET_STAGING }} -Jusername=${{ secrets.SERVICE_ACCOUNT_ID_STAGING }} -Jdriver=${{ needs.build.outputs.uber-jar }} -Jenvironment=staging -Jthreads=${{ inputs.threads }} -Jloops=${{ inputs.loops }} - name: Upload JMeter report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: performance_test_report path: reports - name: Upload JMeter logs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jmeter_log.log path: jmeter_log.log From d2da66f75120416bb4e252aaa06e30dfcdb629d1 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:14:32 +0200 Subject: [PATCH 41/52] chore: Bump version to 3.2.0 (#456) --- gradle.properties | 2 +- src/test/java/com/firebolt/FireboltDriverTest.java | 2 +- .../jdbc/metadata/FireboltDatabaseMetadataTest.java | 4 ++-- src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3aa759746..bed2e6860 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=3.1.1 +version=3.2.0 jdbcVersion=4.3 diff --git a/src/test/java/com/firebolt/FireboltDriverTest.java b/src/test/java/com/firebolt/FireboltDriverTest.java index 0f72b83d5..f4dd19450 100644 --- a/src/test/java/com/firebolt/FireboltDriverTest.java +++ b/src/test/java/com/firebolt/FireboltDriverTest.java @@ -93,7 +93,7 @@ void jdbcCompliant() { void version() { FireboltDriver fireboltDriver = new FireboltDriver(); assertEquals(3, fireboltDriver.getMajorVersion()); - assertEquals(1, fireboltDriver.getMinorVersion()); + assertEquals(2, fireboltDriver.getMinorVersion()); } @ParameterizedTest diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 6825e1976..137c75ba2 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -348,12 +348,12 @@ void shouldGetDriverMajorVersion() { @Test void shouldGetDriverMinorVersion() { - assertEquals(1, fireboltDatabaseMetadata.getDriverMinorVersion()); + assertEquals(2, fireboltDatabaseMetadata.getDriverMinorVersion()); } @Test void shouldGetDriverVersion() throws SQLException { - assertEquals("3.1.1", fireboltDatabaseMetadata.getDriverVersion()); + assertEquals("3.2.0", fireboltDatabaseMetadata.getDriverVersion()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java index ae4a27381..d65f68787 100644 --- a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java @@ -13,11 +13,13 @@ void shouldGetDriverMajorVersion() { @Test void shouldGetDriverMinorVersion() { - assertEquals(1, VersionUtil.getDriverMinorVersion()); + assertEquals(2, VersionUtil.getDriverMinorVersion()); } @Test - void shouldGetProjectVersion() { assertEquals("3.1.1", VersionUtil.getDriverVersion()); } + void shouldGetProjectVersion() { + assertEquals("3.2.0", VersionUtil.getDriverVersion()); + } @Test void shouldGetMinorVersionFromString() { From dc4463f439f2d8ad756dcfc43b4827c34ac69970 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:29:45 +0200 Subject: [PATCH 42/52] docs: Fix readme link (#463) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06a6ec21e..ca90b5af7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The official JDBC driver for Firebolt. ## Documentation -To download the JDBC driver and learn how to use it, please see the official [Firebolt documentation](https://docs.firebolt.io/developing-with-firebolt/connecting-with-jdbc.html). +To download the JDBC driver and learn how to use it, please see the official [Firebolt documentation](https://docs.firebolt.io/Guides/developing-with-firebolt/connecting-with-jdbc.html). ## Development The code of this repository is formatted using the Eclipse formatter, which was chosen because it is supported by multiple modern IDEs (such as Intellij). From ed3af1ef7d9ef1f7e72ff4eb58f70a2040505059 Mon Sep 17 00:00:00 2001 From: Mosha Pasumansky <93998884+moshap-firebolt@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:42:11 -0700 Subject: [PATCH 43/52] Remove old/unused settings from FireboltConnectionTest (#466) --- .../com/firebolt/jdbc/connection/FireboltConnectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java index a372e3b98..d4d4b30d5 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionTest.java @@ -85,7 +85,7 @@ @ExtendWith(MockitoExtension.class) abstract class FireboltConnectionTest { - private static final String LOCAL_URL = "jdbc:firebolt:local_dev_db?account=dev&ssl=false&max_query_size=10000000&mask_internal_errors=0&firebolt_case_insensitive_identifiers=1&rest_api_pull_timeout_sec=3600&rest_api_pull_interval_millisec=5000&rest_api_retry_times=10&host=localhost"; + private static final String LOCAL_URL = "jdbc:firebolt:local_dev_db?account=dev&ssl=false&max_query_size=10000000&mask_internal_errors=0&host=localhost"; private final FireboltConnectionTokens fireboltConnectionTokens = new FireboltConnectionTokens(null, 0); @Captor private ArgumentCaptor propertiesArgumentCaptor; From 4cdd782a112785c24473aa1485ee705220c26200 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:30:08 +0200 Subject: [PATCH 44/52] test: Fix unit tests when run locally from Mac OS (#465) --- src/test/java/com/firebolt/jdbc/client/UserAgentFormatter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/firebolt/jdbc/client/UserAgentFormatter.java b/src/test/java/com/firebolt/jdbc/client/UserAgentFormatter.java index 933cea4d7..e61ae04d5 100644 --- a/src/test/java/com/firebolt/jdbc/client/UserAgentFormatter.java +++ b/src/test/java/com/firebolt/jdbc/client/UserAgentFormatter.java @@ -8,7 +8,8 @@ public static String userAgent(String format) { } public static String userAgent(String format, String driverVersion, String javaVersion, String osName, String osVersion) { - return String.format(format, driverVersion, javaVersion, osName, osVersion); + // Mac OS is renamed to Darwin in the user agent string + return String.format(format, driverVersion, javaVersion, osName, osVersion).replace("Mac OS X", "Darwin"); } public static String osName() { From 4248ee40341228525b3917f64bb95da2f06a7869 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:30:21 +0200 Subject: [PATCH 45/52] tests: Fix integration tests (#467) --- .../integration/tests/ConnectionTest.java | 2 +- .../tests/DatabaseMetaDataTest.java | 2 +- .../integration/tests/SpecialValuesTest.java | 36 ++++++++++++++----- .../java/integration/tests/StatementTest.java | 19 +++++----- .../integration/tests/SystemEngineTest.java | 1 + .../java/integration/tests/TimeoutTest.java | 2 +- .../FireboltConnectionServiceSecret.java | 1 - 7 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/integrationTest/java/integration/tests/ConnectionTest.java b/src/integrationTest/java/integration/tests/ConnectionTest.java index 2dd2289a9..fb50440ea 100644 --- a/src/integrationTest/java/integration/tests/ConnectionTest.java +++ b/src/integrationTest/java/integration/tests/ConnectionTest.java @@ -55,7 +55,7 @@ void connectToNotExistingDb(EngineType engineType) { String url = format("jdbc:firebolt:%s?env=%s&account=%s%s", database, params.getEnv(), params.getAccount(), engineSuffix); FireboltException e = assertThrows(FireboltException.class, () -> DriverManager.getConnection(url, params.getPrincipal(), params.getSecret())); if (infraVersion >= 2) { - assertEquals(ExceptionType.ERROR, e.getType()); + assertEquals(ExceptionType.INVALID_REQUEST, e.getType()); String expectedMessage = format("Database '%s' does not exist or not authorized", database); assertTrue(e.getMessage().contains(expectedMessage), format("Error message '%s' does not match '%s'", e.getMessage(), expectedMessage)); } else { diff --git a/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java b/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java index ba83a7d50..0da3917fe 100644 --- a/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java +++ b/src/integrationTest/java/integration/tests/DatabaseMetaDataTest.java @@ -143,7 +143,7 @@ void shouldReturnTable() throws SQLException { ",,,VIEW,views;tables,integration_test", // table name pattern - ",,%account%,,service_account_users;service_accounts,tables;columns;views", + ",,%account%,,accounts;service_accounts,tables;columns;views", ",,%test,,integration_test,tables;columns;views", // schema name pattern diff --git a/src/integrationTest/java/integration/tests/SpecialValuesTest.java b/src/integrationTest/java/integration/tests/SpecialValuesTest.java index 823110219..0ab357fe5 100644 --- a/src/integrationTest/java/integration/tests/SpecialValuesTest.java +++ b/src/integrationTest/java/integration/tests/SpecialValuesTest.java @@ -1,9 +1,10 @@ package integration.tests; -import integration.EnvironmentCondition; import integration.IntegrationTest; +import lombok.CustomLog; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -15,25 +16,34 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +@CustomLog public class SpecialValuesTest extends IntegrationTest { private Connection systemConnection; private Connection userConnection; @BeforeAll void beforeAll() throws SQLException { - systemConnection = createConnection(getSystemEngineName()); + try { + systemConnection = createConnection(getSystemEngineName()); + } catch (Exception e) { + log.warn("Could not create system engine connection", e); + } userConnection = createConnection(); } @AfterAll void afterAll() throws SQLException { - systemConnection.close(); + try { + systemConnection.close(); + } catch (Exception e) { + log.warn("Could not create system engine connection", e); + } userConnection.close(); } @ParameterizedTest @ValueSource(strings = {"select 'inf'::float", "select '+inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) + @Tag("v1") void infFloatUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); } @@ -46,25 +56,28 @@ void infRealUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select 'inf'::real", "select '+inf'::real"}) + @Tag("v2") void infRealSystemEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); } @ParameterizedTest @ValueSource(strings = {"select 'inf'::float", "select '+inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) + @Tag("v2") void infFloatAsDoubleUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); } @ParameterizedTest @ValueSource(strings = {"select 'inf'::float", "select '+inf'::float"}) + @Tag("v2") void infFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); } @ParameterizedTest @ValueSource(strings = {"select 'inf'::double", "select '+inf'::double"}) + @Tag("v2") void infDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); } @@ -77,14 +90,14 @@ void infDoubleUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select '-inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) + @Tag("v1") void minusInfFloatUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); } @ParameterizedTest @ValueSource(strings = {"select '-inf'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) + @Tag("v2") void minusInfFloatAsDoubleUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); } @@ -97,12 +110,14 @@ void minusInfRealUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select '-inf'::real"}) + @Tag("v2") void minusInfRealSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); } @ParameterizedTest @ValueSource(strings = {"select '-inf'::float"}) + @Tag("v2") void minusInfFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); } @@ -115,7 +130,7 @@ void minusInfDoubleUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select 'nan'::float", "select '+nan'::float", "select '-nan'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.LT) + @Tag("v1") void nanFloatUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.NaN, Double.NaN, Float.NaN); } @@ -128,13 +143,14 @@ void nanRealUserEngine(String query) throws SQLException { @ParameterizedTest @ValueSource(strings = {"select 'nan'::real", "select '+nan'::real", "select '-nan'::real"}) + @Tag("v2") void nanRealSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NaN, Double.NaN, Float.NaN); } @ParameterizedTest @ValueSource(strings = {"select 'nan'::float", "select '+nan'::float", "select '-nan'::float"}) - @EnvironmentCondition(value = "2", comparison = EnvironmentCondition.Comparison.GE) + @Tag("v2") void nanFloatAsDoubleUserEngine(String query) throws SQLException { specialSelect(userConnection, query, Float.NaN, Double.NaN, Double.NaN); } @@ -143,6 +159,7 @@ void nanFloatAsDoubleUserEngine(String query) throws SQLException { @ValueSource(strings = { "select 'nan'::double", "select '+nan'::double", "select '-nan'::double" }) + @Tag("v2") void nanDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NaN, Double.NaN, Double.NaN); } @@ -151,6 +168,7 @@ void nanDoubleSystemEngine(String query) throws SQLException { @ValueSource(strings = { "select 'nan'::float", "select '+nan'::float", "select '-nan'::float", }) + @Tag("v2") void nanFloatAsDoubleSystemEngine(String query) throws SQLException { specialSelect(systemConnection, query, Float.NaN, Double.NaN, Double.NaN); } diff --git a/src/integrationTest/java/integration/tests/StatementTest.java b/src/integrationTest/java/integration/tests/StatementTest.java index 054177107..3df908b5c 100644 --- a/src/integrationTest/java/integration/tests/StatementTest.java +++ b/src/integrationTest/java/integration/tests/StatementTest.java @@ -102,6 +102,7 @@ void shouldThrowExceptionWhenTryingToReuseStatementClosedOnCompletion() throws S } } + @Tag("v2") @Test void shouldThrowExceptionWhenExecutingWrongQuery() throws SQLException { try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { @@ -110,7 +111,17 @@ void shouldThrowExceptionWhenExecutingWrongQuery() throws SQLException { } } + @Tag("v1") + @Test + void shouldThrowExceptionWhenExecutingWrongQueryV1() throws SQLException { + try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { + String errorMessage = assertThrows(FireboltException.class, () -> statement.executeQuery("select wrong query")).getMessage(); + assertTrue(errorMessage.contains("wrong")); + } + } + @Test + @Tag("v2") @EnvironmentCondition(value = "4.2.0", comparison = EnvironmentCondition.Comparison.GE) void shouldThrowExceptionWhenExecutingWrongQueryWithJsonError() throws SQLException { try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { @@ -337,14 +348,6 @@ void empty(String sql) throws SQLException { } } - @Test - @Tag("v1") - void divisionByZero() throws SQLException { - try (Connection connection = createConnection(); Statement statement = connection.createStatement()) { - assertThrows(SQLException.class, () -> statement.executeQuery("SELECT 1/0")); - } - } - /** * This test validates that null values are sorted last. * @throws SQLException if something is going wrong diff --git a/src/integrationTest/java/integration/tests/SystemEngineTest.java b/src/integrationTest/java/integration/tests/SystemEngineTest.java index 6e400ca16..df76f0e2b 100644 --- a/src/integrationTest/java/integration/tests/SystemEngineTest.java +++ b/src/integrationTest/java/integration/tests/SystemEngineTest.java @@ -49,6 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @CustomLog +@Tag("v2") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class SystemEngineTest extends IntegrationTest { diff --git a/src/integrationTest/java/integration/tests/TimeoutTest.java b/src/integrationTest/java/integration/tests/TimeoutTest.java index 0a8b281b6..0719f4ee0 100644 --- a/src/integrationTest/java/integration/tests/TimeoutTest.java +++ b/src/integrationTest/java/integration/tests/TimeoutTest.java @@ -24,7 +24,7 @@ @CustomLog class TimeoutTest extends IntegrationTest { private static final int MIN_TIME_SECONDS = 350; - private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 600000000000L); + private static final Map SERIES_SIZE = Map.of(1, 80000000000L, 2, 700000000000L); private long startTime; @BeforeEach diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index 72122f9a4..a99335f59 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -54,7 +54,6 @@ public class FireboltConnectionServiceSecret extends FireboltConnection { super(url, connectionSettings, PROTOCOL_VERSION); OkHttpClient httpClient = getHttpClient(loginProperties); this.fireboltGatewayUrlService = new FireboltGatewayUrlService(createFireboltAccountRetriever(httpClient, GatewayUrlResponse.class)); - // initialization of fireboltEngineService depends on the infraVersion (the version of engine) connect(); } From 9615299d53070be0ac1de3d58c30367c90d73834 Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:02:25 +0200 Subject: [PATCH 46/52] fix(FIR-37280): parameter formatting for the new Firebolt (#464) --- .../tests/PreparedStatementTest.java | 20 ++++++++++ .../jdbc/connection/FireboltConnection.java | 19 ++++++++-- .../FireboltConnectionServiceSecret.java | 12 ++++-- .../FireboltConnectionUserPassword.java | 12 ++++-- .../FireboltPreparedStatement.java | 8 +++- .../java/com/firebolt/jdbc/type/BaseType.java | 2 +- .../type/JavaTypeToFireboltSQLString.java | 37 ++++++++++++++----- .../com/firebolt/jdbc/type/ParserVersion.java | 5 +++ .../client/query/StatementClientImplTest.java | 3 +- .../FireboltConnectionServiceSecretTest.java | 8 +++- .../FireboltConnectionUserPasswordTest.java | 4 +- .../type/JavaTypeToFireboltSQLStringTest.java | 23 +++++++++++- 12 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/firebolt/jdbc/type/ParserVersion.java diff --git a/src/integrationTest/java/integration/tests/PreparedStatementTest.java b/src/integrationTest/java/integration/tests/PreparedStatementTest.java index 779ab50a9..84f44423d 100644 --- a/src/integrationTest/java/integration/tests/PreparedStatementTest.java +++ b/src/integrationTest/java/integration/tests/PreparedStatementTest.java @@ -435,6 +435,26 @@ void shouldInsertAndRetrieveUrl() throws SQLException, MalformedURLException { } } + @Test + void shouldFetchSpecialCharacters() throws SQLException, MalformedURLException { + try (Connection connection = createConnection()) { + try (PreparedStatement statement = connection + .prepareStatement("SELECT ? as a, ? as b, ? as c, ? as d")) { + statement.setString(1, "ї"); + statement.setString(2, "\n"); + statement.setString(3, "\\"); + statement.setString(4, "don't"); + statement.execute(); + ResultSet rs = statement.getResultSet(); + assertTrue(rs.next()); + assertEquals("ї", rs.getString(1)); + assertEquals("\n", rs.getString(2)); + assertEquals("\\", rs.getString(3)); + assertEquals("don't", rs.getString(4)); + } + } + } + @Builder @Value @EqualsAndHashCode diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java index 1129935f8..1b5976229 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java @@ -18,11 +18,13 @@ import com.firebolt.jdbc.statement.FireboltStatement; import com.firebolt.jdbc.statement.preparedstatement.FireboltPreparedStatement; import com.firebolt.jdbc.type.FireboltDataType; +import com.firebolt.jdbc.type.ParserVersion; import com.firebolt.jdbc.type.array.FireboltArray; import com.firebolt.jdbc.type.lob.FireboltBlob; import com.firebolt.jdbc.type.lob.FireboltClob; import com.firebolt.jdbc.util.PropertyUtil; import lombok.CustomLog; +import lombok.Getter; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -83,12 +85,16 @@ public abstract class FireboltConnection extends JdbcBase implements Connection, //Properties that are used at the beginning of the connection for authentication protected final FireboltProperties loginProperties; private final Collection cacheListeners = Collections.newSetFromMap(new IdentityHashMap<>()); + // Parameter parser is determined by the version we're running on + @Getter + public final ParserVersion parserVersion; protected FireboltConnection(@NonNull String url, Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltStatementService fireboltStatementService, - String protocolVersion) { + String protocolVersion, + ParserVersion parserVersion) { this.loginProperties = extractFireboltProperties(url, connectionSettings); this.fireboltAuthenticationService = fireboltAuthenticationService; @@ -99,11 +105,13 @@ protected FireboltConnection(@NonNull String url, this.connectionTimeout = loginProperties.getConnectionTimeoutMillis(); this.networkTimeout = loginProperties.getSocketTimeoutMillis(); this.protocolVersion = protocolVersion; + this.parserVersion = parserVersion; } // This code duplication between constructors is done because of back reference: dependent services require reference to current instance of FireboltConnection that prevents using constructor chaining or factory method. @ExcludeFromJacocoGeneratedReport - protected FireboltConnection(@NonNull String url, Properties connectionSettings, String protocolVersion) throws SQLException { + protected FireboltConnection(@NonNull String url, Properties connectionSettings, String protocolVersion, + ParserVersion parserVersion) throws SQLException { this.loginProperties = extractFireboltProperties(url, connectionSettings); OkHttpClient httpClient = getHttpClient(loginProperties); @@ -115,6 +123,7 @@ protected FireboltConnection(@NonNull String url, Properties connectionSettings, this.connectionTimeout = loginProperties.getConnectionTimeoutMillis(); this.networkTimeout = loginProperties.getSocketTimeoutMillis(); this.protocolVersion = protocolVersion; + this.parserVersion = parserVersion; } protected abstract FireboltAuthenticationClient createFireboltAuthenticationClient(OkHttpClient httpClient); @@ -125,8 +134,10 @@ public static FireboltConnection create(@NonNull String url, Properties connecti private static FireboltConnection createConnectionInstance(@NonNull String url, Properties connectionSettings) throws SQLException { switch(getUrlVersion(url, connectionSettings)) { - case 1: return new FireboltConnectionUserPassword(url, connectionSettings); - case 2: return new FireboltConnectionServiceSecret(url, connectionSettings); + case 1: + return new FireboltConnectionUserPassword(url, connectionSettings, ParserVersion.LEGACY); + case 2: + return new FireboltConnectionServiceSecret(url, connectionSettings, ParserVersion.CURRENT); default: throw new IllegalArgumentException(format("Cannot distinguish version from url %s", url)); } } diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java index a99335f59..ccc5dcd74 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecret.java @@ -16,6 +16,7 @@ import com.firebolt.jdbc.service.FireboltEngineVersion2Service; import com.firebolt.jdbc.service.FireboltGatewayUrlService; import com.firebolt.jdbc.service.FireboltStatementService; +import com.firebolt.jdbc.type.ParserVersion; import com.firebolt.jdbc.util.PropertyUtil; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -42,16 +43,19 @@ public class FireboltConnectionServiceSecret extends FireboltConnection { FireboltGatewayUrlService fireboltGatewayUrlService, FireboltStatementService fireboltStatementService, FireboltEngineInformationSchemaService fireboltEngineService, - FireboltAccountIdService fireboltAccountIdService) throws SQLException { - super(url, connectionSettings, fireboltAuthenticationService, fireboltStatementService, PROTOCOL_VERSION); + FireboltAccountIdService fireboltAccountIdService, + ParserVersion parserVersion) throws SQLException { + super(url, connectionSettings, fireboltAuthenticationService, fireboltStatementService, PROTOCOL_VERSION, + parserVersion); this.fireboltGatewayUrlService = fireboltGatewayUrlService; this.fireboltEngineService = fireboltEngineService; connect(); } @ExcludeFromJacocoGeneratedReport - FireboltConnectionServiceSecret(@NonNull String url, Properties connectionSettings) throws SQLException { - super(url, connectionSettings, PROTOCOL_VERSION); + FireboltConnectionServiceSecret(@NonNull String url, Properties connectionSettings, ParserVersion parserVersion) + throws SQLException { + super(url, connectionSettings, PROTOCOL_VERSION, parserVersion); OkHttpClient httpClient = getHttpClient(loginProperties); this.fireboltGatewayUrlService = new FireboltGatewayUrlService(createFireboltAccountRetriever(httpClient, GatewayUrlResponse.class)); connect(); diff --git a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionUserPassword.java b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionUserPassword.java index e36845c1b..84058571b 100644 --- a/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionUserPassword.java +++ b/src/main/java/com/firebolt/jdbc/connection/FireboltConnectionUserPassword.java @@ -11,6 +11,7 @@ import com.firebolt.jdbc.service.FireboltEngineInformationSchemaService; import com.firebolt.jdbc.service.FireboltEngineService; import com.firebolt.jdbc.service.FireboltStatementService; +import com.firebolt.jdbc.type.ParserVersion; import lombok.NonNull; import okhttp3.OkHttpClient; @@ -27,15 +28,18 @@ public class FireboltConnectionUserPassword extends FireboltConnection { Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltStatementService fireboltStatementService, - FireboltEngineInformationSchemaService fireboltEngineService) throws SQLException { - super(url, connectionSettings, fireboltAuthenticationService, fireboltStatementService, PROTOCOL_VERSION); + FireboltEngineInformationSchemaService fireboltEngineService, + ParserVersion parserVersion) throws SQLException { + super(url, connectionSettings, fireboltAuthenticationService, fireboltStatementService, PROTOCOL_VERSION, + parserVersion); this.fireboltEngineService = fireboltEngineService; connect(); } @ExcludeFromJacocoGeneratedReport - FireboltConnectionUserPassword(@NonNull String url, Properties connectionSettings) throws SQLException { - super(url, connectionSettings, PROTOCOL_VERSION); + FireboltConnectionUserPassword(@NonNull String url, Properties connectionSettings, ParserVersion parserVersion) + throws SQLException { + super(url, connectionSettings, PROTOCOL_VERSION, parserVersion); OkHttpClient httpClient = getHttpClient(loginProperties); this.fireboltEngineService = new FireboltEngineApiService(new FireboltAccountClient(httpClient, this, loginProperties.getUserDrivers(), loginProperties.getUserClients())); connect(); diff --git a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java index 41ce33462..12e479b04 100644 --- a/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java +++ b/src/main/java/com/firebolt/jdbc/statement/preparedstatement/FireboltPreparedStatement.java @@ -12,6 +12,7 @@ import com.firebolt.jdbc.statement.StatementInfoWrapper; import com.firebolt.jdbc.statement.StatementUtil; import com.firebolt.jdbc.statement.rawstatement.RawStatementWrapper; +import com.firebolt.jdbc.type.ParserVersion; import com.firebolt.jdbc.type.JavaTypeToFireboltSQLString; import com.firebolt.jdbc.util.InputStreamUtil; import lombok.CustomLog; @@ -57,6 +58,7 @@ public class FireboltPreparedStatement extends FireboltStatement implements Prep private final RawStatementWrapper rawStatement; private final List> rows; private Map providedParameters; + private final ParserVersion parserVersion; public FireboltPreparedStatement(FireboltStatementService statementService, FireboltConnection connection, String sql) { this(statementService, connection.getSessionProperties(), connection, sql); @@ -70,6 +72,7 @@ public FireboltPreparedStatement(FireboltStatementService statementService, Fire this.rawStatement = StatementUtil.parseToRawStatementWrapper(sql); rawStatement.getSubStatements().forEach(statement -> createValidator(statement, connection).validate(statement)); this.rows = new ArrayList<>(); + this.parserVersion = connection.getParserVersion(); } @Override @@ -155,7 +158,7 @@ public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException public void setString(int parameterIndex, String x) throws SQLException { validateStatementIsNotClosed(); validateParamIndex(parameterIndex); - providedParameters.put(parameterIndex, JavaTypeToFireboltSQLString.STRING.transform(x)); + providedParameters.put(parameterIndex, JavaTypeToFireboltSQLString.STRING.transform(x, parserVersion)); } @Override @@ -198,7 +201,8 @@ public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQ validateStatementIsNotClosed(); validateParamIndex(parameterIndex); try { - providedParameters.put(parameterIndex, JavaTypeToFireboltSQLString.transformAny(x, targetSqlType)); + providedParameters.put(parameterIndex, + JavaTypeToFireboltSQLString.transformAny(x, targetSqlType, parserVersion)); } catch (FireboltException fbe) { if (ExceptionType.TYPE_NOT_SUPPORTED.equals(fbe.getType())) { throw new SQLFeatureNotSupportedException(fbe.getMessage(), fbe); diff --git a/src/main/java/com/firebolt/jdbc/type/BaseType.java b/src/main/java/com/firebolt/jdbc/type/BaseType.java index c2b4caf97..e99e0838f 100644 --- a/src/main/java/com/firebolt/jdbc/type/BaseType.java +++ b/src/main/java/com/firebolt/jdbc/type/BaseType.java @@ -135,7 +135,7 @@ private static String checkInfinity(String s) { } public static boolean isNull(String value) { - return NULL_VALUE.equalsIgnoreCase(value); + return NULL_VALUE.equals(value); } private static boolean isNan(String value) { diff --git a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java index 2229f622a..cb3db7ba9 100644 --- a/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java +++ b/src/main/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLString.java @@ -35,7 +35,7 @@ public enum JavaTypeToFireboltSQLString { UUID(java.util.UUID.class, Object::toString), BYTE(Byte.class, value -> Byte.toString(((Number) value).byteValue())), SHORT(Short.class, value -> Short.toString(((Number) value).shortValue())), - STRING(String.class, getSQLStringValueOfString()), + STRING(String.class, getSQLStringValueOfString(ParserVersion.CURRENT), getSQLStringValueOfStringVersioned()), LONG(Long.class, value -> Long.toString(((Number)value).longValue())), INTEGER(Integer.class, value -> Integer.toString(((Number)value).intValue())), BIG_INTEGER(BigInteger.class, value -> value instanceof BigInteger ? value.toString() : Long.toString(((Number)value).longValue())), @@ -47,8 +47,11 @@ public enum JavaTypeToFireboltSQLString { ARRAY(Array.class, SqlArrayUtil::arrayToString), BYTE_ARRAY(byte[].class, value -> ofNullable(byteArrayToHexString((byte[])value, true)).map(x -> format("E'%s'::BYTEA", x)).orElse(null)), ; - private static final List> characterToEscapedCharacterPairs = List.of( + + private static final List> legacyCharacterToEscapedCharacterPairs = List.of( Map.entry("\0", "\\0"), Map.entry("\\", "\\\\"), Map.entry("'", "''")); + private static final List> characterToEscapedCharacterPairs = List.of( + Map.entry("'", "''")); //https://docs.oracle.com/javase/1.5.0/docs/guide/jdbc/getstart/mapping.html private static final Map> jdbcTypeToClass = Map.ofEntries( Map.entry(JDBCType.CHAR, String.class), @@ -100,22 +103,33 @@ public enum JavaTypeToFireboltSQLString { } public static String transformAny(Object object) throws SQLException { - return transformAny(object, () -> getType(object)); + return transformAny(object, ParserVersion.CURRENT); + } + + public static String transformAny(Object object, ParserVersion version) throws SQLException { + return transformAny(object, () -> getType(object), version); } public static String transformAny(Object object, int sqlType) throws SQLException { - return transformAny(object, () -> getType(sqlType)); + return transformAny(object, sqlType, ParserVersion.CURRENT); } - private static String transformAny(Object object, CheckedSupplier> classSupplier) throws SQLException { - return object == null ? NULL_VALUE : transformAny(object, classSupplier.get()); + public static String transformAny(Object object, int sqlType, ParserVersion version) throws SQLException { + return transformAny(object, () -> getType(sqlType), version); } - private static String transformAny(Object object, Class objectType) throws SQLException { + private static String transformAny(Object object, CheckedSupplier> classSupplier, ParserVersion version) throws SQLException { + return object == null ? NULL_VALUE : transformAny(object, classSupplier.get(), version); + } + + private static String transformAny(Object object, Class objectType, ParserVersion version) throws SQLException { JavaTypeToFireboltSQLString converter = Optional.ofNullable(classToType.get(objectType)) .orElseThrow(() -> new FireboltException( format("Cannot convert type %s. The type is not supported.", objectType), TYPE_NOT_SUPPORTED)); + if (version == ParserVersion.LEGACY && object instanceof String) { + return converter.transform(object, version); + } return converter.transform(object); } @@ -133,10 +147,15 @@ private static Class getType(int sqlType) throws SQLException { } } - private static CheckedFunction getSQLStringValueOfString() { + private static CheckedBiFunction getSQLStringValueOfStringVersioned() { + return (value, version) -> getSQLStringValueOfString((ParserVersion) version).apply(value); + } + + private static CheckedFunction getSQLStringValueOfString(ParserVersion version) { return value -> { String escaped = (String) value; - for (Entry specialCharacter : characterToEscapedCharacterPairs) { + List> charactersToEscape = version == ParserVersion.LEGACY ? legacyCharacterToEscapedCharacterPairs : characterToEscapedCharacterPairs; + for (Entry specialCharacter : charactersToEscape) { escaped = escaped.replace(specialCharacter.getKey(), specialCharacter.getValue()); } return format("'%s'", escaped); diff --git a/src/main/java/com/firebolt/jdbc/type/ParserVersion.java b/src/main/java/com/firebolt/jdbc/type/ParserVersion.java new file mode 100644 index 000000000..31a061212 --- /dev/null +++ b/src/main/java/com/firebolt/jdbc/type/ParserVersion.java @@ -0,0 +1,5 @@ +package com.firebolt.jdbc.type; + +public enum ParserVersion { + LEGACY, CURRENT +} diff --git a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java index eae589a79..e6c0e5b0a 100644 --- a/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java +++ b/src/test/java/com/firebolt/jdbc/client/query/StatementClientImplTest.java @@ -10,6 +10,7 @@ import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.statement.StatementInfoWrapper; import com.firebolt.jdbc.statement.StatementUtil; +import com.firebolt.jdbc.type.ParserVersion; import lombok.NonNull; import okhttp3.Call; import okhttp3.Dispatcher; @@ -349,7 +350,7 @@ private FireboltConnection use(int mockedInfraVersion, Properties props, String Call useCall = getMockedCallWithResponse(200, "", responseHeaders); Call select1Call = getMockedCallWithResponse(200, ""); when(okHttpClient.newCall(any())).thenReturn(useCall, select1Call); - FireboltConnection connection = new FireboltConnection("url", props, "0") { + FireboltConnection connection = new FireboltConnection("url", props, "0", ParserVersion.CURRENT) { { this.infraVersion = mockedInfraVersion; try { diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecretTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecretTest.java index 4c02fc295..381d01f05 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecretTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionServiceSecretTest.java @@ -5,6 +5,7 @@ import com.firebolt.jdbc.connection.settings.FireboltProperties; import com.firebolt.jdbc.exception.FireboltException; import com.firebolt.jdbc.service.FireboltGatewayUrlService; +import com.firebolt.jdbc.type.ParserVersion; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -100,7 +101,9 @@ void checkSystemEngineEndpoint(String gatewayUrl, String expectedHost, String ex @SuppressWarnings("unchecked") FireboltAccountRetriever fireboltGatewayUrlClient = mock(FireboltAccountRetriever.class); when(fireboltGatewayUrlClient.retrieve(any(), any())).thenReturn(new GatewayUrlResponse(gatewayUrl)); FireboltGatewayUrlService gatewayUrlService = new FireboltGatewayUrlService(fireboltGatewayUrlClient); - FireboltConnection connection = new FireboltConnectionServiceSecret(SYSTEM_ENGINE_URL, connectionProperties, fireboltAuthenticationService, gatewayUrlService, fireboltStatementService, fireboltEngineService, fireboltAccountIdService); + FireboltConnection connection = new FireboltConnectionServiceSecret(SYSTEM_ENGINE_URL, connectionProperties, + fireboltAuthenticationService, gatewayUrlService, fireboltStatementService, fireboltEngineService, + fireboltAccountIdService, ParserVersion.CURRENT); FireboltProperties sessionProperties = connection.getSessionProperties(); assertEquals(expectedHost, sessionProperties.getHost()); assertEquals(expectedProps == null ? Map.of() : Arrays.stream(expectedProps.split(";")).map(kv -> kv.split("=")).collect(toMap(kv -> kv[0], kv -> kv[1])), sessionProperties.getAdditionalProperties()); @@ -113,6 +116,7 @@ void shouldNotFetchTokenNorEngineHostForLocalFirebolt() throws SQLException { } protected FireboltConnection createConnection(String url, Properties props) throws SQLException { - return new FireboltConnectionServiceSecret(url, props, fireboltAuthenticationService, fireboltGatewayUrlService, fireboltStatementService, fireboltEngineService, fireboltAccountIdService); + return new FireboltConnectionServiceSecret(url, props, fireboltAuthenticationService, fireboltGatewayUrlService, + fireboltStatementService, fireboltEngineService, fireboltAccountIdService, ParserVersion.CURRENT); } } diff --git a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionUserPasswordTest.java b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionUserPasswordTest.java index 927fcdf34..473f72bc3 100644 --- a/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionUserPasswordTest.java +++ b/src/test/java/com/firebolt/jdbc/connection/FireboltConnectionUserPasswordTest.java @@ -1,5 +1,6 @@ package com.firebolt.jdbc.connection; +import com.firebolt.jdbc.type.ParserVersion; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -73,6 +74,7 @@ void getMetadata(String engine) throws SQLException { } protected FireboltConnection createConnection(String url, Properties props) throws SQLException { - return new FireboltConnectionUserPassword(url, props, fireboltAuthenticationService, fireboltStatementService, fireboltEngineService); + return new FireboltConnectionUserPassword(url, props, fireboltAuthenticationService, fireboltStatementService, + fireboltEngineService, ParserVersion.LEGACY); } } diff --git a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java index 86c111c17..7e7b24ff1 100644 --- a/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java +++ b/src/test/java/com/firebolt/jdbc/type/JavaTypeToFireboltSQLStringTest.java @@ -69,9 +69,30 @@ void shouldTransformShortToString() throws SQLException { @Test void shouldEscapeCharactersWhenTransformingFromString() throws SQLException { + // quotes are escaped assertEquals("'105'' OR 1=1--'' '", JavaTypeToFireboltSQLString.STRING.transform("105' OR 1=1--' ")); - assertEquals("'105'' OR 1=1--'' '", JavaTypeToFireboltSQLString.transformAny("105' OR 1=1--' ")); + // \0 is not escaped + assertEquals("'105\0'", JavaTypeToFireboltSQLString.STRING.transform("105\0")); + assertEquals("'105\0'", JavaTypeToFireboltSQLString.transformAny("105\0")); + // backslashes are not escaped + assertEquals("'105\\'", JavaTypeToFireboltSQLString.STRING.transform("105\\")); + assertEquals("'105\\'", JavaTypeToFireboltSQLString.transformAny("105\\")); + } + + @Test + void shouldEscapeCharactersWhenTransformingFromStringLegacy() throws SQLException { + // quotes are escaped + assertEquals("'105'' OR 1=1--'' '", + JavaTypeToFireboltSQLString.STRING.transform("105' OR 1=1--' ", ParserVersion.LEGACY)); + assertEquals("'105'' OR 1=1--'' '", + JavaTypeToFireboltSQLString.transformAny("105' OR 1=1--' ", ParserVersion.LEGACY)); + // \0 is escaped + assertEquals("'105\\\\0'", JavaTypeToFireboltSQLString.STRING.transform("105\0", ParserVersion.LEGACY)); + assertEquals("'105\\\\0'", JavaTypeToFireboltSQLString.transformAny("105\0", ParserVersion.LEGACY)); + // backslashes are escaped + assertEquals("'105\\\\'", JavaTypeToFireboltSQLString.STRING.transform("105\\", ParserVersion.LEGACY)); + assertEquals("'105\\\\'", JavaTypeToFireboltSQLString.transformAny("105\\", ParserVersion.LEGACY)); } @Test From 57b4257a573a92adf3f62cd9910b9a5f2e54786b Mon Sep 17 00:00:00 2001 From: Petro Tiurin <93913847+ptiurin@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:10:33 +0200 Subject: [PATCH 47/52] chore: Bump version to 3.2.1 (#472) --- gradle.properties | 2 +- .../firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java | 2 +- src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index bed2e6860..95ced1b4b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=3.2.0 +version=3.2.1 jdbcVersion=4.3 diff --git a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java index 137c75ba2..74092ecc4 100644 --- a/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java +++ b/src/test/java/com/firebolt/jdbc/metadata/FireboltDatabaseMetadataTest.java @@ -353,7 +353,7 @@ void shouldGetDriverMinorVersion() { @Test void shouldGetDriverVersion() throws SQLException { - assertEquals("3.2.0", fireboltDatabaseMetadata.getDriverVersion()); + assertEquals("3.2.1", fireboltDatabaseMetadata.getDriverVersion()); } @Test diff --git a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java index d65f68787..8d71257a6 100644 --- a/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java +++ b/src/test/java/com/firebolt/jdbc/util/VersionUtilTest.java @@ -18,7 +18,7 @@ void shouldGetDriverMinorVersion() { @Test void shouldGetProjectVersion() { - assertEquals("3.2.0", VersionUtil.getDriverVersion()); + assertEquals("3.2.1", VersionUtil.getDriverVersion()); } @Test From 79710b1fcbd950cf712875663ba20e5ed6a46349 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:48:08 +0200 Subject: [PATCH 48/52] Bump org.projectlombok:lombok from 1.18.32 to 1.18.34 (#433) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stepan Burlakov --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 5078fcf3d..8643ed016 100644 --- a/build.gradle +++ b/build.gradle @@ -69,10 +69,10 @@ dependencies { implementation fileTree(dir: 'libs', includes: ['*.jar']) compileOnly 'org.slf4j:slf4j-api:2.0.13' - compileOnly 'org.projectlombok:lombok:1.18.32' - annotationProcessor 'org.projectlombok:lombok:1.18.32' - testCompileOnly 'org.projectlombok:lombok:1.18.32' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.32' + compileOnly 'org.projectlombok:lombok:1.18.34' + annotationProcessor 'org.projectlombok:lombok:1.18.34' + testCompileOnly 'org.projectlombok:lombok:1.18.34' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.34' testImplementation 'ch.qos.logback:logback-classic:1.5.6' testImplementation 'org.mockito:mockito-junit-jupiter:5.10.0' From 04aff53453db5296311ecb6190ab68abb2442bf1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:02:57 +0200 Subject: [PATCH 49/52] Bump org.sonarqube from 5.0.0.4638 to 5.1.0.4882 (#443) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stepan Burlakov --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8643ed016..cc02ba322 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ import java.util.jar.JarFile plugins { id 'java' id 'jacoco' - id "org.sonarqube" version "5.0.0.4638" + id "org.sonarqube" version "5.1.0.4882" id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.0.0' id 'signing' From bdd42214eae6d95bdc6df28a9057d343fd90fe8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:03:05 +0200 Subject: [PATCH 50/52] Bump org.junit.jupiter:junit-jupiter-engine from 5.10.2 to 5.11.3 (#469) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stepan Burlakov --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cc02ba322..219c06518 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,7 @@ dependencies { testImplementation 'org.mockito:mockito-core:5.10.0' testImplementation 'org.mockito:mockito-inline:5.2.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.11.3' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2' testImplementation 'org.junit-pioneer:junit-pioneer:2.2.0' testImplementation 'org.hamcrest:hamcrest-library:2.2' From c3057ea2285305df6b33bbc929b2f866731a6029 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:04:40 +0200 Subject: [PATCH 51/52] Bump org.junit.jupiter:junit-jupiter-api from 5.10.2 to 5.11.3 (#471) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stepan Burlakov --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 219c06518..0f0ff4d32 100644 --- a/build.gradle +++ b/build.gradle @@ -78,7 +78,7 @@ dependencies { testImplementation 'org.mockito:mockito-junit-jupiter:5.10.0' testImplementation 'org.mockito:mockito-core:5.10.0' testImplementation 'org.mockito:mockito-inline:5.2.0' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.11.3' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2' testImplementation 'org.junit-pioneer:junit-pioneer:2.2.0' @@ -87,7 +87,7 @@ dependencies { testImplementation 'com.squareup.okhttp3:okhttp-tls:4.12.0' testImplementation 'io.zonky.test:embedded-postgres:2.0.7' testCompileOnly 'org.slf4j:slf4j-api:2.0.13' - testCommonImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' + testCommonImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3' testImplementation sourceSets.testCommon.output compileTestJava.dependsOn processTestResources jar.dependsOn processTestResources From 7c502954f335eb9fb52dfd693ab5b71a874daec8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:04:51 +0200 Subject: [PATCH 52/52] Bump org.junit.jupiter:junit-jupiter-params from 5.10.2 to 5.11.3 (#470) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stepan Burlakov --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0f0ff4d32..bb18c53e2 100644 --- a/build.gradle +++ b/build.gradle @@ -80,7 +80,7 @@ dependencies { testImplementation 'org.mockito:mockito-inline:5.2.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.11.3' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.3' testImplementation 'org.junit-pioneer:junit-pioneer:2.2.0' testImplementation 'org.hamcrest:hamcrest-library:2.2' testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0'