[jOOQ/jOOQ#11485] Support for Trino DB

- Correct parser and interpreter name cases
- Remove workarounds for https://github.com/trinodb/trino/issues/16489
- Emulate LISTAGG .. FILTER
- Emulate INSERT INTO <aliased table>
- Support TIMESTAMPTZ literals and binds
- Correctly recognise ARRAY types in MetaTable
- Add M_SOURCES query to MetaSQL
This commit is contained in:
Lukas Eder 2023-04-12 16:22:39 +02:00
parent 1c367c0511
commit 56e36a422d
10 changed files with 74 additions and 10 deletions

View File

@ -53,6 +53,7 @@ import java.util.List;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Record12;
import org.jooq.Record4;
import org.jooq.Record6;
import org.jooq.ResultQuery;
import org.jooq.SQLDialect;
@ -65,6 +66,7 @@ import org.jooq.meta.DefaultRelations;
import org.jooq.meta.DomainDefinition;
import org.jooq.meta.EnumDefinition;
import org.jooq.meta.PackageDefinition;
import org.jooq.meta.ResultQueryDatabase;
import org.jooq.meta.RoutineDefinition;
import org.jooq.meta.SchemaDefinition;
import org.jooq.meta.SequenceDefinition;
@ -73,12 +75,14 @@ import org.jooq.meta.UDTDefinition;
import org.jooq.meta.XMLSchemaCollectionDefinition;
import org.jooq.meta.hsqldb.HSQLDBDatabase;
import org.jetbrains.annotations.Nullable;
/**
* The Trino database
*
* @author Lukas Eder
*/
public class TrinoDatabase extends AbstractDatabase {
public class TrinoDatabase extends AbstractDatabase implements ResultQueryDatabase {
@Override
protected DSLContext create0() {
@ -96,7 +100,7 @@ public class TrinoDatabase extends AbstractDatabase {
when(TABLES.TABLE_TYPE.eq(inline("VIEW")), inline(TableType.VIEW.name()))
.else_(inline(TableType.TABLE.name())).trim().as("table_type"),
when(VIEWS.VIEW_DEFINITION.lower().like(inline("create%")), VIEWS.VIEW_DEFINITION)
.else_(inline("create view \"").concat(TABLES.TABLE_NAME).concat("\" as ").concat(VIEWS.VIEW_DEFINITION)).as(VIEWS.VIEW_DEFINITION)
.else_(inline("create view \"").concat(TABLES.TABLE_NAME).concat(inline("\" as ")).concat(VIEWS.VIEW_DEFINITION)).as(VIEWS.VIEW_DEFINITION)
)
.from(TABLES)
.leftJoin(VIEWS)
@ -135,6 +139,38 @@ public class TrinoDatabase extends AbstractDatabase {
protected void loadCheckConstraints(DefaultRelations relations) throws SQLException {
}
@Override
public final ResultQuery<Record6<String, String, String, String, String, Integer>> primaryKeys(List<String> schemas) {
return null;
}
@Override
public final ResultQuery<Record6<String, String, String, String, String, Integer>> uniqueKeys(List<String> schemas) {
return null;
}
@Override
public final ResultQuery<Record12<String, String, String, String, Integer, Integer, Long, Long, BigDecimal, BigDecimal, Boolean, Long>> sequences(List<String> schemas) {
return null;
}
@Override
public final ResultQuery<Record4<String, String, String, String>> sources(List<String> schemas) {
return create()
.select(
inline("").as(VIEWS.TABLE_CATALOG),
VIEWS.TABLE_SCHEMA,
VIEWS.TABLE_NAME,
when(VIEWS.VIEW_DEFINITION.lower().like(inline("create%")), VIEWS.VIEW_DEFINITION)
.else_(inline("create view \"").concat(VIEWS.TABLE_NAME).concat(inline("\" as ")).concat(VIEWS.VIEW_DEFINITION)).as(VIEWS.VIEW_DEFINITION)
)
.from(VIEWS)
.where(VIEWS.TABLE_SCHEMA.in(schemas))
.orderBy(
VIEWS.TABLE_SCHEMA,
VIEWS.TABLE_NAME);
}
@Override
protected List<DomainDefinition> getDomains0() throws SQLException {
return new ArrayList<>();

View File

@ -343,7 +343,7 @@ implements
}
}
private final boolean supportsFilter(Context<?> ctx) {
/* non-final */ boolean supportsFilter(Context<?> ctx) {
return !(
NO_SUPPORT_FILTER.contains(ctx.dialect())
|| NO_SUPPORT_WINDOW_FILTER.contains(ctx.dialect()) && isWindow()

View File

@ -181,7 +181,7 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
private static final JooqLogger log = JooqLogger.getLogger(AbstractQuery.class);
private static final Set<SQLDialect> NO_SUPPORT_INSERT_ALIASED_TABLE = SQLDialect.supportedBy(DERBY, FIREBIRD, H2, MARIADB, MYSQL);
private static final Set<SQLDialect> NO_SUPPORT_INSERT_ALIASED_TABLE = SQLDialect.supportedBy(DERBY, FIREBIRD, H2, MARIADB, MYSQL, TRINO);
private static final Set<SQLDialect> NO_NATIVE_SUPPORT_INSERT_RETURNING = SQLDialect.supportedUntil(CUBRID, DERBY, H2, HSQLDB, IGNITE, MYSQL, SQLITE, TRINO);
private static final Set<SQLDialect> NO_NATIVE_SUPPORT_UPDATE_RETURNING = SQLDialect.supportedUntil(CUBRID, DERBY, H2, HSQLDB, IGNITE, MYSQL, SQLITE, TRINO);
private static final Set<SQLDialect> NO_NATIVE_SUPPORT_DELETE_RETURNING = SQLDialect.supportedUntil(CUBRID, DERBY, H2, HSQLDB, IGNITE, MYSQL, SQLITE, TRINO);

View File

@ -823,6 +823,16 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
}
if (dataType.getType() == OffsetDateTime.class ||
dataType.getType() == OffsetTime.class ||
dataType.getType() == Instant.class
) {
switch (ctx.family()) {
case TRINO:
return true;
}
}
@ -3320,6 +3330,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
case HSQLDB:
case TRINO:
ctx.render().visit(K_TIMESTAMP).sql(" '").sql(escape(format(value, family), ctx.render())).sql('\'');
break;

View File

@ -48,6 +48,7 @@ import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.SQLDialect.TRINO;
import static org.jooq.SQLDialect.YUGABYTEDB;
import static org.jooq.impl.CommentImpl.NO_COMMENT;
import static org.jooq.impl.DSL.systemName;
@ -141,6 +142,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
private static final Set<SQLDialect> NO_SUPPORT_TIMESTAMP_PRECISION = SQLDialect.supportedBy(FIREBIRD, MYSQL, SQLITE);
private static final Set<SQLDialect> SUPPORT_POSTGRES_ARRAY_NOTATION = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB);
private static final Set<SQLDialect> SUPPORT_HSQLDB_ARRAY_NOTATION = SQLDialect.supportedBy(H2, HSQLDB);
private static final Set<SQLDialect> SUPPORT_TRINO_ARRAY_NOTATION = SQLDialect.supportedBy(TRINO);
/**
* A pattern for data type name normalisation.
@ -692,6 +694,10 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
else if (result == null && SUPPORT_HSQLDB_ARRAY_NOTATION.contains(dialect) && upper.equals("ARRAY"))
result = SQLDataType.OTHER.getArrayDataType();
// [#11485] Trino lists arrays as array(component_type)
else if (result == null && SUPPORT_TRINO_ARRAY_NOTATION.contains(dialect) && upper.startsWith("ARRAY("))
result = getDataType(dialect, typeName.substring(6, typeName.length() - 1)).getArrayDataType();

View File

@ -1422,6 +1422,7 @@ final class Interpreter {
case MARIADB:
case MYSQL:
case SQLITE:
case TRINO:
return InterpreterNameLookupCaseSensitivity.NEVER;
case DEFAULT:

View File

@ -298,12 +298,6 @@ final class JSONEntryImpl<T> extends AbstractQueryPart implements JSONEntry<T>,
case TRINO:
// [#11485] https://github.com/trinodb/trino/issues/16489
// This isn't necessary when emulating JSON_OBJECT and JSON_ARRAY
// with CAST(MAP) and CAST(ARRAY), however:
// if (field instanceof Param)
// return inlined(field);
// [#11485] CHAR types can't be cast to JSON: https://trino.io/docs/current/functions/json.html#cast-to-json
if (type.getSQLDataType() == SQLDataType.CHAR)
return field.cast(VARCHAR);

View File

@ -180,6 +180,16 @@ final class ListAgg extends AbstractAggregateFunction<String> implements UNotYet
return i == 0;
}
@Override
boolean supportsFilter(Context<?> ctx) {
switch (ctx.family()) {
case TRINO:
return false;
default:
return super.supportsFilter(ctx);
}
}
/**
* [#1273] <code>LIST_AGG</code> emulation for MySQL
*/

View File

@ -103,6 +103,7 @@ final class MetaSQL {
M_SEQUENCES.put(DERBY, "select cast(null as varchar(32672)) as catalog, alias_8805161.SCHEMANAME, SYS.SYSSEQUENCES.SEQUENCENAME, SYS.SYSSEQUENCES.SEQUENCEDATATYPE, cast(null as int) as numeric_precision, cast(null as int) as numeric_scale, nullif(SYS.SYSSEQUENCES.STARTVALUE, 1) as STARTVALUE, nullif(SYS.SYSSEQUENCES.INCREMENT, 1) as INCREMENT, nullif(SYS.SYSSEQUENCES.MINIMUMVALUE, case when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'SMALLINT' then -32768 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'INTEGER' then -2147483648 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'BIGINT' then -9223372036854775808 end) as MINIMUMVALUE, nullif(SYS.SYSSEQUENCES.MAXIMUMVALUE, case when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'SMALLINT' then 32767 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'INTEGER' then 2147483647 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'BIGINT' then 9223372036854775807 end) as MAXIMUMVALUE, (SYS.SYSSEQUENCES.CYCLEOPTION = 'Y') as CYCLEOPTION, cast(null as bigint) as cache from (SYS.SYSSEQUENCES join SYS.SYSSCHEMAS as alias_8805161 on SYS.SYSSEQUENCES.SCHEMAID = alias_8805161.SCHEMAID) where cast(alias_8805161.SCHEMANAME as varchar(32672)) in (cast(? as varchar(32672))) order by alias_8805161.SCHEMANAME, SYS.SYSSEQUENCES.SEQUENCENAME");
@ -153,6 +154,7 @@ final class MetaSQL {
M_SEQUENCES_INCLUDING_SYSTEM_SEQUENCES.put(DERBY, "select cast(null as varchar(32672)) as catalog, alias_8805161.SCHEMANAME, SYS.SYSSEQUENCES.SEQUENCENAME, SYS.SYSSEQUENCES.SEQUENCEDATATYPE, cast(null as int) as numeric_precision, cast(null as int) as numeric_scale, nullif(SYS.SYSSEQUENCES.STARTVALUE, 1) as STARTVALUE, nullif(SYS.SYSSEQUENCES.INCREMENT, 1) as INCREMENT, nullif(SYS.SYSSEQUENCES.MINIMUMVALUE, case when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'SMALLINT' then -32768 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'INTEGER' then -2147483648 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'BIGINT' then -9223372036854775808 end) as MINIMUMVALUE, nullif(SYS.SYSSEQUENCES.MAXIMUMVALUE, case when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'SMALLINT' then 32767 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'INTEGER' then 2147483647 when cast(SYS.SYSSEQUENCES.SEQUENCEDATATYPE as varchar(32672)) = 'BIGINT' then 9223372036854775807 end) as MAXIMUMVALUE, (SYS.SYSSEQUENCES.CYCLEOPTION = 'Y') as CYCLEOPTION, cast(null as bigint) as cache from (SYS.SYSSEQUENCES join SYS.SYSSCHEMAS as alias_8805161 on SYS.SYSSEQUENCES.SCHEMAID = alias_8805161.SCHEMAID) where cast(alias_8805161.SCHEMANAME as varchar(32672)) in (cast(? as varchar(32672))) order by alias_8805161.SCHEMANAME, SYS.SYSSEQUENCES.SEQUENCENAME");
@ -203,6 +205,7 @@ final class MetaSQL {
M_SOURCES.put(DERBY, "select cast(null as varchar(32672)) as catalog, alias_57844683.SCHEMANAME, SYS.SYSTABLES.TABLENAME, SYS.SYSVIEWS.VIEWDEFINITION from (SYS.SYSTABLES join SYS.SYSSCHEMAS as alias_57844683 on SYS.SYSTABLES.SCHEMAID = alias_57844683.SCHEMAID) left outer join SYS.SYSVIEWS on SYS.SYSTABLES.TABLEID = SYS.SYSVIEWS.TABLEID where cast(alias_57844683.SCHEMANAME as varchar(32672)) in (cast(? as varchar(32672))) order by alias_57844683.SCHEMANAME, SYS.SYSTABLES.TABLENAME");
@ -213,6 +216,7 @@ final class MetaSQL {
M_SOURCES.put(MYSQL, "select information_schema.VIEWS.TABLE_CATALOG, information_schema.VIEWS.TABLE_SCHEMA, information_schema.VIEWS.TABLE_NAME, information_schema.VIEWS.VIEW_DEFINITION from information_schema.VIEWS where information_schema.VIEWS.TABLE_SCHEMA in (?) order by information_schema.VIEWS.TABLE_SCHEMA, information_schema.VIEWS.TABLE_NAME");
M_SOURCES.put(POSTGRES, "select information_schema.views.table_catalog, information_schema.views.table_schema, information_schema.views.table_name, information_schema.views.view_definition from information_schema.views where information_schema.views.table_schema in (?) order by information_schema.views.table_schema, information_schema.views.table_name");
M_SOURCES.put(SQLITE, "select null as catalog, null as schema, sqlite_master.name, sqlite_master.sql from sqlite_master order by sqlite_master.name");
M_SOURCES.put(TRINO, "select '' TABLE_CATALOG, INFORMATION_SCHEMA.VIEWS.TABLE_SCHEMA, INFORMATION_SCHEMA.VIEWS.TABLE_NAME, case when lower(INFORMATION_SCHEMA.VIEWS.VIEW_DEFINITION) like 'create%' then INFORMATION_SCHEMA.VIEWS.VIEW_DEFINITION else ((('create view \"' || INFORMATION_SCHEMA.VIEWS.TABLE_NAME) || '\" as ') || INFORMATION_SCHEMA.VIEWS.VIEW_DEFINITION) end VIEW_DEFINITION from INFORMATION_SCHEMA.VIEWS where INFORMATION_SCHEMA.VIEWS.TABLE_SCHEMA in (?) order by INFORMATION_SCHEMA.VIEWS.TABLE_SCHEMA, INFORMATION_SCHEMA.VIEWS.TABLE_NAME");
M_SOURCES.put(YUGABYTEDB, "select information_schema.views.table_catalog, information_schema.views.table_schema, information_schema.views.table_name, information_schema.views.view_definition from information_schema.views where information_schema.views.table_schema in (?) order by information_schema.views.table_schema, information_schema.views.table_name");
@ -283,6 +287,7 @@ final class MetaSQL {
}

View File

@ -6896,6 +6896,7 @@ final class Tools {
case MARIADB:
case MYSQL:
case SQLITE:
case TRINO:
return ParseNameCase.AS_IS;
default: