--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.diag.ErrorLogReader\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.Types;\r
+\r
+import org.apache.derby.vti.VTITemplate;\r
+import org.apache.derby.iapi.reference.Limits;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+import org.apache.derby.iapi.sql.ResultColumnDescriptor;\r
+import org.apache.derby.impl.jdbc.EmbedResultSetMetaData;\r
+\r
+/**\r
+\r
+ ErrorLogReader is a virtual table interface (VTI) which contains all the statements\r
+ of "interest" in db2j.<!-- -->log or a specified file when\r
+ db2j.<!-- -->language.<!-- -->logStatementText=true.\r
+ \r
+ \r
+ <P>One use of this VTI is to determine the active transactions\r
+ and the SQL statements in those transactions at a given point in time, say\r
+ when a deadlock or lock timeout occurred. In order to do that, you must first\r
+ find the timestamp (timestampConstant) of interest in the error log. \r
+ The SQL to view the active transactions at a given in time is:\r
+ <PRE>SELECT vti.ts, threadid, cast(xid as int) as xid_int, cast(lccid as int) as lccid_int, logtext \r
+ FROM new org.apache.derby.diag.ErrorLogReader() vti, \r
+ (VALUES timestampConstant) t(ts)\r
+ WHERE vti.ts <= t.ts AND \r
+ vti.ts >\r
+ (SELECT MAX(ts) IS NULL ? '2000-01-01 00:00:00.1' : MAX(ts)\r
+ FROM new org.apache.derby.diag.ErrorLogReader() vti_i\r
+ WHERE (logtext LIKE 'Committing%' OR\r
+ logtext LIKE 'Rolling%') AND\r
+ vti.xid = vti_i.xid AND ts < t.ts)\r
+ ORDER BY xid_int, vti.ts\r
+ </PRE>\r
+\r
+ <P>The ErrorLogReader virtual table has the following columns:\r
+ <UL><LI>TS varchar(26) - the timestamp of the statement.</LI>\r
+ <LI>THREADID varchar(40) - the thread name.</LI>\r
+ <LI>XID varchar(15) - the transaction ID.</LI>\r
+ <LI>LCCID varchar(15) - the connection ID.</LI>\r
+ <LI>DATABASE varchar(128) - Database name\r
+ <LI>DRDAID varchar(50) - nullable. DRDA ID for network server session.\r
+ <LI>LOGTEXT long varchar - text of the statement or commit or rollback.</LI>\r
+ </UL>\r
+\r
+ */\r
+public class ErrorLogReader 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
+\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 int databaseIndex;\r
+ private int drdaidIndex;\r
+\r
+\r
+ private static final String GMT_STRING = " GMT";\r
+ private static final String PARAMETERS_STRING = "Parameters:";\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_DATABASE_STRING = "(DATABASE =";\r
+ private static final String END_DATABASE_STRING = ")";\r
+ private static final String BEGIN_DRDAID_STRING = "(DRDAID =";\r
+ private static final String END_DRDAID_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
+ ErrorLogReader() accesses the derby.log in\r
+ derby.system.home, if set, otherwise it looks in the current directory.\r
+ ErrorLogReader('filename') will access the specified\r
+ file name.\r
+ */\r
+ public ErrorLogReader()\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 ErrorLogReader(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
+\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
+ databaseIndex = line.indexOf(BEGIN_DATABASE_STRING, lccidIndex + 1);\r
+ drdaidIndex = line.indexOf(BEGIN_DRDAID_STRING, databaseIndex + 1);\r
+\r
+ // Skip parameters\r
+ if (line.indexOf(PARAMETERS_STRING) != -1)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (gmtIndex != -1 && threadIndex != -1 && xidIndex != -1 && \r
+ databaseIndex != -1)\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 the Db2jLogReader VTI have a of String type.\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
+ 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
+ return line.substring(databaseIndex + BEGIN_DATABASE_STRING.length(), line.indexOf(END_DATABASE_STRING, databaseIndex));\r
+ case 6:\r
+ return line.substring(drdaidIndex + BEGIN_DRDAID_STRING.length(), line.indexOf(END_DRDAID_STRING, drdaidIndex));\r
+ case 7:\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_DRDAID_STRING, drdaidIndex) + 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, drdaidIndex);\r
+ if (endIndex == -1)\r
+ {\r
+ output = line.substring(line.indexOf(END_DRDAID_STRING, drdaidIndex) + 3);\r
+ }\r
+ else\r
+ {\r
+ output = line.substring(line.indexOf(END_XID_STRING, drdaidIndex) + 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
+ return output;\r
+\r
+ default:\r
+ return "";\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ @see java.sql.ResultSet#wasNull\r
+ */\r
+ public boolean wasNull()\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /* MetaData\r
+ */\r
+ \r
+ // column1: TS varchar(26) not null\r
+ // column2: THREADID varchar(40) not null\r
+ // column3: XID varchar(15) not null\r
+ // column4: LCCID varchar(15) not null\r
+ // column5: DATABASE varchar(128) not null\r
+ // column6: DRDAID varchar(50) nullable\r
+ // column5: LOGTEXT VARCHAR(max) not null\r
+ private static final ResultColumnDescriptor[] columnInfo = {\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("TS", Types.VARCHAR, false, 26),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("THREADID", Types.VARCHAR, false, 40),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("XID", Types.VARCHAR, false, 15),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("LCCID", Types.VARCHAR, false, 15),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("DATABASE", Types.VARCHAR, false, 128),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("DRDAID", Types.VARCHAR, true, 50),\r
+ EmbedResultSetMetaData.getResultColumnDescriptor("LOGTEXT",Types.VARCHAR, false, Limits.DB2_VARCHAR_MAXWIDTH)\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
+\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
+\r
+\r