001: /*
002:
003: Derby - Class org.apache.derby.diag.ErrorLogReader
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.diag;
023:
024: import java.io.BufferedReader;
025: import java.io.FileNotFoundException;
026: import java.io.InputStream;
027: import java.io.InputStreamReader;
028: import java.io.FileInputStream;
029:
030: import java.util.Hashtable;
031: import java.util.Enumeration;
032: import java.util.Properties;
033: import java.sql.ResultSetMetaData;
034: import java.sql.SQLException;
035: import java.sql.Types;
036: import org.apache.derby.vti.VTITemplate;
037: import org.apache.derby.iapi.reference.Limits;
038: import org.apache.derby.iapi.util.StringUtil;
039:
040: import org.apache.derby.iapi.sql.ResultColumnDescriptor;
041: import org.apache.derby.impl.jdbc.EmbedResultSetMetaData;
042:
043: /**
044:
045: ErrorLogReader is a virtual table interface (VTI) which contains all the statements
046: of "interest" in db2j.<!-- -->log or a specified file when
047: db2j.<!-- -->language.<!-- -->logStatementText=true.
048:
049:
050: <P>One use of this VTI is to determine the active transactions
051: and the SQL statements in those transactions at a given point in time, say
052: when a deadlock or lock timeout occurred. In order to do that, you must first
053: find the timestamp (timestampConstant) of interest in the error log.
054: The SQL to view the active transactions at a given in time is:
055: <PRE>SELECT vti.ts, threadid, cast(xid as int) as xid_int, cast(lccid as int) as lccid_int, logtext
056: FROM new org.apache.derby.diag.ErrorLogReader() vti,
057: (VALUES timestampConstant) t(ts)
058: WHERE vti.ts <= t.ts AND
059: vti.ts >
060: (SELECT MAX(ts) IS NULL ? '2000-01-01 00:00:00.1' : MAX(ts)
061: FROM new org.apache.derby.diag.ErrorLogReader() vti_i
062: WHERE (logtext LIKE 'Committing%' OR
063: logtext LIKE 'Rolling%') AND
064: vti.xid = vti_i.xid AND ts < t.ts)
065: ORDER BY xid_int, vti.ts
066: </PRE>
067:
068: <P>The ErrorLogReader virtual table has the following columns:
069: <UL><LI>TS varchar(26) - the timestamp of the statement.</LI>
070: <LI>THREADID varchar(40) - the thread name.</LI>
071: <LI>XID varchar(15) - the transaction ID.</LI>
072: <LI>LCCID varchar(15) - the connection ID.</LI>
073: <LI>DATABASE varchar(128) - Database name
074: <LI>DRDAID varchar(50) - nullable. DRDA ID for network server session.
075: <LI>LOGTEXT long varchar - text of the statement or commit or rollback.</LI>
076: </UL>
077:
078: */
079: public class ErrorLogReader extends VTITemplate {
080: /*
081: ** private
082: */
083: private boolean gotFile;
084: private InputStreamReader inputFileStreamReader;
085: private InputStream inputStream;
086: private BufferedReader bufferedReader;
087: private String inputFileName;
088:
089: // Variables for current row
090: private String line;
091: private int gmtIndex;
092: private int threadIndex;
093: private int xidIndex;
094: private int lccidIndex;
095: private int databaseIndex;
096: private int drdaidIndex;
097:
098: private static final String GMT_STRING = " GMT";
099: private static final String PARAMETERS_STRING = "Parameters:";
100: private static final String BEGIN_THREAD_STRING = "[";
101: private static final String END_THREAD_STRING = "]";
102: private static final String BEGIN_XID_STRING = "= ";
103: private static final String END_XID_STRING = ")";
104: private static final String BEGIN_DATABASE_STRING = "(DATABASE =";
105: private static final String END_DATABASE_STRING = ")";
106: private static final String BEGIN_DRDAID_STRING = "(DRDAID =";
107: private static final String END_DRDAID_STRING = ")";
108: private static final String BEGIN_EXECUTING_STRING = "Executing prepared";
109: private static final String END_EXECUTING_STRING = " :End prepared";
110:
111: /**
112: ErrorLogReader() accesses the derby.log in
113: derby.system.home, if set, otherwise it looks in the current directory.
114: ErrorLogReader('filename') will access the specified
115: file name.
116: */
117: public ErrorLogReader() {
118: String home = System.getProperty("derby.system.home");
119:
120: inputFileName = "derby.log";
121:
122: if (home != null) {
123: inputFileName = home + "/" + inputFileName;
124: }
125: }
126:
127: public ErrorLogReader(String inputFileName) {
128: this .inputFileName = inputFileName;
129: }
130:
131: /**
132: @see java.sql.ResultSet#getMetaData
133: */
134: public ResultSetMetaData getMetaData() {
135: return metadata;
136: }
137:
138: /**
139: @see java.sql.ResultSet#next
140: @exception SQLException If database-access error occurs.
141: */
142: public boolean next() throws SQLException {
143: if (!gotFile) {
144: gotFile = true;
145: try {
146: inputFileStreamReader = new InputStreamReader(
147: new FileInputStream(inputFileName));
148: bufferedReader = new BufferedReader(
149: inputFileStreamReader, 32 * 1024);
150: } catch (FileNotFoundException ex) {
151: throw new SQLException(ex.getMessage());
152: }
153: }
154:
155: while (true) {
156: try {
157: line = bufferedReader.readLine();
158: } catch (java.io.IOException ioe) {
159: throw new SQLException(ioe.getMessage());
160: }
161:
162: if (line == null) {
163: return false;
164: }
165:
166: gmtIndex = line.indexOf(GMT_STRING);
167: threadIndex = line.indexOf(BEGIN_THREAD_STRING);
168: xidIndex = line.indexOf(BEGIN_XID_STRING);
169: lccidIndex = line.indexOf(BEGIN_XID_STRING, xidIndex + 1);
170: databaseIndex = line.indexOf(BEGIN_DATABASE_STRING,
171: lccidIndex + 1);
172: drdaidIndex = line.indexOf(BEGIN_DRDAID_STRING,
173: databaseIndex + 1);
174:
175: // Skip parameters
176: if (line.indexOf(PARAMETERS_STRING) != -1) {
177: continue;
178: }
179:
180: if (gmtIndex != -1 && threadIndex != -1 && xidIndex != -1
181: && databaseIndex != -1) {
182: return true;
183: }
184: }
185: }
186:
187: /**
188: @see java.sql.ResultSet#close
189: */
190: public void close() {
191: if (bufferedReader != null) {
192: try {
193: bufferedReader.close();
194: inputFileStreamReader.close();
195: } catch (java.io.IOException ioe) {
196: // eat exceptions during close;
197: } finally {
198: bufferedReader = null;
199: inputFileStreamReader = null;
200: }
201: }
202: }
203:
204: /**
205: All columns in the Db2jLogReader VTI have a of String type.
206: @see java.sql.ResultSet#getString
207: @exception SQLException If database-access error occurs.
208: */
209: public String getString(int columnNumber) throws SQLException {
210: switch (columnNumber) {
211: case 1:
212: return line.substring(0, gmtIndex);
213:
214: case 2:
215: return line.substring(threadIndex + 1, line
216: .indexOf(END_THREAD_STRING));
217:
218: case 3:
219: return line.substring(xidIndex + 2, line.indexOf(
220: END_XID_STRING, xidIndex));
221:
222: case 4:
223: return line.substring(lccidIndex + 2, line.indexOf(
224: END_XID_STRING, lccidIndex));
225:
226: case 5:
227: return line.substring(databaseIndex
228: + BEGIN_DATABASE_STRING.length(), line.indexOf(
229: END_DATABASE_STRING, databaseIndex));
230: case 6:
231: return line.substring(drdaidIndex
232: + BEGIN_DRDAID_STRING.length(), line.indexOf(
233: END_DRDAID_STRING, drdaidIndex));
234: case 7:
235: /* Executing prepared statement is a special case as
236: * it could span multiple lines
237: */
238: String output;
239: if (line.indexOf(BEGIN_EXECUTING_STRING) == -1) {
240: output = line.substring(line.indexOf(END_DRDAID_STRING,
241: drdaidIndex) + 3);
242: } else {
243:
244: /* We need to build string until we find the end of the text */
245: int endIndex = line.indexOf(END_EXECUTING_STRING,
246: drdaidIndex);
247: if (endIndex == -1) {
248: output = line.substring(line.indexOf(
249: END_DRDAID_STRING, drdaidIndex) + 3);
250: } else {
251: output = line.substring(line.indexOf(
252: END_XID_STRING, drdaidIndex) + 3, endIndex);
253: }
254:
255: while (endIndex == -1) {
256: try {
257: line = bufferedReader.readLine();
258: } catch (java.io.IOException ioe) {
259: throw new SQLException("Error reading file "
260: + ioe);
261: }
262: endIndex = line.indexOf(END_EXECUTING_STRING);
263: if (endIndex == -1) {
264: output = output + line;
265: } else {
266: output = output + line.substring(0, endIndex);
267: }
268: }
269: }
270:
271: output = StringUtil.truncate(output,
272: Limits.DB2_VARCHAR_MAXWIDTH);
273:
274: return output;
275:
276: default:
277: return "";
278: }
279: }
280:
281: /**
282: @see java.sql.ResultSet#wasNull
283: */
284: public boolean wasNull() {
285: return false;
286: }
287:
288: /* MetaData
289: */
290:
291: // column1: TS varchar(26) not null
292: // column2: THREADID varchar(40) not null
293: // column3: XID varchar(15) not null
294: // column4: LCCID varchar(15) not null
295: // column5: DATABASE varchar(128) not null
296: // column6: DRDAID varchar(50) nullable
297: // column5: LOGTEXT VARCHAR(max) not null
298: private static final ResultColumnDescriptor[] columnInfo = {
299: EmbedResultSetMetaData.getResultColumnDescriptor("TS",
300: Types.VARCHAR, false, 26),
301: EmbedResultSetMetaData.getResultColumnDescriptor(
302: "THREADID", Types.VARCHAR, false, 40),
303: EmbedResultSetMetaData.getResultColumnDescriptor("XID",
304: Types.VARCHAR, false, 15),
305: EmbedResultSetMetaData.getResultColumnDescriptor("LCCID",
306: Types.VARCHAR, false, 15),
307: EmbedResultSetMetaData.getResultColumnDescriptor(
308: "DATABASE", Types.VARCHAR, false, 128),
309: EmbedResultSetMetaData.getResultColumnDescriptor("DRDAID",
310: Types.VARCHAR, true, 50),
311: EmbedResultSetMetaData.getResultColumnDescriptor("LOGTEXT",
312: Types.VARCHAR, false, Limits.DB2_VARCHAR_MAXWIDTH) };
313: private static final ResultSetMetaData metadata = new EmbedResultSetMetaData(
314: columnInfo);
315:
316: }
|