[jOOQ/jOOQ#18988] Regression: Wrong DDL exported by MetaImpl for MySQL
DEFAULT CURRENT_TIMESTAMP columns
This commit is contained in:
parent
e4981c5f15
commit
6bc46e6645
@ -232,4 +232,24 @@ public interface ResultQueryDatabase extends Database {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A query that produces generator expressions for computed columns for a
|
||||
* set of input schemas.
|
||||
* <p>
|
||||
* The resulting columns are:
|
||||
* <ol>
|
||||
* <li>Catalog name</li>
|
||||
* <li>Schema name</li>
|
||||
* <li>Table name</li>
|
||||
* <li>Column name</li>
|
||||
* <li>Generator expression as in {@link DataType#generatedAlwaysAs()}</li>
|
||||
* <li>Generation option as in {@link DataType#generationOption()}</li>
|
||||
* </ol>
|
||||
*
|
||||
* @return The query or <code>null</code> if this implementation doesn't
|
||||
* support the query.
|
||||
*/
|
||||
@Internal
|
||||
@Nullable
|
||||
ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas);
|
||||
}
|
||||
|
||||
@ -366,6 +366,11 @@ public class ClickHouseDatabase extends AbstractDatabase implements ResultQueryD
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
List<XMLSchemaCollectionDefinition> result = new ArrayList<>();
|
||||
|
||||
@ -658,6 +658,11 @@ public class DerbyDatabase extends AbstractDatabase implements ResultQueryDataba
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -418,6 +418,11 @@ public class DuckDBDatabase extends AbstractDatabase implements ResultQueryDatab
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record12<String, String, String, String, Integer, Integer, Long, Long, BigDecimal, BigDecimal, Boolean, Long>> sequences(List<String> schemas) {
|
||||
return create()
|
||||
|
||||
@ -709,6 +709,11 @@ public class FirebirdDatabase extends AbstractDatabase implements ResultQueryDat
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -774,6 +774,11 @@ public class H2Database extends AbstractDatabase implements ResultQueryDatabase
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<SequenceDefinition> getSequences0() throws SQLException {
|
||||
|
||||
@ -713,6 +713,11 @@ public class HSQLDBDatabase extends AbstractDatabase implements ResultQueryDatab
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -112,6 +112,7 @@ import org.jooq.TableOptions.TableType;
|
||||
// ...
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.QOM.ForeignKeyRule;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.meta.AbstractDatabase;
|
||||
import org.jooq.meta.AbstractIndexDefinition;
|
||||
import org.jooq.meta.ArrayDefinition;
|
||||
@ -716,6 +717,28 @@ public class MySQLDatabase extends AbstractDatabase implements ResultQueryDataba
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return create()
|
||||
.select(
|
||||
inline(null, VARCHAR).as("table_catalog"),
|
||||
COLUMNS.TABLE_SCHEMA,
|
||||
COLUMNS.TABLE_NAME,
|
||||
COLUMNS.COLUMN_NAME,
|
||||
generationExpression(COLUMNS.GENERATION_EXPRESSION),
|
||||
when(COLUMNS.EXTRA.in(inline("VIRTUAL"), inline("VIRTUAL GENERATED")), inline(GenerationOption.VIRTUAL.name()))
|
||||
.when(COLUMNS.EXTRA.in(inline("PERSISTENT"), inline("STORED GENERATED")), inline(GenerationOption.STORED.name()))
|
||||
.as("generationOption"))
|
||||
.from(COLUMNS)
|
||||
.where(COLUMNS.TABLE_SCHEMA.in(schemas))
|
||||
.and(COLUMNS.EXTRA.in(
|
||||
inline("VIRTUAL"),
|
||||
inline("VIRTUAL GENERATED"),
|
||||
inline("PERSISTENT"),
|
||||
inline("STORED GENERATED")))
|
||||
.orderBy(COLUMNS.ORDINAL_POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -1082,6 +1082,11 @@ public class PostgresDatabase extends AbstractDatabase implements ResultQueryDat
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -616,6 +616,11 @@ public class SQLiteDatabase extends AbstractDatabase implements ResultQueryDatab
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLSchemaCollectionDefinition> getXMLSchemaCollections0() throws SQLException {
|
||||
|
||||
@ -198,6 +198,11 @@ public class TrinoDatabase extends AbstractDatabase implements ResultQueryDataba
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ResultQuery<Record6<String, String, String, String, String, String>> generators(List<String> schemas) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CatalogDefinition> getCatalogs0() throws SQLException {
|
||||
List<CatalogDefinition> result = new ArrayList<>();
|
||||
|
||||
@ -90,7 +90,6 @@ import static org.jooq.impl.SQLDataType.SMALLINT;
|
||||
import static org.jooq.impl.SQLDataType.VARCHAR;
|
||||
import static org.jooq.impl.Tools.EMPTY_OBJECT;
|
||||
import static org.jooq.impl.Tools.EMPTY_SORTFIELD;
|
||||
import static org.jooq.impl.Tools.anyMatch;
|
||||
import static org.jooq.impl.Tools.flatMap;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.tools.StringUtils.defaultIfEmpty;
|
||||
@ -111,7 +110,6 @@ import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -153,12 +151,9 @@ import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataDefinitionException;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.impl.QOM.ForeignKeyRule;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.tools.jdbc.JDBCUtils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An implementation of the public {@link Meta} type.
|
||||
@ -465,6 +460,8 @@ final class MetaImpl extends AbstractMeta {
|
||||
}
|
||||
}
|
||||
|
||||
static final record Generator(String expression, GenerationOption option) {}
|
||||
|
||||
private final class MetaSchema extends SchemaImpl {
|
||||
private final boolean empty;
|
||||
private transient volatile Map<Name, Result<Record>> columnCache;
|
||||
@ -472,6 +469,7 @@ final class MetaImpl extends AbstractMeta {
|
||||
private transient volatile Map<Name, Result<Record>> sequenceCache;
|
||||
private transient volatile Map<Name, String> sourceCache;
|
||||
private transient volatile Map<Name, String> commentCache;
|
||||
private transient volatile Map<Name, Generator> generatorCache;
|
||||
|
||||
|
||||
|
||||
@ -1001,6 +999,38 @@ final class MetaImpl extends AbstractMeta {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Generator generator(String tableName, String columnName) {
|
||||
if (generatorCache == null) {
|
||||
String sql = MetaSQL.M_GENERATORS(dialect());
|
||||
|
||||
if (sql != null) {
|
||||
Result<Record> result = meta(() -> "Error while fetching sources for schema " + this, meta ->
|
||||
withCatalog(getCatalog(), ctx(meta), ctx ->
|
||||
ctx.resultQuery(patchSchema(sql), MetaSchema.this.getName()).fetch()
|
||||
)
|
||||
);
|
||||
|
||||
// TODO Support catalogs as well
|
||||
generatorCache = new LinkedHashMap<>();
|
||||
for (Record r : result) {
|
||||
String e = r.get(4, String.class);
|
||||
|
||||
if (e != null) {
|
||||
generatorCache.put(
|
||||
name(r.get(1, String.class), r.get(2, String.class), r.get(3, String.class)),
|
||||
new Generator(r.get(4, String.class), r.get(5, GenerationOption.class))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (generatorCache != null)
|
||||
return generatorCache.get(name(MetaSchema.this.getName(), tableName, columnName));
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
final String comment(String tableName) {
|
||||
return comment(tableName, null);
|
||||
}
|
||||
@ -1705,6 +1735,10 @@ final class MetaImpl extends AbstractMeta {
|
||||
type = new DefaultDataType(family(), Object.class, typeName);
|
||||
}
|
||||
|
||||
// [#18988] MySQL JDBC reports DEFAULT CURRENT_TIMESTAMP columns as generated, not defaulted.
|
||||
Generator g = schema.generator(getName(), columnName);
|
||||
if (isGenerated && g == null && MYSQL == family())
|
||||
isGenerated = false;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ final class MetaSQL {
|
||||
private static final EnumMap<SQLDialect, String> M_ENUMS = new EnumMap<>(SQLDialect.class);
|
||||
private static final EnumMap<SQLDialect, String> M_SOURCES = new EnumMap<>(SQLDialect.class);
|
||||
private static final EnumMap<SQLDialect, String> M_COMMENTS = new EnumMap<>(SQLDialect.class);
|
||||
private static final EnumMap<SQLDialect, String> M_GENERATORS = new EnumMap<>(SQLDialect.class);
|
||||
private static final EnumMap<SQLDialect, String> M_TRIGGERS = new EnumMap<>(SQLDialect.class);
|
||||
private static final EnumMap<SQLDialect, String> M_SYNONYMS = new EnumMap<>(SQLDialect.class);
|
||||
|
||||
@ -47,6 +48,11 @@ final class MetaSQL {
|
||||
return result != null ? result : M_COMMENTS.get(dialect.family());
|
||||
}
|
||||
|
||||
static final String M_GENERATORS(SQLDialect dialect) {
|
||||
String result = M_GENERATORS.get(dialect);
|
||||
return result != null ? result : M_GENERATORS.get(dialect.family());
|
||||
}
|
||||
|
||||
static final String M_TRIGGERS(SQLDialect dialect) {
|
||||
String result = M_TRIGGERS.get(dialect);
|
||||
return result != null ? result : M_TRIGGERS.get(dialect.family());
|
||||
@ -254,8 +260,8 @@ final class MetaSQL {
|
||||
|
||||
|
||||
|
||||
M_ENUMS.put(MARIADB, "with recursive e as (select information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, regexp_replace(information_schema.COLUMNS.COLUMN_TYPE, 'enum\\((.*)\\)', '$1') as e from information_schema.COLUMNS where information_schema.COLUMNS.DATA_TYPE = 'enum'), l as (select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, e, cast('' as char(32767)) as l, 0 as p from e union all select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, regexp_replace(e, '''.*?''(?:,|$)(.*)', '$1', 1, 1), replace(regexp_replace(e, '''(.*?)''(?:,|$).*', '$1', 1, 1), '''''', ''''), (p + 1) from l as e where char_length(e) > 0) select l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, null as DATA_TYPE, l.l, l.p from l where (p > 0 and l.TABLE_SCHEMA in (?)) order by l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, l.p");
|
||||
M_ENUMS.put(MYSQL, "with recursive e as (select information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, regexp_replace(information_schema.COLUMNS.COLUMN_TYPE, 'enum\\((.*)\\)', '$1') as e from information_schema.COLUMNS where information_schema.COLUMNS.DATA_TYPE = 'enum'), l as (select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, e, cast('' as char(32767)) as l, 0 as p from e union all select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, regexp_replace(e, '''.*?''(?:,|$)(.*)', '$1', 1, 1), replace(regexp_replace(e, '''(.*?)''(?:,|$).*', '$1', 1, 1), '''''', ''''), (p + 1) from l as e where char_length(e) > 0) select l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, null as DATA_TYPE, l.l, l.p from l where (p > 0 and l.TABLE_SCHEMA in (?)) order by l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, l.p");
|
||||
M_ENUMS.put(MARIADB, "with recursive e as (select information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, regexp_replace(information_schema.COLUMNS.COLUMN_TYPE, 'enum\\\\((.*)\\\\)', '$1') as e from information_schema.COLUMNS where information_schema.COLUMNS.DATA_TYPE = 'enum'), l as (select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, e, cast('' as char(32767)) as l, 0 as p from e union all select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, regexp_replace(e, '''.*?''(?:,|$)(.*)', '$1', 1, 1), replace(regexp_replace(e, '''(.*?)''(?:,|$).*', '$1', 1, 1), '''''', ''''), (p + 1) from l as e where char_length(e) > 0) select l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, null as DATA_TYPE, l.l, l.p from l where (p > 0 and l.TABLE_SCHEMA in (?)) order by l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, l.p");
|
||||
M_ENUMS.put(MYSQL, "with recursive e as (select information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, regexp_replace(information_schema.COLUMNS.COLUMN_TYPE, 'enum\\\\((.*)\\\\)', '$1') as e from information_schema.COLUMNS where information_schema.COLUMNS.DATA_TYPE = 'enum'), l as (select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, e, cast('' as char(32767)) as l, 0 as p from e union all select e.TABLE_SCHEMA, e.TABLE_NAME, e.COLUMN_NAME, regexp_replace(e, '''.*?''(?:,|$)(.*)', '$1', 1, 1), replace(regexp_replace(e, '''(.*?)''(?:,|$).*', '$1', 1, 1), '''''', ''''), (p + 1) from l as e where char_length(e) > 0) select l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, null as DATA_TYPE, l.l, l.p from l where (p > 0 and l.TABLE_SCHEMA in (?)) order by l.TABLE_SCHEMA, l.TABLE_NAME, l.COLUMN_NAME, l.p");
|
||||
|
||||
|
||||
|
||||
@ -425,6 +431,31 @@ final class MetaSQL {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
M_GENERATORS.put(MARIADB, "select null as table_catalog, information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, information_schema.COLUMNS.GENERATION_EXPRESSION, case when information_schema.COLUMNS.EXTRA in ('VIRTUAL', 'VIRTUAL GENERATED') then 'VIRTUAL' when information_schema.COLUMNS.EXTRA in ('PERSISTENT', 'STORED GENERATED') then 'STORED' end as generationOption from information_schema.COLUMNS where (information_schema.COLUMNS.TABLE_SCHEMA in (?) and information_schema.COLUMNS.EXTRA in ('VIRTUAL', 'VIRTUAL GENERATED', 'PERSISTENT', 'STORED GENERATED')) order by information_schema.COLUMNS.ORDINAL_POSITION");
|
||||
M_GENERATORS.put(MYSQL, "select null as table_catalog, information_schema.COLUMNS.TABLE_SCHEMA, information_schema.COLUMNS.TABLE_NAME, information_schema.COLUMNS.COLUMN_NAME, information_schema.COLUMNS.GENERATION_EXPRESSION, case when information_schema.COLUMNS.EXTRA in ('VIRTUAL', 'VIRTUAL GENERATED') then 'VIRTUAL' when information_schema.COLUMNS.EXTRA in ('PERSISTENT', 'STORED GENERATED') then 'STORED' end as generationOption from information_schema.COLUMNS where (information_schema.COLUMNS.TABLE_SCHEMA in (?) and information_schema.COLUMNS.EXTRA in ('VIRTUAL', 'VIRTUAL GENERATED', 'PERSISTENT', 'STORED GENERATED')) order by information_schema.COLUMNS.ORDINAL_POSITION");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user