All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.JDUtilities Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: JDUtilities.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2001 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.*; // @J1c
import java.util.Hashtable;

/**
 * The JDUtilities class provides utilities for use in the implementation of the
 * JDBC driver.
 **/
class JDUtilities {
  static final String copyright = "Copyright (C) 1997-2001 International Business Machines Corporation and others.";

  private static final byte escape = (byte) 0x1B; // @D0A

  // @j4 the following two constants are now final
  static final int vrm740 = AS400.generateVRM(7, 4, 0); 
  static final int vrm710 = AS400.generateVRM(7, 1, 0); // @710 //@128sch
  static final int vrm610 = AS400.generateVRM(6, 1, 0); // @610
  static final int vrm540 = AS400.generateVRM(5, 4, 0); // @540
  static final int vrm530 = AS400.generateVRM(5, 3, 0); // @G0A
  static final int vrm520 = AS400.generateVRM(5, 2, 0); // @J2a @J3a
  static final int vrm510 = AS400.generateVRM(5, 1, 0); // @J31a
  static final int vrm450 = AS400.generateVRM(4, 5, 0); // @G0A
  static final int vrm440 = AS400.generateVRM(4, 4, 0);
  static final int vrm430 = AS400.generateVRM(4, 3, 0);

  static int JDBCLevel_ = 30; // @J4a
  static int JVMLevel_ = 120; // 1.2.0 //@big
  private final static Object bigDecimalLock_ = new Object(); // @big

  // @J4a
  static {
    try {
      Class.forName("java.util.concurrent.Semaphore"); // @big
      JVMLevel_ = 150; // jre 5.0 //@big

      Class.forName("java.sql.SQLXML"); // @big
      JDBCLevel_ = 40; // @big
      JVMLevel_ = 160; // jre 6.0 //@big
    } catch (Throwable e) {
    }
  }

  // @D0A
  /**
   * Decompresses data from one byte array to another.
   * 
   * @param source
   *          The source (compressed) bytes.
   * @param sourceOffset
   *          The offset in the source bytes to start decompressing.
   * @param sourceLength
   *          The length (compressed) of the bytes to decompress.
   * @param destination
   *          The destination (uncompressed) bytes. It is assumed that this byte
   *          array is already created.
   * @param destinationOffset
   *          The offset in the destination bytes.
   **/
  static final void decompress(byte[] source, int sourceOffset,
      int sourceLength, byte[] destination, int destinationOffset) {
    int i = sourceOffset; // Index into source.
    int j = destinationOffset; // Index into destination.

    int sourceEnd = sourceOffset + sourceLength;
    while (i < sourceEnd) {
      if (source[i] == escape) {
        if (source[i + 1] == escape) {
          destination[j++] = escape;
          i += 2;
        } else {
          int repetitions = BinaryConverter.byteArrayToInt(source, i + 2);
          for (int k = 1; k <= repetitions; ++k)
            destination[j++] = source[i + 1];
          i += 6;
        }
      } else
        destination[j++] = source[i++];
    }
  }

  /**
   * Pads a numeric value on the left with zeros. This is a utility for use in
   * implementing various pieces of the JDBC driver.
   * 
   * @param value
   *          The numeric value.
   * @param digits
   *          The number of digits.
   * @return The padded string.
   **/
  static final String padZeros(int value, int digits) {
    String temp = "000000000" + Integer.toString(value); // @A1C
    return temp.substring(temp.length() - digits);
  }

  static final String padZeros(long value, int digits) {
    String temp = "000000000000" + Long.toString(value); // @A1C
    return temp.substring(temp.length() - digits);
  }

  // @DELIMa
  /**
   * Returns the names of the libraries on the system. This will return a
   * ResultSet with a list of all the libraries.
   * 
   * @param caller
   *          The calling object.
   * @param connection
   *          The connection to the database.
   * @param setting
   *          The conversion settings (optional).
   * @param libraryListOnly
   *          If true, returns only the libraries on the library list. Otherwise
   *          returns all libraries on the system.
   * @return A ResultSet containing the list of the libraries.
   * @exception SQLException
   *              If the connection is not open or an error occurs.
   **/
  static final ResultSet getLibraries(Object caller,
      AS400JDBCConnection connection, SQLConversionSettings settings,
      boolean libraryListOnly) throws SQLException {
    // Schema = library
    connection.checkOpen();

    JDRowCache rowCache = null; // Creates a set of rows that
                                // are readable one at a time

    if (settings == null) {
      settings = SQLConversionSettings.getConversionSettings(connection);
    }
    int id = connection.getID();
    DBReplyRequestedDS reply = null;

    try {
      // Create a request
      // @P0C
      DBReturnObjectInformationRequestDS request = null;
      try {
        request = DBDSPool
            .getDBReturnObjectInformationRequestDS(
                DBReturnObjectInformationRequestDS.FUNCTIONID_RETRIEVE_LIBRARY_INFO,
                id, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
                    + DBBaseRequestDS.ORS_BITMAP_DATA_FORMAT
                    + DBBaseRequestDS.ORS_BITMAP_RESULT_DATA, 0);

        if (!libraryListOnly) // Return list of all libraries on the system
        {

          request.setLibraryName("%", connection.getConverter());
          request.setLibraryNameSearchPatternIndicator(0xF1);
        } else {
          request.setLibraryName("*LIBL", connection.getConverter()); // @libl
          request.setLibraryNameSearchPatternIndicator(0xF0); // @libl
        }

        // Set the Library Information to Return Bitmap
        // Return only the library name
        request.setLibraryReturnInfoBitmap(0x80000000);

        // Send the request and cache all results from the system
        reply = connection.sendAndReceive(request);

        // Check for errors - throw exception if errors were
        // returned
        int errorClass = reply.getErrorClass();
        if (errorClass != 0) {
          int returnCode = reply.getReturnCode();
          JDError.throwSQLException(caller, connection, id, errorClass,
              returnCode);
        }

        // Get the data format and result data
        DBDataFormat dataFormat = reply.getDataFormat();
        DBData resultData = reply.getResultData();

        // Put the result data into a row cache
        JDServerRow row = new JDServerRow(connection, id, dataFormat, settings);

        // Put the data format into a row format object
        JDRowCache serverRowCache = new JDSimpleRowCache(new JDServerRowCache(
            row, connection, id, 1, resultData, true,
            ResultSet.TYPE_SCROLL_INSENSITIVE));
        boolean isJDBC3 = true;

        JDFieldMap[] maps = null; // @F2C
        String[] fieldNames = null; // @F2C
        SQLData[] sqlData = null; // @F2C
        int[] fieldNullables = null; // @F2C
        // Set up the result set in the format required by JDBC
        if (!isJDBC3) {
          fieldNames = new String[] { "TABLE_SCHEM" };

          sqlData = new SQLData[] { new SQLVarchar(128, settings) }; // schema
                                                                     // name

          fieldNullables = new int[] { AS400JDBCDatabaseMetaData.columnNoNulls };
          maps = new JDFieldMap[1];
        } else {
          fieldNames = new String[] { "TABLE_SCHEM", "TABLE_CATALOG" }; // @G4A

          sqlData = new SQLData[] { new SQLVarchar(128, settings), // schema
                                                                   // name
              new SQLVarchar(128, settings) }; // table catalog //@G4A

          fieldNullables = new int[] { AS400JDBCDatabaseMetaData.columnNoNulls,
              AS400JDBCDatabaseMetaData.columnNullable }; // @G4A
          maps = new JDFieldMap[2]; // @G4C
        }

        // Create the mapped row format that is returned in the
        // result set.
        // This does not actual move the data, it just sets up
        // the mapping
        maps[0] = new JDSimpleFieldMap(1); // table schema // @A3C @E4C
        if (isJDBC3) // @F2A
        {
          maps[1] = new JDHardcodedFieldMap(connection.getCatalog()); // table
                                                                      // catalog
                                                                      // //@G4A
        }

        // Create the mapped row cache that is returned in the
        // result set
        JDMappedRow mappedRow = new JDMappedRow(fieldNames, sqlData,
            fieldNullables, maps);
        rowCache = new JDMappedRowCache(mappedRow, serverRowCache);
      } finally {
        if (request != null) {
          request.returnToPool();
          request = null;
        }
        // Cannot close this reply. Pass to AS400JDBCResultSet to close
        // if (reply != null) { reply.returnToPool(); reply = null; }
      }

    } // End of try block

    catch (DBDataStreamException e) {
      JDError.throwSQLException(caller, JDError.EXC_INTERNAL, e);
    }

    // Return the results
    return new AS400JDBCResultSet(rowCache, connection.getCatalog(), "Schemas",
        connection, reply); // @in2

  }

  /**
   * Strips outer double-quotes from name (if present).
   **/
  static final String stripOuterDoubleQuotes(String name/* , boolean uppercase */) {
    if (name.startsWith("\"") && name.endsWith("\"")) {
      name = name.substring(1, name.length() - 1);
    }
    return name;
  }

  /**
   * Prepares the name to be enclosed in double-quotes, for example for use as
   * column-name values in an INSERT INTO statement. 1. Strip outer
   * double-quotes (if present). 2. Double-up any embedded double-quotes.
   **/
  static final String prepareForDoubleQuotes(String name) {
    // Strip outer double-quotes.
    name = stripOuterDoubleQuotes(name);

    // Double-up any embedded double-quotes.
    if (name.indexOf('\"') == -1) {
      return name; // name has no embedded double-quotes, so nothing more to do
    } else {
      StringBuffer buf = new StringBuffer(name);
      for (int i = name.length() - 1; i >= 0; i--) // examine char-by-char, from
                                                   // end
      {
        if (buf.charAt(i) == '\"') {
          buf.insert(i, '\"'); // double the embedded double-quote
        }
      }
      return buf.toString();
    }
  }

  /**
   * Prepares the name to be enclosed in single-quotes, for example for use in
   * the WHERE clause of a SELECT statement. 1. Unless name is delimited by
   * outer double-quotes, uppercase the name. 2. Strip outer double-quotes (if
   * present). 3. Collapse any doubled embedded double-quotes, to single
   * double-quotes. 4. Double-up any embedded single-quotes.
   **/
  static final String prepareForSingleQuotes(String name, boolean uppercase) {
    // 1. Unless name is delimited by outer double-quotes, uppercase the name.
    if (name.startsWith("\"") && name.endsWith("\"")) {
      // 2. Strip outer double-quotes.
      name = name.substring(1, name.length() - 1);
    } else {
      // Don't uppercase if any embedded quotes.
      if (uppercase && name.indexOf('\'') == -1) {
        name = name.toUpperCase();
      }
    }

    // 3. Collapse any doubled embedded double-quotes, to single double-quotes.
    // 4. Double-up any embedded single-quotes.
    if (name.indexOf('\"') == -1 && name.indexOf('\'') == -1) {
      return name; // name has no embedded double-quotes, so nothing more to do
    } else {
      StringBuffer buf = new StringBuffer(name);
      for (int i = name.length() - 1; i >= 0; i--) // examine char-by-char, from
                                                   // end
      {
        char thisChar = buf.charAt(i);
        if (thisChar == '\"') {
          if (i > 0 && buf.charAt(i - 1) == '\"') {
            buf.deleteCharAt(i);
            i--; // don't re-examine the prior double-quote
          }
        } else if (thisChar == '\'') {
          buf.insert(i, '\''); // double the single-quote
        }
      }
      return buf.toString();
    }
  }

  /**
   * Strips out beginning/ending matching double-quotes, and internal double
   * embedded double-quotes get collapsed to one double-quote. 1. Strip outer
   * double-quotes (if present). 2. Collapse any doubled embedded double-quotes,
   * to single double-quotes.
   **/
  static final String stripOutDoubleEmbededQuotes(String name) {
    if (name.startsWith("\"") && name.endsWith("\"")) {
      // 1. Strip outer double-quotes.
      name = name.substring(1, name.length() - 1);
    }

    // 2. Collapse any doubled embedded double-quotes, to single double-quotes.
    if (name.indexOf('\"') == -1) {
      return name; // name has no embedded double-quotes, so nothing more to do
    } else {
      StringBuffer buf = new StringBuffer(name);
      for (int i = name.length() - 1; i >= 0; i--) // examine char-by-char, from
                                                   // end
      {
        char thisChar = buf.charAt(i);
        if (thisChar == '\"') {
          if (i > 0 && buf.charAt(i - 1) == '\"') {
            buf.deleteCharAt(i);
            i--; // don't re-examine the prior double-quote
          }
        }
      }
      return buf.toString();
    }
  }

  /**
   * Reads a reader and returns its data as a String.
   * 
   * @param input
   *          The reader.
   * @param length
   *          The length.
   * @return The string.
   * @exception SQLException
   *              If the length is not valid or the conversion is not possible.
   **/
  static final String readerToString(Reader input, int length)
      throws SQLException {
    StringBuffer buffer = new StringBuffer();
    try {
      char[] rawChars = new char[(length == 0) ? 1 : length];
      int actualLength = 0;
      while (input.ready()) {
        int length2 = input.read(rawChars);
        if (length2 < 0)
          break;
        // buffer.append (new String (rawChars, 0, length2)); //@pdd jdbc40
        buffer.append(rawChars, 0, length2); // @pda jdbc40 performance
        actualLength += length2;
      }

      // The spec says to throw an exception when the
      // actual length does not match the specified length.
      // I think this is strange since this means the length
      // parameter is essentially not needed. I.e., we always
      // read the exact number of bytes in the stream.
      if (actualLength != length)
        JDError.throwSQLException(JDError.EXC_BUFFER_LENGTH_INVALID);
    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
    }

    return buffer.toString();
  }

  // @pda jdbc40 new method for unknown length
  /**
   * Reads a reader and returns its data as a String. Reads until reader returns
   * -1 for eof.
   * 
   * @param input
   *          The reader.
   * @return The string.
   **/
  static final String readerToString(Reader input) throws SQLException {
    StringBuffer buffer = new StringBuffer();
    try {

      char[] rawChars = new char[32000];
      int actualLength = 0;
      while (input.ready()) {
        int length2 = input.read(rawChars);
        if (length2 < 0)
          break;
        // buffer.append (new String (rawChars, 0, length2)); //@pdd jdbc40
        buffer.append(rawChars, 0, length2); // @pda jdbc40 performance
        actualLength += length2;
      }

    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
    }

    return buffer.toString();
  }

  // @j1 new method
  /**
   * Runs a CL command via the database host server. It uses the QCMDEXC stored
   * procedure to run the command
   * 
   * @param connection
   *          Connection to the system
   * @param command
   *          The CL command to run
   * @exception SQLException
   *              If the command failed.
   **/
  static final void runCommand(Connection connection, String command,
      boolean SQLNaming) throws SQLException {
    Statement statement = null; // @scan1
    try {
      statement = connection.createStatement();

      // We run commands via the QCMDEXC stored procedure. That procedure
      // requires the length of the command be included with the command
      // specified in precision 15, scale 5 format. That is,
      // "CALL QSYS.QCMDEXC('command-to-run', 000000nnnn.00000)"
      String commandLength = "0000000000" + command.length();
      commandLength = commandLength.substring(commandLength.length() - 10)
          + ".00000";

      String commandPreface;

      if (SQLNaming)
        commandPreface = "CALL QSYS.QCMDEXC('";
      else
        commandPreface = "CALL QSYS/QCMDEXC('";

      String SQLCommand = commandPreface + command + "', " + commandLength
          + ")";

      statement.executeUpdate(SQLCommand);
    } finally // @scan1
    {
      if (statement != null)
        statement.close();
    }

  }

  /**
   * Reads an input stream and returns its data as a byte array.
   * 
   * @param input
   *          The input stream.
   * @param length
   *          The length.
   * @return The string.
   * @exception SQLException
   *              If the length is not valid or the conversion is not possible.
   **/
  static final byte[] streamToBytes(InputStream input, int length)
      throws SQLException {
    byte[] buffer = new byte[length];
    try {
      byte[] rawBytes = new byte[(length == 0) ? 1 : length];
      int actualLength = 0;
      //
      // Restructured logic to not use available ..
      // @A5C
      int length2 = input.read(rawBytes); /* @A5A */

      while (length2 >= 0 && actualLength < length) { /* @A5C */
        if (length2 > 0) { /* @A5A */
          if (actualLength + length2 <= length) {
            System.arraycopy(rawBytes, 0, buffer, actualLength, length2);
          } else {
            // copy part (if needed).
            System.arraycopy(rawBytes, 0, buffer, actualLength, length
                - actualLength);
          }
          actualLength += length2;
        } /* @A5A */
        length2 = input.read(rawBytes); /* @A5A */
      }

      // The spec says to throw an exception when the
      // actual length does not match the specified length.
      // I think this is strange since this means the length
      // parameter is essentially not needed. I.e., we always
      // read the exact number of bytes in the stream.
      // @KKC if (actualLength != length)
      // @KKC JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);

      // @KKC throw an exception if length is greater than the actual length
      if (actualLength < length) // @KKC
        JDError.throwSQLException(JDError.EXC_DATA_TYPE_MISMATCH); // @KKC
    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
    }

    return buffer;
  }

  // @PDA jdbc40
  /**
   * Reads an input stream and returns its data as a byte array.
   * 
   * @param input
   *          The input stream.
   * @return The string.
   * @exception SQLException
   *              If the length is not valid or the conversion is not possible.
   **/
  static final byte[] streamToBytes(InputStream input) throws SQLException {
    // @pda copy code from native since ByteBuffer is not available on ibm java
    ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();

    int blocksize = 4096;
    byte[] buffer = new byte[blocksize];
    try {
      int length2 = input.read(buffer);

      while (length2 >= 0) {
        outBuffer.write(buffer, 0, length2);
        length2 = input.read(buffer);
      }
    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
    }

    return outBuffer.toByteArray();
  }

  // @pda method from native
  /**
   * Reads an input stream and returns its data as a String.
   * 
   * @param input
   *          The input stream.
   * @param encoding
   *          The encoding.
   * @return The string.
   * @exception SQLException
   *              If the length is not valid or the conversion is not possible.
   **/
  static String streamToString(InputStream input, String encoding)
      throws SQLException {
    byte[] rawBytes = streamToBytes(input);

    try {
      return new String(rawBytes, 0, rawBytes.length, encoding);
    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
      return null;
    }
  }

  /**
   * Reads an input stream and returns its data as a String.
   * 
   * @param input
   *          The input stream.
   * @param length
   *          The length.
   * @param encoding
   *          The encoding.
   * @return The string.
   * @exception SQLException
   *              If the length is not valid or the conversion is not possible.
   **/
  static final String streamToString(InputStream input, int length,
      String encoding) throws SQLException {
    StringBuffer buffer = new StringBuffer();
    try {
      byte[] rawBytes = new byte[(length == 0) ? 1 : length];
      int actualLength = 0;
      while (input.available() > 0) {
        int length2 = input.read(rawBytes);
        buffer.append(new String(rawBytes, 0, length2, encoding));
        actualLength += length2;
      }

      // The spec says to throw an exception when the
      // actual length does not match the specified length.
      // I think this is strange since this means the length
      // parameter is essentially not needed. I.e., we always
      // read the exact number of bytes in the stream.
      if (actualLength != length)
        JDError.throwSQLException(JDError.EXC_BUFFER_LENGTH_INVALID);
    } catch (IOException e) {
      JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
    }

    return buffer.toString();
  }

  // @DELIMa
  /**
   * Uppercases the name if it's not enclosed in double-quotes.
   **/
  static final String upperCaseIfNotQuoted(String name) {
    // 1. Unless name is delimited by outer double-quotes, uppercase the name.
    if (name.startsWith("\""))
      return name;
    else
      return name.toUpperCase();
  }

  // @big For 1.4 backlevel support of Decimal and Numeric types
  /**
   * bigDecimalToPlainString takes a big decimal and converts it into a plain
   * string, without an exponent. This was the default behavior of toString
   * before JDK 1.5. bigDecimalToPlainString was taken from Native driver for
   * java 1.5 support and changed a bit for toolbox Coded so it will compile on
   * java 1.4 also
   */
  static java.lang.reflect.Method toPlainStringMethod = null;
  static Object[] emptyArgs;

  public static String bigDecimalToPlainString(BigDecimal bigDecimal) {
    if (JVMLevel_ >= 150) {
      // We compile using JDK 1.4, so we have to get to the new method via
      // reflection

      if (toPlainStringMethod == null) {
        synchronized (bigDecimalLock_) {
          if (toPlainStringMethod == null) {
            try {
              Class bigDecimalClass = Class.forName("java.math.BigDecimal");
              Class[] parameterTypes = new Class[0];
              toPlainStringMethod = bigDecimalClass.getMethod("toPlainString",
                  parameterTypes);
              emptyArgs = new Object[0];
            } catch (Exception e) {
              if (JDTrace.isTraceOn()) {
                JDTrace.logException(null,
                    "Exception while calling BigDecimal.toPlainString.", e);
              }
              toPlainStringMethod = null;

              return bigDecimal.toString();
            }
          } /* if */
        } /* synchronized */
      } /* toPlainStringMethod == null */
      String returnString;
      try {
        returnString = (String) toPlainStringMethod.invoke((Object) bigDecimal,
            emptyArgs);
      } catch (Exception e) {
        if (JDTrace.isTraceOn()) {
          JDTrace.logException(null,
              "Exception while calling BigDecimal.toPlainString.", e);
        }

        returnString = bigDecimal.toString();
      }

      return returnString;

    } else { /* not JDK15 */

      return bigDecimal.toString();
    }
  }

  // @xml3
  // removes declaration (header)
  // returns input string if there is no xml declaration
  // @xmlNat changed to be same as native driver
  static final String stripXMLDeclaration(String s) throws SQLException {
    int i = 0;
    int len = s.length();
    while (i < len
        && (s.charAt(i) == '\ufeff' || Character.isWhitespace(s.charAt(i)))) {
      i++;
    }
    if ((i + 1) < len && s.charAt(i) == '<' && s.charAt(i + 1) == '?') {
      i += 2;
      while ((i + 1) < len && (s.charAt(i) != '?' || s.charAt(i + 1) != '>')) {
        i++;
      }
      if ((i + 1) < len && s.charAt(i) == '?' && s.charAt(i + 1) == '>') {
        return s.substring(i + 2);
      }

    }
    return s;

  }

  // @xmlutf8
  static final boolean hasXMLDeclaration(String xml) {
    if (xml.length() < 6) // @BE1
      return false; // @BE1
    if (xml.substring(0, 7).indexOf("");
      int encStart = xml.indexOf("encoding=");
      if (end != -1 && encStart != -1) {
        int encEnd = xml.indexOf(" ", encStart);
        if (encEnd == -1 || encEnd > end)
          encEnd = end; // end of declaration with no space after encoding

        return xml.substring(0, encStart) + xml.substring(encEnd);
      }
    }
    return xml;
  }

  /**
   * returns the type names based on the type from java.sql.Types
   * 
   * @param typeNumber
   *          java.sql.Types value
   * @return name corresponding to the java.sql.Types value
   */

  public static String getTypeName(int typeNumber) {
    switch (typeNumber) {
    case Types.SMALLINT:
      return "SMALLINT";
    case Types.INTEGER:
      return "INTEGER";
    case Types.BIGINT:
      return "BIGINT";
    case Types.FLOAT:
      return "FLOAT";
    case Types.REAL:
      return "REAL";
    case Types.DOUBLE:
      return "DOUBLE";
    case Types.NUMERIC:
      return "NUMERIC";
    case Types.DECIMAL:
      return "DECIMAL";
    case -360:
      return "DECFLOAT";
    case Types.CHAR:
      return "CHAR";
    case Types.VARCHAR:
      return "VARCHAR";
    case Types.DATALINK:
      return "DATALINK";
    case Types.BINARY:
      return "BINARY";
    case Types.VARBINARY:
      return "VARBINARY";
    case Types.TIME:
      return "TIME";
    case Types.DATE:
      return "DATE";
    case Types.TIMESTAMP:
      return "TIMESTAMP";
    case Types.BLOB:
      return "BLOB";
    case Types.CLOB:
      return "CLOB";

      //
      // New for JDK 1.6
      //

    case -8: /* Types.ROWID */
      return "ROWID";
    case -15: /* Types.NCHAR */
      return "NCHAR";
    case -9: /* Types.NVARCHAR */
      return "NVARCHAR";
    case 2011: /* Types.NCLOB */
      return "NCLOB";
    case -16: /* Types.LONGNVARCHAR */
      return "NVARCHAR";
    case 2009: /* Types.SQLXML */
      return "SQLXML";
    case Types.BOOLEAN: /* boolean */ 
      return "BOOLEAN"; 
    default:
      return "UNKNOWN";

    }
  }

  static String[][] typeNameToTypeCode = {

  { "ARRAY", "2003" }, { "BIGINT", "-5" }, { "BINARY", "-2" }, { "BIT", "-7" },
      { "BLOB", "2004" }, { "BOOLEAN", "16" }, { "CHAR", "1" },
      { "CLOB", "2005" }, { "DATALINK", "70" }, { "DATE", "91" },
      { "DBCLOB", "2005" }, { "DECIMAL", "3" }, { "DISTINCT", "2001" },
      { "DOUBLE", "8" }, { "FLOAT", "6" }, { "INTEGER", "4" },
      { "JAVA_OBJECT", "2000" }, { "LONGNVARCHAR", "-16" },
      { "LONGVARBINARY", "-4" }, { "LONGVARCHAR", "-1" }, { "NULL", "0" },
      { "NUMERIC", "2" }, { "DECFLOAT", "-360" }, { "OTHER", "1111" },
      { "REAL", "7" }, { "REF", "2006" }, { "ROWID", "-8" },
      { "SMALLINT", "5" }, { "STRUCT", "2002" }, { "TIME", "92" },
      { "TIMESTAMP", "93" }, { "TINYINT", "-6" }, { "VARBINARY", "-3" },
      { "VARCHAR", "12" },
      /* ifndef JDBC40 */
      { "NCHAR", "1" }, { "GRAPHIC", "1" }, { "NCLOB", "2005" },
      { "NVARCHAR", "12" }, { "SQLXML", "2005" }, { "VARGRAPHIC", "12" },
  /* endif */
  /* ifdef JDBC40 
   
      {"NCHAR","-15"}, 
      {"GRAPHIC", "-15"}, 
      {"NCLOB","2011"},
      {"NVARCHAR","-9"}, 
      {"SQLXML","2009"}, 
      {"VARGRAPHIC", "-9"}, 
      
  endif */

  };

  static Hashtable typeNameHashtable = null;

  public static int getTypeCode(String typeName) throws SQLException {
    synchronized (typeNameToTypeCode) {
      if (typeNameHashtable == null) {
        typeNameHashtable = new Hashtable();
        for (int i = 0; i < typeNameToTypeCode.length; i++) {
          typeNameHashtable.put(typeNameToTypeCode[i][0], new Integer(
              typeNameToTypeCode[i][1]));
        }
      }
    }

    Integer integer = (Integer) typeNameHashtable.get(typeName);
    if (integer == null) {
      if (JDTrace.isTraceOn())
        JDTrace.logInformation(null, "Unable to get type from " + typeName);
      JDError.throwSQLException(JDError.EXC_DATA_TYPE_MISMATCH);
      return 0;
    } else {
      int typecode = integer.intValue();
      if (typecode != 0) {
        return typecode;
      } else {
        if (JDTrace.isTraceOn())
          JDTrace.logInformation(null, "Unable to get type from " + typeName);
        JDError.throwSQLException(JDError.EXC_DATA_TYPE_INVALID);
        return 0;
      }
    }
  }

  public static Hashtable instanceHashtable;

  public static boolean classIsInstanceOf(Class thisClass, String interfaceName) {
    synchronized (typeNameToTypeCode) {
      if (instanceHashtable == null) {
        instanceHashtable = new Hashtable();
      }
    }
    Hashtable interfaceHash = (Hashtable) instanceHashtable.get(thisClass);
    if (interfaceHash == null) {
      interfaceHash = new Hashtable();
      instanceHashtable.put(thisClass, interfaceHash);
    }

    Boolean answer = (Boolean) interfaceHash.get(interfaceName);
    if (answer == null) {
      boolean booleanAnswer = false;

      Class lookClass = thisClass;
      while (lookClass != null && !booleanAnswer) {
        if (JDTrace.isTraceOn()) {
          JDTrace.logInformation(null, "JDUtilities.classIsInstance checking "
              + lookClass.getName() + " of " + thisClass.getName() + " for "
              + interfaceName);
        }
        if (interfaceName.equals(lookClass.getName())) {
          booleanAnswer = true;
        } else {
          Class[] interfaces = lookClass.getInterfaces();
          for (int i = 0; !booleanAnswer && i < interfaces.length; i++) {
            if (JDTrace.isTraceOn()) {
              JDTrace.logInformation(
                  null,
                  "DB2Utilities.classIsInstance checking "
                      + interfaces[i].getName() + " of " + thisClass.getName()
                      + " for " + interfaceName);
            }
            if (interfaces[i].getName().equals(interfaceName)) {
              booleanAnswer = true;
            }
          }
          if (!booleanAnswer) {
            lookClass = lookClass.getSuperclass();
          }
        }
      }
      answer = new Boolean(booleanAnswer);
      interfaceHash.put(interfaceName, answer);
    }

    return answer.booleanValue();

  }

  /**
   * Remove all trailing space from a String.
   * 
   * @param inString
   * @return the updated string
   */
  /* @O7A */
  public static String trimTrailingSpace(String inString) {
    int lastCharacterIndex = inString.length() - 1;
    if (lastCharacterIndex >= 0) {
      if (inString.charAt(lastCharacterIndex) == ' ') {
        while ((lastCharacterIndex >= 0)
            && (inString.charAt(lastCharacterIndex) == ' ')) {
          lastCharacterIndex--;
        }
        if (lastCharacterIndex >= 0) {
          return inString.substring(0, lastCharacterIndex + 1);
        } else {
          return "";
        }
      }
    }

    return inString;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy