diff --git a/jdbc-adapter/README.md b/jdbc-adapter/README.md index 1a8bf80a2..985650330 100644 --- a/jdbc-adapter/README.md +++ b/jdbc-adapter/README.md @@ -136,6 +136,7 @@ Property | Value **ORA_CONNECTION_NAME** | Name of the connection to an Oracle database created with `CREATE CONNECTION`. Used by `IMPORT FROM ORA`. **IS_LOCAL** | Only relevant if your data source is the same Exasol database where you create the virtual schema. Either `TRUE` or `FALSE` (default). If true, you are connecting to the local Exasol database (e.g. for testing purposes). In this case, the adapter can avoid the `IMPORT FROM JDBC` overhead. **EXCEPTION_HANDLING** | Activates or deactivates different exception handling modes. Supported values: `IGNORE_INVALID_VIEWS` and `NONE` (default). Currently this property only affects the Teradata dialect. +**IGNORE_ERRORS** | Is used to ignore errors thrown by the adapter. Supported values: 'POSTGRESQL_UPPERCASE_TABLES' (see PostgreSQL dialect documentation). ## Debugging diff --git a/jdbc-adapter/doc/sql_dialects/postgresql.md b/jdbc-adapter/doc/sql_dialects/postgresql.md index d71d7054a..fe8e5f4f2 100644 --- a/jdbc-adapter/doc/sql_dialects/postgresql.md +++ b/jdbc-adapter/doc/sql_dialects/postgresql.md @@ -34,4 +34,25 @@ CREATE VIRTUAL SCHEMA postgres SCHEMA_NAME = 'public' CONNECTION_NAME = 'POSTGRES_DOCKER' ; -``` \ No newline at end of file +``` + +## Postgres identifiers + +In contrast to EXASOL, PostgreSQL does not treat identifiers as specified in the SQL standard. PostgreSQL folds unquoted identifiers to lower case instead of upper case. The adapter can do the identifier conversion as long as there are no identifiers in the PostgreSQL database that contain upper case characters. If that is the case an error will be thrown when creating or refreshing the virtual schema. +In order to create or refresh the virtual schema regrardlessly, you can specifiy that the adapter should ignore this specific error: +```sql +CREATE VIRTUAL SCHEMA postgres + USING adapter.jdbc_adapter + WITH + SQL_DIALECT = 'POSTGRESQL' + CATALOG_NAME = 'postgres' + SCHEMA_NAME = 'public' + CONNECTION_NAME = 'POSTGRES_DOCKER' + IGNORE_ERRORS = 'POSTGRESQL_UPPERCASE_TABLES' +; +``` +You can also set this property for an exitsing virtual schema: +```sql +ALTER VIRTUAL SCHEMA postgres SET IGNORE_ERRORS = 'POSTGRESQL_UPPERCASE_TABLES'; +``` +However you won't be able to query the identifier containing the upper case character. \ No newline at end of file diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java index 8c28c94cf..39c8497a5 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/AbstractSqlDialect.java @@ -3,11 +3,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import com.exasol.adapter.jdbc.ColumnAdapterNotes; import com.exasol.adapter.jdbc.JdbcAdapterProperties; @@ -40,7 +36,7 @@ public String getTableCatalogAndSchemaSeparator() { } @Override - public MappedTable mapTable(final ResultSet tables) throws SQLException { + public MappedTable mapTable(final ResultSet tables, final List ignoreErrorList) throws SQLException { String commentString = tables.getString("REMARKS"); if (commentString == null) { commentString = ""; diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/SqlDialect.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/SqlDialect.java index c6394ae1f..016ab796e 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/SqlDialect.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/SqlDialect.java @@ -3,6 +3,7 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; import java.util.Map; import com.exasol.adapter.capabilities.Capabilities; @@ -153,9 +154,10 @@ public String getTableComment() { * @param tables A jdbc Resultset for the * {@link DatabaseMetaData#getTables(String, String, String, String[])} * call, pointing to the current table. + * @param ignoreErrorList The elements of this list suppress certain errors the adapter would throw * @return An instance of {@link MappedTable} describing the mapped table. */ - public MappedTable mapTable(ResultSet tables) throws SQLException; + public MappedTable mapTable(ResultSet tables, final List ignoreErrorList) throws SQLException; /** * @param columns A jdbc Resultset for the diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/OracleSqlDialect.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/OracleSqlDialect.java index 8d0ff6ae5..1e0f909f0 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/OracleSqlDialect.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/OracleSqlDialect.java @@ -4,6 +4,7 @@ import java.sql.SQLException; import java.sql.Types; import java.util.EnumMap; +import java.util.List; import java.util.Map; import com.exasol.adapter.capabilities.AggregateFunctionCapability; @@ -331,7 +332,7 @@ public SchemaOrCatalogSupport supportsJdbcSchemas() { } @Override - public MappedTable mapTable(final ResultSet tables) throws SQLException { + public MappedTable mapTable(final ResultSet tables, final List ignoreErrorList) throws SQLException { final String tableName = tables.getString("TABLE_NAME"); if (tableName.startsWith("BIN$")) { // In case of Oracle we may see deleted tables with strange names @@ -341,7 +342,7 @@ public MappedTable mapTable(final ResultSet tables) throws SQLException { System.out.println("Skip table: " + tableName); return MappedTable.createIgnoredTable(); } else { - return super.mapTable(tables); + return super.mapTable(tables, ignoreErrorList); } } diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialect.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialect.java index 75adba8d9..f8d6a79be 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialect.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialect.java @@ -1,8 +1,10 @@ package com.exasol.adapter.dialects.impl; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.EnumMap; +import java.util.List; import java.util.Map; import com.exasol.adapter.capabilities.AggregateFunctionCapability; @@ -20,6 +22,9 @@ import com.exasol.adapter.sql.ScalarFunction; public class PostgreSQLSqlDialect extends AbstractSqlDialect { + + public static final String POSTGRES_IGNORE_UPPERCASE_TABLES = "POSTGRESQL_UPPERCASE_TABLES"; + public PostgreSQLSqlDialect(final SqlDialectContext context) { super(context); } @@ -298,6 +303,21 @@ public DataType dialectSpecificMapJdbcType(final JdbcTypeDescription jdbcTypeDes return colType; } + @Override + public MappedTable mapTable(final ResultSet tables, final List ignoreErrorList) throws SQLException { + final String tableName = tables.getString("TABLE_NAME"); + if (!ignoreErrorList.contains(POSTGRES_IGNORE_UPPERCASE_TABLES) && containsUppercaseCharacter(tableName)) { + throw new IllegalArgumentException("Table " + tableName + " cannot be used in virtual schema. " + + "Set property IGNORE_ERRORS to POSTGRES_UPPERCASE_TABLES to enforce schema creation."); + } else { + return super.mapTable(tables, ignoreErrorList); + } + } + + private boolean containsUppercaseCharacter(final String tableName) { + return !tableName.equals(tableName.toLowerCase()); + } + @Override public Map getScalarFunctionAliases() { @@ -345,7 +365,12 @@ public IdentifierCaseHandling getQuotedIdentifierHandling() { @Override public String applyQuote(final String identifier) { - return "\"" + identifier.replace("\"", "\"\"") + "\""; + final String lowercaseIdentifier = convertIdentifierToLowerCase(identifier); + return "\"" + lowercaseIdentifier.replace("\"", "\"\"") + "\""; + } + + private String convertIdentifierToLowerCase(final String identifier) { + return identifier.toLowerCase(); } @Override diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapter.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapter.java index 42b956ff9..b4e6389f8 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapter.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapter.java @@ -135,7 +135,8 @@ private static SchemaMetadata readMetadata(final SchemaMetadataInfo meta, final return JdbcMetadataReader.readRemoteMetadata(connection.getAddress(), connection.getUser(), connection.getPassword(), catalog, schema, tables, JdbcAdapterProperties.getSqlDialectName(meta.getProperties()), - JdbcAdapterProperties.getExceptionHandlingMode(meta.getProperties())); + JdbcAdapterProperties.getExceptionHandlingMode(meta.getProperties()), + JdbcAdapterProperties.getIgnoreErrorList(meta.getProperties())); } private static String handleRefresh(final RefreshRequest request, final ExaMetadata meta) @@ -165,7 +166,8 @@ private static String handleSetProperty(final SetPropertiesRequest request, fina connection.getUser(), connection.getPassword(), JdbcAdapterProperties.getCatalog(newSchemaMeta), JdbcAdapterProperties.getSchema(newSchemaMeta), tableFilter, JdbcAdapterProperties.getSqlDialectName(newSchemaMeta), - JdbcAdapterProperties.getExceptionHandlingMode(newSchemaMeta)); + JdbcAdapterProperties.getExceptionHandlingMode(newSchemaMeta), + JdbcAdapterProperties.getIgnoreErrorList(newSchemaMeta)); return ResponseJsonSerializer.makeSetPropertiesResponse(remoteMeta); } return ResponseJsonSerializer.makeSetPropertiesResponse(null); diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapterProperties.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapterProperties.java index f73cd97c1..e73ecd759 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapterProperties.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcAdapterProperties.java @@ -1,12 +1,9 @@ package com.exasol.adapter.jdbc; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import com.exasol.ExaConnectionAccessException; import com.exasol.ExaConnectionInformation; @@ -43,6 +40,7 @@ public final class JdbcAdapterProperties { static final String PROP_EXCLUDED_CAPABILITIES = "EXCLUDED_CAPABILITIES"; static final String PROP_EXCEPTION_HANDLING = "EXCEPTION_HANDLING"; static final String PROP_LOG_LEVEL = "LOG_LEVEL"; + static final String PROP_IGNORE_ERROR_LIST = "IGNORE_ERRORS"; private static final String DEFAULT_LOG_LEVEL = "INFO"; @@ -64,21 +62,37 @@ private static String getProperty(final Map properties, final St } } + private static String getProperty(final Map properties, final String name) { + return getProperty(properties, name, ""); + } + + public static List getIgnoreErrorList(final Map properties) { + final String ignoreErrors = getProperty(properties, PROP_IGNORE_ERROR_LIST); + if (ignoreErrors.trim().isEmpty()) { + return Collections.emptyList(); + } + return Arrays. + stream(ignoreErrors.split(",")) + .map(String::trim) + .map(String::toUpperCase) + .collect(Collectors.toList()); + } + public static String getCatalog(final Map properties) { - return getProperty(properties, PROP_CATALOG_NAME, ""); + return getProperty(properties, PROP_CATALOG_NAME); } public static String getSchema(final Map properties) { - return getProperty(properties, PROP_SCHEMA_NAME, ""); + return getProperty(properties, PROP_SCHEMA_NAME); } public static boolean userSpecifiedConnection(final Map properties) { - final String connName = getProperty(properties, PROP_CONNECTION_NAME, ""); + final String connName = getProperty(properties, PROP_CONNECTION_NAME); return (connName != null && !connName.isEmpty()); } public static String getConnectionName(final Map properties) { - final String connName = getProperty(properties, PROP_CONNECTION_NAME, ""); + final String connName = getProperty(properties, PROP_CONNECTION_NAME); assert (connName != null && !connName.isEmpty()); return connName; } @@ -90,7 +104,7 @@ public static String getConnectionName(final Map properties) { */ public static ExaConnectionInformation getConnectionInformation(final Map properties, final ExaMetadata exaMeta) { - final String connName = getProperty(properties, PROP_CONNECTION_NAME, ""); + final String connName = getProperty(properties, PROP_CONNECTION_NAME); if (connName != null && !connName.isEmpty()) { try { final ExaConnectionInformation connInfo = exaMeta.getConnection(connName); @@ -112,12 +126,25 @@ public static void checkPropertyConsistency(final Map properties checkMandatoryProperties(properties); checkImportPropertyConsistency(properties, PROP_IMPORT_FROM_EXA, PROP_EXA_CONNECTION_STRING); checkImportPropertyConsistency(properties, PROP_IMPORT_FROM_ORA, PROP_ORA_CONNECTION_NAME); + checkIgnoreErrors(properties); + } + + private static void checkIgnoreErrors(final Map properties) throws InvalidPropertyException { + final String dialect = getSqlDialectName(properties); + List errorsToIgnore = getIgnoreErrorList(properties); + for (String errorToIgnore : errorsToIgnore) { + if (!errorToIgnore.startsWith(dialect)) { + throw new InvalidPropertyException( + "Error " + errorToIgnore + " cannot be ignored in " + dialect + " dialect." + ); + } + } } private static void checkImportPropertyConsistency(final Map properties, final String propImportFromX, final String propConnection) throws InvalidPropertyException { - final boolean isImport = getProperty(properties, propImportFromX, "").toUpperCase().equals("TRUE"); - final boolean connectionIsEmpty = getProperty(properties, propConnection, "").isEmpty(); + final boolean isImport = getProperty(properties, propImportFromX).toUpperCase().equals("TRUE"); + final boolean connectionIsEmpty = getProperty(properties, propConnection).isEmpty(); if (isImport) { if (connectionIsEmpty) { throw new InvalidPropertyException( @@ -206,23 +233,23 @@ private static void checkMandatoryProperties(final Map propertie } public static boolean isImportFromExa(final Map properties) { - return getProperty(properties, PROP_IMPORT_FROM_EXA, "").toUpperCase().equals("TRUE"); + return getProperty(properties, PROP_IMPORT_FROM_EXA).toUpperCase().equals("TRUE"); } public static boolean isImportFromOra(final Map properties) { - return getProperty(properties, PROP_IMPORT_FROM_ORA, "").toUpperCase().equals("TRUE"); + return getProperty(properties, PROP_IMPORT_FROM_ORA).toUpperCase().equals("TRUE"); } public static String getExaConnectionString(final Map properties) { - return getProperty(properties, PROP_EXA_CONNECTION_STRING, ""); + return getProperty(properties, PROP_EXA_CONNECTION_STRING); } public static String getOraConnectionName(final Map properties) { - return getProperty(properties, PROP_ORA_CONNECTION_NAME, ""); + return getProperty(properties, PROP_ORA_CONNECTION_NAME); } public static List getTableFilter(final Map properties) { - final String tableNames = getProperty(properties, PROP_TABLES, ""); + final String tableNames = getProperty(properties, PROP_TABLES); if (!tableNames.isEmpty()) { final List tables = Arrays.asList(tableNames.split(",")); for (int i = 0; i < tables.size(); ++i) { @@ -235,24 +262,24 @@ public static List getTableFilter(final Map properties) } public static String getExcludedCapabilities(final Map properties) { - return getProperty(properties, PROP_EXCLUDED_CAPABILITIES, ""); + return getProperty(properties, PROP_EXCLUDED_CAPABILITIES); } public static String getDebugAddress(final Map properties) { - return getProperty(properties, PROP_DEBUG_ADDRESS, ""); + return getProperty(properties, PROP_DEBUG_ADDRESS); } public static boolean isLocal(final Map properties) { - return getProperty(properties, PROP_IS_LOCAL, "").toUpperCase().equals("TRUE"); + return getProperty(properties, PROP_IS_LOCAL).toUpperCase().equals("TRUE"); } public static String getSqlDialectName(final Map properties) { - return getProperty(properties, PROP_SQL_DIALECT, ""); + return getProperty(properties, PROP_SQL_DIALECT); } public static SqlDialect getSqlDialect(final Map properties, final SqlDialectContext dialectContext) throws InvalidPropertyException { - final String dialectName = getProperty(properties, PROP_SQL_DIALECT, ""); + final String dialectName = getProperty(properties, PROP_SQL_DIALECT); final SqlDialect dialect = SqlDialects.getInstance().getDialectInstanceForNameWithContext(dialectName, dialectContext); if (dialect == null) { @@ -263,7 +290,7 @@ public static SqlDialect getSqlDialect(final Map properties, fin } public static ExceptionHandlingMode getExceptionHandlingMode(final Map properties) { - final String propertyValue = getProperty(properties, PROP_EXCEPTION_HANDLING, ""); + final String propertyValue = getProperty(properties, PROP_EXCEPTION_HANDLING); if (propertyValue == null || propertyValue.isEmpty()) { return ExceptionHandlingMode.NONE; } diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcMetadataReader.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcMetadataReader.java index a8acf9167..22392cee6 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcMetadataReader.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/main/java/com/exasol/adapter/jdbc/JdbcMetadataReader.java @@ -19,13 +19,12 @@ public class JdbcMetadataReader { private static final Logger LOGGER = Logger.getLogger(JdbcMetadataReader.class.getName()); public static SchemaMetadata readRemoteMetadata(final String connectionString, final String user, - final String password, String catalog, String schema, final List tableFilter, - final String dialectName, final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode) + final String password, String catalog, String schema, final List tableFilter, + final String dialectName, final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode, final List ignoreErrorList) throws SQLException, AdapterException { assert (catalog != null); assert (schema != null); - try { - final Connection conn = establishConnection(connectionString, user, password); + try (final Connection conn = establishConnection(connectionString, user, password);) { final DatabaseMetaData dbMeta = conn.getMetaData(); // Retrieve relevant parts of DatabaseMetadata. Will be cached in adapternotes @@ -45,9 +44,8 @@ public static SchemaMetadata readRemoteMetadata(final String connectionString, f schema = findSchema(schema, dbMeta, dialect); - final List tables = findTables(catalog, schema, tableFilter, dbMeta, dialect, exceptionMode); + final List tables = findTables(catalog, schema, tableFilter, dbMeta, dialect, exceptionMode, ignoreErrorList); - conn.close(); return new SchemaMetadata(SchemaAdapterNotes.serialize(schemaAdapterNotes), tables); } catch (final SQLException e) { e.printStackTrace(); @@ -56,7 +54,7 @@ public static SchemaMetadata readRemoteMetadata(final String connectionString, f } private static Connection establishConnection(final String connectionString, final String user, - final String password) throws SQLException { + final String password) throws SQLException { LOGGER.fine(() -> "Establishing connection with paramters: " + connectionString); final java.util.Properties info = new java.util.Properties(); if (user != null) { @@ -242,25 +240,24 @@ private static String findSchema(final String schema, final DatabaseMetaData dbM } private static List findTables(final String catalog, final String schema, - final List tableFilter, final DatabaseMetaData dbMeta, final SqlDialect dialect, - final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode) throws SQLException { + final List tableFilter, final DatabaseMetaData dbMeta, final SqlDialect dialect, + final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode, List ignoreErrorList) throws SQLException { final List tables = new ArrayList<>(); - final String[] supportedTableTypes = { "TABLE", "VIEW", "SYSTEM TABLE" }; + final String[] supportedTableTypes = {"TABLE", "VIEW", "SYSTEM TABLE"}; - final ResultSet resTables = dbMeta.getTables(catalog, schema, null, supportedTableTypes); final List tablesMapped = new ArrayList<>(); - // List tableComments = new ArrayList<>(); - while (resTables.next()) { - final SqlDialect.MappedTable mappedTable = dialect.mapTable(resTables); - if (!mappedTable.isIgnored()) { - tablesMapped.add(mappedTable); - // tableComments.add(mappedTable.getTableComment()); + try (final ResultSet resTables = dbMeta.getTables(catalog, schema, null, supportedTableTypes)) { + // List tableComments = new ArrayList<>(); + while (resTables.next()) { + final SqlDialect.MappedTable mappedTable = dialect.mapTable(resTables, ignoreErrorList); + if (!mappedTable.isIgnored()) { + tablesMapped.add(mappedTable); + // tableComments.add(mappedTable.getTableComment()); + } } } - resTables.close(); - // Columns for (int i = 0; i < tablesMapped.size(); ++i) { final SqlDialect.MappedTable table = tablesMapped.get(i); @@ -300,8 +297,8 @@ private static boolean identifiersAreCaseInsensitive(final SqlDialect dialect) { } private static List readColumns(final DatabaseMetaData dbMeta, final String catalog, - final String schema, final String table, final SqlDialect dialect, - final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode) throws SQLException { + final String schema, final String table, final SqlDialect dialect, + final JdbcAdapterProperties.ExceptionHandlingMode exceptionMode) throws SQLException { final List columns = new ArrayList<>(); try { final ResultSet cols = dbMeta.getColumns(catalog, schema, table, null); diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/ExasolSqlDialectIT.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/ExasolSqlDialectIT.java index fbffbcefd..77634da69 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/ExasolSqlDialectIT.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/ExasolSqlDialectIT.java @@ -9,6 +9,7 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Assume; @@ -308,7 +309,7 @@ public void testDifferentDataTypes() final List tables = new ArrayList<>(Arrays.asList(tableNames)); final SchemaMetadata meta = JdbcMetadataReader.readRemoteMetadata("jdbc:exa:" + getConfig().getExasolAddress(), getConfig().getExasolUser(), getConfig().getExasolPassword(), "EXA_DB", "JDBC_ADAPTER_TEST_SCHEMA", - tables, ExasolSqlDialect.getPublicName(), getConfig().getExceptionHandlingMode()); + tables, ExasolSqlDialect.getPublicName(), getConfig().getExceptionHandlingMode(), Collections.emptyList()); if (getConfig().isDebugOn()) { System.out.println("Meta: " + SchemaMetadataSerializer.serialize(meta).build().toString()); } diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialectTest.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialectTest.java new file mode 100644 index 000000000..65d07b39b --- /dev/null +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/dialects/impl/PostgreSQLSqlDialectTest.java @@ -0,0 +1,74 @@ +package com.exasol.adapter.dialects.impl; + +import com.exasol.adapter.dialects.SqlDialectContext; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import static org.mockito.Mockito.*; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +public class PostgreSQLSqlDialectTest { + @Mock + SqlDialectContext sqlDialectContext; + + @Before + public void setUp() throws SQLException { + + } + + @Test + public void testApplyQuoteOnUpperCase() { + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + assertEquals("\"abc\"", postgresDialect.applyQuote("ABC")); + } + + @Test + public void testApplyQuoteOnMixedCase() { + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + assertEquals("\"abcde\"", postgresDialect.applyQuote("AbCde")); + } + + @Test(expected = IllegalArgumentException.class) + public void testMapTableWithUpperCaseCharactersAndNoErrorIgnoredThrowsException() throws SQLException { + ResultSet resultSet = mock(ResultSet.class); + when(resultSet.getString("TABLE_NAME")).thenReturn("uPPer"); + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + postgresDialect.mapTable(resultSet, Collections.emptyList()); + } + + @Test(expected = IllegalArgumentException.class) + public void testMapTableWithRussianUpperCaseCharactersAndNoErrorIgnoredThrowsException() throws SQLException { + ResultSet resultSet = mock(ResultSet.class); + when(resultSet.getString("TABLE_NAME")).thenReturn("аППер"); + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + postgresDialect.mapTable(resultSet, Collections.emptyList()); + } + + @Test + public void testMapTableWithLowerCaseCharacters() throws SQLException { + ResultSet resultSet = mock(ResultSet.class); + when(resultSet.getString("TABLE_NAME")).thenReturn("lower"); + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + postgresDialect.mapTable(resultSet, Collections.emptyList()); + } + + @Test + public void testMapTableWithIgnoreUppercaseCharactersError() throws SQLException { + ResultSet resultSet = mock(ResultSet.class); + when(resultSet.getString("TABLE_NAME")).thenReturn("Upper"); + List ignoreList = new ArrayList<>(); + ignoreList.add("Dummy_Error"); + ignoreList.add("POSTGRESQL_UPPERCASE_TABLES"); + PostgreSQLSqlDialect postgresDialect = new PostgreSQLSqlDialect(sqlDialectContext); + postgresDialect.mapTable(resultSet, ignoreList); + } +} \ No newline at end of file diff --git a/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/jdbc/JdbcAdapterPropertiesTest.java b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/jdbc/JdbcAdapterPropertiesTest.java index e4ca68d5f..01ac7ac6c 100644 --- a/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/jdbc/JdbcAdapterPropertiesTest.java +++ b/jdbc-adapter/virtualschema-jdbc-adapter/src/test/java/com/exasol/adapter/jdbc/JdbcAdapterPropertiesTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -246,4 +247,24 @@ public void testNoneAsExceptionValue() throws AdapterException { JdbcAdapterProperties.getExceptionHandlingMode(properties)); JdbcAdapterProperties.checkPropertyConsistency(properties); } + + @Test + public void getIgnoreErrors() { + Map properties = new HashMap<>(); + properties.put("IGNORE_ERRORS", "ERrror_foo, error_bar , another_error, уккщк"); + List expectedErrorList = new ArrayList<>(); + expectedErrorList.add("ERRROR_FOO"); + expectedErrorList.add("ERROR_BAR"); + expectedErrorList.add("ANOTHER_ERROR"); + expectedErrorList.add("УККЩК"); + assertEquals(expectedErrorList, JdbcAdapterProperties.getIgnoreErrorList(properties)); + } + + @Test(expected = InvalidPropertyException.class) + public void checkIgnoreErrorsConsistency() throws AdapterException { + Map properties = new HashMap<>(); + properties.put("IGNORE_ERRORS", "ORACLE_ERROR"); + properties.put("dialect", "postgresql"); + JdbcAdapterProperties.checkPropertyConsistency(properties); + } }