
net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfo Maven / Gradle / Ivy
package net.sourceforge.squirrel_sql.client.session.schemainfo;
/*
* Copyright (C) 2001-2003 Colin Bell
* [email protected]
*
* Copyright (C) 2001 Johan Compagner
* [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.SwingUtilities;
import net.sourceforge.squirrel_sql.client.IApplication;
import net.sourceforge.squirrel_sql.client.gui.db.SQLAliasSchemaProperties;
import net.sourceforge.squirrel_sql.client.gui.db.SchemaLoadInfo;
import net.sourceforge.squirrel_sql.client.gui.db.SchemaNameLoadInfo;
import net.sourceforge.squirrel_sql.client.session.ExtendedColumnInfo;
import net.sourceforge.squirrel_sql.client.session.ISession;
import net.sourceforge.squirrel_sql.client.session.schemainfo.ObjFilterMatcher;
import net.sourceforge.squirrel_sql.client.session.event.SessionAdapter;
import net.sourceforge.squirrel_sql.client.session.event.SessionEvent;
import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
import net.sourceforge.squirrel_sql.fw.sql.DataTypeInfo;
import net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType;
import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
import net.sourceforge.squirrel_sql.fw.sql.IProcedureInfo;
import net.sourceforge.squirrel_sql.fw.sql.ISQLConnection;
import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
import net.sourceforge.squirrel_sql.fw.sql.ProcedureInfo;
import net.sourceforge.squirrel_sql.fw.sql.ProgressCallBack;
import net.sourceforge.squirrel_sql.fw.sql.ProgressCallBackAdaptor;
import net.sourceforge.squirrel_sql.fw.sql.SQLDatabaseMetaData;
import net.sourceforge.squirrel_sql.fw.sql.TableColumnInfo;
import net.sourceforge.squirrel_sql.fw.sql.TableInfo;
import net.sourceforge.squirrel_sql.fw.util.StringManager;
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
public class SchemaInfo
{
public static final int TABLE_EXT_NOT_A_TABLE = 0;
public static final int TABLE_EXT_COLS_LOADED_IN_THIS_CALL = 1;
public static final int TABLE_EXT_COLS_LOADED_BEFORE = 2;
private static final StringManager s_stringMgr =
StringManagerFactory.getStringManager(SchemaInfo.class);
private boolean _loading = false;
private boolean _loaded = false;
private SQLDatabaseMetaData _dmd;
ISession _session = null;
private static final ILogger s_log = LoggerController.createLogger(SchemaInfo.class);
private SessionAdapter _sessionListener;
/**
* The number of load methods
*/
private static final int LOAD_METHODS_COUNT = 7;
private static final int MAX_PROGRESS = 100;
static interface i18n {
// i18n[SchemaInfo.loadingCatalogs=Loading catalogs]
String LOADING_CATALOGS_MSG =
s_stringMgr.getString("SchemaInfo.loadingCatalogs");
// i18n[SchemaInfo.loadingKeywords=Loading keywords]
String LOADING_KEYWORDS_MSG =
s_stringMgr.getString("SchemaInfo.loadingKeywords");
// i18n[SchemaInfo.loadingDataTypes=Loading data types]
String LOADING_DATATYPES_MSG =
s_stringMgr.getString("SchemaInfo.loadingDataTypes");
// i18n[SchemaInfo.loadingFunctions=Loading functions]
String LOADING_FUNCTIONS_MSG =
s_stringMgr.getString("SchemaInfo.loadingFunctions");
// i18n[SchemaInfo.loadingTables=Loading tables]
String LOADING_TABLES_MSG =
s_stringMgr.getString("SchemaInfo.loadingTables");
// i18n[SchemaInfo.loadingStoredProcedures=Loading stored procedures]
String LOADING_PROCS_MSG =
s_stringMgr.getString("SchemaInfo.loadingStoredProcedures");
// i18n[SchemaInfo.loadingSchemas=Loading schemas]
String LOADING_SCHEMAS_MSG =
s_stringMgr.getString("SchemaInfo.loadingSchemas");
}
final HashMap _tablesLoadingColsInBackground =
new HashMap();
private SchemaInfoCache _schemaInfoCache;
private Vector _listeners =
new Vector();
private boolean _inInitialLoad;
private long _initalLoadBeginTime;
private boolean _sessionStartupTimeHintShown;
private boolean _schemasAndCatalogsLoaded;
private boolean _tablesLoaded;
private boolean _storedProceduresLoaded;
public SchemaInfo(IApplication app)
{
_sessionListener = new SessionAdapter()
{
public void connectionClosedForReconnect(SessionEvent evt)
{
if (null != _session && _session.getIdentifier().equals(evt.getSession().getIdentifier()))
{
_dmd = null;
}
}
public void reconnected(SessionEvent evt)
{
if (null != _session && _session.getIdentifier().equals(evt.getSession().getIdentifier()))
{
_dmd = _session.getSQLConnection().getSQLMetaData();
if (null != _dmd)
{
s_log.info(s_stringMgr.getString("SchemaInfo.SuccessfullyRestoredDatabaseMetaData"));
}
}
}
public void sessionClosing(SessionEvent evt)
{
SchemaInfoCacheSerializer.store(_session, _schemaInfoCache);
}
};
if (app != null)
{
app.getSessionManager().addSessionListener(_sessionListener);
}
}
public void initialLoad(ISession session)
{
_session = session;
breathing();
_schemaInfoCache = SchemaInfoCacheSerializer.load(_session);
try
{
_inInitialLoad = true;
_initalLoadBeginTime = System.currentTimeMillis();
privateLoadAll();
}
finally
{
_inInitialLoad = false;
_schemaInfoCache.initialLoadDone();
}
}
public void reloadAll()
{
reloadAll(true);
}
/**
* @param fireSchemaInfoUpdate Should only be false when the caller makes sure fireSchemaInfoUpdate() is called later.
*/
void reloadAll(boolean fireSchemaInfoUpdate)
{
_schemaInfoCache.clearAll();
privateLoadAll();
if(fireSchemaInfoUpdate)
{
GUIUtils.processOnSwingEventThread(new Runnable() {
public void run() {
fireSchemaInfoUpdate();
}
});
}
}
/**
* Will re-read all table data into the cache.
*/
public void reloadAllTables()
{
GUIUtils.processOnSwingEventThread(new Runnable() {
public void run() {
_session.getSessionSheet().setStatusBarProgress(i18n.LOADING_TABLES_MSG, 0, MAX_PROGRESS, 50);
}
});
breathing();
_schemaInfoCache.clearAllTableData();
loadTables(null, null, null, null, 0);
notifyTablesLoaded();
GUIUtils.processOnSwingEventThread(new Runnable() {
public void run() {
fireSchemaInfoUpdate();
_session.getSessionSheet().setStatusBarProgressFinished();
}
});
}
private void privateLoadAll()
{
synchronized (this)
{
if(_loading)
{
return;
}
_loading = true;
_schemasAndCatalogsLoaded = false;
_tablesLoaded = false;
_storedProceduresLoaded = false;
}
breathing();
long mstart = System.currentTimeMillis();
long mfinish = 0;
try
{
ISQLConnection conn = _session.getSQLConnection();
_dmd = conn.getSQLMetaData();
_dmd.clearCache();
int progress = 0;
progress = loadCatalogs(progress);
progress = loadSchemas(progress);
notifySchemasAndCatalogsLoad();
long start = 0, finish = 0;
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_KEYWORDS_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_KEYWORDS_MSG, beginProgress);
loadKeywords(i18n.LOADING_KEYWORDS_MSG, beginProgress);
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Keywords loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading keywords", ex);
}
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_DATATYPES_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_DATATYPES_MSG, beginProgress);
loadDataTypes(i18n.LOADING_DATATYPES_MSG, beginProgress);
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Data types loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading data types", ex);
}
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_FUNCTIONS_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_FUNCTIONS_MSG, beginProgress);
loadGlobalFunctions(i18n.LOADING_FUNCTIONS_MSG, beginProgress);
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Functions loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading functions", ex);
}
progress = loadTables(null, null, null, null, progress);
notifyTablesLoaded();
progress = loadStoredProcedures(null, null, null, progress);
notifyStoredProceduresLoaded();
}
finally
{
if (_session != null && _session.getSessionSheet() != null)
{
_session.getSessionSheet().setStatusBarProgressFinished();
}
_loading = false;
_loaded = true;
}
if (s_log.isDebugEnabled()) {
mfinish = System.currentTimeMillis();
s_log.debug("SchemaInfo.load took " + (mfinish - mstart) + " ms");
}
}
private void notifyStoredProceduresLoaded()
{
synchronized(this)
{
_storedProceduresLoaded = true;
this.notifyAll();
}
}
private void notifyTablesLoaded()
{
synchronized(this)
{
_tablesLoaded = true;
this.notifyAll();
}
}
private void notifySchemasAndCatalogsLoad()
{
synchronized(this)
{
_schemasAndCatalogsLoaded = true;
this.notifyAll();
}
}
private int loadStoredProcedures(String catalog, String schema, String procNamePattern, int progress)
{
long start = 0, finish = 0;
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_PROCS_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_PROCS_MSG, beginProgress);
privateLoadStoredProcedures(catalog,
schema,
procNamePattern,
i18n.LOADING_PROCS_MSG,
beginProgress);
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("stored procedures loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading stored procedures", ex);
}
return progress;
}
private int loadTables(String catalog,
String schema,
String tableNamePattern,
String[] types,
int progress)
{
long start = 0, finish = 0;
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_TABLES_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_TABLES_MSG, beginProgress);
privateLoadTables(catalog,
schema,
tableNamePattern,
types,
i18n.LOADING_TABLES_MSG,
beginProgress);
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Tables loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading tables", ex);
}
return progress;
}
private int loadSchemas(int progress)
{
long start = 0, finish = 0;
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_SCHEMAS_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_SCHEMAS_MSG, beginProgress);
privateLoadSchemas();
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Schemas loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading schemas", ex);
}
return progress;
}
private int loadCatalogs(int progress)
{
long start = 0, finish = 0;
try
{
if (s_log.isDebugEnabled()) {
s_log.debug(i18n.LOADING_CATALOGS_MSG);
start = System.currentTimeMillis();
}
int beginProgress = getLoadMethodProgress(progress++);
setProgress(i18n.LOADING_CATALOGS_MSG, beginProgress);
privateLoadCatalogs();
if (s_log.isDebugEnabled()) {
finish = System.currentTimeMillis();
s_log.debug("Catalogs loaded in " + (finish - start) + " ms");
}
}
catch (Exception ex)
{
s_log.error("Error loading catalogs", ex);
}
return progress;
}
private int getLoadMethodProgress(int progress)
{
return (int)(((double)progress) / ((double)LOAD_METHODS_COUNT) * (MAX_PROGRESS));
}
private void setProgress(final String note, final int value)
{
breathing();
if (_session == null || _session.getSessionSheet() == null)
{
return;
}
_session.getSessionSheet().setStatusBarProgress(note, 0, MAX_PROGRESS, value);
if(_inInitialLoad
&& false == _sessionStartupTimeHintShown
&& false == _session.getAlias().getSchemaProperties().isCacheSchemaIndependentMetaData()
&& SQLAliasSchemaProperties.GLOBAL_STATE_LOAD_ALL_CACHE_NONE == _session.getAlias().getSchemaProperties().getGlobalState()
&& _session.getApplication().getSquirrelPreferences().getShowSessionStartupTimeHint()
&& System.currentTimeMillis() - _initalLoadBeginTime > 3000)
{
_sessionStartupTimeHintShown = true;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new SessionStartupTimeHintController(_session);
}
});
}
}
/**
* We found that the UI behaves much nicer at startup if
* loading schema info interupted for little moments.
*/
private void breathing()
{
// In case this is called by the AWT thread, log a message - this is most likey a bug
if (SwingUtilities.isEventDispatchThread()) {
if (s_log.isDebugEnabled()) {
s_log.debug("breathing: ignoring request to sleep the event dispatch thread");
}
return;
}
synchronized(this) {
try
{
wait(50);
}
catch (InterruptedException e)
{
if (s_log.isInfoEnabled()) {
s_log.info("breathing: Interrupted", e);
}
}
}
}
private void privateLoadStoredProcedures(String catalog, String schema, String procNamePattern, final String msg, final int beginProgress)
{
try
{
ProgressCallBack pcb = new ProgressCallBackAdaptor()
{ @Override
public void currentlyLoading(String simpleName)
{
setProgress(msg + " (" + simpleName + ")", beginProgress);
}
};
SchemaLoadInfo[] schemaLoadInfos = _schemaInfoCache.getMatchingSchemaLoadInfos(schema);
for (int i = 0; i < schemaLoadInfos.length; i++)
{
if(schemaLoadInfos[i].loadProcedures)
{
IProcedureInfo[] procedures = _dmd.getProcedures(catalog, schemaLoadInfos[i].schemaName, procNamePattern, pcb);
for (int j = 0; j < procedures.length; j++)
{
_schemaInfoCache.writeToProcedureCache(procedures[j]);
}
}
}
}
catch (Throwable th)
{
s_log.error("Failed to load stored procedures", th);
}
}
private void privateLoadCatalogs()
{
try
{
if(false == _schemaInfoCache.loadSchemaIndependentMetaData())
{
return;
}
_schemaInfoCache.writeCatalogs(_dmd.getCatalogs());
}
catch (Throwable th)
{
s_log.error("failed to load catalog names", th);
}
}
private void privateLoadSchemas()
{
try
{
_session.getApplication().getSessionManager().clearAllowedSchemaCache(_session);
SchemaNameLoadInfo schemaNameLoadInfo = _schemaInfoCache.getSchemaNameLoadInfo();
if(SchemaNameLoadInfo.STATE_DONT_REFERESH_SCHEMA_NAMES == schemaNameLoadInfo.state)
{
return;
}
String[] schemasToWrite;
if(SchemaNameLoadInfo.STATE_REFERESH_SCHEMA_NAMES_FROM_DB == schemaNameLoadInfo.state)
{
schemasToWrite = _session.getApplication().getSessionManager().getAllowedSchemas(_session);
}
else if(SchemaNameLoadInfo.STATE_USES_PROVIDED_SCHEMA_NAMES == schemaNameLoadInfo.state)
{
schemasToWrite = schemaNameLoadInfo.schemaNames;
}
else
{
throw new IllegalArgumentException("Unknown SchemaNameLoadInfo.state = " + schemaNameLoadInfo.state);
}
_schemaInfoCache.writeSchemas(schemasToWrite);
}
catch (Throwable th)
{
s_log.error("failed to load schema names", th);
}
}
public boolean isKeyword(String data)
{
return isKeyword(new CaseInsensitiveString(data));
}
/**
* Retrieve whether the passed string is a keyword.
*
* @param keyword String to check.
*
* @return true if a keyword.
*/
public boolean isKeyword(CaseInsensitiveString data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getKeywordsForReadOnly().containsKey(data);
}
return false;
}
public boolean isDataType(String data)
{
return isDataType(new CaseInsensitiveString(data));
}
/**
* Retrieve whether the passed string is a data type.
*
* @param keyword String to check.
*
* @return true if a data type.
*/
public boolean isDataType(CaseInsensitiveString data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getDataTypesForReadOnly().containsKey(data);
}
return false;
}
public boolean isFunction(String data)
{
return isFunction(new CaseInsensitiveString(data));
}
/**
* Retrieve whether the passed string is a function.
*
* @param keyword String to check.
*
* @return true if a function.
*/
public boolean isFunction(CaseInsensitiveString data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getFunctionsForReadOnly().containsKey(data);
}
return false;
}
public boolean isTable(String data)
{
return isTable(new CaseInsensitiveString(data));
}
public boolean isTable(CaseInsensitiveString data)
{
int tableExtRes = isTableExt(data);
return TABLE_EXT_COLS_LOADED_IN_THIS_CALL == tableExtRes || TABLE_EXT_COLS_LOADED_BEFORE == tableExtRes;
}
/**
* Retrieve whether the passed string is a table and wether this table's colums where loaded before this call.
*
* @param keyword String to check.
*
* @return true if a table.
*/
public int isTableExt(CaseInsensitiveString data)
{
if (!_loading && data != null)
{
if(_schemaInfoCache.getTableNamesForReadOnly().containsKey(data))
{
if (loadColumns(data))
{
return TABLE_EXT_COLS_LOADED_IN_THIS_CALL;
}
else
{
return TABLE_EXT_COLS_LOADED_BEFORE;
}
}
}
return TABLE_EXT_NOT_A_TABLE;
}
public boolean isColumn(String data)
{
return isColumn(new CaseInsensitiveString(data));
}
/**
* Retrieve whether the passed string is a column.
*
* @param keyword String to check.
*
* @return true if a column.
*/
public boolean isColumn(CaseInsensitiveString data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getExtColumnInfosByColumnNameForReadOnly().containsKey(data);
}
return false;
}
/**
* This method returns the case sensitive name of a table as it is stored
* in the database.
* The case sensitive name is needed for example if you want to retrieve
* a table's meta data. Quote from the API doc of DataBaseMetaData.getTables():
* Parameters:
* ...
* tableNamePattern - a table name pattern; must match the table name as it is stored in the database
*
*
* @param data The tables name in arbitrary case.
* @return the table name as it is stored in the database
*/
public String getCaseSensitiveTableName(String data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getTableNamesForReadOnly().get(new CaseInsensitiveString(data));
}
return null;
}
public String getCaseSensitiveProcedureName(String data)
{
if (!_loading && data != null)
{
return _schemaInfoCache.getProcedureNamesForReadOnly().get(new CaseInsensitiveString(data));
}
return null;
}
private void loadKeywords(String msg, int beginProgress)
{
try
{
if(false == _schemaInfoCache.loadSchemaIndependentMetaData())
{
return;
}
setProgress(msg + " (default keywords)", beginProgress);
Hashtable keywordsBuf =
new Hashtable();
for (int i = 0; i < DefaultKeywords.KEY_WORDS.length; i++)
{
String kw = DefaultKeywords.KEY_WORDS[i];
keywordsBuf.put(new CaseInsensitiveString(kw), kw);
}
// Extra keywords that this DBMS supports.
if (_dmd != null)
{
setProgress(msg + " (DB specific keywords)", beginProgress);
String[] sqlKeywords = _dmd.getSQLKeywords();
for (int i = 0; i < sqlKeywords.length; i++)
{
keywordsBuf.put(new CaseInsensitiveString(sqlKeywords[i]), sqlKeywords[i]);
}
String catalogTerm = _dmd.getCatalogTerm();
if (catalogTerm != null) {
keywordsBuf.put(new CaseInsensitiveString(catalogTerm), catalogTerm);
}
String schemaTerm = _dmd.getSchemaTerm();
if (schemaTerm != null) {
keywordsBuf.put(new CaseInsensitiveString(schemaTerm), schemaTerm);
}
String procedureTerm = _dmd.getProcedureTerm();
if (procedureTerm != null) {
keywordsBuf.put(new CaseInsensitiveString(procedureTerm), procedureTerm);
}
}
_schemaInfoCache.writeKeywords(keywordsBuf);
}
catch (Throwable ex)
{
s_log.error("Error occured creating keyword collection", ex);
}
}
private void loadDataTypes(String msg, int beginProgress)
{
try
{
if(false == _schemaInfoCache.loadSchemaIndependentMetaData())
{
return;
}
Hashtable dataTypesBuf =
new Hashtable();
DataTypeInfo[] infos = _dmd.getDataTypes();
for (int i = 0; i < infos.length; i++)
{
String typeName = infos[i].getSimpleName();
dataTypesBuf.put(new CaseInsensitiveString(typeName), typeName);
if(0 == i % 100 )
{
setProgress(msg + " (" + typeName + ")", beginProgress);
}
}
_schemaInfoCache.writeDataTypes(dataTypesBuf);
}
catch (Throwable ex)
{
s_log.error("Error occured creating data types collection", ex);
}
}
private void loadGlobalFunctions(String msg, int beginProgress)
{
if(false == _schemaInfoCache.loadSchemaIndependentMetaData())
{
return;
}
ArrayList buf = new ArrayList();
try
{
setProgress(msg + " (numeric functions)", beginProgress);
buf.addAll(Arrays.asList(_dmd.getNumericFunctions()));
}
catch (Throwable ex)
{
s_log.error("Error", ex);
}
try
{
setProgress(msg + " (string functions)", beginProgress);
buf.addAll(Arrays.asList((_dmd.getStringFunctions())));
}
catch (Throwable ex)
{
s_log.error("Error", ex);
}
try
{
setProgress(msg + " (time/date functions)", beginProgress);
buf.addAll(Arrays.asList(_dmd.getTimeDateFunctions()));
}
catch (Throwable ex)
{
s_log.error("Error", ex);
}
Hashtable functionsBuf =
new Hashtable();
for (int i = 0; i < buf.size(); i++)
{
String func = buf.get(i);
if (func.length() > 0)
{
functionsBuf.put(new CaseInsensitiveString(func) ,func);
}
}
_schemaInfoCache.writeFunctions(functionsBuf);
}
public String[] getKeywords()
{
return _schemaInfoCache.getKeywordsForReadOnly().values().toArray(new String[_schemaInfoCache.getKeywordsForReadOnly().size()]);
}
public String[] getDataTypes()
{
return _schemaInfoCache.getDataTypesForReadOnly().values().toArray(new String[_schemaInfoCache.getDataTypesForReadOnly().size()]);
}
public String[] getFunctions()
{
return _schemaInfoCache.getFunctionsForReadOnly().values().toArray(new String[_schemaInfoCache.getFunctionsForReadOnly().size()]);
}
public String[] getTables()
{
return _schemaInfoCache.getTableNamesForReadOnly().values().toArray(new String[_schemaInfoCache.getTableNamesForReadOnly().size()]);
}
public String[] getCatalogs()
{
return _schemaInfoCache.getCatalogsForReadOnly().toArray(new String[_schemaInfoCache.getCatalogsForReadOnly().size()]);
}
public String[] getSchemas()
{
return _schemaInfoCache.getSchemasForReadOnly().toArray(new String[_schemaInfoCache.getSchemasForReadOnly().size()]);
}
public ITableInfo[] getITableInfos()
{
return getITableInfos(null, null);
}
public ITableInfo[] getITableInfos(String catalog, String schema)
{
return getITableInfos(catalog, schema, null);
}
public ITableInfo[] getITableInfos(String catalog, String schema, String simpleName)
{
return getITableInfos(catalog, schema, new ObjFilterMatcher(simpleName), null);
}
public ITableInfo[] getITableInfos(String catalog, String schema, ObjFilterMatcher filterMatcher, String[] types)
{
ArrayList ret = new ArrayList();
if (null != types)
{
// By default null == types we return only cached types
ITableInfo[] tableInfosForUncachedTypes = getTableInfosForUncachedTypes(catalog, schema, filterMatcher, types);
ret.addAll(Arrays.asList(tableInfosForUncachedTypes));
}
List tis =
_schemaInfoCache.getITableInfosForReadOnly();
for(ITableInfo iTableInfo : tis)
{
if(null != catalog &&
false == catalog.equalsIgnoreCase(iTableInfo.getCatalogName()) &&
false == fulfillsPlatformDependendMatches(iTableInfo, catalog)
)
{
continue;
}
if(null != schema && false == schema.equalsIgnoreCase(iTableInfo.getSchemaName()) )
{
continue;
}
if(false == SchemaInfoCache.containsType(types, iTableInfo.getType()))
{
continue;
}
if(filterMatcher.matches(iTableInfo.getSimpleName()))
{
ret.add(iTableInfo);
}
// if(null != tableNamePattern && false == tableNamePattern.endsWith("%") && false == iTableInfo.getSimpleName().equals(tableNamePattern))
// {
// continue;
// }
//
// if(null != tableNamePattern && tableNamePattern.endsWith("%"))
// {
// String tableNameBegin = tableNamePattern.substring(0, tableNamePattern.length() - 1);
// if(false == iTableInfo.getSimpleName().startsWith(tableNameBegin))
// {
// continue;
// }
// }
//
// ret.add(iTableInfo);
}
return ret.toArray(new ITableInfo[ret.size()]);
}
private boolean fulfillsPlatformDependendMatches(ITableInfo iTableInfo, String catalog)
{
if(SQLDatabaseMetaData.DriverMatch.isComHttxDriver(_session.getSQLConnection()))
{
return ( iTableInfo.getCatalogName()==null && "\".\"".equals(catalog));
}
else
{
return false;
}
}
private ITableInfo[] getTableInfosForUncachedTypes(String catalog, String schema, ObjFilterMatcher filterMatcher, String[] types)
{
try
{
ArrayList missingTypes = new ArrayList();
for (int i = 0; i < types.length; i++)
{
if(false == _schemaInfoCache.isCachedTableType(types[i]))
{
missingTypes.add(types[i]);
}
}
if(0 < missingTypes.size())
{
try
{
String[] buf = missingTypes.toArray(new String[missingTypes.size()]);
ProgressCallBack pcb = new ProgressCallBackAdaptor()
{
@Override
public void currentlyLoading(String simpleName)
{
StringBuilder tmp = new StringBuilder(i18n.LOADING_TABLES_MSG);
tmp.append(" (");
tmp.append(simpleName);
tmp.append(")");
setProgress(tmp.toString(), 1);
}
};
return _dmd.getTables(catalog, schema, filterMatcher.getMetaDataMatchString(), buf, pcb);
}
finally
{
_session.getSessionSheet().setStatusBarProgressFinished();
}
}
}
catch (SQLException e)
{
s_log.error("Error loading uncached tables", e);
}
return new ITableInfo[0];
}
public IProcedureInfo[] getStoredProceduresInfos(String catalog, String schema)
{
return getStoredProceduresInfos(catalog, schema, new ObjFilterMatcher());
}
public IProcedureInfo[] getStoredProceduresInfos(String catalog, String schema, ObjFilterMatcher filterMatcher)
{
ArrayList ret = new ArrayList();
for (Iterator i =
_schemaInfoCache.getIProcedureInfosForReadOnly().keySet().iterator(); i.hasNext();)
{
IProcedureInfo iProcInfo = i.next();
boolean toAdd = true;
if (null != catalog && false == catalog.equalsIgnoreCase(iProcInfo.getCatalogName()))
{
toAdd = false;
}
if (null != schema && false == schema.equalsIgnoreCase(iProcInfo.getSchemaName()))
{
toAdd = false;
}
if(false == filterMatcher.matches(iProcInfo.getSimpleName()))
{
toAdd = false;
}
if (toAdd)
{
ret.add(iProcInfo);
}
}
return ret.toArray(new IProcedureInfo[ret.size()]);
}
public boolean isLoaded()
{
return _loaded;
}
private void privateLoadTables(String catalog,
String schema,
String tableNamePattern,
String[] types,
final String msg,
final int beginProgress)
{
try
{
ProgressCallBack pcb = new ProgressCallBackAdaptor()
{ @Override
public void currentlyLoading(String simpleName)
{
setProgress(msg + " (" + simpleName + ")", beginProgress);
}
};
SchemaLoadInfo[] schemaLoadInfos =
_schemaInfoCache.getMatchingSchemaLoadInfos(schema, types);
for (int i = 0; i < schemaLoadInfos.length; i++)
{
ITableInfo[] infos = _dmd.getTables(catalog,
schemaLoadInfos[i].schemaName, tableNamePattern,
schemaLoadInfos[i].tableTypes, pcb);
_schemaInfoCache.writeToTableCache(infos);
}
}
catch (Throwable th)
{
s_log.error("failed to load table names", th);
}
}
/**
*
* @return true only when the table's columns are loaded within this call.
*/
private boolean loadColumns(final CaseInsensitiveString tableName)
{
try
{
if(_schemaInfoCache.didTryLoadingColumns(tableName))
{
return false;
}
if (_session.getProperties().getLoadColumnsInBackground())
{
if(_tablesLoadingColsInBackground.containsKey(tableName))
{
return false;
}
// Note: A CaseInsensitiveString can be a mutable string.
// In fact it is a mutable string here because this is usually called from
// within Syntax coloring which uses a mutable string.
final CaseInsensitiveString imutableString = new CaseInsensitiveString(tableName.toString());
_tablesLoadingColsInBackground.put(imutableString, imutableString);
_session.getApplication().getThreadPool().addTask(new Runnable()
{
public void run()
{
try
{
accessDbToLoadColumns(imutableString);
}
catch (Throwable th)
{
s_log.error("failed to load columns", th);
}
finally
{
_tablesLoadingColsInBackground.remove(imutableString);
}
}
});
}
else
{
accessDbToLoadColumns(tableName);
}
}
catch (Throwable th)
{
s_log.error("failed to load table names", th);
}
return true;
}
private void accessDbToLoadColumns(CaseInsensitiveString tableName)
throws SQLException
{
if (null == _dmd)
{
s_log.warn(s_stringMgr.getString("SchemaInfo.UnableToLoadColumns", tableName));
return;
}
String name = getCaseSensitiveTableName(tableName.toString());
TableInfo ti = new TableInfo(null, null, name, "TABLE", null, _dmd);
try
{
TableColumnInfo[] infos = _dmd.getColumnInfo(ti);
_schemaInfoCache.writeColumsToCache(infos, tableName);
}
catch (Throwable th)
{
_schemaInfoCache.writeColumsNotAccessible(th, tableName);
}
}
public ExtendedColumnInfo[] getExtendedColumnInfos(String tableName)
{
return getExtendedColumnInfos(null, null, tableName);
}
public ExtendedColumnInfo[] getExtendedColumnInfos(String catalog, String schema, String tableName)
{
CaseInsensitiveString cissTableName = new CaseInsensitiveString(tableName);
loadColumns(cissTableName);
List extColInfo = _schemaInfoCache.getExtendedColumnInfosForReadOnly(cissTableName);
if (null == extColInfo)
{
return new ExtendedColumnInfo[0];
}
if (null == catalog && null == schema)
{
return extColInfo.toArray(new ExtendedColumnInfo[extColInfo.size()]);
}
else
{
ArrayList ret = new ArrayList();
for (int i = 0; i < extColInfo.size(); i++)
{
ExtendedColumnInfo extendedColumnInfo = extColInfo.get(i);
boolean toAdd = true;
if (null != catalog && null != extendedColumnInfo.getCatalog() && false == catalog.equalsIgnoreCase(extendedColumnInfo.getCatalog()))
{
toAdd = false;
}
if (null != schema && null != extendedColumnInfo.getSchema() && false == schema.equalsIgnoreCase(extendedColumnInfo.getSchema()))
{
toAdd = false;
}
if (toAdd)
{
ret.add(extendedColumnInfo);
}
}
return ret.toArray(new ExtendedColumnInfo[ret.size()]);
}
}
public void dispose()
{
// The SessionManager is global to SQuirreL.
// If we don't remove the listeners the
// Session won't get Garbeage Collected.
_session.getApplication().getSessionManager().removeSessionListener(_sessionListener);
}
public boolean isProcedure(CaseInsensitiveString data)
{
return _schemaInfoCache.getProcedureNamesForReadOnly().containsKey(data);
}
public void reload(IDatabaseObjectInfo doi)
{
reload(doi, true);
}
/**
* @param fireSchemaInfoUpdate Should only be false when the caller makes sure fireSchemaInfoUpdate() is called later.
*/
void reload(IDatabaseObjectInfo doi, boolean fireSchemaInfoUpdate)
{
boolean doReloadAll = false;
try
{
synchronized (this)
{
if(_loading)
{
return;
}
_loading = true;
_schemasAndCatalogsLoaded = false;
_tablesLoaded = false;
_storedProceduresLoaded = false;
}
if (doi instanceof ITableInfo)
{
ITableInfo ti = (ITableInfo) doi;
DatabaseObjectType dot = ti.getDatabaseObjectType();
String[] types = null;
if (DatabaseObjectType.TABLE == dot)
{
types = new String[]{"TABLE"};
}
else if (DatabaseObjectType.VIEW == dot)
{
types = new String[]{"VIEW"};
}
_schemaInfoCache.clearTables(ti.getCatalogName(), ti.getSchemaName(), ti.getSimpleName(), types);
loadTables(ti.getCatalogName(), ti.getSchemaName(), ti.getSimpleName(), types, 1);
}
else if(doi instanceof IProcedureInfo)
{
IProcedureInfo pi = (IProcedureInfo) doi;
_schemaInfoCache.clearStoredProcedures(pi.getCatalogName(), pi.getSchemaName(), pi.getSimpleName());
loadStoredProcedures(pi.getCatalogName(), pi.getSchemaName(), pi.getSimpleName(), 1);
}
else if(DatabaseObjectType.TABLE_TYPE_DBO == doi.getDatabaseObjectType())
{
// load all table types with catalog = doi.getCatalog() and schema = doi.getSchema()
_schemaInfoCache.clearTables(doi.getCatalogName(), doi.getSchemaName(), null, null);
loadTables(doi.getCatalogName(), doi.getSchemaName(), null, null, 0);
}
else if(DatabaseObjectType.TABLE == doi.getDatabaseObjectType())
{
// load tables with catalog = doi.getCatalog() and schema = doi.getSchema()
_schemaInfoCache.clearTables(doi.getCatalogName(), doi.getSchemaName(), null, new String[]{"TABLE"});
loadTables(doi.getCatalogName(), doi.getSchemaName(), null, new String[]{"TABLE"}, 1);
}
else if(DatabaseObjectType.VIEW == doi.getDatabaseObjectType())
{
// load views with catalog = doi.getCatalog() and schema = doi.getSchema()
_schemaInfoCache.clearTables(doi.getCatalogName(), doi.getSchemaName(), null, new String[]{"VIEW"});
loadTables(doi.getCatalogName(), doi.getSchemaName(), null, new String[]{"VIEW"}, 1);
}
else if(DatabaseObjectType.PROCEDURE == doi.getDatabaseObjectType() || DatabaseObjectType.PROC_TYPE_DBO == doi.getDatabaseObjectType())
{
_schemaInfoCache.clearStoredProcedures(doi.getCatalogName(), doi.getSchemaName(), null);
loadStoredProcedures(doi.getCatalogName(), doi.getSchemaName(), null, 1);
}
else if(DatabaseObjectType.SCHEMA == doi.getDatabaseObjectType())
{
//int progress = loadSchemas(1);
// load tables with catalog = null
_schemaInfoCache.clearTables(null, doi.getSchemaName(), null, null);
int progress = loadTables(null, doi.getSchemaName(), null, null, 1);
// load procedures with catalog = null
_schemaInfoCache.clearStoredProcedures(null, doi.getSchemaName(), null);
loadStoredProcedures(null, doi.getSchemaName(), null, progress);
}
else if(DatabaseObjectType.CATALOG == doi.getDatabaseObjectType())
{
//int progress = loadCatalogs(1);
// load tables with schema = null
_schemaInfoCache.clearTables(doi.getCatalogName(), null, null, null);
int progress = loadTables(doi.getCatalogName(), null, null, null, 1);
// load procedures with schema = null
_schemaInfoCache.clearStoredProcedures(doi.getCatalogName(), null, null);
loadStoredProcedures(doi.getCatalogName(), null, null, progress);
}
else if(DatabaseObjectType.SESSION == doi.getDatabaseObjectType())
{
doReloadAll = true;
}
// If called here it is called far to often and restoring selection in the
// Object tree doesn't work.
//fireSchemaInfoUpdate();
}
finally
{
_session.getSessionSheet().setStatusBarProgressFinished();
_loading = false;
_schemasAndCatalogsLoaded = true;
_tablesLoaded = true;
_storedProceduresLoaded = true;
notifySchemasAndCatalogsLoad();
notifyTablesLoaded();
notifyStoredProceduresLoaded();
if(doReloadAll)
{
reloadAll(fireSchemaInfoUpdate);
}
else
{
if(fireSchemaInfoUpdate)
{
fireSchemaInfoUpdate();
}
}
}
}
public void fireSchemaInfoUpdate()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
SchemaInfoUpdateListener[] listeners =
_listeners.toArray(new SchemaInfoUpdateListener[0]);
for (int i = 0; i < listeners.length; i++)
{
listeners[i].schemaInfoUpdated();
}
}
});
}
public void addSchemaInfoUpdateListener(SchemaInfoUpdateListener l)
{
_listeners.remove(l);
_listeners.add(l);
}
public void removeSchemaInfoUpdateListener(SchemaInfoUpdateListener l)
{
_listeners.remove(l);
}
public void refershCacheForSimpleTableName(String simpleTableName)
{
refershCacheForSimpleTableName(simpleTableName, true);
}
/**
* @param fireSchemaInfoUpdate Should only be false when the caller makes sure fireSchemaInfoUpdate() is called later.
*/
void refershCacheForSimpleTableName(String simpleTableName, boolean fireSchemaInfoUpdate)
{
HashMap caseSensitiveTableNames = new HashMap();
CaseInsensitiveString caseInsensitiveTableName = new CaseInsensitiveString(simpleTableName);
String caseSensitiveTableName = _schemaInfoCache.getTableNamesForReadOnly().get(caseInsensitiveTableName);
caseSensitiveTableNames.put(caseSensitiveTableName, caseSensitiveTableName);
////////////////////////////////////////////////////////////////////////
// Reload all matching table types
for(Iterator i=caseSensitiveTableNames.keySet().iterator(); i.hasNext();)
{
String buf = i.next();
TableInfo ti = new TableInfo(null, null, buf, null, null, _dmd);
reload(ti, fireSchemaInfoUpdate);
}
//
////////////////////////////////////////////////////////////////////////
// is done in reload
// if(fireSchemaInfoUpdate)
// {
// fireSchemaInfoUpdate();
// }
}
public void refreshCacheForSimpleProcedureName(String simpleProcName)
{
refreshCacheForSimpleProcedureName(simpleProcName, true);
}
/**
* @param fireSchemaInfoUpdate Should only be false when the caller makes sure fireSchemaInfoUpdate() is called later.
*/
void refreshCacheForSimpleProcedureName(String simpleProcName, boolean fireSchemaInfoUpdate)
{
HashMap caseSensitiveProcNames = new HashMap();
CaseInsensitiveString caseInsensitiveProcName = new CaseInsensitiveString(simpleProcName);
String caseSensitiveProcName = _schemaInfoCache.getProcedureNamesForReadOnly().remove(caseInsensitiveProcName);
caseSensitiveProcNames.put(caseSensitiveProcName, caseSensitiveProcName);
////////////////////////////////////////////////////////////////////////
// Reload all matching procedure types
for(Iterator i=caseSensitiveProcNames.keySet().iterator(); i.hasNext();)
{
String buf = i.next();
ProcedureInfo pi = new ProcedureInfo(null, null, buf, null, DatabaseMetaData.procedureResultUnknown, _dmd);
reload(pi, fireSchemaInfoUpdate);
}
//
////////////////////////////////////////////////////////////////////////
// is done in reload
// if(fireSchemaInfoUpdate)
// {
// fireSchemaInfoUpdate();
// }
}
public void waitTillSchemasAndCatalogsLoaded()
{
try
{
synchronized (this)
{
while (false == _schemasAndCatalogsLoaded)
{
this.wait();
}
}
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
public void waitTillTablesLoaded()
{
try
{
synchronized (this)
{
while (false == _tablesLoaded)
{
this.wait();
}
}
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
public void waitTillStoredProceduresLoaded()
{
try
{
synchronized (this)
{
while (false == _storedProceduresLoaded)
{
this.wait();
}
}
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy