use of io.trino.plugin.jdbc.JdbcTypeHandle in project trino by trinodb.
the class PostgreSqlClient method toColumnMapping.
@Override
public Optional<ColumnMapping> toColumnMapping(ConnectorSession session, Connection connection, JdbcTypeHandle typeHandle) {
String jdbcTypeName = typeHandle.getJdbcTypeName().orElseThrow(() -> new TrinoException(JDBC_ERROR, "Type name is missing: " + typeHandle));
Optional<ColumnMapping> mapping = getForcedMappingToVarchar(typeHandle);
if (mapping.isPresent()) {
return mapping;
}
switch(jdbcTypeName) {
case "money":
return Optional.of(moneyColumnMapping());
case "uuid":
return Optional.of(uuidColumnMapping());
case "jsonb":
case "json":
return Optional.of(jsonColumnMapping());
case "timestamptz":
// PostgreSQL's "timestamp with time zone" is reported as Types.TIMESTAMP rather than Types.TIMESTAMP_WITH_TIMEZONE
int decimalDigits = typeHandle.getRequiredDecimalDigits();
return Optional.of(timestampWithTimeZoneColumnMapping(decimalDigits));
case "hstore":
return Optional.of(hstoreColumnMapping(session));
}
switch(typeHandle.getJdbcType()) {
case Types.BIT:
return Optional.of(booleanColumnMapping());
case Types.SMALLINT:
return Optional.of(smallintColumnMapping());
case Types.INTEGER:
return Optional.of(integerColumnMapping());
case Types.BIGINT:
return Optional.of(bigintColumnMapping());
case Types.REAL:
return Optional.of(realColumnMapping());
case Types.DOUBLE:
return Optional.of(doubleColumnMapping());
case Types.NUMERIC:
{
int columnSize = typeHandle.getRequiredColumnSize();
int precision;
int decimalDigits = typeHandle.getDecimalDigits().orElse(0);
if (getDecimalRounding(session) == ALLOW_OVERFLOW) {
if (columnSize == PRECISION_OF_UNSPECIFIED_DECIMAL) {
// decimal type with unspecified scale - up to 131072 digits before the decimal point; up to 16383 digits after the decimal point)
return Optional.of(decimalColumnMapping(createDecimalType(Decimals.MAX_PRECISION, getDecimalDefaultScale(session)), getDecimalRoundingMode(session)));
}
precision = columnSize;
if (precision > Decimals.MAX_PRECISION) {
int scale = min(decimalDigits, getDecimalDefaultScale(session));
return Optional.of(decimalColumnMapping(createDecimalType(Decimals.MAX_PRECISION, scale), getDecimalRoundingMode(session)));
}
}
// Map decimal(p, -s) (negative scale) to decimal(p+s, 0).
precision = columnSize + max(-decimalDigits, 0);
if (columnSize == PRECISION_OF_UNSPECIFIED_DECIMAL || precision > Decimals.MAX_PRECISION) {
break;
}
return Optional.of(decimalColumnMapping(createDecimalType(precision, max(decimalDigits, 0)), UNNECESSARY));
}
case Types.CHAR:
return Optional.of(charColumnMapping(typeHandle.getRequiredColumnSize()));
case Types.VARCHAR:
if (!jdbcTypeName.equals("varchar")) {
// This can be e.g. an ENUM
return Optional.of(typedVarcharColumnMapping(jdbcTypeName));
}
return Optional.of(varcharColumnMapping(typeHandle.getRequiredColumnSize()));
case Types.BINARY:
return Optional.of(varbinaryColumnMapping());
case Types.DATE:
return Optional.of(ColumnMapping.longMapping(DATE, (resultSet, index) -> LocalDate.parse(resultSet.getString(index), DATE_FORMATTER).toEpochDay(), dateWriteFunctionUsingLocalDate()));
case Types.TIME:
return Optional.of(timeColumnMapping(typeHandle.getRequiredDecimalDigits()));
case Types.TIMESTAMP:
TimestampType timestampType = createTimestampType(typeHandle.getRequiredDecimalDigits());
return Optional.of(ColumnMapping.longMapping(timestampType, timestampReadFunction(timestampType), PostgreSqlClient::shortTimestampWriteFunction));
case Types.ARRAY:
Optional<ColumnMapping> columnMapping = arrayToTrinoType(session, connection, typeHandle);
if (columnMapping.isPresent()) {
return columnMapping;
}
break;
}
if (getUnsupportedTypeHandling(session) == CONVERT_TO_VARCHAR) {
return mapToUnboundedVarchar(typeHandle);
}
return Optional.empty();
}
use of io.trino.plugin.jdbc.JdbcTypeHandle in project trino by trinodb.
the class PostgreSqlClient method arrayToTrinoType.
private Optional<ColumnMapping> arrayToTrinoType(ConnectorSession session, Connection connection, JdbcTypeHandle typeHandle) {
checkArgument(typeHandle.getJdbcType() == Types.ARRAY, "Not array type");
ArrayMapping arrayMapping = getArrayMapping(session);
if (arrayMapping == DISABLED) {
return Optional.empty();
}
// resolve and map base array element type
JdbcTypeHandle baseElementTypeHandle = getArrayElementTypeHandle(connection, typeHandle);
String baseElementTypeName = baseElementTypeHandle.getJdbcTypeName().orElseThrow(() -> new TrinoException(JDBC_ERROR, "Element type name is missing: " + baseElementTypeHandle));
if (baseElementTypeHandle.getJdbcType() == Types.BINARY) {
// https://github.com/pgjdbc/pgjdbc/pull/1184
return Optional.empty();
}
Optional<ColumnMapping> baseElementMapping = toColumnMapping(session, connection, baseElementTypeHandle);
if (arrayMapping == AS_ARRAY) {
if (typeHandle.getArrayDimensions().isEmpty()) {
return Optional.empty();
}
return baseElementMapping.map(elementMapping -> {
ArrayType prestoArrayType = new ArrayType(elementMapping.getType());
ColumnMapping arrayColumnMapping = arrayColumnMapping(session, prestoArrayType, elementMapping, baseElementTypeName);
int arrayDimensions = typeHandle.getArrayDimensions().get();
for (int i = 1; i < arrayDimensions; i++) {
prestoArrayType = new ArrayType(prestoArrayType);
arrayColumnMapping = arrayColumnMapping(session, prestoArrayType, arrayColumnMapping, baseElementTypeName);
}
return arrayColumnMapping;
});
}
if (arrayMapping == AS_JSON) {
return baseElementMapping.map(elementMapping -> arrayAsJsonColumnMapping(session, elementMapping));
}
throw new IllegalStateException("Unsupported array mapping type: " + arrayMapping);
}
use of io.trino.plugin.jdbc.JdbcTypeHandle in project trino by trinodb.
the class PostgreSqlClient method getColumns.
@Override
public List<JdbcColumnHandle> getColumns(ConnectorSession session, JdbcTableHandle tableHandle) {
if (tableHandle.getColumns().isPresent()) {
return tableHandle.getColumns().get();
}
checkArgument(tableHandle.isNamedRelation(), "Cannot get columns for %s", tableHandle);
SchemaTableName schemaTableName = tableHandle.getRequiredNamedRelation().getSchemaTableName();
try (Connection connection = connectionFactory.openConnection(session)) {
Map<String, Integer> arrayColumnDimensions = ImmutableMap.of();
if (getArrayMapping(session) == AS_ARRAY) {
arrayColumnDimensions = getArrayColumnDimensions(connection, tableHandle);
}
try (ResultSet resultSet = getColumns(tableHandle, connection.getMetaData())) {
int allColumns = 0;
List<JdbcColumnHandle> columns = new ArrayList<>();
while (resultSet.next()) {
allColumns++;
String columnName = resultSet.getString("COLUMN_NAME");
JdbcTypeHandle typeHandle = new JdbcTypeHandle(getInteger(resultSet, "DATA_TYPE").orElseThrow(() -> new IllegalStateException("DATA_TYPE is null")), Optional.of(resultSet.getString("TYPE_NAME")), getInteger(resultSet, "COLUMN_SIZE"), getInteger(resultSet, "DECIMAL_DIGITS"), Optional.ofNullable(arrayColumnDimensions.get(columnName)), Optional.empty());
Optional<ColumnMapping> columnMapping = toColumnMapping(session, connection, typeHandle);
log.debug("Mapping data type of '%s' column '%s': %s mapped to %s", schemaTableName, columnName, typeHandle, columnMapping);
// skip unsupported column types
if (columnMapping.isPresent()) {
boolean nullable = (resultSet.getInt("NULLABLE") != columnNoNulls);
Optional<String> comment = Optional.ofNullable(resultSet.getString("REMARKS"));
columns.add(JdbcColumnHandle.builder().setColumnName(columnName).setJdbcTypeHandle(typeHandle).setColumnType(columnMapping.get().getType()).setNullable(nullable).setComment(comment).build());
}
if (columnMapping.isEmpty()) {
UnsupportedTypeHandling unsupportedTypeHandling = getUnsupportedTypeHandling(session);
verify(unsupportedTypeHandling == IGNORE, "Unsupported type handling is set to %s, but toColumnMapping() returned empty for %s", unsupportedTypeHandling, typeHandle);
}
}
if (columns.isEmpty()) {
// A table may have no supported columns. In rare cases a table might have no columns at all.
throw new TableNotFoundException(tableHandle.getSchemaTableName(), format("Table '%s' has no supported columns (all %s columns are not supported)", tableHandle.getSchemaTableName(), allColumns));
}
return ImmutableList.copyOf(columns);
}
} catch (SQLException e) {
throw new TrinoException(JDBC_ERROR, e);
}
}
use of io.trino.plugin.jdbc.JdbcTypeHandle in project trino by trinodb.
the class ImplementSum method rewrite.
@Override
public Optional<JdbcExpression> rewrite(AggregateFunction aggregateFunction, Captures captures, RewriteContext<String> context) {
Variable argument = captures.get(ARGUMENT);
JdbcColumnHandle columnHandle = (JdbcColumnHandle) context.getAssignment(argument.getName());
JdbcTypeHandle resultTypeHandle;
if (columnHandle.getColumnType().equals(aggregateFunction.getOutputType())) {
resultTypeHandle = columnHandle.getJdbcTypeHandle();
} else if (aggregateFunction.getOutputType() instanceof DecimalType) {
Optional<JdbcTypeHandle> decimalTypeHandle = this.decimalTypeHandle.apply(((DecimalType) aggregateFunction.getOutputType()));
if (decimalTypeHandle.isEmpty()) {
return Optional.empty();
}
resultTypeHandle = decimalTypeHandle.get();
} else {
return Optional.empty();
}
return Optional.of(new JdbcExpression(format("sum(%s)", context.rewriteExpression(argument).orElseThrow()), resultTypeHandle));
}
use of io.trino.plugin.jdbc.JdbcTypeHandle in project trino by trinodb.
the class MySqlClient method toColumnMapping.
@Override
public Optional<ColumnMapping> toColumnMapping(ConnectorSession session, Connection connection, JdbcTypeHandle typeHandle) {
String jdbcTypeName = typeHandle.getJdbcTypeName().orElseThrow(() -> new TrinoException(JDBC_ERROR, "Type name is missing: " + typeHandle));
Optional<ColumnMapping> mapping = getForcedMappingToVarchar(typeHandle);
if (mapping.isPresent()) {
return mapping;
}
switch(jdbcTypeName.toLowerCase(ENGLISH)) {
case "tinyint unsigned":
return Optional.of(smallintColumnMapping());
case "smallint unsigned":
return Optional.of(integerColumnMapping());
case "int unsigned":
return Optional.of(bigintColumnMapping());
case "bigint unsigned":
return Optional.of(decimalColumnMapping(createDecimalType(20)));
case "json":
return Optional.of(jsonColumnMapping());
}
switch(typeHandle.getJdbcType()) {
case Types.BIT:
return Optional.of(booleanColumnMapping());
case Types.TINYINT:
return Optional.of(tinyintColumnMapping());
case Types.SMALLINT:
return Optional.of(smallintColumnMapping());
case Types.INTEGER:
return Optional.of(integerColumnMapping());
case Types.BIGINT:
return Optional.of(bigintColumnMapping());
case Types.REAL:
// attempts to treat them as exact in comparisons may lead to problems
return Optional.of(ColumnMapping.longMapping(REAL, (resultSet, columnIndex) -> floatToRawIntBits(resultSet.getFloat(columnIndex)), realWriteFunction(), DISABLE_PUSHDOWN));
case Types.DOUBLE:
return Optional.of(doubleColumnMapping());
case Types.NUMERIC:
case Types.DECIMAL:
int decimalDigits = typeHandle.getDecimalDigits().orElseThrow(() -> new IllegalStateException("decimal digits not present"));
int precision = typeHandle.getRequiredColumnSize();
if (getDecimalRounding(session) == ALLOW_OVERFLOW && precision > Decimals.MAX_PRECISION) {
int scale = min(decimalDigits, getDecimalDefaultScale(session));
return Optional.of(decimalColumnMapping(createDecimalType(Decimals.MAX_PRECISION, scale), getDecimalRoundingMode(session)));
}
// TODO does mysql support negative scale?
// Map decimal(p, -s) (negative scale) to decimal(p+s, 0).
precision = precision + max(-decimalDigits, 0);
if (precision > Decimals.MAX_PRECISION) {
break;
}
return Optional.of(decimalColumnMapping(createDecimalType(precision, max(decimalDigits, 0))));
case Types.CHAR:
return Optional.of(defaultCharColumnMapping(typeHandle.getRequiredColumnSize(), false));
// TODO not all these type constants are necessarily used by the JDBC driver
case Types.VARCHAR:
case Types.NVARCHAR:
case Types.LONGVARCHAR:
case Types.LONGNVARCHAR:
return Optional.of(defaultVarcharColumnMapping(typeHandle.getRequiredColumnSize(), false));
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return Optional.of(ColumnMapping.sliceMapping(VARBINARY, varbinaryReadFunction(), varbinaryWriteFunction(), FULL_PUSHDOWN));
case Types.DATE:
return Optional.of(dateColumnMappingUsingLocalDate());
case Types.TIME:
TimeType timeType = createTimeType(getTimePrecision(typeHandle.getRequiredColumnSize()));
return Optional.of(timeColumnMapping(timeType));
case Types.TIMESTAMP:
TimestampType timestampType = createTimestampType(getTimestampPrecision(typeHandle.getRequiredColumnSize()));
return Optional.of(timestampColumnMapping(timestampType));
}
if (getUnsupportedTypeHandling(session) == CONVERT_TO_VARCHAR) {
return mapToUnboundedVarchar(typeHandle);
}
return Optional.empty();
}
Aggregations