/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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 org.jkiss.dbeaver.ext.generic.model; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.ext.generic.GenericConstants; import org.jkiss.dbeaver.ext.generic.model.meta.GenericMetaObject; import org.jkiss.dbeaver.model.DBPIdentifierCase; import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession; import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet; import org.jkiss.dbeaver.model.impl.jdbc.JDBCConstants; import org.jkiss.dbeaver.model.impl.jdbc.JDBCStructureAssistant; import org.jkiss.dbeaver.model.impl.struct.AbstractObjectReference; import org.jkiss.dbeaver.model.impl.struct.RelationalObjectType; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.dbeaver.model.struct.DBSObjectReference; import org.jkiss.dbeaver.model.struct.DBSObjectType; import org.jkiss.utils.CommonUtils; import java.sql.SQLException; import java.util.List; /** * GenericDataSource */ public class GenericStructureAssistant extends JDBCStructureAssistant { private final GenericDataSource dataSource; public GenericStructureAssistant(GenericDataSource dataSource) { this.dataSource = dataSource; } @Override protected GenericDataSource getDataSource() { return dataSource; } @Override public DBSObjectType[] getSupportedObjectTypes() { return new DBSObjectType[] { RelationalObjectType.TYPE_TABLE, RelationalObjectType.TYPE_PROCEDURE }; } public DBSObjectType[] getHyperlinkObjectTypes() { return getSupportedObjectTypes(); } @Override public DBSObjectType[] getAutoCompleteObjectTypes() { return getSupportedObjectTypes(); } @Override protected void findObjectsByMask(JDBCSession session, DBSObjectType objectType, DBSObject parentObject, String objectNameMask, boolean caseSensitive, boolean globalSearch, int maxResults, List<DBSObjectReference> references) throws DBException, SQLException { GenericSchema schema = parentObject instanceof GenericSchema ? (GenericSchema)parentObject : null; GenericCatalog catalog = parentObject instanceof GenericCatalog ? (GenericCatalog)parentObject : schema == null ? null : schema.getCatalog(); final GenericDataSource dataSource = getDataSource(); DBPIdentifierCase convertCase = caseSensitive ? dataSource.getSQLDialect().storesQuotedCase() : dataSource.getSQLDialect().storesUnquotedCase(); objectNameMask = convertCase.transform(objectNameMask); if (objectType == RelationalObjectType.TYPE_TABLE) { findTablesByMask(session, catalog, schema, objectNameMask, maxResults, references); } else if (objectType == RelationalObjectType.TYPE_PROCEDURE) { findProceduresByMask(session, catalog, schema, objectNameMask, maxResults, references); } } private void findTablesByMask(JDBCSession session, GenericCatalog catalog, GenericSchema schema, String tableNameMask, int maxResults, List<DBSObjectReference> objects) throws SQLException, DBException { final GenericMetaObject tableObject = getDataSource().getMetaObject(GenericConstants.OBJECT_TABLE); final DBRProgressMonitor monitor = session.getProgressMonitor(); try (JDBCResultSet dbResult = session.getMetaData().getTables( catalog == null ? null : catalog.getName(), schema == null ? null : schema.getName(), tableNameMask, null)) { while (dbResult.next()) { if (monitor.isCanceled()) { break; } String catalogName = GenericUtils.safeGetStringTrimmed(tableObject, dbResult, JDBCConstants.TABLE_CAT); String schemaName = GenericUtils.safeGetStringTrimmed(tableObject, dbResult, JDBCConstants.TABLE_SCHEM); String tableName = GenericUtils.safeGetStringTrimmed(tableObject, dbResult, JDBCConstants.TABLE_NAME); if (CommonUtils.isEmpty(tableName)) { continue; } objects.add(new TableReference( findContainer(session.getProgressMonitor(), catalog, schema, catalogName, schemaName), tableName, GenericUtils.safeGetString(tableObject, dbResult, JDBCConstants.REMARKS))); if (objects.size() >= maxResults) { break; } } } } private void findProceduresByMask(JDBCSession session, GenericCatalog catalog, GenericSchema schema, String procNameMask, int maxResults, List<DBSObjectReference> objects) throws SQLException, DBException { final GenericMetaObject procObject = getDataSource().getMetaObject(GenericConstants.OBJECT_PROCEDURE); DBRProgressMonitor monitor = session.getProgressMonitor(); try (JDBCResultSet dbResult = session.getMetaData().getProcedures( catalog == null ? null : catalog.getName(), schema == null ? null : schema.getName(), procNameMask)) { while (dbResult.next()) { if (monitor.isCanceled()) { break; } String catalogName = GenericUtils.safeGetStringTrimmed(procObject, dbResult, JDBCConstants.PROCEDURE_CAT); String schemaName = GenericUtils.safeGetStringTrimmed(procObject, dbResult, JDBCConstants.PROCEDURE_SCHEM); String procName = GenericUtils.safeGetStringTrimmed(procObject, dbResult, JDBCConstants.PROCEDURE_NAME); String uniqueName = GenericUtils.safeGetStringTrimmed(procObject, dbResult, JDBCConstants.SPECIFIC_NAME); if (CommonUtils.isEmpty(procName)) { continue; } if (CommonUtils.isEmpty(uniqueName)) { uniqueName = procName; } objects.add(new ProcedureReference( findContainer(session.getProgressMonitor(), catalog, schema, catalogName, schemaName), catalogName, procName, uniqueName)); if (objects.size() >= maxResults) { break; } } } } protected GenericStructContainer findContainer(DBRProgressMonitor monitor, GenericCatalog parentCatalog, GenericSchema parentSchema, String catalogName, String schemaName) throws DBException { GenericCatalog tableCatalog = parentCatalog != null ? parentCatalog : CommonUtils.isEmpty(catalogName) ? null : dataSource.getCatalog(catalogName); if (tableCatalog == null && CommonUtils.isEmpty(catalogName) && !CommonUtils.isEmpty(dataSource.getCatalogs()) && dataSource.getCatalogs().size() == 1) { // there is only one catalog - let's use it (PostgreSQL) tableCatalog = dataSource.getCatalogs().iterator().next(); } GenericSchema tableSchema = parentSchema != null ? parentSchema : CommonUtils.isEmpty(schemaName) ? null : tableCatalog == null ? dataSource.getSchema(schemaName) : tableCatalog.getSchema(monitor, schemaName); return tableSchema != null ? tableSchema : tableCatalog != null ? tableCatalog : dataSource; } private abstract class ObjectReference extends AbstractObjectReference { protected ObjectReference(GenericStructContainer container, String name, String description, Class<?> objectClass, DBSObjectType type) { super(name, container, description, objectClass, type); } @Override public GenericStructContainer getContainer() { return (GenericStructContainer)super.getContainer(); } } private class TableReference extends ObjectReference { private TableReference(GenericStructContainer container, String tableName, String description) { super(container, tableName, description, GenericTable.class, RelationalObjectType.TYPE_TABLE); } @Override public DBSObject resolveObject(DBRProgressMonitor monitor) throws DBException { GenericTable table = getContainer().getTable(monitor, getName()); if (table == null) { throw new DBException("Can't find table '" + getName() + "' in '" + DBUtils.getFullQualifiedName(dataSource, getContainer()) + "'"); } return table; } } private class ProcedureReference extends ObjectReference { private final String catalogName; private String uniqueName; private ProcedureReference(GenericStructContainer container, String catalogName, String procedureName, String uniqueName) { super(container, procedureName, null, GenericProcedure.class, RelationalObjectType.TYPE_PROCEDURE); this.catalogName = catalogName; this.uniqueName = uniqueName; } @Override public DBSObject resolveObject(DBRProgressMonitor monitor) throws DBException { GenericProcedure procedure = null; if (getContainer() instanceof GenericSchema) { // Try to use catalog name as package name (Oracle) if (!CommonUtils.isEmpty(catalogName)) { GenericPackage procPackage = ((GenericSchema)getContainer()).getPackage(monitor, catalogName); if (procPackage != null) { procedure = procPackage.getProcedure(monitor, uniqueName); } } } if (procedure == null) { procedure = getContainer().getProcedure(monitor, uniqueName); } if (procedure == null) { throw new DBException("Can't find procedure '" + getName() + "' (" + uniqueName + ")" + "' in '" + DBUtils.getFullQualifiedName(dataSource, getContainer()) + "'"); } return procedure; } } }