Skip to content

Commit

Permalink
#69 Fix hashtype mapping (#70)
Browse files Browse the repository at this point in the history
* #69: Map hashtype with correct length

* Add changelog entry

* Upgrade to latest Exasol versions

* Add tests for INTERVAL, HASHTYPE and GEOMETRY columns

* Remove HASHTYPE exception for JDBC connection
  • Loading branch information
kaklakariada authored Feb 2, 2022
1 parent f45ca92 commit b7f94aa
Show file tree
Hide file tree
Showing 10 changed files with 444 additions and 54 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ jobs:
strategy:
fail-fast: false
matrix:
docker_db_version: [ 7.0.14, 7.1.4 ]
docker_db_version: [ 7.0.15, 7.1.5 ]
env:
DEFAULT_DB_VERSION: "7.1.4"
DEFAULT_DB_VERSION: "7.1.5"
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
Expand Down
2 changes: 1 addition & 1 deletion doc/changes/changes_6.0.1.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Exasol Virtual Schema 6.0.1, released 2022-01-31
# Exasol Virtual Schema 6.0.1, released 2022-02-02

Code name: Fix data type mapping

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.exasol.adapter.dialects.exasol;

import java.sql.*;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -38,32 +39,45 @@ public ExasolColumnMetadataReader(final Connection connection, final AdapterProp

@Override
public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) {
final DataType resultType = getJdbcType(jdbcTypeDescription);
final DataType resultType = getDataTypeBasedOnJdbcType(jdbcTypeDescription) //
.or(() -> getDataTypeBasedOnTypeName(jdbcTypeDescription)) //
.orElseGet(() -> super.mapJdbcType(jdbcTypeDescription));
LOGGER.fine(() -> "Mapped JDBC type " + jdbcTypeDescription.getTypeName() + " ("
+ jdbcTypeDescription.getJdbcType() + ") with byte size " + jdbcTypeDescription.getByteSize()
+ ", decimal scale " + jdbcTypeDescription.getDecimalScale() + ", precision/size "
+ jdbcTypeDescription.getPrecisionOrSize() + " to " + resultType);
return resultType;
}

private DataType getJdbcType(final JDBCTypeDescription jdbcTypeDescription) {
private Optional<DataType> getDataTypeBasedOnJdbcType(final JDBCTypeDescription jdbcTypeDescription) {
switch (jdbcTypeDescription.getJdbcType()) {
case EXASOL_INTERVAL_DAY_TO_SECONDS:
return DataType.createIntervalDaySecond(jdbcTypeDescription.getPrecisionOrSize(),
jdbcTypeDescription.getDecimalScale());
return Optional.of(DataType.createIntervalDaySecond(jdbcTypeDescription.getPrecisionOrSize(),
jdbcTypeDescription.getDecimalScale()));
case EXASOL_INTERVAL_YEAR_TO_MONTHS:
return DataType.createIntervalYearMonth(jdbcTypeDescription.getPrecisionOrSize());
return Optional.of(DataType.createIntervalYearMonth(jdbcTypeDescription.getPrecisionOrSize()));
case EXASOL_GEOMETRY:
return DataType.createGeometry(jdbcTypeDescription.getPrecisionOrSize());
return Optional.of(DataType.createGeometry(jdbcTypeDescription.getPrecisionOrSize()));
case EXASOL_TIMESTAMP:
return DataType.createTimestamp(true);
return Optional.of(DataType.createTimestamp(true));
case EXASOL_HASHTYPE:
return DataType.createHashtype(jdbcTypeDescription.getByteSize());
return Optional.of(DataType.createHashtype(jdbcTypeDescription.getByteSize()));
default:
return super.mapJdbcType(jdbcTypeDescription);
return Optional.empty();
}
}

private Optional<DataType> getDataTypeBasedOnTypeName(final JDBCTypeDescription jdbcTypeDescription) {
if ("HASHTYPE".equals(jdbcTypeDescription.getTypeName())) {
if (jdbcTypeDescription.getByteSize() != 0) {
return Optional.of(DataType.createHashtype(jdbcTypeDescription.getByteSize() / 2));
} else if (jdbcTypeDescription.getPrecisionOrSize() != 0) {
return Optional.of(DataType.createHashtype(jdbcTypeDescription.getPrecisionOrSize() / 2));
}
}
return Optional.empty();
}

@Override
public JDBCTypeDescription readJdbcTypeDescription(final ResultSet remoteColumn) throws SQLException {
final JDBCTypeDescription typeDescription = super.readJdbcTypeDescription(remoteColumn);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.exasol.adapter.dialects.exasol;

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

import com.exasol.adapter.dialects.SqlDialect;
import com.exasol.adapter.dialects.rewriting.AbstractQueryRewriter;
import com.exasol.adapter.jdbc.RemoteMetadataReader;
Expand All @@ -11,7 +8,6 @@
* Exasol-specific query rewriter for {@code IMPORT FROM EXA}.
*/
public class ExasolFromExaQueryRewriter extends AbstractQueryRewriter {
private static final Logger LOGGER = Logger.getLogger(ExasolFromExaQueryRewriter.class.getName());

/**
* Create a new instance of the {@link ExasolFromExaQueryRewriter}.
Expand All @@ -24,11 +20,7 @@ public ExasolFromExaQueryRewriter(final SqlDialect dialect, final RemoteMetadata
}

@Override
protected String generateImportStatement(final String connectionDefinition, final String pushdownQuery)
throws SQLException {
final String importStatement = "IMPORT FROM EXA " + connectionDefinition + " STATEMENT '"
+ pushdownQuery.replace("'", "''") + "'";
LOGGER.finer(() -> "IMPORT push-down statement:\n" + importStatement);
return importStatement;
protected String generateImportStatement(final String connectionDefinition, final String pushdownQuery) {
return "IMPORT FROM EXA " + connectionDefinition + " STATEMENT '" + pushdownQuery.replace("'", "''") + "'";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,83 @@ void testSelectStarConvertedToColumnsListNestedJoinReversed() {
.matches());
}

@Test
void testDefaultHashType() {
typeAssertionFor("HASHTYPE").withValue("550e8400-e29b-11d4-a716-446655440000")
.expectDescribeType("HASHTYPE(16 BYTE)") //
.expectTypeOf("HASHTYPE(16 BYTE)") //
.expectResultSetType("HASHTYPE") //
.expectValue("550e8400e29b11d4a716446655440000").runAssert();
}

@Test
void testNonDefaultHashType() {
typeAssertionFor("HASHTYPE(4 BYTE)").withValue("550e8400") //
.expectDescribeType("HASHTYPE(4 BYTE)") //
.expectTypeOf("HASHTYPE(4 BYTE)") //
.expectResultSetType("HASHTYPE") //
.runAssert();
}

@Test
void testHashTypeWithBitSize() {
typeAssertionFor("HASHTYPE(16 BIT)").withValue("550e") //
.expectDescribeType("HASHTYPE(2 BYTE)") //
.expectTypeOf("HASHTYPE(2 BYTE)") //
.expectResultSetType("HASHTYPE") //
.runAssert();
}

@Test
void testDefaultGeometry() {
typeAssertionFor("GEOMETRY").withValue("POINT (2 5)") //
.expectDescribeType("GEOMETRY(3857)") //
.runAssert();
}

@Test
void testNonDefaultGeometry() {
typeAssertionFor("GEOMETRY(4321)").withValue("POINT (2 5)") //
.expectResultSetType("GEOMETRY") //
.runAssert();
}

@Test
void testDefaultIntervalYearToMonth() {
typeAssertionFor("INTERVAL YEAR TO MONTH").withValue("5-3") //
.expectTypeOf("INTERVAL YEAR(2) TO MONTH") //
.expectDescribeType("INTERVAL YEAR(2) TO MONTH") //
.expectResultSetType("INTERVAL YEAR TO MONTH") //
.expectValue("+05-03") //
.runAssert();
}

@Test
void testNonDefaultIntervalYearToMonth() {
typeAssertionFor("INTERVAL YEAR(5) TO MONTH").withValue("5-3") //
.expectResultSetType("INTERVAL YEAR TO MONTH") //
.expectValue("+00005-03") //
.runAssert();
}

@Test
void testDefaultIntervalDayToSecond() {
typeAssertionFor("INTERVAL DAY TO SECOND").withValue("2 12:50:10.123") //
.expectTypeOf("INTERVAL DAY(2) TO SECOND(3)") //
.expectDescribeType("INTERVAL DAY(2) TO SECOND(3)") //
.expectResultSetType("INTERVAL DAY TO SECOND") //
.expectValue("+02 12:50:10.123") //
.runAssert();
}

@Test
void testNonDefaultIntervalDayToSecond() {
typeAssertionFor("INTERVAL DAY(4) TO SECOND(6)").withValue("2 12:50:10.123") //
.expectResultSetType("INTERVAL DAY TO SECOND") //
.expectValue("+0002 12:50:10.123000") //
.runAssert();
}

protected com.exasol.adapter.dialects.exasol.DataTypeAssertion.Builder typeAssertionFor(final String columnType) {
return DataTypeAssertion.builder(this).withColumnType(columnType);
}
Expand All @@ -775,7 +852,7 @@ private void assertResultSetType(final VirtualSchema virtualSchema, final Table
final Object expectedValue) throws SQLException {
try (final ResultSet result = query(
"SELECT " + COLUMN1_NAME + " FROM " + getVirtualTableName(virtualSchema, table))) {
assertThat(result, table(expectedType).row(expectedValue).matches());
assertThat("ResultSet type and value", result, table(expectedType).row(expectedValue).matches());
}
}

Expand All @@ -797,7 +874,7 @@ private void assertTypeofColumn(final VirtualSchema virtualSchema, final Table t
}
try (final ResultSet result = query(
"SELECT TYPEOF(" + COLUMN1_NAME + ") AS TYPE FROM " + getVirtualTableName(virtualSchema, table))) {
assertThat(result, table("VARCHAR").row(expectedType).matches());
assertThat("TYPEOF result", result, table("VARCHAR").row(expectedType).matches());
}
}

Expand Down
Loading

0 comments on commit b7f94aa

Please sign in to comment.