Skip to content

Commit

Permalink
26: Leave connection creation to dialects (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
redcatbear authored Feb 4, 2020
1 parent 1777376 commit 3e2f564
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 147 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<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>2.2.1</product.version>
<product.version>3.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>
Expand Down
24 changes: 10 additions & 14 deletions src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.logging.Logger;
Expand All @@ -12,6 +11,7 @@
import com.exasol.ExaMetadata;
import com.exasol.adapter.AdapterException;
import com.exasol.adapter.AdapterProperties;
import com.exasol.adapter.jdbc.ConnectionFactory;
import com.exasol.adapter.jdbc.RemoteMetadataReader;
import com.exasol.adapter.metadata.SchemaMetadata;
import com.exasol.adapter.sql.*;
Expand All @@ -21,25 +21,21 @@
*/
public abstract class AbstractSqlDialect implements SqlDialect {
protected Set<ScalarFunction> omitParenthesesMap = EnumSet.noneOf(ScalarFunction.class);
protected RemoteMetadataReader remoteMetadataReader;
protected AdapterProperties properties;
protected final Connection connection;
protected QueryRewriter queryRewriter;
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());

/**
* Create a new instance of an {@link AbstractSqlDialect}.
*
* @param connection JDBC connection to remote data source
* @param properties user properties
* @param connectionFactory factory for JDBC connection to remote data source
* @param properties user properties
*/
public AbstractSqlDialect(final Connection connection, final AdapterProperties properties) {
this.connection = connection;
public AbstractSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) {
this.connectionFactory = connectionFactory;
this.properties = properties;
this.remoteMetadataReader = createRemoteMetadataReader();
this.queryRewriter = createQueryRewriter();
}

/**
Expand Down Expand Up @@ -109,17 +105,17 @@ public Map<ScalarFunction, String> getPrefixFunctionAliases() {
@Override
public String rewriteQuery(final SqlStatement statement, final ExaMetadata exaMetadata)
throws AdapterException, SQLException {
return this.queryRewriter.rewrite(statement, exaMetadata, this.properties);
return createQueryRewriter().rewrite(statement, exaMetadata, this.properties);
}

@Override
public SchemaMetadata readSchemaMetadata() throws SQLException {
return this.remoteMetadataReader.readRemoteSchemaMetadata();
return createRemoteMetadataReader().readRemoteSchemaMetadata();
}

@Override
public SchemaMetadata readSchemaMetadata(final List<String> tables) {
return this.remoteMetadataReader.readRemoteSchemaMetadata(tables);
return createRemoteMetadataReader().readRemoteSchemaMetadata(tables);
}

@Override
Expand Down Expand Up @@ -282,4 +278,4 @@ protected void validateCastNumberToDecimalProperty(final String castNumberToDeci
}
}
}
}
}
15 changes: 7 additions & 8 deletions src/main/java/com/exasol/adapter/dialects/BaseQueryRewriter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.exasol.adapter.dialects;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.logging.Logger;

Expand All @@ -18,21 +17,21 @@ public class BaseQueryRewriter implements QueryRewriter {
private static final Logger LOGGER = Logger.getLogger(BaseQueryRewriter.class.getName());
protected final SqlDialect dialect;
protected final RemoteMetadataReader remoteMetadataReader;
protected final Connection connection;
protected final ConnectionFactory connectionFactory;
protected final ConnectionDefinitionBuilder connectionDefinitionBuilder;

/**
* Create a new instance of a {@link BaseQueryRewriter}.
*
* @param dialect dialect
* @param remoteMetadataReader remote metadata reader
* @param connection JDBC connection to remote data source
* @param connectionFactory JDBC connection to remote data source
*/
public BaseQueryRewriter(final SqlDialect dialect, final RemoteMetadataReader remoteMetadataReader,
final Connection connection) {
final ConnectionFactory connectionFactory) {
this.dialect = dialect;
this.remoteMetadataReader = remoteMetadataReader;
this.connection = connection;
this.connectionFactory = connectionFactory;
this.connectionDefinitionBuilder = createConnectionDefinitionBuilder();
}

Expand Down Expand Up @@ -71,10 +70,10 @@ private String createPushdownQuery(final SqlStatement statement, final AdapterPr
return pushdownQuery;
}

private String createImportColumnsDescription(final String query) {
private String createImportColumnsDescription(final String query) throws SQLException {
final ColumnMetadataReader columnMetadataReader = this.remoteMetadataReader.getColumnMetadataReader();
final ResultSetMetadataReader resultSetMetadataReader = new ResultSetMetadataReader(this.connection,
columnMetadataReader);
final ResultSetMetadataReader resultSetMetadataReader = new ResultSetMetadataReader(
this.connectionFactory.getConnection(), columnMetadataReader);
final String columnsDescription = resultSetMetadataReader.describeColumns(query);
LOGGER.finer(() -> "Import columns: " + columnsDescription);
return columnsDescription;
Expand Down
11 changes: 5 additions & 6 deletions src/main/java/com/exasol/adapter/dialects/SqlDialectFactory.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.exasol.adapter.dialects;

import java.sql.Connection;

import com.exasol.adapter.AdapterProperties;
import com.exasol.adapter.jdbc.ConnectionFactory;

/**
* This is the common interface for all factories that produce SQL dialects.
Expand All @@ -11,11 +10,11 @@ public interface SqlDialectFactory {
/**
* Create an instance of the SQL dialect adapter matching the dialect name.
*
* @param connection JDBC connection to the remote data source
* @param properties user-defined adapter properties
* @param connectionFactory Factory for JDBC connection to the remote data source
* @param properties user-defined adapter properties
* @return SQL dialect adapter
*/
public SqlDialect createSqlDialect(final Connection connection, final AdapterProperties properties);
public SqlDialect createSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties);

/**
* Get the name of the SQL dialect this factory can produce.
Expand All @@ -30,4 +29,4 @@ public interface SqlDialectFactory {
* @return SQL dialect version
*/
public String getSqlDialectVersion();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.exasol.adapter.dialects;

import java.sql.Connection;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import com.exasol.adapter.AdapterProperties;
import com.exasol.adapter.jdbc.ConnectionFactory;

/**
* This class implements a registry for supported SQL dialects.
Expand Down Expand Up @@ -72,18 +72,18 @@ public Set<String> getRegisteredAdapterNames() {
/**
* Get the SQL dialect registered under the given name.
*
* @param name name of the SQL dialect
* @param connection JDBC connection to the remote data source
* @param properties user-defined adapter properties
* @param name name of the SQL dialect
* @param connectionFactory factory for JDBC connection to the remote data source
* @param properties user-defined adapter properties
* @return dialect instance
*/
public SqlDialect getDialectForName(final String name, final Connection connection,
public SqlDialect getDialectForName(final String name, final ConnectionFactory connectionFactory,
final AdapterProperties properties) {
if (hasDialectWithName(name)) {
final SqlDialectFactory factory = this.registeredFactories.get(name);
LOGGER.config(() -> "Loading SQL dialect: " + factory.getSqlDialectName() + " dialect adapter "
+ factory.getSqlDialectVersion());
return factory.createSqlDialect(connection, properties);
return factory.createSqlDialect(connectionFactory, properties);
} else {
throw new IllegalArgumentException("Unknown SQL dialect \"" + name + "\" requested. " + describe());
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/exasol/adapter/jdbc/ConnectionFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.exasol.adapter.jdbc;

import java.sql.Connection;
import java.sql.SQLException;

/**
* Interface for factories creating custom JDBC connections.
*/
public interface ConnectionFactory {
/**
* Create a JDBC connection to the remote data source.
*
* @return JDBC connection to remote data source
* @throws SQLException if the connection to the remote source could not be established
*/
Connection getConnection() throws SQLException;
}
71 changes: 28 additions & 43 deletions src/main/java/com/exasol/adapter/jdbc/JdbcAdapter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.exasol.adapter.jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.logging.Logger;
Expand All @@ -24,7 +23,6 @@ public class JdbcAdapter implements VirtualSchemaAdapter {
private static final String LITERAL_PREFIX = "LITERAL_";
private static final String TABLES_PROPERTY = "TABLE_FILTER";
private static final Logger LOGGER = Logger.getLogger(JdbcAdapter.class.getName());
private final RemoteConnectionFactory connectionFactory = new RemoteConnectionFactory();

@Override
public CreateVirtualSchemaResponse createVirtualSchema(final ExaMetadata exasolMetadata,
Expand All @@ -51,30 +49,28 @@ private AdapterProperties getPropertiesFromRequest(final AdapterRequest request)
private SchemaMetadata readMetadata(final AdapterProperties properties, final ExaMetadata exasolMetadata)
throws SQLException, PropertyValidationException {
final List<String> tables = properties.getFilteredTables();
try (final Connection connection = this.connectionFactory.createConnection(exasolMetadata, properties)) {
final SqlDialect dialect = createDialect(connection, properties);
dialect.validateProperties();
if (tables.isEmpty()) {
return dialect.readSchemaMetadata();
} else {
return dialect.readSchemaMetadata(tables);
}
final ConnectionFactory connectionFactory = new RemoteConnectionFactory(exasolMetadata, properties);
final SqlDialect dialect = createDialect(connectionFactory, properties);
dialect.validateProperties();
if (tables.isEmpty()) {
return dialect.readSchemaMetadata();
} else {
return dialect.readSchemaMetadata(tables);
}
}

protected SchemaMetadata readMetadata(final AdapterProperties properties,
final List<String> whiteListedRemoteTables, final ExaMetadata exasolMetadata)
throws SQLException, PropertyValidationException {
try (final Connection connection = this.connectionFactory.createConnection(exasolMetadata, properties)) {
final SqlDialect dialect = createDialect(connection, properties);
dialect.validateProperties();
return dialect.readSchemaMetadata(whiteListedRemoteTables);
}
throws PropertyValidationException {
final ConnectionFactory connectionFactory = new RemoteConnectionFactory(exasolMetadata, properties);
final SqlDialect dialect = createDialect(connectionFactory, properties);
dialect.validateProperties();
return dialect.readSchemaMetadata(whiteListedRemoteTables);
}

private SqlDialect createDialect(final Connection connection, final AdapterProperties properties) {
private SqlDialect createDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) {
final String dialectName = properties.getSqlDialect();
return SqlDialectRegistry.getInstance().getDialectForName(dialectName, connection, properties);
return SqlDialectRegistry.getInstance().getDialectForName(dialectName, connectionFactory, properties);
}

@Override
Expand Down Expand Up @@ -117,15 +113,7 @@ public SetPropertiesResponse setProperties(final ExaMetadata metadata, final Set
final AdapterProperties mergedProperties = new AdapterProperties(mergedRawProperties);
if (AdapterProperties.isRefreshingVirtualSchemaRequired(requestRawProperties)) {
final List<String> tableFilter = getTableFilter(mergedRawProperties);
final SchemaMetadata remoteMeta;
try {
remoteMeta = readMetadata(mergedProperties, tableFilter, metadata);
} catch (final SQLException exception) {
throw new AdapterException("Unable to set new properties for the virtual schema \""
+ schemaMetadataInfo.getSchemaName()
+ ("\", because metadata of the remote source could not be read. Cause: \" + exception.getMessage()"),
exception);
}
final SchemaMetadata remoteMeta = readMetadata(mergedProperties, tableFilter, metadata);
return SetPropertiesResponse.builder().schemaMetadata(remoteMeta).build();
}
return SetPropertiesResponse.builder().schemaMetadata(null).build();
Expand Down Expand Up @@ -162,19 +150,15 @@ public GetCapabilitiesResponse getCapabilities(final ExaMetadata exaMetadata, fi
throws AdapterException {
LOGGER.fine(() -> "Received request to list the adapter's capabilites.");
final AdapterProperties properties = getPropertiesFromRequest(request);
try (final Connection connection = this.connectionFactory.createConnection(exaMetadata, properties)) {
final SqlDialect dialect = createDialect(connection, properties);
final Capabilities capabilities = dialect.getCapabilities();
final Capabilities excludedCapabilities = getExcludedCapabilities(properties);
capabilities.subtractCapabilities(excludedCapabilities);
return GetCapabilitiesResponse //
.builder()//
.capabilities(capabilities)//
.build();
} catch (final SQLException exception) {
throw new AdapterException(
"Unable to execute request to get capabilities. Cause: " + exception.getMessage(), exception);
}
final ConnectionFactory connectionFactory = new RemoteConnectionFactory(exaMetadata, properties);
final SqlDialect dialect = createDialect(connectionFactory, properties);
final Capabilities capabilities = dialect.getCapabilities();
final Capabilities excludedCapabilities = getExcludedCapabilities(properties);
capabilities.subtractCapabilities(excludedCapabilities);
return GetCapabilitiesResponse //
.builder()//
.capabilities(capabilities)//
.build();
}

private Capabilities getExcludedCapabilities(final AdapterProperties properties) {
Expand Down Expand Up @@ -219,9 +203,10 @@ private Capabilities.Builder parseExcludedCapabilities(final String excludedCapa
@Override
public PushDownResponse pushdown(final ExaMetadata exaMetadata, final PushDownRequest request)
throws AdapterException {
final AdapterProperties properties = getPropertiesFromRequest(request);
try (final Connection connection = this.connectionFactory.createConnection(exaMetadata, properties)) {
final SqlDialect dialect = createDialect(connection, properties);
try {
final AdapterProperties properties = getPropertiesFromRequest(request);
final ConnectionFactory connectionFactory = new RemoteConnectionFactory(exaMetadata, properties);
final SqlDialect dialect = createDialect(connectionFactory, properties);
final String importFromPushdownQuery = dialect.rewriteQuery(request.getSelect(), exaMetadata);
return PushDownResponse.builder().pushDownSql(importFromPushdownQuery).build();
} catch (final SQLException exception) {
Expand Down
Loading

0 comments on commit 3e2f564

Please sign in to comment.