Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* 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
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* 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 static java.util.Arrays.asList;
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.impl.DSL.name;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jooq.Catalog;
import org.jooq.Configuration;
import org.jooq.ConnectionCallable;
import org.jooq.Constraint;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Meta;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.Sequence;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.exception.SQLDialectNotSupportedException;
/**
* An implementation of the public {@link Meta} type.
*
* This implementation implements {@link Serializable}, without taking care of
* properly deserialising the referenced executor.
*
* @author Lukas Eder
*/
final class MetaImpl implements Meta, Serializable {
/**
* Generated UID
*/
private static final long serialVersionUID = 3582980783173033809L;
private final DSLContext ctx;
private final Configuration configuration;
private final boolean inverseSchemaCatalog;
MetaImpl(Configuration configuration) {
this.ctx = DSL.using(configuration);
this.configuration = configuration;
this.inverseSchemaCatalog = asList(MYSQL, MARIADB).contains(configuration.family());
}
private interface MetaFunction {
Result run(DatabaseMetaData meta) throws SQLException;
}
private final Result meta(final MetaFunction consumer) {
return ctx.connectionResult(new ConnectionCallable>() {
@Override
public Result run(Connection connection) throws SQLException {
return consumer.run(connection.getMetaData());
}
});
}
@Override
public final List getCatalogs() {
List result = new ArrayList();
// [#2760] MySQL JDBC confuses "catalog" and "schema"
if (!inverseSchemaCatalog) {
Result catalogs = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
return ctx.fetch(
meta.getCatalogs(),
SQLDataType.VARCHAR // TABLE_CATALOG
);
}
});
for (String name : catalogs.getValues(0, String.class))
result.add(new MetaCatalog(name));
}
// There should always be at least one (empty) catalog in a database
if (result.isEmpty())
result.add(new MetaCatalog(""));
return result;
}
@Override
public final List getSchemas() {
List result = new ArrayList();
for (Catalog catalog : getCatalogs())
result.addAll(catalog.getSchemas());
return result;
}
@Override
public final List
> getTables() {
List
> result = new ArrayList
>();
for (Schema schema : getSchemas())
result.addAll(schema.getTables());
return result;
}
@Override
public final List> getSequences() {
List> result = new ArrayList>();
for (Schema schema : getSchemas())
result.addAll(schema.getSequences());
return result;
}
@Override
public final List> getPrimaryKeys() {
List> result = new ArrayList>();
for (Table> table : getTables()) {
UniqueKey> pk = table.getPrimaryKey();
if (pk != null)
result.add(pk);
}
return result;
}
private class MetaCatalog extends CatalogImpl {
/**
* Generated UID
*/
private static final long serialVersionUID = -2821093577201327275L;
MetaCatalog(String name) {
super(name);
}
@Override
public final List getSchemas() {
List result = new ArrayList();
if (!inverseSchemaCatalog) {
Result schemas = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
return ctx.fetch(
meta.getSchemas(),
// [#2681] Work around a flaw in the MySQL JDBC driver
SQLDataType.VARCHAR // TABLE_SCHEM
);
}
});
for (String name : schemas.getValues(0, String.class)) {
result.add(new MetaSchema(name, MetaCatalog.this));
}
}
// [#2760] MySQL JDBC confuses "catalog" and "schema"
else {
Result schemas = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
return ctx.fetch(
meta.getCatalogs(),
SQLDataType.VARCHAR // TABLE_CATALOG
);
}
});
for (String name : schemas.getValues(0, String.class)) {
result.add(new MetaSchema(name, MetaCatalog.this));
}
}
// There should always be at least one (empty) schema in a database
if (result.isEmpty()) {
result.add(new MetaSchema("", MetaCatalog.this));
}
return result;
}
}
private class MetaSchema extends SchemaImpl {
/**
* Generated UID
*/
private static final long serialVersionUID = -2621899850912554198L;
private transient volatile Map> columnCache;
MetaSchema(String name, Catalog catalog) {
super(name, catalog);
}
@Override
public final synchronized List
> getTables() {
Result tables = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
String[] types = null;
switch (configuration.family()) {
// [#3977] PostgreSQL returns other object types, too
case POSTGRES:
types = new String[] { "TABLE", "VIEW", "SYSTEM_TABLE", "SYSTEM_VIEW", "MATERIALIZED VIEW" };
break;
// [#2323] SQLite JDBC drivers have a bug. They return other
// object types, too: https://bitbucket.org/xerial/sqlite-jdbc/issue/68
case SQLITE:
types = new String[] { "TABLE", "VIEW" };
break;
}
ResultSet rs;
if (!inverseSchemaCatalog) {
rs = meta.getTables(null, getName(), "%", types);
}
// [#2760] MySQL JDBC confuses "catalog" and "schema"
else {
rs = meta.getTables(getName(), null, "%", types);
}
return ctx.fetch(
rs,
// [#2681] Work around a flaw in the MySQL JDBC driver
SQLDataType.VARCHAR, // TABLE_CAT
SQLDataType.VARCHAR, // TABLE_SCHEM
SQLDataType.VARCHAR, // TABLE_NAME
SQLDataType.VARCHAR // TABLE_TYPE
);
}
});
List
> result = new ArrayList
>();
for (Record table : tables) {
String catalog = table.get(0, String.class);
String schema = table.get(1, String.class);
String name = table.get(2, String.class);
// [#2760] MySQL JDBC confuses "catalog" and "schema"
result.add(new MetaTable(name, this, getColumns(
inverseSchemaCatalog ? catalog : schema,
name
)));
// TODO: Find a more efficient way to do this
// Result pkColumns = executor.fetch(meta().getPrimaryKeys(catalog, schema, name))
// .sortAsc("KEY_SEQ");
//
// result.add(new MetaTable(name, this, columnCache.get(name)));
}
return result;
}
@SuppressWarnings("unchecked")
private final Result getColumns(String schema, String table) {
// SQLite JDBC's DatabaseMetaData.getColumns() can only return a single
// table's columns
if (columnCache == null && configuration.dialect() != SQLITE) {
Result columns = getColumns0(schema, "%");
Field tableCat = (Field) columns.field(0); // TABLE_CAT
Field tableSchem = (Field) columns.field(1); // TABLE_SCHEM
Field tableName = (Field) columns.field(2); // TABLE_NAME
Map> groups =
columns.intoGroups(new Field[] {
inverseSchemaCatalog ? tableCat : tableSchem,
tableName
});
columnCache = new LinkedHashMap>();
for (Entry> entry : groups.entrySet()) {
Record key = entry.getKey();
Result value = entry.getValue();
columnCache.put(name(key.get(inverseSchemaCatalog ? tableCat : tableSchem), key.get(tableName)), value);
}
}
if (columnCache != null) {
return columnCache.get(name(schema, table));
}
else {
return getColumns0(schema, table);
}
}
private final Result getColumns0(final String schema, final String table) {
return meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
ResultSet rs;
if (!inverseSchemaCatalog) {
rs = meta.getColumns(null, schema, table, "%");
}
// [#2760] MySQL JDBC confuses "catalog" and "schema"
else {
rs = meta.getColumns(schema, null, table, "%");
}
return ctx.fetch(
rs,
// Work around a bug in the SQL Server JDBC driver by
// coercing data types to the expected types
// The bug was reported here:
// https://connect.microsoft.com/SQLServer/feedback/details/775425/jdbc-4-0-databasemetadata-getcolumns-returns-a-resultset-whose-resultsetmetadata-is-inconsistent
String.class, // TABLE_CAT
String.class, // TABLE_SCHEM
String.class, // TABLE_NAME
String.class, // COLUMN_NAME
int.class, // DATA_TYPE
String.class, // TYPE_NAME
int.class, // COLUMN_SIZE
String.class, // BUFFER_LENGTH
int.class, // DECIMAL_DIGITS
int.class, // NUM_PREC_RADIX
int.class // NULLABLE
);
}
});
}
}
private class MetaTable extends TableImpl {
/**
* Generated UID
*/
private static final long serialVersionUID = 4843841667753000233L;
MetaTable(String name, Schema schema, Result columns) {
super(name, schema);
// Possible scenarios for columns being null:
// - The "table" is in fact a SYNONYM
if (columns != null) {
init(columns);
}
}
@Override
public final List> getKeys() {
UniqueKey pk = getPrimaryKey();
return pk == null ? Collections.>emptyList() : Collections.>singletonList(pk);
}
@Override
public final UniqueKey getPrimaryKey() {
SQLDialect family = configuration.family();
final String schema = getSchema() == null ? null : getSchema().getName();
Result result = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
ResultSet rs;
if (!inverseSchemaCatalog) {
rs = meta.getPrimaryKeys(null, schema, getName());
}
// [#2760] MySQL JDBC confuses "catalog" and "schema"
else {
rs = meta.getPrimaryKeys(schema, null, getName());
}
return
ctx.fetch(
rs,
String.class, // TABLE_CAT
String.class, // TABLE_SCHEM
String.class, // TABLE_NAME
String.class, // COLUMN_NAME
int.class, // KEY_SEQ
String.class // PK_NAME
);
}
});
// Sort by KEY_SEQ
result.sortAsc(4);
return createPrimaryKey(result, 3);
}
@Override
@SuppressWarnings("unchecked")
public List> getReferences() {
List> references = new ArrayList>();
Result result = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
ResultSet rs = meta.getImportedKeys(null, getSchema().getName(), getName());
return
ctx.fetch(
rs,
String.class, // PKTABLE_CAT
String.class, // PKTABLE_SCHEM
String.class, // PKTABLE_NAME
String.class, // PKCOLUMN_NAME
String.class, // FKTABLE_CAT
String.class, // FKTABLE_SCHEM
String.class, // FKTABLE_NAME
String.class, // FKCOLUMN_NAME
Short.class, // KEY_SEQ
Short.class, // UPDATE_RULE
Short.class, // DELETE_RULE
String.class, // FK_NAME
String.class // PK_NAME
);
}
});
Map> groups = result.intoGroups(new Field[] {
result.field(inverseSchemaCatalog ? 1 : 0),
result.field(inverseSchemaCatalog ? 0 : 1),
result.field(2),
result.field(11),
result.field(12),
});
Map schemas = new HashMap();
for (Schema schema : getSchemas()) {
schemas.put(schema.getName(), schema);
}
for (Entry> entry : groups.entrySet()) {
Schema schema = schemas.get(entry.getKey().get(1));
String pkName = entry.getKey().get(4, String.class);
Table pkTable = (Table) schema.getTable(entry.getKey().get(2, String.class));
TableField[] pkFields = new TableField[entry.getValue().size()];
TableField[] fkFields = new TableField[entry.getValue().size()];
for (int i = 0; i < entry.getValue().size(); i++) {
Record record = entry.getValue().get(i);
pkFields[i] = (TableField) pkTable.field(record.get(3, String.class));
fkFields[i] = (TableField) field(record.get(7, String.class));
}
references.add(new ReferenceImpl(new MetaPrimaryKey(pkTable, pkName, pkFields), this, fkFields));
}
return references;
}
@SuppressWarnings("unchecked")
private final UniqueKey createPrimaryKey(Result result, int columnName) {
if (result.size() > 0) {
TableField[] f = new TableField[result.size()];
for (int i = 0; i < f.length; i++) {
String name = result.get(i).get(columnName, String.class);
f[i] = (TableField) field(name);
// [#5097] Work around a bug in the Xerial JDBC driver for SQLite
if (f[i] == null && configuration.family() == SQLITE)
// [#2656] Use native support for case-insensitive column
// lookup, once this is implemented
for (Field> field : fields())
if (field.getName().equalsIgnoreCase(name))
f[i] = (TableField) field;
}
String indexName = result.get(0).get(5, String.class);
return new MetaPrimaryKey(this, indexName, f);
}
else {
return null;
}
}
private final void init(Result columns) {
for (Record column : columns) {
String columnName = column.getValue(3, String.class); // COLUMN_NAME
String typeName = column.getValue(5, String.class); // TYPE_NAME
int precision = column.getValue(6, int.class); // COLUMN_SIZE
int scale = column.getValue(8, int.class); // DECIMAL_DIGITS
int nullable = column.getValue(10, int.class); // NULLABLE
// TODO: Exception handling should be moved inside SQLDataType
DataType> type = null;
try {
type = DefaultDataType.getDataType(configuration.family(), typeName, precision, scale);
// JDBC doesn't distinguish between precision and length
type = type.precision(precision, scale);
type = type.length(precision);
if (nullable == DatabaseMetaData.columnNoNulls)
type = type.nullable(false);
}
catch (SQLDialectNotSupportedException e) {
type = SQLDataType.OTHER;
}
createField(columnName, type, this);
}
}
}
private class MetaPrimaryKey implements UniqueKey {
/**
* Generated UID
*/
private static final long serialVersionUID = 6997258619475953490L;
private final String pkName;
private final Table pkTable;
private final TableField[] pkFields;
MetaPrimaryKey(Table table, String pkName, TableField[] fields) {
this.pkName = pkName;
this.pkTable = table;
this.pkFields = fields;
}
@Override
public final String getName() {
return pkName;
}
@Override
public final Table getTable() {
return pkTable;
}
@Override
public final List> getFields() {
return Collections.unmodifiableList(Arrays.asList(pkFields));
}
@Override
public final TableField[] getFieldsArray() {
return pkFields.clone();
}
@Override
public final boolean isPrimary() {
return true;
}
@Override
@SuppressWarnings("unchecked")
public final List> getReferences() {
List> references = new ArrayList>();
Result result = meta(new MetaFunction() {
@Override
public Result run(DatabaseMetaData meta) throws SQLException {
ResultSet rs = meta.getExportedKeys(null, pkTable.getSchema().getName(), pkTable.getName());
return ctx.fetch(
rs,
String.class, // PKTABLE_CAT
String.class, // PKTABLE_SCHEM
String.class, // PKTABLE_NAME
String.class, // PKCOLUMN_NAME
String.class, // FKTABLE_CAT
String.class, // FKTABLE_SCHEM
String.class, // FKTABLE_NAME
String.class, // FKCOLUMN_NAME
Short.class, // KEY_SEQ
Short.class, // UPDATE_RULE
Short.class, // DELETE_RULE
String.class, // FK_NAME
String.class // PK_NAME
);
}
});
Map> groups = result.intoGroups(new Field[] {
result.field(inverseSchemaCatalog ? 5 : 4),
result.field(inverseSchemaCatalog ? 4 : 5),
result.field(6),
result.field(11),
result.field(12),
});
Map schemas = new HashMap();
for (Schema schema : getSchemas()) {
schemas.put(schema.getName(), schema);
}
for (Entry> entry : groups.entrySet()) {
Schema schema = schemas.get(entry.getKey().get(1));
Table fkTable = (Table) schema.getTable(entry.getKey().get(2, String.class));
TableField[] fkFields = new TableField[entry.getValue().size()];
for (int i = 0; i < entry.getValue().size(); i++) {
Record record = entry.getValue().get(i);
fkFields[i] = (TableField) fkTable.field(record.get(7, String.class));
}
references.add(new ReferenceImpl(this, fkTable, fkFields));
}
return references;
}
@Override
public final Constraint constraint() {
if (isPrimary())
return DSL.constraint(getName()).primaryKey(getFieldsArray());
else
return DSL.constraint(getName()).unique(getFieldsArray());
}
}
}