0001: /*
0002:
0003: Derby - Class org.apache.derby.tools.JDBCDisplayUtil
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.tools;
0023:
0024: import java.io.PrintStream;
0025: import java.io.PrintWriter;
0026: import java.io.File;
0027: import java.io.FileNotFoundException;
0028: import java.io.IOException;
0029:
0030: import java.sql.Connection;
0031: import java.sql.SQLException;
0032: import java.sql.SQLWarning;
0033: import java.sql.Statement;
0034: import java.sql.PreparedStatement;
0035: import java.sql.ResultSet;
0036: import java.sql.ResultSetMetaData;
0037: import java.sql.Types;
0038:
0039: import java.util.Properties;
0040: import java.util.Enumeration;
0041: import java.util.Vector;
0042:
0043: import org.apache.derby.iapi.tools.i18n.LocalizedResource;
0044:
0045: import org.apache.derby.impl.tools.ij.ijException;
0046:
0047: /**
0048:
0049: This class contains utility methods for displaying JDBC objects and results.
0050:
0051: <p>
0052: All of the methods are static. The output stream
0053: to write to is always passed in, along with the
0054: JDBC objects to display.
0055:
0056: @author ames
0057: */
0058: public class JDBCDisplayUtil {
0059:
0060: // used to control display
0061: static final private int MINWIDTH = 4;
0062: static private int maxWidth = 128;
0063: static public boolean showSelectCount = false;
0064:
0065: static {
0066: // initialize the locale support functions to default value of JVM
0067: LocalizedResource.getInstance();
0068: }
0069:
0070: //-----------------------------------------------------------------
0071: // Methods for displaying and checking errors
0072:
0073: /**
0074: Print information about the exception to the given PrintWriter.
0075: For non-SQLExceptions, does a stack trace. For SQLExceptions,
0076: print a standard error message and walk the list, if any.
0077:
0078: @param out the place to write to
0079: @param e the exception to display
0080: */
0081: static public void ShowException(PrintWriter out, Throwable e) {
0082: if (e == null)
0083: return;
0084:
0085: if (e instanceof SQLException)
0086: ShowSQLException(out, (SQLException) e);
0087: else
0088: e.printStackTrace(out);
0089: }
0090:
0091: /**
0092: Print information about the SQL exception to the given PrintWriter.
0093: Walk the list of exceptions, if any.
0094:
0095: @param out the place to write to
0096: @param e the exception to display
0097: */
0098: static public void ShowSQLException(PrintWriter out, SQLException e) {
0099: String errorCode;
0100:
0101: if (Boolean.getBoolean("ij.showErrorCode")) {
0102: errorCode = LocalizedResource.getMessage("UT_Error0",
0103: LocalizedResource.getNumber(e.getErrorCode()));
0104: } else {
0105: errorCode = "";
0106: }
0107:
0108: while (e != null) {
0109: String p1 = mapNull(e.getSQLState(), LocalizedResource
0110: .getMessage("UT_NoSqlst"));
0111: String p2 = mapNull(e.getMessage(), LocalizedResource
0112: .getMessage("UT_NoMessa"));
0113: out.println(LocalizedResource.getMessage("UT_Error012", p1,
0114: p2, errorCode));
0115: doTrace(out, e);
0116: e = e.getNextException();
0117: }
0118: }
0119:
0120: /**
0121: Print information about the SQL warnings for the connection
0122: to the given PrintWriter.
0123: Walks the list of exceptions, if any.
0124:
0125: @param out the place to write to
0126: @param theConnection the connection that may have warnings.
0127: */
0128: static public void ShowWarnings(PrintWriter out,
0129: Connection theConnection) {
0130: try {
0131: // GET CONNECTION WARNINGS
0132: SQLWarning warning = null;
0133:
0134: if (theConnection != null) {
0135: ShowWarnings(out, theConnection.getWarnings());
0136: }
0137:
0138: if (theConnection != null) {
0139: theConnection.clearWarnings();
0140: }
0141: } catch (SQLException e) {
0142: ShowSQLException(out, e);
0143: }
0144: } // ShowWarnings
0145:
0146: /**
0147: @param out the place to write to
0148: @param warning the SQLWarning
0149: */
0150: static public void ShowWarnings(PrintWriter out, SQLWarning warning) {
0151: while (warning != null) {
0152: String p1 = mapNull(warning.getSQLState(),
0153: LocalizedResource.getMessage("UT_NoSqlst_7"));
0154: String p2 = mapNull(warning.getMessage(), LocalizedResource
0155: .getMessage("UT_NoMessa_8"));
0156: out.println(LocalizedResource.getMessage("UT_Warni01", p1,
0157: p2));
0158: warning = warning.getNextWarning();
0159: }
0160: }
0161:
0162: /**
0163: Print information about the SQL warnings for the ResultSet
0164: to the given PrintWriter.
0165: Walk the list of exceptions, if any.
0166:
0167: @param out the place to write to
0168: @param rs the ResultSet that may have warnings on it
0169: */
0170: static public void ShowWarnings(PrintWriter out, ResultSet rs) {
0171: try {
0172: // GET RESULTSET WARNINGS
0173: SQLWarning warning = null;
0174:
0175: if (rs != null) {
0176: ShowWarnings(out, rs.getWarnings());
0177: }
0178:
0179: if (rs != null) {
0180: rs.clearWarnings();
0181: }
0182: } catch (SQLException e) {
0183: ShowSQLException(out, e);
0184: }
0185: } // ShowResultSetWarnings
0186:
0187: /**
0188: Print information about the SQL warnings for the Statement
0189: to the given PrintWriter.
0190: Walks the list of exceptions, if any.
0191:
0192: @param out the place to write to
0193: @param s the Statement that may have warnings on it
0194: */
0195: static public void ShowWarnings(PrintWriter out, Statement s) {
0196: try {
0197: // GET STATEMENT WARNINGS
0198: SQLWarning warning = null;
0199:
0200: if (s != null) {
0201: ShowWarnings(out, s.getWarnings());
0202: }
0203:
0204: if (s != null) {
0205: s.clearWarnings();
0206: }
0207: } catch (SQLException e) {
0208: ShowSQLException(out, e);
0209: }
0210: } // ShowStatementWarnings
0211:
0212: //-----------------------------------------------------------------
0213: // Methods for displaying and checking results
0214:
0215: // REMIND: make this configurable...
0216: static final private int MAX_RETRIES = 0;
0217:
0218: /**
0219: Pretty-print the results of a statement that has been executed.
0220: If it is a select, gathers and prints the results. Display
0221: partial results up to the first error.
0222: If it is not a SELECT, determine if rows were involved or not,
0223: and print the appropriate message.
0224:
0225: @param out the place to write to
0226: @param stmt the Statement to display
0227: @param conn the Connection against which the statement was executed
0228:
0229: @exception SQLException on JDBC access failure
0230: */
0231: static public void DisplayResults(PrintWriter out, Statement stmt,
0232: Connection conn) throws SQLException {
0233: indent_DisplayResults(out, stmt, conn, 0, null, null);
0234: }
0235:
0236: static private void indent_DisplayResults(PrintWriter out,
0237: Statement stmt, Connection conn, int indentLevel,
0238: int[] displayColumns, int[] displayColumnWidths)
0239: throws SQLException {
0240:
0241: checkNotNull(stmt, "Statement");
0242:
0243: ResultSet rs = stmt.getResultSet();
0244: if (rs != null) {
0245: indent_DisplayResults(out, rs, conn, indentLevel,
0246: displayColumns, displayColumnWidths);
0247: rs.close(); // let the result set go away
0248: } else {
0249: DisplayUpdateCount(out, stmt.getUpdateCount(), indentLevel);
0250: }
0251:
0252: ShowWarnings(out, stmt);
0253: } // DisplayResults
0254:
0255: /**
0256: @param out the place to write to
0257: @param count the update count to display
0258: @param indentLevel number of tab stops to indent line
0259: */
0260: static void DisplayUpdateCount(PrintWriter out, int count,
0261: int indentLevel) {
0262: if (count == 1) {
0263: indentedPrintLine(out, indentLevel, LocalizedResource
0264: .getMessage("UT_1RowInserUpdatDelet"));
0265: } else if (count >= 0) {
0266: indentedPrintLine(out, indentLevel, LocalizedResource
0267: .getMessage("UT_0RowsInserUpdatDelet",
0268: LocalizedResource.getNumber(count)));
0269: } else {
0270: indentedPrintLine(out, indentLevel, LocalizedResource
0271: .getMessage("UT_StateExecu"));
0272: }
0273: }
0274:
0275: /**
0276: Calculates column display widths from the default widths of the
0277: result set.
0278: */
0279: static private int[] getColumnDisplayWidths(ResultSetMetaData rsmd,
0280: int[] dispColumns, boolean localizedOutput)
0281: throws SQLException {
0282: int count = (dispColumns == null) ? rsmd.getColumnCount()
0283: : dispColumns.length;
0284: int[] widths = new int[count];
0285:
0286: for (int i = 0; i < count; i++) {
0287: int colnum = (dispColumns == null) ? (i + 1)
0288: : dispColumns[i];
0289: int dispsize = localizedOutput ? LocalizedResource
0290: .getInstance().getColumnDisplaySize(rsmd, colnum)
0291: : rsmd.getColumnDisplaySize(colnum);
0292: widths[i] = Math
0293: .min(
0294: maxWidth,
0295: Math
0296: .max(
0297: (rsmd.isNullable(colnum) == ResultSetMetaData.columnNoNulls) ? 0
0298: : MINWIDTH,
0299: dispsize));
0300: }
0301: return widths;
0302: }
0303:
0304: /**
0305: @param out the place to write to
0306: @param rs the ResultSet to display
0307: @param conn the Connection against which the ResultSet was retrieved
0308: @param displayColumns Column numbers to display, or null if all
0309: @param displayColumnWidths Column widths, in characters, if displayColumns is specified.
0310:
0311: @exception SQLException on JDBC access failure
0312: */
0313: static public void DisplayResults(PrintWriter out, ResultSet rs,
0314: Connection conn, int[] displayColumns,
0315: int[] displayColumnWidths) throws SQLException {
0316: indent_DisplayResults(out, rs, conn, 0, displayColumns,
0317: displayColumnWidths);
0318: }
0319:
0320: static private void indent_DisplayResults(PrintWriter out,
0321: ResultSet rs, Connection conn, int indentLevel,
0322: int[] displayColumns, int[] displayColumnWidths)
0323: throws SQLException {
0324: ResultSetMetaData rsmd = rs.getMetaData();
0325: checkNotNull(rsmd, "ResultSetMetaData");
0326: Vector nestedResults;
0327: int numberOfRowsSelected = 0;
0328:
0329: // autocommit must be off or the nested cursors
0330: // are closed when the outer statement completes.
0331: if (!conn.getAutoCommit())
0332: nestedResults = new Vector();
0333: else
0334: nestedResults = null;
0335:
0336: if (displayColumnWidths == null)
0337: displayColumnWidths = getColumnDisplayWidths(rsmd,
0338: displayColumns, true);
0339:
0340: int len = indent_DisplayBanner(out, rsmd, indentLevel,
0341: displayColumns, displayColumnWidths);
0342:
0343: // When displaying rows, keep going past errors
0344: // unless/until the maximum # of errors is reached.
0345: boolean doNext = true;
0346: int retry = 0;
0347: while (doNext) {
0348: try {
0349: doNext = rs.next();
0350: if (doNext) {
0351:
0352: DisplayRow(out, rs, rsmd, len, nestedResults, conn,
0353: indentLevel, displayColumns,
0354: displayColumnWidths);
0355: ShowWarnings(out, rs);
0356: numberOfRowsSelected++;
0357: }
0358: } catch (SQLException e) {
0359: // REVISIT: might want to check the exception
0360: // and for some, not bother with the retry.
0361: if (++retry > MAX_RETRIES)
0362: throw e;
0363: else
0364: ShowSQLException(out, e);
0365: }
0366: }
0367: if (showSelectCount == true) {
0368: if (numberOfRowsSelected == 1) {
0369: out.println();
0370: indentedPrintLine(out, indentLevel, LocalizedResource
0371: .getMessage("UT_1RowSelec"));
0372: } else if (numberOfRowsSelected >= 0) {
0373: out.println();
0374: indentedPrintLine(out, indentLevel, LocalizedResource
0375: .getMessage("UT_0RowsSelec", LocalizedResource
0376: .getNumber(numberOfRowsSelected)));
0377: }
0378: }
0379:
0380: DisplayNestedResults(out, nestedResults, conn, indentLevel);
0381: nestedResults = null;
0382: }
0383:
0384: /**
0385: @param out the place to write to
0386: @param nr the vector of results
0387: @param conn the Connection against which the ResultSet was retrieved
0388: @param indentLevel number of tab stops to indent line
0389:
0390: @exception SQLException thrown on access error
0391: */
0392: static private void DisplayNestedResults(PrintWriter out,
0393: Vector nr, Connection conn, int indentLevel)
0394: throws SQLException {
0395:
0396: if (nr == null)
0397: return;
0398:
0399: String b = LocalizedResource
0400: .getMessage("UT_JDBCDisplayUtil_16");
0401: String oldString = "0";
0402:
0403: for (int i = 0; i < nr.size(); i++) {
0404: LocalizedResource.OutputWriter().println();
0405:
0406: //just too clever to get the extra +s
0407: String t = Integer.toString(i);
0408: if (t.length() > oldString.length()) {
0409: oldString = t;
0410: b = b
0411: + LocalizedResource
0412: .getMessage("UT_JDBCDisplayUtil_17");
0413: }
0414:
0415: LocalizedResource.OutputWriter().println(b);
0416: LocalizedResource.OutputWriter().println(
0417: LocalizedResource.getMessage("UT_Resul0",
0418: LocalizedResource.getNumber(i)));
0419: LocalizedResource.OutputWriter().println(b);
0420: indent_DisplayResults(out, (ResultSet) nr.elementAt(i),
0421: conn, indentLevel, null, null);
0422: }
0423: }
0424:
0425: /**
0426: Fetch the next row of the result set, and if it
0427: exists format and display a banner and the row.
0428:
0429: @param out the place to write to
0430: @param rs the ResultSet in use
0431: @param conn the Connection against which the ResultSet was retrieved
0432:
0433: @exception SQLException on JDBC access failure
0434: */
0435: static public void DisplayNextRow(PrintWriter out, ResultSet rs,
0436: Connection conn) throws SQLException {
0437: indent_DisplayNextRow(out, rs, conn, 0, null,
0438: (rs == null) ? null : getColumnDisplayWidths(rs
0439: .getMetaData(), null, true));
0440: }
0441:
0442: static private void indent_DisplayNextRow(PrintWriter out,
0443: ResultSet rs, Connection conn, int indentLevel,
0444: int[] displayColumns, int[] displayColumnWidths)
0445: throws SQLException {
0446:
0447: Vector nestedResults;
0448:
0449: // autocommit must be off or the nested cursors
0450: // are closed when the outer statement completes.
0451: if (!conn.getAutoCommit())
0452: nestedResults = new Vector();
0453: else
0454: nestedResults = null;
0455:
0456: checkNotNull(rs, "ResultSet");
0457:
0458: ResultSetMetaData rsmd = rs.getMetaData();
0459: checkNotNull(rsmd, "ResultSetMetaData");
0460:
0461: // Only print stuff out if there is a row to be had.
0462: if (rs.next()) {
0463: int rowLen = indent_DisplayBanner(out, rsmd, indentLevel,
0464: displayColumns, displayColumnWidths);
0465: DisplayRow(out, rs, rsmd, rowLen, nestedResults, conn,
0466: indentLevel, null, null);
0467: } else {
0468: indentedPrintLine(out, indentLevel, LocalizedResource
0469: .getMessage("UT_NoCurreRow"));
0470: }
0471:
0472: ShowWarnings(out, rs);
0473:
0474: DisplayNestedResults(out, nestedResults, conn, indentLevel);
0475: nestedResults = null;
0476:
0477: } // DisplayNextRow
0478:
0479: /**
0480: Display the current row of the result set along with
0481: a banner. Assume the result set is on a row.
0482:
0483: @param out the place to write to
0484: @param rs the ResultSet in use
0485: @param conn the Connection against which the ResultSet was retrieved
0486:
0487: @exception SQLException on JDBC access failure
0488: */
0489: static public void DisplayCurrentRow(PrintWriter out, ResultSet rs,
0490: Connection conn) throws SQLException {
0491: indent_DisplayCurrentRow(out, rs, conn, 0, null,
0492: (rs == null) ? null : getColumnDisplayWidths(rs
0493: .getMetaData(), null, true));
0494: }
0495:
0496: static private void indent_DisplayCurrentRow(PrintWriter out,
0497: ResultSet rs, Connection conn, int indentLevel,
0498: int[] displayColumns, int[] displayColumnWidths)
0499: throws SQLException {
0500:
0501: Vector nestedResults;
0502:
0503: if (rs == null) {
0504: indentedPrintLine(out, indentLevel, LocalizedResource
0505: .getMessage("UT_NoCurreRow_19"));
0506: return;
0507: }
0508:
0509: // autocommit must be off or the nested cursors
0510: // are closed when the outer statement completes.
0511: if (!conn.getAutoCommit())
0512: nestedResults = new Vector();
0513: else
0514: nestedResults = null;
0515:
0516: ResultSetMetaData rsmd = rs.getMetaData();
0517: checkNotNull(rsmd, "ResultSetMetaData");
0518:
0519: int rowLen = indent_DisplayBanner(out, rsmd, indentLevel,
0520: displayColumns, displayColumnWidths);
0521: DisplayRow(out, rs, rsmd, rowLen, nestedResults, conn,
0522: indentLevel, displayColumns, displayColumnWidths);
0523:
0524: ShowWarnings(out, rs);
0525:
0526: DisplayNestedResults(out, nestedResults, conn, indentLevel);
0527: nestedResults = null;
0528:
0529: } // DisplayNextRow
0530:
0531: /**
0532: Print a banner containing the column labels separated with '|'s
0533: and a line of '-'s. Each field is as wide as the display
0534: width reported by the metadata.
0535:
0536: @param out the place to write to
0537: @param rsmd the ResultSetMetaData to use
0538:
0539: @exception SQLException on JDBC access failure
0540: */
0541: static public int DisplayBanner(PrintWriter out,
0542: ResultSetMetaData rsmd) throws SQLException {
0543: return indent_DisplayBanner(out, rsmd, 0, null,
0544: getColumnDisplayWidths(rsmd, null, true));
0545: }
0546:
0547: static private int indent_DisplayBanner(PrintWriter out,
0548: ResultSetMetaData rsmd, int indentLevel,
0549: int[] displayColumns, int[] displayColumnWidths)
0550: throws SQLException {
0551:
0552: StringBuffer buf = new StringBuffer();
0553:
0554: int numCols = displayColumnWidths.length;
0555: int rowLen;
0556:
0557: // do some precalculation so the buffer is allocated only once
0558: // buffer is twice as long as the display length plus one for a newline
0559: rowLen = (numCols - 1); // for the column separators
0560: for (int i = 1; i <= numCols; i++)
0561: rowLen += displayColumnWidths[i - 1];
0562: buf.ensureCapacity(rowLen);
0563:
0564: // get column header info
0565: // truncate it to the column display width
0566: // add a bar between each item.
0567: for (int i = 1; i <= numCols; i++) {
0568: int colnum = displayColumns == null ? i
0569: : displayColumns[i - 1];
0570:
0571: if (i > 1)
0572: buf.append('|');
0573:
0574: String s = rsmd.getColumnLabel(colnum);
0575:
0576: int w = displayColumnWidths[i - 1];
0577:
0578: if (s.length() < w) {
0579:
0580: buf.append(s);
0581:
0582: // try to paste on big chunks of space at a time.
0583: int k = w - s.length();
0584: for (; k >= 64; k -= 64)
0585: buf
0586: .append(" ");
0587: for (; k >= 16; k -= 16)
0588: buf.append(" ");
0589: for (; k >= 4; k -= 4)
0590: buf.append(" ");
0591: for (; k > 0; k--)
0592: buf.append(' ');
0593: } else if (s.length() > w) {
0594: if (w > 1)
0595: buf.append(s.substring(0, w - 1));
0596: if (w > 0)
0597: buf.append('&');
0598: } else {
0599: buf.append(s);
0600: }
0601: }
0602:
0603: buf.setLength(Math.min(rowLen, 1024));
0604: indentedPrintLine(out, indentLevel, buf);
0605:
0606: // now print a row of '-'s
0607: for (int i = 0; i < Math.min(rowLen, 1024); i++)
0608: buf.setCharAt(i, '-');
0609: indentedPrintLine(out, indentLevel, buf);
0610:
0611: buf = null;
0612:
0613: return rowLen;
0614: } // DisplayBanner
0615:
0616: /**
0617: Print one row of a result set, padding each field to the
0618: display width and separating them with '|'s
0619:
0620: @param out the place to write to
0621: @param rs the ResultSet to use
0622: @param rsmd the ResultSetMetaData to use
0623: @param rowLen
0624: @param nestedResults
0625: @param conn
0626: @param indentLevel number of tab stops to indent line
0627: @param displayColumns A list of column numbers to display
0628: @param displayColumnWidths If displayColumns is set, the width of
0629: columns to display, in characters.
0630:
0631: @exception SQLException thrown on JDBC access failure
0632: */
0633: static private void DisplayRow(PrintWriter out, ResultSet rs,
0634: ResultSetMetaData rsmd, int rowLen, Vector nestedResults,
0635: Connection conn, int indentLevel, int[] displayColumns,
0636: int[] displayColumnWidths) throws SQLException {
0637: StringBuffer buf = new StringBuffer();
0638: buf.ensureCapacity(rowLen);
0639:
0640: int numCols = displayColumnWidths.length;
0641: int i;
0642:
0643: // get column header info
0644: // truncate it to the column display width
0645: // add a bar between each item.
0646: for (i = 1; i <= numCols; i++) {
0647: int colnum = displayColumns == null ? i
0648: : displayColumns[i - 1];
0649: if (i > 1)
0650: buf.append('|');
0651:
0652: String s;
0653: switch (rsmd.getColumnType(colnum)) {
0654: default:
0655: s = LocalizedResource.getInstance().getLocalizedString(
0656: rs, rsmd, colnum);
0657: break;
0658: case org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT:
0659: case Types.OTHER: {
0660: Object o = rs.getObject(colnum);
0661: if (o == null) {
0662: s = "NULL";
0663: } else if (o instanceof ResultSet
0664: && nestedResults != null) {
0665: s = LocalizedResource.getMessage("UT_Resul0_20",
0666: LocalizedResource.getNumber(nestedResults
0667: .size()));
0668: nestedResults.addElement(o);
0669: } else {
0670: try {
0671: s = rs.getString(colnum);
0672: } catch (SQLException se) {
0673: // oops, they don't support refetching the column
0674: s = o.toString();
0675: }
0676: }
0677: }
0678: break;
0679: }
0680: if (s == null)
0681: s = "NULL";
0682:
0683: int w = displayColumnWidths[i - 1];
0684: if (s.length() < w) {
0685: StringBuffer fullS = new StringBuffer(s);
0686: fullS.ensureCapacity(w);
0687: for (int k = s.length(); k < w; k++)
0688: fullS.append(' ');
0689: s = fullS.toString();
0690: } else if (s.length() > w)
0691: // add the & marker to know it got cut off
0692: s = s.substring(0, w - 1) + "&";
0693:
0694: buf.append(s);
0695: }
0696: indentedPrintLine(out, indentLevel, buf);
0697:
0698: } // DisplayRow
0699:
0700: /**
0701: Check if an object is null, and if it is, throw an exception
0702: with an informative parameter about what was null.
0703: The exception is a run-time exception that is internal to ij.
0704:
0705: @param o the object to test
0706: @param what the information to include in the error if it is null
0707: */
0708: public static void checkNotNull(Object o, String what) {
0709: if (o == null) {
0710: throw ijException.objectWasNull(what);
0711: }
0712: } // checkNotNull
0713:
0714: /**
0715: Map the string to the value if it is null.
0716:
0717: @param s the string to test for null
0718: @param nullValue the value to use if s is null
0719:
0720: @return if s is non-null, s; else nullValue.
0721: */
0722: static public String mapNull(String s, String nullValue) {
0723: if (s == null)
0724: return nullValue;
0725: return s;
0726: }
0727:
0728: /**
0729: If the property ij.exceptionTrace is true, display the stack
0730: trace to the print stream. Otherwise, do nothing.
0731:
0732: @param out the output stream to write to
0733: @param e the exception to display
0734: */
0735: static public void doTrace(PrintWriter out, Exception e) {
0736: if (Boolean.getBoolean("ij.exceptionTrace")) {
0737: e.printStackTrace(out);
0738: out.flush();
0739: }
0740: }
0741:
0742: static public void setMaxDisplayWidth(int maxDisplayWidth) {
0743: maxWidth = maxDisplayWidth;
0744: }
0745:
0746: static private void indentedPrintLine(PrintWriter out,
0747: int indentLevel, String text) {
0748: indent(out, indentLevel);
0749: out.println(text);
0750: }
0751:
0752: static private void indentedPrintLine(PrintWriter out,
0753: int indentLevel, StringBuffer text) {
0754: indent(out, indentLevel);
0755: out.println(text);
0756: }
0757:
0758: static private void indent(PrintWriter out, int indentLevel) {
0759: for (int ictr = 0; ictr < indentLevel; ictr++) {
0760: out.print(" ");
0761: }
0762: }
0763:
0764: // ================
0765:
0766: static public void ShowException(PrintStream out, Throwable e) {
0767: if (e == null)
0768: return;
0769:
0770: if (e instanceof SQLException)
0771: ShowSQLException(out, (SQLException) e);
0772: else
0773: e.printStackTrace(out);
0774: }
0775:
0776: static public void ShowSQLException(PrintStream out, SQLException e) {
0777: String errorCode;
0778:
0779: if (Boolean.getBoolean("ij.showErrorCode")) {
0780: errorCode = " (errorCode = " + e.getErrorCode() + ")";
0781: } else {
0782: errorCode = "";
0783: }
0784:
0785: while (e != null) {
0786: out.println("ERROR "
0787: + mapNull(e.getSQLState(), "(no SQLState)") + ": "
0788: + mapNull(e.getMessage(), "(no message)")
0789: + errorCode);
0790: doTrace(out, e);
0791: e = e.getNextException();
0792: }
0793: }
0794:
0795: static public void ShowWarnings(PrintStream out,
0796: Connection theConnection) {
0797: try {
0798: // GET CONNECTION WARNINGS
0799: SQLWarning warning = null;
0800:
0801: if (theConnection != null) {
0802: ShowWarnings(out, theConnection.getWarnings());
0803: }
0804:
0805: if (theConnection != null) {
0806: theConnection.clearWarnings();
0807: }
0808: } catch (SQLException e) {
0809: ShowSQLException(out, e);
0810: }
0811: } // ShowWarnings
0812:
0813: static public void ShowWarnings(PrintStream out, SQLWarning warning) {
0814: while (warning != null) {
0815: out.println("WARNING "
0816: + mapNull(warning.getSQLState(), "(no SQLState)")
0817: + ": "
0818: + mapNull(warning.getMessage(), "(no message)"));
0819: warning = warning.getNextWarning();
0820: }
0821: }
0822:
0823: static public void ShowWarnings(PrintStream out, ResultSet rs) {
0824: try {
0825: // GET RESULTSET WARNINGS
0826: SQLWarning warning = null;
0827:
0828: if (rs != null) {
0829: ShowWarnings(out, rs.getWarnings());
0830: }
0831:
0832: if (rs != null) {
0833: rs.clearWarnings();
0834: }
0835: } catch (SQLException e) {
0836: ShowSQLException(out, e);
0837: }
0838: } // ShowResultSetWarnings
0839:
0840: static public void ShowWarnings(PrintStream out, Statement s) {
0841: try {
0842: // GET STATEMENT WARNINGS
0843: SQLWarning warning = null;
0844:
0845: if (s != null) {
0846: ShowWarnings(out, s.getWarnings());
0847: }
0848:
0849: if (s != null) {
0850: s.clearWarnings();
0851: }
0852: } catch (SQLException e) {
0853: ShowSQLException(out, e);
0854: }
0855: } // ShowStatementWarnings
0856:
0857: static public void DisplayResults(PrintStream out, Statement stmt,
0858: Connection conn) throws SQLException {
0859: indent_DisplayResults(out, stmt, conn, 0, null, null);
0860: }
0861:
0862: static private void indent_DisplayResults(PrintStream out,
0863: Statement stmt, Connection conn, int indentLevel,
0864: int[] displayColumns, int[] displayColumnWidths)
0865: throws SQLException {
0866:
0867: checkNotNull(stmt, "Statement");
0868:
0869: ResultSet rs = stmt.getResultSet();
0870: if (rs != null) {
0871: indent_DisplayResults(out, rs, conn, indentLevel,
0872: displayColumns, displayColumnWidths);
0873: rs.close(); // let the result set go away
0874: } else {
0875: DisplayUpdateCount(out, stmt.getUpdateCount(), indentLevel);
0876: }
0877:
0878: ShowWarnings(out, stmt);
0879: } // DisplayResults
0880:
0881: static void DisplayUpdateCount(PrintStream out, int count,
0882: int indentLevel) {
0883: if (count == 1) {
0884: indentedPrintLine(out, indentLevel,
0885: "1 row inserted/updated/deleted");
0886: } else if (count >= 0) {
0887: indentedPrintLine(out, indentLevel, count
0888: + " rows inserted/updated/deleted");
0889: } else {
0890: indentedPrintLine(out, indentLevel, "Statement executed.");
0891: }
0892: }
0893:
0894: static public void DisplayResults(PrintStream out, ResultSet rs,
0895: Connection conn) throws SQLException {
0896: indent_DisplayResults(out, rs, conn, 0, null, null);
0897: }
0898:
0899: static private void indent_DisplayResults(PrintStream out,
0900: ResultSet rs, Connection conn, int indentLevel,
0901: int[] displayColumns, int[] displayColumnWidths)
0902: throws SQLException {
0903: ResultSetMetaData rsmd = rs.getMetaData();
0904: checkNotNull(rsmd, "ResultSetMetaData");
0905: Vector nestedResults;
0906: int numberOfRowsSelected = 0;
0907:
0908: // autocommit must be off or the nested cursors
0909: // are closed when the outer statement completes.
0910: if (!conn.getAutoCommit())
0911: nestedResults = new Vector();
0912: else
0913: nestedResults = null;
0914:
0915: if (displayColumnWidths == null)
0916: displayColumnWidths = getColumnDisplayWidths(rsmd,
0917: displayColumns, false);
0918:
0919: int len = indent_DisplayBanner(out, rsmd, indentLevel,
0920: displayColumns, displayColumnWidths);
0921:
0922: // When displaying rows, keep going past errors
0923: // unless/until the maximum # of errors is reached.
0924: boolean doNext = true;
0925: int retry = 0;
0926: while (doNext) {
0927: try {
0928: doNext = rs.next();
0929: if (doNext) {
0930:
0931: DisplayRow(out, rs, rsmd, len, nestedResults, conn,
0932: indentLevel, displayColumns,
0933: displayColumnWidths);
0934: ShowWarnings(out, rs);
0935: numberOfRowsSelected++;
0936: }
0937: } catch (SQLException e) {
0938: // REVISIT: might want to check the exception
0939: // and for some, not bother with the retry.
0940: if (++retry > MAX_RETRIES)
0941: throw e;
0942: else
0943: ShowSQLException(out, e);
0944: }
0945: }
0946: if (showSelectCount == true) {
0947: if (numberOfRowsSelected == 1) {
0948: out.println();
0949: indentedPrintLine(out, indentLevel, "1 row selected");
0950: } else if (numberOfRowsSelected >= 0) {
0951: out.println();
0952: indentedPrintLine(out, indentLevel,
0953: numberOfRowsSelected + " rows selected");
0954: }
0955: }
0956:
0957: DisplayNestedResults(out, nestedResults, conn, indentLevel);
0958: nestedResults = null;
0959: }
0960:
0961: static private void DisplayNestedResults(PrintStream out,
0962: Vector nr, Connection conn, int indentLevel)
0963: throws SQLException {
0964:
0965: if (nr == null)
0966: return;
0967:
0968: String s = "+ ResultSet #";
0969: String b = "++++++++++++++++";
0970: String oldString = "0";
0971:
0972: for (int i = 0; i < nr.size(); i++) {
0973: System.out.println();
0974:
0975: //just too clever to get the extra +s
0976: String t = Integer.toString(i);
0977: if (t.length() > oldString.length()) {
0978: oldString = t;
0979: b = b + "+";
0980: }
0981:
0982: System.out.println(b);
0983: System.out.println(s + i + " +");
0984: System.out.println(b);
0985: indent_DisplayResults(out, (ResultSet) nr.elementAt(i),
0986: conn, indentLevel, null, null);
0987: }
0988: }
0989:
0990: static public void DisplayNextRow(PrintStream out, ResultSet rs,
0991: Connection conn) throws SQLException {
0992: indent_DisplayNextRow(out, rs, conn, 0, null,
0993: (rs == null) ? null : getColumnDisplayWidths(rs
0994: .getMetaData(), null, false));
0995: }
0996:
0997: static private void indent_DisplayNextRow(PrintStream out,
0998: ResultSet rs, Connection conn, int indentLevel,
0999: int[] displayColumns, int[] displayColumnWidths)
1000: throws SQLException {
1001:
1002: Vector nestedResults;
1003:
1004: // autocommit must be off or the nested cursors
1005: // are closed when the outer statement completes.
1006: if (!conn.getAutoCommit())
1007: nestedResults = new Vector();
1008: else
1009: nestedResults = null;
1010:
1011: checkNotNull(rs, "ResultSet");
1012:
1013: ResultSetMetaData rsmd = rs.getMetaData();
1014: checkNotNull(rsmd, "ResultSetMetaData");
1015:
1016: // Only print stuff out if there is a row to be had.
1017: if (rs.next()) {
1018: int rowLen = indent_DisplayBanner(out, rsmd, indentLevel,
1019: null, null);
1020: DisplayRow(out, rs, rsmd, rowLen, nestedResults, conn,
1021: indentLevel, displayColumns, displayColumnWidths);
1022: } else {
1023: indentedPrintLine(out, indentLevel, LocalizedResource
1024: .getMessage("UT_NoCurreRow"));
1025: }
1026:
1027: ShowWarnings(out, rs);
1028:
1029: DisplayNestedResults(out, nestedResults, conn, indentLevel);
1030: nestedResults = null;
1031:
1032: } // DisplayNextRow
1033:
1034: static public void DisplayCurrentRow(PrintStream out, ResultSet rs,
1035: Connection conn) throws SQLException {
1036: indent_DisplayCurrentRow(out, rs, conn, 0, null,
1037: (rs == null) ? null : getColumnDisplayWidths(rs
1038: .getMetaData(), null, false));
1039: }
1040:
1041: static private void indent_DisplayCurrentRow(PrintStream out,
1042: ResultSet rs, Connection conn, int indentLevel,
1043: int[] displayColumns, int[] displayColumnWidths)
1044: throws SQLException {
1045:
1046: Vector nestedResults;
1047:
1048: if (rs == null) {
1049: indentedPrintLine(out, indentLevel, LocalizedResource
1050: .getMessage("UT_NoCurreRow_19"));
1051: return;
1052: }
1053:
1054: // autocommit must be off or the nested cursors
1055: // are closed when the outer statement completes.
1056: if (!conn.getAutoCommit())
1057: nestedResults = new Vector();
1058: else
1059: nestedResults = null;
1060:
1061: ResultSetMetaData rsmd = rs.getMetaData();
1062: checkNotNull(rsmd, "ResultSetMetaData");
1063:
1064: int rowLen = indent_DisplayBanner(out, rsmd, indentLevel,
1065: displayColumns, displayColumnWidths);
1066: DisplayRow(out, rs, rsmd, rowLen, nestedResults, conn,
1067: indentLevel, displayColumns, displayColumnWidths);
1068:
1069: ShowWarnings(out, rs);
1070:
1071: DisplayNestedResults(out, nestedResults, conn, indentLevel);
1072: nestedResults = null;
1073:
1074: } // DisplayNextRow
1075:
1076: static public int DisplayBanner(PrintStream out,
1077: ResultSetMetaData rsmd) throws SQLException {
1078: return indent_DisplayBanner(out, rsmd, 0, null,
1079: getColumnDisplayWidths(rsmd, null, false));
1080: }
1081:
1082: static private int indent_DisplayBanner(PrintStream out,
1083: ResultSetMetaData rsmd, int indentLevel,
1084: int[] displayColumns, int[] displayColumnWidths)
1085: throws SQLException {
1086:
1087: StringBuffer buf = new StringBuffer();
1088:
1089: int numCols = displayColumnWidths.length;
1090: int rowLen;
1091:
1092: // do some precalculation so the buffer is allocated only once
1093: // buffer is twice as long as the display length plus one for a newline
1094: rowLen = (numCols - 1); // for the column separators
1095: for (int i = 1; i <= numCols; i++) {
1096: rowLen += displayColumnWidths[i - 1];
1097: }
1098: buf.ensureCapacity(rowLen);
1099:
1100: // get column header info
1101: // truncate it to the column display width
1102: // add a bar between each item.
1103: for (int i = 1; i <= numCols; i++) {
1104: int colnum = displayColumns == null ? i
1105: : displayColumns[i - 1];
1106:
1107: if (i > 1)
1108: buf.append('|');
1109:
1110: String s = rsmd.getColumnLabel(colnum);
1111:
1112: int w = displayColumnWidths[i - 1];
1113:
1114: if (s.length() < w) {
1115: // build a string buffer to hold the whitespace
1116: StringBuffer blanks = new StringBuffer(s);
1117: blanks.ensureCapacity(w);
1118:
1119: // try to paste on big chunks of space at a time.
1120: for (int k = blanks.length() + 64; k <= w; k += 64)
1121: blanks
1122: .append(" ");
1123: for (int k = blanks.length() + 16; k <= w; k += 16)
1124: blanks.append(" ");
1125: for (int k = blanks.length() + 4; k <= w; k += 4)
1126: blanks.append(" ");
1127: for (int k = blanks.length(); k < w; k++)
1128: blanks.append(' ');
1129:
1130: buf.append(blanks);
1131: // REMIND: could do more cleverness, like keep around
1132: // past buffers to reuse...
1133: } else if (s.length() > w) {
1134: if (w > 1)
1135: buf.append(s.substring(0, w - 1));
1136: if (w > 0)
1137: buf.append('&');
1138: } else {
1139: buf.append(s);
1140: }
1141: }
1142:
1143: buf.setLength(Math.min(rowLen, 1024));
1144: indentedPrintLine(out, indentLevel, buf);
1145:
1146: // now print a row of '-'s
1147: for (int i = 0; i < Math.min(rowLen, 1024); i++)
1148: buf.setCharAt(i, '-');
1149: indentedPrintLine(out, indentLevel, buf);
1150:
1151: buf = null;
1152:
1153: return rowLen;
1154: } // DisplayBanner
1155:
1156: static private void DisplayRow(PrintStream out, ResultSet rs,
1157: ResultSetMetaData rsmd, int rowLen, Vector nestedResults,
1158: Connection conn, int indentLevel, int[] displayColumns,
1159: int[] displayColumnWidths) throws SQLException {
1160: StringBuffer buf = new StringBuffer();
1161: buf.ensureCapacity(rowLen);
1162:
1163: int numCols = displayColumnWidths.length;
1164: int i;
1165:
1166: // get column header info
1167: // truncate it to the column display width
1168: // add a bar between each item.
1169: for (i = 1; i <= numCols; i++) {
1170: int colnum = displayColumns == null ? i
1171: : displayColumns[i - 1];
1172: if (i > 1)
1173: buf.append('|');
1174:
1175: String s;
1176: switch (rsmd.getColumnType(colnum)) {
1177: default:
1178: s = rs.getString(colnum);
1179: break;
1180: case org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT:
1181: case Types.OTHER: {
1182: Object o = rs.getObject(colnum);
1183: if (o == null) {
1184: s = "NULL";
1185: } else if (o instanceof ResultSet
1186: && nestedResults != null) {
1187: s = "ResultSet #" + nestedResults.size();
1188: nestedResults.addElement(o);
1189: } else {
1190: try {
1191: s = rs.getString(colnum);
1192: } catch (SQLException se) {
1193: // oops, they don't support refetching the column
1194: s = o.toString();
1195: }
1196: }
1197: }
1198: break;
1199: }
1200:
1201: if (s == null)
1202: s = "NULL";
1203:
1204: int w = displayColumnWidths[i - 1];
1205: if (s.length() < w) {
1206: StringBuffer fullS = new StringBuffer(s);
1207: fullS.ensureCapacity(w);
1208: for (int k = s.length(); k < w; k++)
1209: fullS.append(' ');
1210: s = fullS.toString();
1211: } else if (s.length() > w)
1212: // add the & marker to know it got cut off
1213: s = s.substring(0, w - 1) + "&";
1214:
1215: buf.append(s);
1216: }
1217: indentedPrintLine(out, indentLevel, buf);
1218:
1219: } // DisplayRow
1220:
1221: static public void doTrace(PrintStream out, Exception e) {
1222: if (Boolean.getBoolean("ij.exceptionTrace")) {
1223: e.printStackTrace(out);
1224: out.flush();
1225: }
1226: }
1227:
1228: static private void indentedPrintLine(PrintStream out,
1229: int indentLevel, String text) {
1230: indent(out, indentLevel);
1231: out.println(text);
1232: }
1233:
1234: static private void indentedPrintLine(PrintStream out,
1235: int indentLevel, StringBuffer text) {
1236: indent(out, indentLevel);
1237: out.println(text);
1238: }
1239:
1240: static private void indent(PrintStream out, int indentLevel) {
1241: for (int ictr = 0; ictr < indentLevel; ictr++) {
1242: out.print(" ");
1243: }
1244: }
1245:
1246: // ==========================
1247: }
|