--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.diag.StatementDuration\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.diag;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.FileNotFoundException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.FileInputStream;\r
+import java.io.Reader;\r
+import java.util.Hashtable;\r
+import java.util.Enumeration;\r
+import java.util.Map;\r
+import java.util.Properties;\r
+import java.sql.NClob;\r
+import java.sql.ResultSetMetaData;\r
+import java.sql.RowId;\r
+import java.sql.SQLException;\r
+import java.sql.SQLXML;\r
+import java.sql.Timestamp;\r
+import java.sql.Types;\r
+\r
+import org.apache.derby.vti.VTITemplate;\r
+import org.apache.derby.iapi.sql.ResultColumnDescriptor;\r
+import org.apache.derby.impl.jdbc.EmbedResultSetMetaData;\r
+import org.apache.derby.iapi.reference.Limits;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+\r
+/**\r
+ \r
+\r
+ StatementDuration is a virtual table which\r
+ can be used to analyze the execution duration of the statements\r
+ of "interest" in db2j.<!-- -->log or a specified file when\r
+ db2j.<!-- -->language.<!-- -->logStatementText=true.\r
+ \r
+\r
+ <P>A limitation is that, for each transaction ID,\r
+ a row will not be returned for the last statement with that\r
+ transaction id. (Transaction IDs change within a connection after\r
+ a commit or rollback, if the transaction that just ended modified data.)\r
+\r
+ <P>The execution duration is the time between the beginning of\r
+ execution of two successive statements. There are a number of reasons\r
+ why this time may not be accurate. The duration could include time\r
+ spent in the application waiting for user input, doing other work, etc.\r
+ It may also only include a portion of the actual execution time, if\r
+ the application executes a new statement before draining the previous\r
+ open ResultSet. StatementDuration can be used to get a rough sense of\r
+ where the bottlenecks in an application's JDBC code are.\r
+\r
+ <P>The StatementDuration virtual table has the following columns:\r
+ <UL><LI>TS varchar(26) - not nullable. The timestamp of the statement.</LI>\r
+ <LI>THREADID varchar(80) - not nullable. The thread name.</LI>\r
+ <LI>XID varchar(15) - not nullable. The transaction ID.</LI>\r
+ <LI>LOGTEXT long varchar - nullable. Text of the statement or commit or rollback.</LI>\r
+ <LI>DURATION varchar(10) - not nullable. Duration, in milliseconds, of the statement.</LI>\r
+ </UL>\r
+\r
+ */\r
+public class StatementDuration extends VTITemplate\r
+{\r
+ /*\r
+ ** private \r
+ */\r
+ private boolean gotFile;\r
+ private InputStreamReader inputFileStreamReader;\r
+ private InputStream inputStream;\r
+ private BufferedReader bufferedReader;\r
+ private String inputFileName;\r
+ private Hashtable hashTable;\r
+\r
+ // Variables for current row\r
+ private String line;\r
+ private int gmtIndex;\r
+ private int threadIndex;\r
+ private int xidIndex;\r
+ private int lccidIndex;\r
+ private String[] currentRow;\r
+\r
+ private static final String GMT_STRING = " GMT";\r
+ private static final String BEGIN_THREAD_STRING = "[";\r
+ private static final String END_THREAD_STRING = "]";\r
+ private static final String BEGIN_XID_STRING = "= ";\r
+ private static final String END_XID_STRING = ")";\r
+ private static final String BEGIN_EXECUTING_STRING = "Executing prepared";\r
+ private static final String END_EXECUTING_STRING = " :End prepared";\r
+\r
+\r
+ /**\r
+ StatementDuration() accesses the error log in\r
+ derby.system.home, if set, otherwise it looks in the current directory.\r
+ StatementDuration('filename') will access the specified\r
+ file name.\r
+ */\r
+ public StatementDuration()\r
+ {\r
+ String home = System.getProperty("derby.system.home");\r
+\r
+ inputFileName = "derby.log";\r
+\r
+ if (home != null)\r
+ {\r
+ inputFileName = home + "/" + inputFileName;\r
+ }\r
+ }\r
+\r
+ public StatementDuration(String inputFileName)\r
+ {\r
+ this.inputFileName = inputFileName;\r
+ }\r
+\r
+ /**\r
+ @see java.sql.ResultSet#getMetaData\r
+ */\r
+ public ResultSetMetaData getMetaData()\r
+ {\r
+ return metadata;\r
+ }\r
+\r
+ /**\r
+ @see java.sql.ResultSet#next\r
+ @exception SQLException If database access error occurs.\r
+ */\r
+ public boolean next() throws SQLException\r
+ {\r
+ if (! gotFile)\r
+ {\r
+ gotFile = true;\r
+ try \r
+ {\r
+ inputFileStreamReader = new InputStreamReader(new FileInputStream(inputFileName));\r
+ bufferedReader = new BufferedReader(inputFileStreamReader, 32*1024);\r
+ } \r
+ catch (FileNotFoundException ex) \r
+ {\r
+ throw new SQLException(ex.getMessage());\r
+ }\r
+\r
+ hashTable = new Hashtable();\r
+ }\r
+\r
+ while (true)\r
+ {\r
+ try\r
+ {\r
+ line = bufferedReader.readLine();\r
+ }\r
+ catch (java.io.IOException ioe)\r
+ {\r
+ throw new SQLException(ioe.getMessage());\r
+ }\r
+\r
+ if (line == null)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ gmtIndex = line.indexOf(GMT_STRING);\r
+ threadIndex = line.indexOf(BEGIN_THREAD_STRING);\r
+ xidIndex = line.indexOf(BEGIN_XID_STRING);\r
+ lccidIndex = line.indexOf(BEGIN_XID_STRING, xidIndex + 1);\r
+\r
+ if (gmtIndex != -1 && threadIndex != -1)\r
+ {\r
+ /* Build a row */\r
+ String[] newRow = new String[6];\r
+ for (int index = 1;\r
+ index <= 5;\r
+ index++)\r
+ {\r
+ newRow[index - 1] = setupColumn(index);\r
+ }\r
+\r
+ /* NOTE: We need to use the LCCID as the key\r
+ */\r
+ Object previousRow = hashTable.put(newRow[3],\r
+ newRow);\r
+ if (previousRow == null)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ currentRow = (String[]) previousRow;\r
+ \r
+ /* Figure out the duration. */\r
+ Timestamp endTs = Timestamp.valueOf(newRow[0]);\r
+ long end = endTs.getTime() + endTs.getNanos() / 1000000;\r
+ Timestamp startTs = Timestamp.valueOf(currentRow[0]);\r
+ long start = startTs.getTime() + startTs.getNanos() / 1000000;\r
+ currentRow[5] = Long.toString(end - start);\r
+\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ @see java.sql.ResultSet#close\r
+ */\r
+ public void close()\r
+ {\r
+ if (bufferedReader != null)\r
+ {\r
+ try\r
+ {\r
+ bufferedReader.close();\r
+ inputFileStreamReader.close();\r
+ }\r
+ catch (java.io.IOException ioe)\r
+ {\r
+ // eat exceptions during close;\r
+ }\r
+ finally\r
+ {\r
+ bufferedReader = null;\r
+ inputFileStreamReader = null;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ All columns in StatementDuration VTI have String data types.\r
+ @see java.sql.ResultSet#getString\r
+ @exception SQLException If database access error occurs.\r
+ */\r
+ public String getString(int columnNumber)\r
+ throws SQLException\r
+ {\r
+ return currentRow[columnNumber - 1];\r
+ }\r
+\r
+ private String setupColumn(int columnNumber)\r
+ throws SQLException\r
+ {\r
+ switch (columnNumber)\r
+ {\r
+ case 1:\r
+ return line.substring(0, gmtIndex);\r
+\r
+ case 2:\r
+ return line.substring(threadIndex + 1, line.indexOf(END_THREAD_STRING));\r
+\r
+ case 3:\r
+ return line.substring(xidIndex + 2, line.indexOf(END_XID_STRING, xidIndex));\r
+\r
+ case 4:\r
+ return line.substring(lccidIndex + 2, line.indexOf(END_XID_STRING, lccidIndex));\r
+\r
+ case 5:\r
+ /* Executing prepared statement is a special case as\r
+ * it could span multiple lines\r
+ */\r
+ String output;\r
+ if (line.indexOf(BEGIN_EXECUTING_STRING) == -1)\r
+ {\r
+ output = line.substring(line.indexOf(END_XID_STRING, lccidIndex) + 3);\r
+ }\r
+ else\r
+ {\r
+\r
+ /* We need to build string until we find the end of the text */\r
+ int endIndex = line.indexOf(END_EXECUTING_STRING, lccidIndex);\r
+ if (endIndex == -1)\r
+ {\r
+ output = line.substring(line.indexOf(END_XID_STRING, lccidIndex) + 3);\r
+ }\r
+ else\r
+ {\r
+ output = line.substring(line.indexOf(END_XID_STRING, lccidIndex) + 3,\r
+ endIndex);\r
+ }\r
+\r
+ while (endIndex == -1)\r
+ {\r
+ try\r
+ {\r
+ line = bufferedReader.readLine();\r
+ }\r
+ catch (java.io.IOException ioe)\r
+ {\r
+ throw new SQLException("Error reading file " + ioe);\r
+ }\r
+ endIndex = line.indexOf(END_EXECUTING_STRING);\r
+ if (endIndex == -1)\r
+ {\r
+ output = output + line;\r
+ }\r
+ else\r
+ {\r
+ output = output + line.substring(0, endIndex);\r
+ }\r
+ }\r
+ }\r
+\r
+ output = StringUtil.truncate(output, Limits.DB2_VARCHAR_MAXWIDTH);\r
+\r
+\r
+ return output;\r
+\r
+ default:\r
+ return null;\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ @see java.sql.ResultSet#wasNull\r
+ */\r
+ public boolean wasNull()\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /*\r
+ ** Metadata\r
+ */\r
+ private static final ResultColumnDescriptor[] columnInfo = {\r
+\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("TS", Types.VARCHAR, false, 26),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("THREADID", Types.VARCHAR, false, 80),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("XID", Types.VARCHAR, false, 15),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("LCCID", Types.VARCHAR, false, 10),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("LOGTEXT", Types.VARCHAR, true, Limits.DB2_VARCHAR_MAXWIDTH),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("DURATION", Types.VARCHAR, false, 10),\r
+ };\r
+ \r
+ private static final ResultSetMetaData metadata = new EmbedResultSetMetaData(columnInfo);\r
+\r
+\r
+ public int getHoldability() throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return 0;\r
+ }\r
+\r
+ public Reader getNCharacterStream(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public Reader getNCharacterStream(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public NClob getNClob(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public NClob getNClob(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public String getNString(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public String getNString(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public RowId getRowId(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public RowId getRowId(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public SQLXML getSQLXML(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public SQLXML getSQLXML(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public boolean isClosed() throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+ public void updateAsciiStream(int columnIndex, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateAsciiStream(String columnLabel, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateAsciiStream(int columnIndex, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateAsciiStream(String columnLabel, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBinaryStream(int columnIndex, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBinaryStream(String columnLabel, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBinaryStream(int columnIndex, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBinaryStream(String columnLabel, InputStream x,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBlob(int columnIndex, InputStream inputStream)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBlob(String columnLabel, InputStream inputStream)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBlob(int columnIndex, InputStream inputStream, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateBlob(String columnLabel, InputStream inputStream,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateCharacterStream(int columnIndex, Reader x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateCharacterStream(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateCharacterStream(int columnIndex, Reader x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateCharacterStream(String columnLabel, Reader reader,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateClob(int columnIndex, Reader reader) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateClob(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateClob(int columnIndex, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateClob(String columnLabel, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNCharacterStream(int columnIndex, Reader x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNCharacterStream(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNCharacterStream(int columnIndex, Reader x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNCharacterStream(String columnLabel, Reader reader,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(int columnIndex, NClob clob) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(String columnLabel, NClob clob) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(int columnIndex, Reader reader) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(int columnIndex, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNClob(String columnLabel, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNString(int columnIndex, String string)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateNString(String columnLabel, String string)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateRowId(int columnIndex, RowId x) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateRowId(String columnLabel, RowId x) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateSQLXML(int columnIndex, SQLXML xmlObject)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public void updateSQLXML(String columnLabel, SQLXML xmlObject)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+ public <T> T unwrap(Class<T> iface) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+ public <T> T getObject(String columnLabel, Class<T> type)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+}\r
+\r