/* * Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com> * * 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. */ package com.obidea.semantika.database.internal; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.WeakHashMap; import com.obidea.semantika.database.QualifiedName; import com.obidea.semantika.database.base.Column; import com.obidea.semantika.database.base.ForeignKey; import com.obidea.semantika.database.base.IColumn; import com.obidea.semantika.database.base.IForeignKey; import com.obidea.semantika.database.base.IPrimaryKey; import com.obidea.semantika.database.base.ISchema; import com.obidea.semantika.database.base.ITable; import com.obidea.semantika.database.base.PrimaryKey; import com.obidea.semantika.database.base.Schema; import com.obidea.semantika.database.base.Table; import com.obidea.semantika.database.exception.AmbiguousNamesException; import com.obidea.semantika.database.exception.TableNotFoundException; import com.obidea.semantika.util.StringUtils; public class InternalDatabase extends AbstractInternalDatabase { private DatabaseMetaData mDbMetadata; public InternalDatabase(DatabaseMetaData metadata) throws SQLException { mDbMetadata = metadata; } @Override public TemporaryTable findTable(String anyTableName) throws SQLException { List<TemporaryTable> possibleTables = findCandidateTables(anyTableName); if (possibleTables.size() == 0) { throw new TableNotFoundException(anyTableName); } if (possibleTables.size() > 1) { throw new AmbiguousNamesException(anyTableName, possibleTables); } return possibleTables.get(0); } @Override public void retrieveColumns(final ITable table) throws SQLException { final String schemaName = table.getSchemaName(); final String tableName = table.getLocalName(); ResultSet rs = null; try { rs = mDbMetadata.getColumns(null, schemaName, tableName, null); while (rs.next()) { final String columnName = rs.getString("COLUMN_NAME"); //$NON-NLS-1$ final int datatype = rs.getInt("DATA_TYPE"); //$NON-NLS-1$ IColumn column = new Column(table, columnName, datatype); table.addColumn(column); // update the table } } finally { if (rs != null && !rs.isClosed()) { rs.close(); } } } @Override public Set<IPrimaryKey> retrievePrimaryKeys(final ITable table) throws SQLException { final String schemaName = table.getSchemaName(); final String tableName = table.getLocalName(); Set<IPrimaryKey> toReturn = new HashSet<IPrimaryKey>(); ResultSet rs = null; try { WeakHashMap<String, IPrimaryKey> pkCache = new WeakHashMap<String, IPrimaryKey>(); rs = mDbMetadata.getPrimaryKeys(null, schemaName, tableName); while (rs.next()) { int keySequence = rs.getInt("KEY_SEQ"); //$NON-NLS-1$ String pkName = rs.getString("PK_NAME"); //$NON-NLS-1$ String pkColumnName = rs.getString("COLUMN_NAME"); //$NON-NLS-1$ IPrimaryKey pk = pkCache.get(pkName); if (pk == null) { pk = new PrimaryKey(table, pkName); pkCache.put(pkName, pk); toReturn.add(pk); // add to the returned set } IColumn column = table.getColumn(pkColumnName); column.setPrimaryKey(true); pk.addKey(keySequence-1, column); // the key sequence starts at 1 instead of 0 } } finally { if (rs != null && !rs.isClosed()) { rs.close(); } } return toReturn; } @Override public Set<IForeignKey> retrieveForeignKeys(final ITable table) throws SQLException { final String schemaName = table.getSchemaName(); final String tableName = table.getLocalName(); Set<IForeignKey> toReturn = new HashSet<IForeignKey>(); ResultSet rs = null; try { WeakHashMap<String, IForeignKey> fkCache = new WeakHashMap<String, IForeignKey>(); rs = mDbMetadata.getImportedKeys(null, schemaName, tableName); while (rs.next()) { int keySequence = rs.getInt("KEY_SEQ"); //$NON-NLS-1$ String fkName = rs.getString("FK_NAME"); //$NON-NLS-1$ String pkSchemaName = rs.getString("PKTABLE_SCHEM"); //$NON-NLS-1$ if (StringUtils.isEmpty(pkSchemaName)) { /* * Connector/J for MySQL uses table catalog as its table schema. Others, * like Oracle uses TABLE_SCHEM as table schema */ pkSchemaName = rs.getString("PKTABLE_CAT"); //$NON-NLS-1$ } String pkTableName = rs.getString("PKTABLE_NAME"); //$NON-NLS-1$ String pkColumnName = rs.getString("PKCOLUMN_NAME"); //$NON-NLS-1$ String fkColumnName = rs.getString("FKCOLUMN_NAME"); //$NON-NLS-1$ IForeignKey fk = fkCache.get(fkName); if (fk == null) { fk = new ForeignKey(table, fkName); fkCache.put(fkName, fk); toReturn.add(fk); // add to the returned set } IColumn pkColumn = getColumnFromTable(pkSchemaName, pkTableName, pkColumnName); IColumn fkColumn = table.getColumn(fkColumnName); fk.addReference(keySequence-1, pkColumn, fkColumn); // the key sequence starts at 1 instead of 0 } } finally { if (rs != null && !rs.isClosed()) { rs.close(); } } return toReturn; } /* * Private helper methods */ private List<TemporaryTable> findCandidateTables(String anyTableName) throws SQLException { if (StringUtils.isEmpty(anyTableName)) { throw new IllegalArgumentException("The table name must not be empty."); //$NON-NLS-1$ } QualifiedName qname = QualifiedName.create(anyTableName); String schemaPattern = qname.getIdentifier(1); String tableNamePattern = qname.getIdentifier(0); ResultSet rs = null; List<TemporaryTable> toReturn = new ArrayList<TemporaryTable>(); try { rs = mDbMetadata.getTables(null, schemaPattern, tableNamePattern, null); while (rs.next()) { String schemaName = rs.getString("TABLE_SCHEM"); //$NON-NLS-1$ if (StringUtils.isEmpty(schemaName)) { /* * Connector/J for MySQL uses table catalog as its table schema. Others, * like Oracle uses TABLE_SCHEM as table schema */ schemaName = rs.getString("TABLE_CAT"); //$NON-NLS-1$ } String tableName = rs.getString("TABLE_NAME"); //$NON-NLS-1$ TemporaryTable table = new TemporaryTable(schemaName, tableName); toReturn.add(table); } } finally { if (rs != null && !rs.isClosed()) { rs.close(); } } return toReturn; } private IColumn getColumnFromTable(String schemaName, String tableName, String columnName) throws SQLException { ITable table = new Table(getSchema(schemaName), tableName); retrieveColumns(table); return table.getColumn(columnName); } private static ISchema getSchema(String name) { return new Schema(name); } }