[jOOQ/jOOQ#8972] jOOQ-meta should query dictionary views for column
existence rather than the column itself
This commit is contained in:
parent
83a6711412
commit
4e9a29dbd6
@ -68,6 +68,7 @@ import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteListenerProvider;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.Table;
|
||||
@ -369,59 +370,62 @@ public abstract class AbstractDatabase implements Database {
|
||||
}
|
||||
}
|
||||
|
||||
// [#8972] TODO: Implement these for all non-PostgresDatabase databases.
|
||||
@Override
|
||||
public TableQualifier tableQualifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnQualifier columnQualifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean exists(TableField<?, ?> field) {
|
||||
Boolean result = existFields.get(field);
|
||||
|
||||
if (result == null) {
|
||||
ColumnQualifier qualifier = columnQualifier();
|
||||
|
||||
// [#8972] In the presence of a qualifier, avoid running an error-
|
||||
// triggering query, which may lead to unwanted log messages
|
||||
if (qualifier == null) {
|
||||
try {
|
||||
create(true)
|
||||
.select(field)
|
||||
.from(field.getTable())
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
result = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Condition condition = qualifier.columnName().eq(field.getName());
|
||||
|
||||
Table<?> table = field.getTable();
|
||||
condition = condition.and(qualifier.tableName().eq(table.getName()));
|
||||
|
||||
Schema schema = table.getSchema();
|
||||
if (schema != null)
|
||||
condition = condition.and(qualifier.tableSchema().eq(schema.getName()));
|
||||
|
||||
result = create().fetchExists(qualifier.table(), condition);
|
||||
}
|
||||
|
||||
existFields.put(field, result);
|
||||
}
|
||||
if (result == null)
|
||||
existFields.put(field, result = exists0(field));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* [#8972] Subclasses may override this method for a more efficient implementation.
|
||||
*/
|
||||
protected boolean exists0(TableField<?, ?> field) {
|
||||
try {
|
||||
create(true)
|
||||
.select(field)
|
||||
.from(field.getTable())
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to look up a field in a single dictionary view.
|
||||
*
|
||||
* @param find The field to look up
|
||||
* @param in The dictionary view
|
||||
* @param schemaQualifier The column in the dictionary view qualifying the schema
|
||||
* @param tableQualifier The column in the dictionary view qualifying the table
|
||||
* @param columnQualifier The column in the dictionary view qualifying the column
|
||||
*/
|
||||
protected final <R extends Record> boolean exists1(
|
||||
TableField<?, ?> find,
|
||||
Table<R> in,
|
||||
TableField<R, String> schemaQualifier,
|
||||
TableField<R, String> tableQualifier,
|
||||
TableField<R, String> columnQualifier
|
||||
) {
|
||||
Condition condition = columnQualifier.eq(find.getName());
|
||||
|
||||
Table<?> table = find.getTable();
|
||||
condition = condition.and(tableQualifier.eq(table.getName()));
|
||||
|
||||
Schema schema = table.getSchema();
|
||||
if (schema != null)
|
||||
condition = condition.and(schemaQualifier.eq(schema.getName()));
|
||||
|
||||
return create().fetchExists(in, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean existAll(TableField<?, ?>... f) {
|
||||
for (TableField<?, ?> field : f)
|
||||
@ -435,41 +439,53 @@ public abstract class AbstractDatabase implements Database {
|
||||
public final boolean exists(Table<?> table) {
|
||||
Boolean result = existTables.get(table);
|
||||
|
||||
if (result == null) {
|
||||
TableQualifier qualifier = tableQualifier();
|
||||
|
||||
// [#8972] In the presence of a qualifier, avoid running an error-
|
||||
// triggering query, which may lead to unwanted log messages
|
||||
if (qualifier == null) {
|
||||
try {
|
||||
create(true)
|
||||
.selectOne()
|
||||
.from(table)
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
result = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Condition condition = qualifier.tableName().eq(table.getName());
|
||||
|
||||
Schema schema = table.getSchema();
|
||||
if (schema != null)
|
||||
condition = condition.and(qualifier.tableSchema().eq(schema.getName()));
|
||||
|
||||
result = create().fetchExists(qualifier.table(), condition);
|
||||
}
|
||||
|
||||
existTables.put(table, result);
|
||||
}
|
||||
if (result == null)
|
||||
existTables.put(table, result = exists0(table));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* [#8972] Subclasses may override this method for a more efficient implementation.
|
||||
*/
|
||||
protected boolean exists0(Table<?> table) {
|
||||
try {
|
||||
create(true)
|
||||
.selectOne()
|
||||
.from(table)
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to look up a table in a single dictionary view.
|
||||
*
|
||||
* @param find The table to look up
|
||||
* @param in The dictionary view
|
||||
* @param schemaQualifier The column in the dictionary view qualifying the schema
|
||||
* @param tableQualifier The column in the dictionary view qualifying the table
|
||||
*/
|
||||
protected final <R extends Record> boolean exists1(
|
||||
Table<?> find,
|
||||
Table<R> in,
|
||||
TableField<R, String> schemaQualifier,
|
||||
TableField<R, String> tableQualifier
|
||||
) {
|
||||
Condition condition = tableQualifier.eq(find.getName());
|
||||
|
||||
Schema schema = find.getSchema();
|
||||
if (schema != null)
|
||||
condition = condition.and(schemaQualifier.eq(schema.getName()));
|
||||
|
||||
return create().fetchExists(in, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean existAll(Table<?>... t) {
|
||||
for (Table<?> table : t)
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.meta;
|
||||
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
|
||||
/**
|
||||
* A qualifier for columns in the dictionary views.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface ColumnQualifier {
|
||||
|
||||
/**
|
||||
* The table containing column meta information.
|
||||
*/
|
||||
Table<?> table();
|
||||
|
||||
/**
|
||||
* The field specifying the column table's catalog name.
|
||||
*/
|
||||
TableField<?, String> tableCatalog();
|
||||
|
||||
/**
|
||||
* The field specifying the column table's schema name.
|
||||
*/
|
||||
TableField<?, String> tableSchema();
|
||||
|
||||
/**
|
||||
* The field specifying the column table's table name.
|
||||
*/
|
||||
TableField<?, String> tableName();
|
||||
|
||||
/**
|
||||
* The field specifying the column name.
|
||||
*/
|
||||
TableField<?, String> columnName();
|
||||
|
||||
}
|
||||
@ -904,18 +904,6 @@ public interface Database extends AutoCloseable {
|
||||
*/
|
||||
boolean tableValuedFunctions();
|
||||
|
||||
/**
|
||||
* The table qualifier used by this database, or <code>null</code>, if this
|
||||
* database doesn't specify such a qualifier.
|
||||
*/
|
||||
TableQualifier tableQualifier();
|
||||
|
||||
/**
|
||||
* The column qualifier used by this database, or <code>null</code>, if this
|
||||
* database doesn't specify such a qualifier.
|
||||
*/
|
||||
ColumnQualifier columnQualifier();
|
||||
|
||||
/**
|
||||
* Check for the existence of a table field in the dictionary views.
|
||||
*/
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.meta;
|
||||
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class DefaultColumnQualifier implements ColumnQualifier {
|
||||
|
||||
private final Table<?> table;
|
||||
private final TableField<?, String> tableCatalog;
|
||||
private final TableField<?, String> tableSchema;
|
||||
private final TableField<?, String> tableName;
|
||||
private final TableField<?, String> columnName;
|
||||
|
||||
public DefaultColumnQualifier(
|
||||
Table<?> table,
|
||||
TableField<?, String> tableCatalog,
|
||||
TableField<?, String> tableSchema,
|
||||
TableField<?, String> tableName,
|
||||
TableField<?, String> columnName
|
||||
) {
|
||||
this.table = table;
|
||||
this.tableCatalog = tableCatalog;
|
||||
this.tableSchema = tableSchema;
|
||||
this.tableName = tableName;
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table<?> table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableCatalog() {
|
||||
return tableCatalog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableSchema() {
|
||||
return tableSchema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> columnName() {
|
||||
return columnName;
|
||||
}
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.meta;
|
||||
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class DefaultTableQualifier implements TableQualifier {
|
||||
|
||||
private final Table<?> table;
|
||||
private final TableField<?, String> tableCatalog;
|
||||
private final TableField<?, String> tableSchema;
|
||||
private final TableField<?, String> tableName;
|
||||
|
||||
public DefaultTableQualifier(
|
||||
Table<?> table,
|
||||
TableField<?, String> tableCatalog,
|
||||
TableField<?, String> tableSchema,
|
||||
TableField<?, String> tableName
|
||||
) {
|
||||
this.table = table;
|
||||
this.tableCatalog = tableCatalog;
|
||||
this.tableSchema = tableSchema;
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table<?> table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableCatalog() {
|
||||
return tableCatalog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableSchema() {
|
||||
return tableSchema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableField<?, String> tableName() {
|
||||
return tableName;
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.meta;
|
||||
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
|
||||
/**
|
||||
* A qualifier for tables in the dictionary views.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface TableQualifier {
|
||||
|
||||
/**
|
||||
* The table containing table meta information.
|
||||
*/
|
||||
Table<?> table();
|
||||
|
||||
/**
|
||||
* The field specifying the table's catalog name.
|
||||
*/
|
||||
TableField<?, String> tableCatalog();
|
||||
|
||||
/**
|
||||
* The field specifying the table's schema name.
|
||||
*/
|
||||
TableField<?, String> tableSchema();
|
||||
|
||||
/**
|
||||
* The field specifying the table's table name.
|
||||
*/
|
||||
TableField<?, String> tableName();
|
||||
|
||||
}
|
||||
@ -37,7 +37,6 @@
|
||||
*/
|
||||
package org.jooq.meta.h2;
|
||||
|
||||
import static org.jooq.impl.DSL.falseCondition;
|
||||
import static org.jooq.impl.DSL.field;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
@ -67,7 +66,8 @@ import org.jooq.Record4;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.SortOrder;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.meta.AbstractDatabase;
|
||||
import org.jooq.meta.AbstractIndexDefinition;
|
||||
@ -115,6 +115,16 @@ public class H2Database extends AbstractDatabase {
|
||||
return DSL.using(getConnection(), SQLDialect.H2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exists0(TableField<?, ?> field) {
|
||||
return exists1(field, COLUMNS, Columns.TABLE_SCHEMA, Columns.TABLE_NAME, Columns.COLUMN_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exists0(Table<?> table) {
|
||||
return exists1(table, TABLES, Tables.TABLE_SCHEMA, Tables.TABLE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IndexDefinition> getIndexes0() throws SQLException {
|
||||
List<IndexDefinition> result = new ArrayList<>();
|
||||
@ -619,43 +629,19 @@ public class H2Database extends AbstractDatabase {
|
||||
private static Boolean is1_4_198;
|
||||
|
||||
boolean is1_4_197() {
|
||||
if (is1_4_197 == null) {
|
||||
|
||||
// [#5874] The COLUMNS.COLUMN_TYPE column was introduced in H2 1.4.197
|
||||
try {
|
||||
create(true)
|
||||
.select(Columns.COLUMN_TYPE)
|
||||
.from(COLUMNS)
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
is1_4_197 = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
is1_4_197 = false;
|
||||
}
|
||||
}
|
||||
// [#5874] The COLUMNS.COLUMN_TYPE column was introduced in H2 1.4.197
|
||||
if (is1_4_197 == null)
|
||||
is1_4_197 = exists(Columns.COLUMN_TYPE);
|
||||
|
||||
return is1_4_197;
|
||||
}
|
||||
|
||||
boolean is1_4_198() {
|
||||
if (is1_4_198 == null) {
|
||||
|
||||
// [#5874] The COLUMNS.IS_VISIBLE column was introduced in H2 1.4.198
|
||||
try {
|
||||
create(true)
|
||||
.select(Columns.IS_VISIBLE)
|
||||
.from(COLUMNS)
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
is1_4_198 = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
is1_4_198 = false;
|
||||
}
|
||||
}
|
||||
// [#5874] The COLUMNS.IS_VISIBLE column was introduced in H2 1.4.198
|
||||
if (is1_4_198 == null)
|
||||
is1_4_198 = exists(Columns.IS_VISIBLE);
|
||||
|
||||
return is1_4_198;
|
||||
}
|
||||
|
||||
@ -64,7 +64,8 @@ import org.jooq.Record6;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.SortOrder;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.meta.AbstractDatabase;
|
||||
import org.jooq.meta.AbstractIndexDefinition;
|
||||
@ -223,17 +224,10 @@ public class MySQLDatabase extends AbstractDatabase {
|
||||
}
|
||||
|
||||
protected boolean is8() {
|
||||
if (is8 == null) {
|
||||
|
||||
// [#6602] The mysql.proc table got removed in MySQL 8.0
|
||||
try {
|
||||
create(true).fetchExists(PROC);
|
||||
is8 = false;
|
||||
}
|
||||
catch (DataAccessException ignore) {
|
||||
is8 = true;
|
||||
}
|
||||
}
|
||||
// [#6602] The mysql.proc table got removed in MySQL 8.0
|
||||
if (is8 == null)
|
||||
is8 = !exists(PROC);
|
||||
|
||||
return is8;
|
||||
}
|
||||
@ -532,4 +526,14 @@ public class MySQLDatabase extends AbstractDatabase {
|
||||
protected DSLContext create0() {
|
||||
return DSL.using(getConnection(), SQLDialect.MYSQL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exists0(TableField<?, ?> field) {
|
||||
return exists1(field, Columns.COLUMNS, Columns.TABLE_SCHEMA, Columns.TABLE_NAME, Columns.COLUMN_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exists0(Table<?> table) {
|
||||
return exists1(table, Tables.TABLES, Tables.TABLE_SCHEMA, Tables.TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +95,8 @@ import org.jooq.Result;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SortOrder;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.SQLDataType;
|
||||
@ -103,17 +105,14 @@ import org.jooq.meta.AbstractIndexDefinition;
|
||||
import org.jooq.meta.ArrayDefinition;
|
||||
import org.jooq.meta.CatalogDefinition;
|
||||
import org.jooq.meta.ColumnDefinition;
|
||||
import org.jooq.meta.ColumnQualifier;
|
||||
import org.jooq.meta.DataTypeDefinition;
|
||||
import org.jooq.meta.DefaultCheckConstraintDefinition;
|
||||
import org.jooq.meta.DefaultColumnQualifier;
|
||||
import org.jooq.meta.DefaultDataTypeDefinition;
|
||||
import org.jooq.meta.DefaultDomainDefinition;
|
||||
import org.jooq.meta.DefaultEnumDefinition;
|
||||
import org.jooq.meta.DefaultIndexColumnDefinition;
|
||||
import org.jooq.meta.DefaultRelations;
|
||||
import org.jooq.meta.DefaultSequenceDefinition;
|
||||
import org.jooq.meta.DefaultTableQualifier;
|
||||
import org.jooq.meta.DomainDefinition;
|
||||
import org.jooq.meta.EnumDefinition;
|
||||
import org.jooq.meta.IndexColumnDefinition;
|
||||
@ -123,7 +122,6 @@ import org.jooq.meta.RoutineDefinition;
|
||||
import org.jooq.meta.SchemaDefinition;
|
||||
import org.jooq.meta.SequenceDefinition;
|
||||
import org.jooq.meta.TableDefinition;
|
||||
import org.jooq.meta.TableQualifier;
|
||||
import org.jooq.meta.UDTDefinition;
|
||||
import org.jooq.meta.hsqldb.HSQLDBDatabase;
|
||||
import org.jooq.meta.postgres.information_schema.tables.CheckConstraints;
|
||||
@ -622,7 +620,6 @@ public class PostgresDatabase extends AbstractDatabase {
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected List<DomainDefinition> getDomains0() throws SQLException {
|
||||
List<DomainDefinition> result = new ArrayList<>();
|
||||
@ -850,46 +847,34 @@ public class PostgresDatabase extends AbstractDatabase {
|
||||
}
|
||||
|
||||
boolean is94() {
|
||||
if (is94 == null) {
|
||||
|
||||
// [#4254] INFORMATION_SCHEMA.PARAMETERS.PARAMETER_DEFAULT was added
|
||||
// in PostgreSQL 9.4 only
|
||||
try {
|
||||
create(true)
|
||||
.select(PARAMETERS.PARAMETER_DEFAULT)
|
||||
.from(PARAMETERS)
|
||||
.where(falseCondition())
|
||||
.fetch();
|
||||
|
||||
is94 = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
is94 = false;
|
||||
}
|
||||
}
|
||||
// [#4254] INFORMATION_SCHEMA.PARAMETERS.PARAMETER_DEFAULT was added
|
||||
// in PostgreSQL 9.4 only
|
||||
if (is94 == null)
|
||||
is94 = exists(PARAMETERS.PARAMETER_DEFAULT);
|
||||
|
||||
return is94;
|
||||
}
|
||||
|
||||
boolean is11() {
|
||||
if (is11 == null) {
|
||||
|
||||
// [#7785] pg_proc.prokind was added in PostgreSQL 11 only, and
|
||||
// pg_proc.proisagg was removed, incompatibly
|
||||
// [#7785] pg_proc.prokind was added in PostgreSQL 11 only, and
|
||||
// pg_proc.proisagg was removed, incompatibly
|
||||
if (is11 == null)
|
||||
is11 = exists(PG_PROC.PROKIND);
|
||||
}
|
||||
|
||||
return is11;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TableQualifier tableQualifier() {
|
||||
return new DefaultTableQualifier(TABLES, TABLES.TABLE_CATALOG, TABLES.TABLE_SCHEMA, TABLES.TABLE_NAME);
|
||||
protected boolean exists0(TableField<?, ?> field) {
|
||||
return exists1(field, COLUMNS, COLUMNS.TABLE_SCHEMA, COLUMNS.TABLE_NAME, COLUMNS.COLUMN_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnQualifier columnQualifier() {
|
||||
return new DefaultColumnQualifier(COLUMNS, COLUMNS.TABLE_CATALOG, COLUMNS.TABLE_SCHEMA, COLUMNS.TABLE_NAME, COLUMNS.COLUMN_NAME);
|
||||
protected boolean exists0(Table<?> table) {
|
||||
return exists1(table, TABLES, TABLES.TABLE_SCHEMA, TABLES.TABLE_NAME);
|
||||
}
|
||||
|
||||
boolean canCombineArrays() {
|
||||
@ -929,18 +914,11 @@ public class PostgresDatabase extends AbstractDatabase {
|
||||
}
|
||||
|
||||
boolean canUseRoutines() {
|
||||
if (canUseRoutines == null) {
|
||||
|
||||
// [#7892] The information_schema.routines table is not available in all PostgreSQL
|
||||
// style databases, e.g. CockroachDB
|
||||
try {
|
||||
create(true).fetchExists(ROUTINES);
|
||||
canUseRoutines = true;
|
||||
}
|
||||
catch (DataAccessException e) {
|
||||
canUseRoutines = false;
|
||||
}
|
||||
}
|
||||
// [#7892] The information_schema.routines table is not available in all PostgreSQL
|
||||
// style databases, e.g. CockroachDB
|
||||
if (canUseRoutines == null)
|
||||
canUseRoutines = exists(ROUTINES);
|
||||
|
||||
return canUseRoutines;
|
||||
}
|
||||
|
||||
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.conf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.jooq.exception.ConfigurationException;
|
||||
import org.jooq.tools.Convert;
|
||||
import org.jooq.tools.reflect.Reflect;
|
||||
import org.jooq.tools.reflect.ReflectException;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* This class allows for mashalling / unmarshalling XML content to jOOQ
|
||||
* configuration objects.
|
||||
* <p>
|
||||
* With jOOQ 3.12, the JAXB dependency has been removed in favour of this home
|
||||
* grown solution. Due to the modularisation that happened with JDK 9+ and the
|
||||
* removal of JAXB from the JDK 11+, it is unreasonable to leave the burden of
|
||||
* properly configuring transitive JAXB dependency to jOOQ users.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class MiniJAXB {
|
||||
|
||||
public static String marshal(Object object) {
|
||||
StringWriter writer = new StringWriter();
|
||||
marshal(object, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public static void marshal(Object object, OutputStream out) {
|
||||
marshal(object, new OutputStreamWriter(out));
|
||||
}
|
||||
|
||||
public static void marshal(Object object, Writer out) {
|
||||
try {
|
||||
XmlRootElement e = object.getClass().getAnnotation(XmlRootElement.class);
|
||||
if (e != null)
|
||||
out.write("<" + e.name() + ">");
|
||||
|
||||
out.write(object.toString());
|
||||
|
||||
if (e != null)
|
||||
out.write("</" + e.name() + ">");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ConfigurationException("Cannot print object", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T unmarshal(InputStream in, Class<T> type) {
|
||||
return unmarshal0(new InputSource(in), type);
|
||||
}
|
||||
|
||||
public static <T> T unmarshal(String xml, Class<T> type) {
|
||||
return unmarshal0(new InputSource(new StringReader(xml)), type);
|
||||
}
|
||||
|
||||
public static <T> T unmarshal(File xml, Class<T> type) {
|
||||
try {
|
||||
return unmarshal0(new InputSource(new FileInputStream(xml)), type);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ConfigurationException("Error while opening file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T unmarshal0(InputSource in, Class<T> type) {
|
||||
try {
|
||||
Document document = builder().parse(in);
|
||||
T result = Reflect.on(type).create().get();
|
||||
unmarshal0(result, document.getDocumentElement());
|
||||
return result;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ConfigurationException("Error while reading xml", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void unmarshal0(Object result, Element element) throws Exception {
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
Class<?> type = result.getClass();
|
||||
for (Field child : type.getDeclaredFields()) {
|
||||
int modifiers = child.getModifiers();
|
||||
if (Modifier.isFinal(modifiers) ||
|
||||
Modifier.isStatic(modifiers))
|
||||
continue;
|
||||
|
||||
XmlElementWrapper w = child.getAnnotation(XmlElementWrapper.class);
|
||||
XmlElement e = child.getAnnotation(XmlElement.class);
|
||||
XmlJavaTypeAdapter a = child.getAnnotation(XmlJavaTypeAdapter.class);
|
||||
|
||||
String childName = child.getName();
|
||||
String childElementName =
|
||||
w != null
|
||||
? "##default".equals(w.name())
|
||||
? child.getName()
|
||||
: w.name()
|
||||
: e == null || "##default".equals(e.name())
|
||||
? childName
|
||||
: e.name();
|
||||
|
||||
Element childElement = child(element, childElementName);
|
||||
if (childElement == null)
|
||||
continue;
|
||||
|
||||
Class<?> childType = child.getType();
|
||||
if (List.class.isAssignableFrom(childType) && w != null && e != null) {
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
unmarshalList0(list, childElement, e.name(), (Class<?>) ((ParameterizedType) child.getGenericType()).getActualTypeArguments()[0]);
|
||||
Reflect.on(result).set(childName, list);
|
||||
}
|
||||
else if (childType.getAnnotation(XmlEnum.class) != null) {
|
||||
Reflect.on(result).set(childName, Convert.convert(childElement.getTextContent().trim(), childType));
|
||||
}
|
||||
else if (childType.getAnnotation(XmlType.class) != null) {
|
||||
Object object = Reflect.on(childType).create().get();
|
||||
Reflect.on(result).set(childName, object);
|
||||
|
||||
unmarshal0(object, childElement);
|
||||
}
|
||||
else if (a != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
XmlAdapter<Object, Object> adapter = a.value().getConstructor().newInstance();
|
||||
Reflect.on(result).set(childName, adapter.unmarshal(childElement.getTextContent().trim()));
|
||||
}
|
||||
else {
|
||||
Reflect.on(result).set(childName, Convert.convert(childElement.getTextContent().trim(), childType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void unmarshalList0(List<Object> result, Element element, String name, Class<?> type) throws Exception {
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
NodeList list = element.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Node item = list.item(i);
|
||||
|
||||
if (item.getNodeType() == Node.ELEMENT_NODE) {
|
||||
if (name.equals(((Element) item).getTagName()) || name.equals(((Element) item).getLocalName())) {
|
||||
Object o = Reflect.on(type).create().get();
|
||||
unmarshal0(o, (Element) item);
|
||||
result.add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Element child(Element element, String name) {
|
||||
NodeList list = element.getChildNodes();
|
||||
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Node item = list.item(i);
|
||||
|
||||
if (item.getNodeType() == Node.ELEMENT_NODE)
|
||||
if (name.equals(((Element) item).getTagName()) || name.equals(((Element) item).getLocalName()))
|
||||
return (Element) item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static DocumentBuilder builder() {
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// [JOOX #136] FIX START: Prevent OWASP attack vectors
|
||||
try {
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
}
|
||||
catch (ParserConfigurationException ignore) {}
|
||||
|
||||
try {
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
}
|
||||
catch (ParserConfigurationException ignore) {}
|
||||
|
||||
try {
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
}
|
||||
catch (ParserConfigurationException ignore) {}
|
||||
|
||||
// [JOOX #149] Not implemented on Android
|
||||
try {
|
||||
factory.setXIncludeAware(false);
|
||||
}
|
||||
catch (UnsupportedOperationException ignore) {}
|
||||
|
||||
factory.setExpandEntityReferences(false);
|
||||
// [JOOX #136] FIX END
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// [JOOX #9] [JOOX #107] In order to take advantage of namespace-related DOM
|
||||
// features, the internal builder should be namespace-aware
|
||||
factory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
|
||||
return builder;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a <code>second</code> JAXB annotated object to a
|
||||
* <code>first</code> one using Maven's
|
||||
* <code>combine.children="append"</code> semantics.
|
||||
*
|
||||
* @return The modified <code>first</code> argument.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static <T> T append(T first, T second) {
|
||||
if (first == null)
|
||||
return second;
|
||||
if (second == null)
|
||||
return first;
|
||||
|
||||
Class<T> klass = (Class<T>) first.getClass();
|
||||
if (klass != second.getClass())
|
||||
throw new IllegalArgumentException("Can only append identical types");
|
||||
// [#8527] support enum types
|
||||
else if (klass.isEnum())
|
||||
return first;
|
||||
|
||||
// We're assuming that XJC generated objects are all in the same package
|
||||
Package pkg = klass.getPackage();
|
||||
try {
|
||||
T defaults = klass.getConstructor().newInstance();
|
||||
|
||||
for (Method setter : klass.getMethods()) {
|
||||
if (setter.getName().startsWith("set")) {
|
||||
Method getter;
|
||||
|
||||
try {
|
||||
getter = klass.getMethod("get" + setter.getName().substring(3));
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
getter = klass.getMethod("is" + setter.getName().substring(3));
|
||||
}
|
||||
|
||||
Class<?> childType = setter.getParameterTypes()[0];
|
||||
Object firstChild = getter.invoke(first);
|
||||
Object secondChild = getter.invoke(second);
|
||||
Object defaultChild = getter.invoke(defaults);
|
||||
|
||||
if (Collection.class.isAssignableFrom(childType))
|
||||
((List) firstChild).addAll((List) secondChild);
|
||||
else if (secondChild != null && (firstChild == null || firstChild.equals(defaultChild)))
|
||||
setter.invoke(first, secondChild);
|
||||
else if (secondChild != null && pkg == childType.getPackage())
|
||||
append(firstChild, secondChild);
|
||||
else
|
||||
; // All other types cannot be merged
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ReflectException(e);
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
}
|
||||
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.Comparator;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.LikeEscapeStep;
|
||||
import org.jooq.Operator;
|
||||
|
||||
final class CombinedCompareCondition extends AbstractCondition implements LikeEscapeStep {
|
||||
|
||||
private static final long serialVersionUID = 1850816878293293314L;
|
||||
|
||||
private final Field<?> field;
|
||||
private final Comparator comparator;
|
||||
private final Quantifier quantifier;
|
||||
private final Collection<? extends Field<String>> values;
|
||||
private Character escape;
|
||||
|
||||
public CombinedCompareCondition(Field<?> field, Comparator comparator, Quantifier quantifier, Collection<? extends Field<String>> values) {
|
||||
this.field = field;
|
||||
this.comparator = comparator;
|
||||
this.quantifier = quantifier;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Condition escape(char c) {
|
||||
this.escape = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
Collection<Condition> conditions = new ArrayList<Condition>();
|
||||
|
||||
switch (comparator) {
|
||||
case LIKE:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.like(value, escape) : field.like(value));
|
||||
break;
|
||||
|
||||
case NOT_LIKE:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.notLike(value, escape) : field.notLike(value));
|
||||
break;
|
||||
|
||||
case SIMILAR_TO:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.similarTo(value, escape) : field.similarTo(value));
|
||||
break;
|
||||
|
||||
case NOT_SIMILAR_TO:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.notSimilarTo(value, escape) : field.notSimilarTo(value));
|
||||
break;
|
||||
|
||||
case LIKE_IGNORE_CASE:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.likeIgnoreCase(value, escape) : field.likeIgnoreCase(value));
|
||||
break;
|
||||
|
||||
case NOT_LIKE_IGNORE_CASE:
|
||||
for (Field<String> value : values)
|
||||
conditions.add(escape != null ? field.notLikeIgnoreCase(value, escape) : field.notLikeIgnoreCase(value));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Condition combinedCondition = CombinedCondition.of(quantifier == Quantifier.ALL ? Operator.AND : Operator.OR, conditions);
|
||||
ctx.visit(combinedCondition);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user