/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.debug; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import com.servoy.base.query.BaseAbstractBaseQuery; import com.servoy.j2db.dataprocessing.Blob; import com.servoy.j2db.dataprocessing.IDataServer; import com.servoy.j2db.dataprocessing.IDataSet; import com.servoy.j2db.dataprocessing.ISQLStatement; import com.servoy.j2db.dataprocessing.ITrackingSQLStatement; import com.servoy.j2db.dataprocessing.QueryData; import com.servoy.j2db.dataprocessing.TableFilter; import com.servoy.j2db.persistence.ITable; import com.servoy.j2db.persistence.QuerySet; import com.servoy.j2db.persistence.RepositoryException; import com.servoy.j2db.query.ISQLQuery; import com.servoy.j2db.query.ISQLSelect; import com.servoy.j2db.query.ISQLUpdate; import com.servoy.j2db.query.QuerySelect; import com.servoy.j2db.server.shared.PerformanceTiming; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.ServoyException; /** * A wrapper/proxy around the actual {@link IDataServer} to profile queries to the database. * * @author jcompagner * @since 6.0 * */ public class ProfileDataServer implements IDataServer { private final IDataServer dataserver; private final List<IDataCallListener> listeners = new ArrayList<IDataCallListener>(); public ProfileDataServer(IDataServer dataserver) { this.dataserver = dataserver; } /** * @param msg * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IMaintenanceServer#logMessage(java.lang.String) */ public void logMessage(String msg) throws RemoteException { dataserver.logMessage(msg); } /** * @param client_id * @param server_name * @param table_name * @param pkhashkeys * @param lockSelect * @param transaction_id * @param filters * @param chunkSize * @return * @throws RemoteException * @throws RepositoryException * @see com.servoy.j2db.dataprocessing.ILockServer#acquireLocks(java.lang.String, java.lang.String, java.lang.String, java.util.Set, com.servoy.j2db.query.QuerySelect, java.lang.String, java.util.ArrayList, int) */ public IDataSet acquireLocks(String client_id, String server_name, String table_name, Set<Object> pkhashkeys, QuerySelect lockSelect, String transaction_id, ArrayList<TableFilter> filters, int chunkSize) throws RemoteException, RepositoryException { long startTime = System.currentTimeMillis(); try { return dataserver.acquireLocks(client_id, server_name, table_name, pkhashkeys, lockSelect, transaction_id, filters, chunkSize); } finally { informListeners("Lock Aquired", server_name + '.' + table_name, lockSelect != null ? lockSelect.toString() : null, transaction_id, startTime, pkhashkeys.toArray()); } } /** * @param server_name * @param table_name * @param lockSelect * @param transaction_id * @param startTime */ private void informListeners(String name, String ds, String sql, String transaction_id, long startTime, Object[] arguments) { if (listeners.size() > 0) { long endTime = System.currentTimeMillis(); String argumentString = null; if (arguments != null && arguments.length > 0) { if (arguments[0] instanceof Object[] && arguments.length == 1) { argumentString = BaseAbstractBaseQuery.toString(arguments[0]); } else { argumentString = BaseAbstractBaseQuery.toString(arguments); } } DataCallProfileData pd = new DataCallProfileData(name, ds, transaction_id, startTime, endTime, sql, argumentString, 1); listeners.get(listeners.size() - 1).addDataCallProfileData(pd); } } /** * @return * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IMaintenanceServer#isInGlobalMaintenanceMode() */ public boolean isInGlobalMaintenanceMode() throws RemoteException { return dataserver.isInGlobalMaintenanceMode(); } /** * @param maintenanceMode * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IMaintenanceServer#setGlobalMaintenanceMode(boolean) */ public void setGlobalMaintenanceMode(boolean maintenanceMode) throws RemoteException { dataserver.setGlobalMaintenanceMode(maintenanceMode); } /** * @return * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IMaintenanceServer#isInServerMaintenanceMode() */ public boolean isInServerMaintenanceMode() throws RemoteException { return dataserver.isInServerMaintenanceMode(); } /** * @param maintenanceMode * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IMaintenanceServer#setServerMaintenanceMode(boolean) */ public void setServerMaintenanceMode(boolean maintenanceMode) throws RemoteException { dataserver.setServerMaintenanceMode(maintenanceMode); } /** * @param client_id * @param server_name * @param table_name * @param pkhashkeys * @return * @throws RemoteException * @throws RepositoryException * @see com.servoy.j2db.dataprocessing.ILockServer#releaseLocks(java.lang.String, java.lang.String, java.lang.String, java.util.Set) */ public boolean releaseLocks(String client_id, String server_name, String table_name, Set<Object> pkhashkeys) throws RemoteException, RepositoryException { long startTime = System.currentTimeMillis(); try { return dataserver.releaseLocks(client_id, server_name, table_name, pkhashkeys); } finally { informListeners("Lock Released", server_name + '.' + table_name, null, null, startTime, pkhashkeys.toArray()); } } /** * @param client_id * @param server_name * @param transaction_id * @param sqlSelect * @param filters * @param distinctInMemory * @param startRow * @param rowsToRetrieve * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, com.servoy.j2db.query.ISQLSelect, java.util.ArrayList, boolean, int, int) */ public IDataSet performQuery(String client_id, String server_name, String transaction_id, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, boolean distinctInMemory, int startRow, int rowsToRetrieve) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, transaction_id, sqlSelect, filters, distinctInMemory, startRow, rowsToRetrieve); } finally { QuerySet set = getSQLQuerySet(server_name, sqlSelect, filters, startRow, rowsToRetrieve, false); informListeners("Query", server_name, set.getSelect().getSql(), transaction_id, startTime, set.getSelect().getParameters()); } } /** * @param client_id * @param server_name * @param driverTableName * @param transaction_id * @param sql * @param questiondata * @param startRow * @param rowsToRetrieve * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[], int, int) */ public IDataSet performQuery(String client_id, String server_name, String driverTableName, String transaction_id, String sql, Object[] questiondata, int startRow, int rowsToRetrieve) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, driverTableName, transaction_id, sql, questiondata, startRow, rowsToRetrieve); } finally { informListeners("Query", server_name, sql, transaction_id, startTime, questiondata); } } /** * @param client_id * @param server_name * @param transaction_id * @param sqlSelect * @param filters * @param distinctInMemory * @param startRow * @param rowsToRetrieve * @param type * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, com.servoy.j2db.query.ISQLSelect, java.util.ArrayList, boolean, int, int, int) */ public IDataSet performQuery(String client_id, String server_name, String transaction_id, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, boolean distinctInMemory, int startRow, int rowsToRetrieve, int type) throws ServoyException, RemoteException { return performQuery(client_id, server_name, transaction_id, sqlSelect, filters, distinctInMemory, startRow, rowsToRetrieve, type, null); } public IDataSet performQuery(String client_id, String server_name, String transaction_id, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, boolean distinctInMemory, int startRow, int rowsToRetrieve, int type, ITrackingSQLStatement trackingInfo) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, transaction_id, sqlSelect, filters, distinctInMemory, startRow, rowsToRetrieve, type, trackingInfo); } finally { QuerySet set = getSQLQuerySet(server_name, sqlSelect, filters, startRow, rowsToRetrieve, false); informListeners("Query[" + PerformanceTiming.getTypeString(type) + ']', server_name, set.getSelect().getSql(), transaction_id, startTime, set.getSelect().getParameters()); } } /** * @param client_id * @param server_name * @param driverTableName * @param transaction_id * @param sql * @param questiondata * @param startRow * @param rowsToRetrieve * @param type * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[], int, int, int) */ public IDataSet performQuery(String client_id, String server_name, String driverTableName, String transaction_id, String sql, Object[] questiondata, int startRow, int rowsToRetrieve, int type) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, driverTableName, transaction_id, sql, questiondata, startRow, rowsToRetrieve, type); } finally { informListeners("Query[" + PerformanceTiming.getTypeString(type) + ']', server_name, sql, transaction_id, startTime, questiondata); } } /** * @param client_id * @param server_name * @param transaction_id * @param sqlSelect * @param filters * @param distinctInMemory * @param startRow * @param rowsToRetrieve * @param updateIdleTimestamp * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, com.servoy.j2db.query.ISQLSelect, java.util.ArrayList, boolean, int, int, boolean) */ public IDataSet performQuery(String client_id, String server_name, String transaction_id, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, boolean distinctInMemory, int startRow, int rowsToRetrieve, boolean updateIdleTimestamp) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, transaction_id, sqlSelect, filters, distinctInMemory, startRow, rowsToRetrieve, updateIdleTimestamp); } finally { QuerySet set = getSQLQuerySet(server_name, sqlSelect, filters, startRow, rowsToRetrieve, false); informListeners("Query", server_name, set.getSelect().getSql(), transaction_id, startTime, set.getSelect().getParameters()); } } /** * @param client_id * @param server_name * @param driverTableName * @param transaction_id * @param sql * @param questiondata * @param startRow * @param rowsToRetrieve * @param updateIdleTimestamp * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performQuery(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[], int, int, boolean) */ public IDataSet performQuery(String client_id, String server_name, String driverTableName, String transaction_id, String sql, Object[] questiondata, int startRow, int rowsToRetrieve, boolean updateIdleTimestamp) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, driverTableName, transaction_id, sql, questiondata, startRow, rowsToRetrieve, updateIdleTimestamp); } finally { informListeners("Query", server_name, sql, transaction_id, startTime, questiondata); } } /** * @param client_id * @param server_name * @param driverTableName * @param transaction_id * @param startRow * @param rowsToRetrieve * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performCustomQuery(java.lang.String, java.lang.String, java.lang.String, java.lang.String, ISQLSelect, int, int) */ public IDataSet performCustomQuery(String client_id, String server_name, String driverTableName, String transaction_id, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, int startRow, int rowsToRetrieve) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performCustomQuery(client_id, server_name, driverTableName, transaction_id, sqlSelect, filters, startRow, rowsToRetrieve); } finally { QuerySet set = getSQLQuerySet(server_name, sqlSelect, null, 0, 1, false); informListeners("Query", server_name, set.getSelect().getSql(), transaction_id, startTime, set.getSelect().getParameters()); } } public IDataSet[] performQuery(String client_id, String server_name, String transaction_id, QueryData[] array) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performQuery(client_id, server_name, transaction_id, array); } finally { int counter = 0; for (QueryData queryData : array) { QuerySet set = getSQLQuerySet(server_name, queryData.getSqlSelect(), queryData.getFilters(), queryData.getStartRow(), queryData.getRowsToRetrieve(), false); informListeners(PerformanceTiming.getTypeString(queryData.getType()) + " Combined Query[" + (counter++) + '/' + array.length + ']', server_name, set.getSelect().getSql(), transaction_id, startTime, set.getSelect().getParameters()); } } } /** * @param action * @param server_name * @param tableName * @param pkColumnData * @param tid * @param sql * @param questiondata * @return * @throws RemoteException * @throws RepositoryException * @see com.servoy.j2db.dataprocessing.IDataServer#createSQLStatement(int, java.lang.String, java.lang.String, java.lang.Object[], java.lang.String, java.lang.String, java.lang.Object[]) */ public ISQLStatement createSQLStatement(int action, String server_name, String tableName, Object[] pkColumnData, String tid, String sql, Object[] questiondata) throws RemoteException, RepositoryException { long startTime = System.currentTimeMillis(); try { return dataserver.createSQLStatement(action, server_name, tableName, pkColumnData, tid, sql, questiondata); } finally { informListeners("Query", server_name, sql, tid, startTime, questiondata); } } public ISQLStatement createSQLStatement(int action, String server_name, String tableName, Object[] pkColumnData, String tid, ISQLUpdate sqlUpdate, ArrayList<TableFilter> filters) throws RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.createSQLStatement(action, server_name, tableName, pkColumnData, tid, sqlUpdate, filters); } finally { QuerySet set; try { set = getSQLQuerySet(server_name, sqlUpdate, null, -1, -1, false); informListeners("Query", server_name, set.getUpdate().getSql(), tid, startTime, set.getUpdate().getParameters()); } catch (RepositoryException e) { Debug.error(e); } } } /** * @param client_id * @param server_name * @param tableName * @param pks * @param action * @param transaction_id * @return * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#notifyDataChange(java.lang.String, java.lang.String, java.lang.String, com.servoy.j2db.dataprocessing.IDataSet, int, java.lang.String) */ public boolean notifyDataChange(String client_id, String server_name, String tableName, IDataSet pks, int action, String transaction_id) throws RemoteException { return dataserver.notifyDataChange(client_id, server_name, tableName, pks, action, transaction_id); } /** * @param clientId * @param statements * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#performUpdates(java.lang.String, com.servoy.j2db.dataprocessing.ISQLStatement[]) */ public Object[] performUpdates(String clientId, ISQLStatement[] statements) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.performUpdates(clientId, statements); } finally { for (ISQLStatement statement : statements) { QuerySet set = getSQLQuerySet(statement.getServerName(), statement.getUpdate(), null, -1, -1, false); informListeners("Update", statement.getServerName() + '.' + statement.getTableName(), set.getUpdate().getSql(), statement.getTransactionID(), startTime, set.getUpdate().getParameters()); } } } /** * @param clientId * @param serverName * @param blobSelect * @param filters * @param tid * @return * @throws RepositoryException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#getBlob(java.lang.String, java.lang.String, com.servoy.j2db.query.ISQLSelect, java.util.ArrayList, java.lang.String) */ public Blob getBlob(String clientId, String serverName, ISQLSelect blobSelect, ArrayList<TableFilter> filters, String tid) throws RepositoryException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.getBlob(clientId, serverName, blobSelect, filters, tid); } finally { QuerySet set = getSQLQuerySet(serverName, blobSelect, filters, 0, 1, false); informListeners("BlobLoad", serverName, set.getSelect().getSql(), tid, startTime, set.getSelect().getParameters()); } } /** * @param clientId * @param server_name * @return * @throws RepositoryException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#startTransaction(java.lang.String, java.lang.String) */ public String startTransaction(String clientId, String server_name) throws RepositoryException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.startTransaction(clientId, server_name); } finally { informListeners("StartTransaction", server_name, null, null, startTime, null); } } /** * @param client_id * @param transaction_id * @param commit * @return * @throws RepositoryException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#endTransactions(java.lang.String, java.lang.String[], boolean) */ public boolean endTransactions(String client_id, String[] transaction_id, boolean commit) throws RepositoryException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.endTransactions(client_id, transaction_id, commit); } finally { informListeners("EndTransactions", null, null, Arrays.toString(transaction_id), startTime, null); } } /** * @param serverName * @param tableName * @param columnName * @param columnInfoID * @return * @throws RepositoryException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#getNextSequence(java.lang.String, java.lang.String, java.lang.String, int) */ public Object getNextSequence(String serverName, String tableName, String columnName, int columnInfoID) throws RepositoryException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.getNextSequence(serverName, tableName, columnName, columnInfoID); } finally { informListeners("GetSequence", serverName + '.' + tableName, columnName, null, startTime, null); } } /** * @param client_id * @param set * @param dataSource * @param serverName * @param tableName * @param tid * @param types * @return * @throws ServoyException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#insertDataSet(java.lang.String, com.servoy.j2db.dataprocessing.IDataSet, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int[], String[]) */ public ITable insertDataSet(String client_id, IDataSet set, String dataSource, String serverName, String tableName, String tid, int[] types, String[] pkNames) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.insertDataSet(client_id, set, dataSource, serverName, tableName, tid, types, pkNames); } finally { informListeners("FillDataSource", dataSource, null, null, startTime, null); } } /** * @param client_id * @param queryServerName * @param queryTid * @param sqlSelect the sql statement * @param filters filters to apply * @param distinctInMemory require distinct values but query is not distinct * @param startRow start row normally 0 * @param rowsToRetrieve rowsToRetrieve number of rows to retrieve * @param type query type * @param dataSource * @param targetServerName * @param targetTableName when null a temporary table will be created * @param targetTid transaction id * @param types the column types * @return the table where the set was inserted into * @throws ServoyException * @throws RemoteException */ public ITable insertQueryResult(String client_id, String queryServerName, String queryTid, ISQLSelect sqlSelect, ArrayList<TableFilter> filters, boolean distinctInMemory, int startRow, int rowsToRetrieve, int type, String dataSource, String targetServerName, String targetTableName, String targetTid, int[] types, String[] pkNames) throws ServoyException, RemoteException { long startTime = System.currentTimeMillis(); try { return dataserver.insertQueryResult(client_id, queryServerName, queryTid, sqlSelect, filters, distinctInMemory, startRow, rowsToRetrieve, type, dataSource, targetServerName, targetTableName, targetTid, types, pkNames); } finally { QuerySet set = getSQLQuerySet(queryServerName, sqlSelect, filters, startRow, rowsToRetrieve, false); informListeners("FillDataSource", queryServerName, set.getSelect().getSql(), queryTid, startTime, set.getSelect().getParameters()); } } /** * @param client_id * @param serverName * @param tableName * @throws RemoteException * @throws RepositoryException * @see com.servoy.j2db.dataprocessing.IDataServer#dropTemporaryTable(java.lang.String, java.lang.String, java.lang.String) */ public void dropTemporaryTable(String client_id, String serverName, String tableName) throws RemoteException, RepositoryException { long startTime = System.currentTimeMillis(); try { dataserver.dropTemporaryTable(client_id, serverName, tableName); } finally { informListeners("DropTempTable", serverName + '.' + tableName, null, null, startTime, null); } } /** * @param client_id * @param serverName * @param tableName * @throws RemoteException * @throws RepositoryException * @see com.servoy.j2db.dataprocessing.IDataServer#addClientAsTableUser(java.lang.String, java.lang.String, java.lang.String) */ public void addClientAsTableUser(String client_id, String serverName, String tableName) throws RemoteException, RepositoryException { dataserver.addClientAsTableUser(client_id, serverName, tableName); } /** * @param serverName * @param sqlQuery * @param filters * @param startRow * @param rowsToRetrieve * @param forceQualifyColumns * @return * @throws RepositoryException * @throws RemoteException * @see com.servoy.j2db.dataprocessing.IDataServer#getSQLQuerySet(java.lang.String, com.servoy.j2db.query.ISQLQuery, java.util.ArrayList, int, int, boolean) */ public QuerySet getSQLQuerySet(String serverName, ISQLQuery sqlQuery, ArrayList<TableFilter> filters, int startRow, int rowsToRetrieve, boolean forceQualifyColumns) throws RepositoryException, RemoteException { return dataserver.getSQLQuerySet(serverName, sqlQuery, filters, startRow, rowsToRetrieve, forceQualifyColumns); } public void addDataCallListener(IDataCallListener listener) { listeners.add(listener); } public void removeDataCallListener(IDataCallListener listener) { listeners.remove(listener); } }