Skip to content

Commit

Permalink
Merge pull request #46 from exasol/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
AnastasiiaSergienko authored Apr 24, 2020
2 parents a731ed3 + b4e9d08 commit 84d0b72
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 315 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
<description>Common module for JDBC-based data access from Virtual Schemas.</description>
<url>https://github.com/exasol/virtual-schema-common-jdbc</url>
<properties>
<product.version>4.0.0</product.version>
<product.version>5.0.0</product.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<junit.version>5.6.1</junit.version>
<junit.platform.version>1.6.1</junit.platform.version>
<maven.surefire.version>3.0.0-M4</maven.surefire.version>
<vscommon.version>9.0.0</vscommon.version>
<vscommon.version>10.0.0</vscommon.version>
<gpg.skip>true</gpg.skip>
</properties>
<licenses>
Expand Down
78 changes: 42 additions & 36 deletions src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,41 @@
* Abstract implementation of a dialect. We recommend that every dialect should extend this abstract class.
*/
public abstract class AbstractSqlDialect implements SqlDialect {
private static final Logger LOGGER = Logger.getLogger(AbstractSqlDialect.class.getName());
private static final Pattern BOOLEAN_PROPERTY_VALUE_PATTERN = Pattern.compile("^TRUE$|^FALSE$",
Pattern.CASE_INSENSITIVE);
private static final Set<String> COMMON_SUPPORTED_PROPERTIES = Set.of(SQL_DIALECT_PROPERTY,
CONNECTION_NAME_PROPERTY, TABLE_FILTER_PROPERTY, EXCLUDED_CAPABILITIES_PROPERTY, DEBUG_ADDRESS_PROPERTY,
LOG_LEVEL_PROPERTY);
protected Set<ScalarFunction> omitParenthesesMap = EnumSet.noneOf(ScalarFunction.class);
protected AdapterProperties properties;
protected final ConnectionFactory connectionFactory;
private static final Pattern BOOLEAN_PROPERTY_VALUE_PATTERN = Pattern.compile("^TRUE$|^FALSE$",
Pattern.CASE_INSENSITIVE);
private static final Logger LOGGER = Logger.getLogger(AbstractSqlDialect.class.getName());
private final Set<String> supportedProperties;

/**
* Create a new instance of an {@link AbstractSqlDialect}.
*
* @param connectionFactory factory for JDBC connection to remote data source
* @param properties user properties
* @param connectionFactory factory for JDBC connection to remote data source
* @param properties user properties
* @param dialectSpecificProperties a set of properties that dialect supports additionally to the common set *
* {@link com.exasol.adapter.dialects.AbstractSqlDialect#COMMON_SUPPORTED_PROPERTIES}
*/
public AbstractSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) {
public AbstractSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties,
final Set<String> dialectSpecificProperties) {
this.connectionFactory = connectionFactory;
this.properties = properties;
this.supportedProperties = new HashSet<>(COMMON_SUPPORTED_PROPERTIES);
this.supportedProperties.addAll(dialectSpecificProperties);
}

/**
* Add additional dialect-specific supported properties that are not in the
* {@link com.exasol.adapter.dialects.AbstractSqlDialect#COMMON_SUPPORTED_PROPERTIES} set.
*
* @param additionalPropertiesToSupport list of properties names
*/
protected void addAdditionalSupportedProperties(final List<String> additionalPropertiesToSupport) {
this.supportedProperties.addAll(additionalPropertiesToSupport);
}

/**
Expand Down Expand Up @@ -79,10 +98,7 @@ public Map<ScalarFunction, String> getScalarFunctionAliases() {

@Override
public Map<AggregateFunction, String> getAggregateFunctionAliases() {
final Map<AggregateFunction, String> aliases = new EnumMap<>(AggregateFunction.class);
aliases.put(AggregateFunction.GEO_INTERSECTION_AGGREGATE, "ST_INTERSECTION");
aliases.put(AggregateFunction.GEO_UNION_AGGREGATE, "ST_UNION");
return aliases;
return new EnumMap<>(AggregateFunction.class);
}

@Override
Expand All @@ -95,6 +111,15 @@ public Map<ScalarFunction, String> getBinaryInfixFunctionAliases() {
return aliases;
}

/**
* Get a set of adapter properties that the dialect supports.
*
* @return set of supported properties
*/
public Set<String> getSupportedProperties() {
return this.supportedProperties;
}

@Override
public Map<ScalarFunction, String> getPrefixFunctionAliases() {
final Map<ScalarFunction, String> aliases = new EnumMap<>(ScalarFunction.class);
Expand Down Expand Up @@ -130,7 +155,7 @@ public String getStringLiteral(final String value) {
@Override
public void validateProperties() throws PropertyValidationException {
validateSupportedPropertiesList();
validateConnectionProperties();
validateConnectionNameProperty();
validateCatalogNameProperty();
validateSchemaNameProperty();
validateDebugOutputAddress();
Expand All @@ -141,39 +166,20 @@ protected void validateSupportedPropertiesList() throws PropertyValidationExcept
final List<String> allProperties = new ArrayList<>(this.properties.keySet());
for (final String property : allProperties) {
if (!getSupportedProperties().contains(property)) {
final String unsupportedElement = property;
throw new PropertyValidationException(createUnsupportedElementMessage(unsupportedElement, property));
throw new PropertyValidationException(createUnsupportedElementMessage(property, property));
}
}
}

/**
* Get the list of user-defined adapter properties which the dialect supports.
*
* @return list of supported properties
*/
protected abstract List<String> getSupportedProperties();

protected String createUnsupportedElementMessage(final String unsupportedElement, final String property) {
return "The dialect " + this.properties.getSqlDialect() + " does not support " + unsupportedElement
+ " property. Please, do not set the " + property + " property.";
+ " property. Please, do not set the \"" + property + "\" property.";
}

private void validateConnectionProperties() throws PropertyValidationException {
if (this.properties.containsKey(CONNECTION_NAME_PROPERTY)) {
if (this.properties.containsKey(CONNECTION_STRING_PROPERTY)
|| this.properties.containsKey(USERNAME_PROPERTY)
|| this.properties.containsKey(PASSWORD_PROPERTY)) {
throw new PropertyValidationException("You specified a connection using the property "
+ CONNECTION_NAME_PROPERTY + " and therefore should not specify the properties "
+ CONNECTION_STRING_PROPERTY + ", " + USERNAME_PROPERTY + " and " + PASSWORD_PROPERTY);
}
} else {
if (!this.properties.containsKey(CONNECTION_STRING_PROPERTY)) {
throw new PropertyValidationException(
"You did not specify a connection using the property " + CONNECTION_NAME_PROPERTY
+ " and therefore have to specify the property " + CONNECTION_STRING_PROPERTY);
}
private void validateConnectionNameProperty() throws PropertyValidationException {
if (!this.properties.hasConnectionName()) {
throw new PropertyValidationException(
"Please specify a connection using the property \"" + CONNECTION_NAME_PROPERTY + "\".");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,12 @@ public DataType mapJdbcType(final JdbcTypeDescription jdbcTypeDescription) {
case Types.BIT:
case Types.BOOLEAN:
return DataType.createBool();
case Types.BINARY:
case Types.CLOB:
case Types.TIME:
return DataType.createVarChar(100, DataType.ExaCharset.UTF8);
case Types.NUMERIC:
return fallBackToMaximumSizeVarChar();
case Types.BINARY:
case Types.CLOB:
case Types.OTHER:
case Types.BLOB:
case Types.NCLOB:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.exasol.adapter.jdbc;

import static com.exasol.adapter.AdapterProperties.*;

import java.util.logging.Logger;
import static com.exasol.adapter.AdapterProperties.CONNECTION_NAME_PROPERTY;

import com.exasol.ExaConnectionInformation;
import com.exasol.adapter.AdapterProperties;
Expand All @@ -13,15 +11,6 @@
* @see <a href="https://docs.exasol.com/sql/import.htm">IMPORT (Exasol documentation)</a>
*/
public class BaseConnectionDefinitionBuilder implements ConnectionDefinitionBuilder {
private static final Logger LOGGER = Logger.getLogger(BaseConnectionDefinitionBuilder.class.getName());
private static final String MISSING_CONNECTION_DETAILS_ERROR = "Incomplete remote connection information."
+ " Please specify either a named connection with " + CONNECTION_NAME_PROPERTY
+ " or individual connetion properties " + CONNECTION_STRING_PROPERTY + ", " + USERNAME_PROPERTY + " and "
+ PASSWORD_PROPERTY + ".";
protected static final String CONFLICTING_CONNECTION_DETAILS_ERROR = "Mixing named connections in property "
+ CONNECTION_NAME_PROPERTY + " and individual conneciton properties " + CONNECTION_STRING_PROPERTY + ", "
+ USERNAME_PROPERTY + " and " + PASSWORD_PROPERTY + " is not allowed.";

/**
* Get the connection definition part of a push-down query.
*
Expand All @@ -32,44 +21,16 @@ public class BaseConnectionDefinitionBuilder implements ConnectionDefinitionBuil
@Override
public String buildConnectionDefinition(final AdapterProperties properties,
final ExaConnectionInformation exaConnectionInformation) {
if (hasIndividualConnectionPropertiesOnly(properties)) {
return getConnectionFromPropertiesOnly(properties);
} else if (hasConflictingConnectionProperties(properties)) {
throw new IllegalArgumentException(CONFLICTING_CONNECTION_DETAILS_ERROR);
} else if (properties.hasConnectionName()) {
return getNamedConnection(properties);
if (properties.hasConnectionName()) {
return "AT " + properties.getConnectionName();
} else {
throw new IllegalArgumentException(MISSING_CONNECTION_DETAILS_ERROR);
throw new IllegalArgumentException(
"Please, provide a mandatory property \"" + CONNECTION_NAME_PROPERTY + "\".");
}
}

private String getConnectionFromPropertiesOnly(final AdapterProperties properties) {
warnConnectionPropertiesDeprecated();
return getConnectionDefinition(properties.getConnectionString(), properties.getUsername(),
properties.getPassword());
}

protected void warnConnectionPropertiesDeprecated() {
LOGGER.warning(() -> "Defining credentials individually with properties is deprecated."
+ " Provide a connection name instead in property " + CONNECTION_NAME_PROPERTY + ".");
}

protected String getConnectionDefinition(final String connectionString, final String username,
final String password) {
return "AT '" + connectionString + "' USER '" + username + "' IDENTIFIED BY '" + password + "'";
}

protected boolean hasIndividualConnectionPropertiesOnly(final AdapterProperties properties) {
return !properties.hasConnectionName() && properties.hasConnectionString() && properties.hasUsername()
&& properties.hasPassword();
}

protected boolean hasConflictingConnectionProperties(final AdapterProperties properties) {
return properties.hasConnectionName()
&& (properties.hasConnectionString() || properties.hasUsername() || properties.hasPassword());
}

private String getNamedConnection(final AdapterProperties properties) {
return "AT " + properties.getConnectionName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Exception for remote connection problems.
*/
public class RemoteConnectionException extends RuntimeException {
private static final long serialVersionUID = 550162141981742445L;
private static final long serialVersionUID = 2818034094289319833L;

/**
* Create a new instance of a {@link RemoteConnectionException}.
Expand All @@ -15,4 +15,13 @@ public class RemoteConnectionException extends RuntimeException {
public RemoteConnectionException(final String message, final Throwable cause) {
super(message, cause);
}

/**
* Create a new instance of a {@link RemoteConnectionException}.
*
* @param message error message
*/
public RemoteConnectionException(final String message) {
super(message);
}
}
41 changes: 17 additions & 24 deletions src/main/java/com/exasol/adapter/jdbc/RemoteConnectionFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.exasol.adapter.jdbc;

import static com.exasol.adapter.AdapterProperties.CONNECTION_NAME_PROPERTY;

import java.sql.*;
import java.util.Properties;
import java.util.logging.Logger;
Expand Down Expand Up @@ -35,35 +37,13 @@ public synchronized Connection getConnection() throws SQLException {
if ((connectionName != null) && !connectionName.isEmpty()) {
this.cachedConnection = createConnection(connectionName, this.exaMetadata);
} else {
this.cachedConnection = createConnectionWithUserCredentials(this.properties.getUsername(),
this.properties.getPassword(), this.properties.getConnectionString());
throw new RemoteConnectionException("\"" + CONNECTION_NAME_PROPERTY
+ "\" property is missing or empty. Please, check the property and try to connect again.");
}
}
return this.cachedConnection;
}

private Connection createConnectionWithUserCredentials(final String username, final String password,
final String connectionString) throws SQLException {
logConnectionAttempt(username, password);
final long start = System.currentTimeMillis();
final Connection connection = DriverManager.getConnection(connectionString, username, password);
logRemoteDatabaseDetails(connection, System.currentTimeMillis() - start);
return connection;
}

protected void logConnectionAttempt(final String address, final String username) {
LOGGER.fine(
() -> "Connecting to \"" + address + "\" as user \"" + username + "\" using password authentication.");
}

protected void logRemoteDatabaseDetails(final Connection connection, final long connectionTime)
throws SQLException {
final String databaseProductName = connection.getMetaData().getDatabaseProductName();
final String databaseProductVersion = connection.getMetaData().getDatabaseProductVersion();
LOGGER.info(() -> "Connected to " + databaseProductName + " " + databaseProductVersion + " in " + connectionTime
+ " milliseconds.");
}

private Connection createConnection(final String connectionName, final ExaMetadata exaMetadata)
throws SQLException {
try {
Expand Down Expand Up @@ -101,6 +81,14 @@ private void logConnectionAttemptWithKerberos(final String address, final String
() -> "Connecting to \"" + address + "\" as user \"" + username + "\" using Kerberos authentication.");
}

protected void logRemoteDatabaseDetails(final Connection connection, final long connectionTime)
throws SQLException {
final String databaseProductName = connection.getMetaData().getDatabaseProductName();
final String databaseProductVersion = connection.getMetaData().getDatabaseProductVersion();
LOGGER.info(() -> "Connected to " + databaseProductName + " " + databaseProductVersion + " in " + connectionTime
+ " milliseconds.");
}

private Connection establishConnectionWithRegularCredentials(final String password, final String username,
final String address) throws SQLException {
logConnectionAttempt(address, username);
Expand All @@ -109,4 +97,9 @@ private Connection establishConnectionWithRegularCredentials(final String passwo
logRemoteDatabaseDetails(connection, System.currentTimeMillis() - start);
return connection;
}

protected void logConnectionAttempt(final String address, final String username) {
LOGGER.fine(
() -> "Connecting to \"" + address + "\" as user \"" + username + "\" using password authentication.");
}
}
Loading

0 comments on commit 84d0b72

Please sign in to comment.