Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,9 @@ private static RelDataType sqlType(RelDataTypeFactory typeFactory, int dataType,
int precision, int scale, @Nullable String typeString) {
// Fall back to ANY if type is unknown
final SqlTypeName sqlTypeName =
Util.first(SqlTypeName.getNameForJdbcType(dataType), SqlTypeName.ANY);
Util.first(typeString != null && typeString.toUpperCase(Locale.ROOT).contains("UNSIGNED")
? SqlTypeName.getNameForUnsignedJdbcType(dataType)
: SqlTypeName.getNameForJdbcType(dataType), SqlTypeName.ANY);
switch (sqlTypeName) {
case ARRAY:
RelDataType component = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ private static ColumnMetaData metaData(JavaTypeFactory typeFactory, int ordinal,
type.isNullable()
? DatabaseMetaData.columnNullable
: DatabaseMetaData.columnNoNulls,
true,
!SqlTypeName.UNSIGNED_TYPES.contains(type.getSqlTypeName()),
type.getPrecision(),
fieldName,
origin(origins, 0),
Expand Down
22 changes: 22 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@ public enum SqlTypeName {
.put(Types.ARRAY, ARRAY)
.build();

/**
* Mapping between JDBC type codes and their corresponding
* {@link org.apache.calcite.sql.type.SqlTypeName} for unsigned types.
*/
private static final Map<Integer, SqlTypeName> UNSIGNED_JDBC_TYPE_TO_NAME =
ImmutableMap.<Integer, SqlTypeName>builder()
.put(Types.TINYINT, UTINYINT)
.put(Types.SMALLINT, USMALLINT)
.put(Types.INTEGER, UINTEGER)
.put(Types.BIGINT, UBIGINT)
.build();

/**
* Bitwise-or of flags indicating allowable precision/scale combinations.
*/
Expand Down Expand Up @@ -447,6 +459,16 @@ public int getDefaultScale() {
return JDBC_TYPE_TO_NAME.get(jdbcType);
}

/**
* Gets the SqlTypeName corresponding to an unsigned JDBC type.
*
* @param jdbcType the unsigned JDBC type of interest
* @return corresponding SqlTypeName, or null if the type is not known
*/
public static @Nullable SqlTypeName getNameForUnsignedJdbcType(int jdbcType) {
return UNSIGNED_JDBC_TYPE_TO_NAME.get(jdbcType);
}

/**
* Returns the limit of this datatype. For example,
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
import static org.apache.calcite.sql.type.SqlTypeName.TIME;
import static org.apache.calcite.sql.type.SqlTypeName.TIMESTAMP;
import static org.apache.calcite.sql.type.SqlTypeName.TINYINT;
import static org.apache.calcite.sql.type.SqlTypeName.UBIGINT;
import static org.apache.calcite.sql.type.SqlTypeName.UINTEGER;
import static org.apache.calcite.sql.type.SqlTypeName.USMALLINT;
import static org.apache.calcite.sql.type.SqlTypeName.UTINYINT;
import static org.apache.calcite.sql.type.SqlTypeName.VARBINARY;
import static org.apache.calcite.sql.type.SqlTypeName.VARCHAR;

Expand Down Expand Up @@ -81,6 +85,30 @@ class SqlTypeNameTest {
assertThat("BIGINT did not map to BIGINT", tn, is(BIGINT));
}

@Test void testUnsignedTinyint() {
SqlTypeName tn =
SqlTypeName.getNameForUnsignedJdbcType(Types.TINYINT);
assertThat("TINYINT did not map to UTINYINT", tn, is(UTINYINT));
}

@Test void testUnsignedSmallint() {
SqlTypeName tn =
SqlTypeName.getNameForUnsignedJdbcType(Types.SMALLINT);
assertThat("SMALLINT did not map to USMALLINT", tn, is(USMALLINT));
}

@Test void testUnsignedInteger() {
SqlTypeName tn =
SqlTypeName.getNameForUnsignedJdbcType(Types.INTEGER);
assertThat("INTEGER did not map to UINTEGER", tn, is(UINTEGER));
}

@Test void testUnsignedBigint() {
SqlTypeName tn =
SqlTypeName.getNameForUnsignedJdbcType(Types.BIGINT);
assertThat("BIGINT did not map to UBIGINT", tn, is(UBIGINT));
}

@Test void testFloat() {
SqlTypeName tn =
SqlTypeName.getNameForJdbcType(Types.FLOAT);
Expand Down
33 changes: 33 additions & 0 deletions core/src/test/java/org/apache/calcite/test/JdbcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9077,6 +9077,39 @@ void checkCalciteSchemaGetSubSchemaMap(boolean cache) {
});
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5094">[CALCITE-5094]
* Calcite JDBC Adapter and Avatica should support
* MySQL UNSIGNED types of TINYINT, SMALLINT, INT, BIGINT</a>. */
@Test void testMySQLUnsignedType() {
CalciteAssert.that()
.with(CalciteAssert.SchemaSpec.UNSIGNED_TYPE)
.with(Lex.MYSQL)
.query("SELECT * FROM test_unsigned WHERE utiny_value = ? "
+ "AND usmall_value = ? AND uint_value = ? AND ubig_value = ?")
.consumesPreparedStatement(p -> {
p.setInt(1, 255);
p.setInt(2, 65535);
p.setLong(3, 4294967295L);
p.setBigDecimal(4, new BigDecimal("18446744073709551615"));
})
.returns(resultSet -> {
try {
assertTrue(resultSet.next());
final Integer uTinyInt = resultSet.getInt(1);
final Integer uSmallInt = resultSet.getInt(2);
final Long uInteger = resultSet.getLong(3);
final BigDecimal uBigInt = resultSet.getBigDecimal(4);
assertThat(uTinyInt, is(255));
assertThat(uSmallInt, is(65535));
assertThat(uInteger, is(4294967295L));
assertThat(uBigInt, is(new BigDecimal("18446744073709551615")));
} catch (SQLException e) {
throw TestUtil.rethrow(e);
}
});
}

@Test void bindByteParameter() {
for (SqlTypeName tpe : SqlTypeName.INT_TYPES) {
final String sql =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ public static ULong toULong(double n) {
private static ULong toULongNonNull(Number n, RoundingMode mode) {
if (n instanceof BigDecimal) {
BigDecimal d = ((BigDecimal) n).setScale(0, mode);
return Unsigned.ulong(d.longValueExact());
return Unsigned.ulong(d.toBigIntegerExact());
} else if (n instanceof Byte || n instanceof Short || n instanceof Integer
|| n instanceof Long || n instanceof Float || n instanceof Double
|| n instanceof UByte || n instanceof UShort || n instanceof UInteger) {
Expand Down
49 changes: 48 additions & 1 deletion testkit/src/main/java/org/apache/calcite/test/CalciteAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import org.apache.calcite.jdbc.CalciteMetaImpl;
import org.apache.calcite.jdbc.CalcitePrepare;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.materialize.Lattice;
import org.apache.calcite.model.ModelHandler;
Expand All @@ -47,6 +49,7 @@
import org.apache.calcite.runtime.Hook;
import org.apache.calcite.runtime.SpatialTypeFunctions;
import org.apache.calcite.runtime.UnionOperation;
import org.apache.calcite.schema.ScannableTable;
import org.apache.calcite.schema.Schema;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.SchemaVersion;
Expand Down Expand Up @@ -90,6 +93,7 @@
import org.apache.calcite.util.Util;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
Expand All @@ -105,6 +109,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
Expand Down Expand Up @@ -865,7 +870,8 @@ static SchemaPlus addSchema_(SchemaPlus rootSchema, SchemaSpec schema) {

case MY_DB:
return rootSchema.add(schema.schemaName, MY_DB_SCHEMA);

case UNSIGNED_TYPE:
return rootSchema.add(schema.schemaName, UNSIGNED_TYPE_SCHEMA);
case SCOTT:
jdbcScott = addSchemaIfNotExists(rootSchema, SchemaSpec.JDBC_SCOTT);
return rootSchema.add(schema.schemaName, new CloneSchema(jdbcScott));
Expand Down Expand Up @@ -2077,6 +2083,7 @@ public enum SchemaSpec {
GEO("GEO"),
HR("hr"),
MY_DB("myDb"),
UNSIGNED_TYPE("UNSIGNED_TYPE"),
JDBC_SCOTT("JDBC_SCOTT"),
SCOTT("scott"),
SCOTT_WITH_TEMPORAL("scott_temporal"),
Expand Down Expand Up @@ -2355,4 +2362,44 @@ static List<String> unwrap(String java) {
throw new UnsupportedOperationException("snapshot");
}
};

/** Schema instance for {@link SchemaSpec#UNSIGNED_TYPE}. */
private static final Schema UNSIGNED_TYPE_SCHEMA = new AbstractSchema() {

@Override protected Map<String, Table> getTableMap() {
return ImmutableMap.of("test_unsigned", new UnsingedScannableTable());
}
};

/** Scannable table for unsigned types test. */
private static class UnsingedScannableTable extends AbstractTable implements ScannableTable {

/**
* {@inheritDoc}
*
* <p>Table schema is as follows:
*
* <pre>{@code
* test_unsigned(
* utiny_value: TINYINT UNSIGNED,
* usmall_value: SMALLINT UNSIGNED,
* uint_value: INT UNSIGNED,
* ubig_value: BIGINT UNSIGNED)
* }</pre>
*/
@Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
return typeFactory.builder()
.add("utiny_value", typeFactory.createSqlType(SqlTypeName.UTINYINT))
.add("usmall_value", typeFactory.createSqlType(SqlTypeName.USMALLINT))
.add("uint_value", typeFactory.createSqlType(SqlTypeName.UINTEGER))
.add("ubig_value", typeFactory.createSqlType(SqlTypeName.UBIGINT))
.build();
}

@Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
return Linq4j.asEnumerable(new Object[][] {
{255, 65535, 4294967295L, new BigDecimal("18446744073709551615")}
});
}
}
}
Loading