Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DateTime.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DateTime.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DateTime.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DateTime.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,639 @@ +/* + + Derby - Class org.apache.derby.client.am.DateTime + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package org.apache.derby.client.am; + + +/** + * High performance converters from date/time byte encodings to JDBC Date, Time and Timestamp objects. + * <p> + * Using this class for direct date/time conversions from bytes offers + * superior performance over the alternative method of first constructing + * a Java String from the encoded bytes, and then using + * [EMAIL PROTECTED] java.sql.Date#valueOf java.sql.Date.valueOf()}, + * [EMAIL PROTECTED] java.sql.Time#valueOf java.sql.Time.valueOf()} or + * [EMAIL PROTECTED] java.sql.Timestamp#valueOf java.sql.Timestamp.valueOf()}. + * <p> + */ +public class DateTime +{ + + // Hide the default constructor + private DateTime () {} + + private static final int dateRepresentationLength = 10; + private static final int timeRepresentationLength = 8; + private static final int timestampRepresentationLength = 26; + + // ********************************************************* + // ********** Output converters (byte[] -> class) ********** + // ********************************************************* + + /** + * Expected character representation is DERBY string representation + * of a date, which is in one of the following format. + */ + public static final java.sql.Date dateBytesToDate (byte[] buffer, + int offset, + java.sql.Date recyclableDate) + { + int year, month, day; + + String date = new String (buffer, offset, DateTime.dateRepresentationLength); + int yearIndx, monthIndx, dayIndx; + if (date.charAt (4) == '-') { + // JIS format: yyyy-mm-dd. + yearIndx = 0; + monthIndx = 5; + dayIndx = 8; + } + else throw new java.lang.IllegalArgumentException ("Unsupported date format!"); + + int zeroBase = ((int) '0'); + // Character arithmetic is used rather than + // the less efficient Integer.parseInt (date.substring()). + year = + 1000*(((int) date.charAt (yearIndx)) - zeroBase) + + 100*(((int) date.charAt (yearIndx+1)) - zeroBase) + + 10*(((int) date.charAt (yearIndx+2)) - zeroBase) + + (((int) date.charAt (yearIndx+3)) - zeroBase) - + 1900; + month = + 10*(((int) date.charAt (monthIndx)) - zeroBase) + + (((int) date.charAt (monthIndx+1)) - zeroBase) - + 1; + day = + 10*(((int) date.charAt (dayIndx)) - zeroBase) + + (((int) date.charAt (dayIndx+1)) - zeroBase); + + if (recyclableDate == null) + return new java.sql.Date (year, month, day); + else { + recyclableDate.setYear (year); + recyclableDate.setMonth (month); + recyclableDate.setDate (day); + return recyclableDate; + } + } + + /** + * Expected character representation is DERBY string representation + * of a time, which is in one of the following format: hh.mm.ss. + */ + public static final java.sql.Time timeBytesToTime (byte[] buffer, + int offset, + java.sql.Time recyclableTime) + { + int hour, minute, second; + + String time = new String (buffer, offset, DateTime.timeRepresentationLength); + int zeroBase = ((int) '0'); + + // compute hour. + hour = + 10*(((int) time.charAt (0)) - zeroBase) + + (((int) time.charAt (1)) - zeroBase); + // compute minute. + minute = + 10*(((int) time.charAt (3)) - zeroBase) + + (((int) time.charAt (4)) - zeroBase); + // compute second. + second = + 10*(((int) time.charAt (6)) - zeroBase) + + (((int) time.charAt (7)) - zeroBase); + + if (recyclableTime == null) + return new java.sql.Time (hour, minute, second); + else { + recyclableTime.setHours (hour); + recyclableTime.setMinutes (minute); + recyclableTime.setSeconds (second); + return recyclableTime; + } + } + + /** + * Expected character representation is DERBY string representation + * of a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + * + */ + public static final java.sql.Timestamp timestampBytesToTimestamp (byte[] buffer, + int offset, + java.sql.Timestamp recyclableTimestamp) + { + int year, month, day, hour, minute, second, fraction; + + String timestamp = new String (buffer, offset, DateTime.timestampRepresentationLength); + int zeroBase = ((int) '0'); + + year = + 1000*(((int) timestamp.charAt (0)) - zeroBase) + + 100*(((int) timestamp.charAt (1)) - zeroBase) + + 10*(((int) timestamp.charAt (2)) - zeroBase) + + (((int) timestamp.charAt (3)) - zeroBase) - + 1900; + month = + 10*(((int) timestamp.charAt (5)) - zeroBase) + + (((int) timestamp.charAt (6)) - zeroBase) - + 1; + day = + 10*(((int) timestamp.charAt (8)) - zeroBase) + + (((int) timestamp.charAt (9)) - zeroBase); + hour = + 10*(((int) timestamp.charAt (11)) - zeroBase) + + (((int) timestamp.charAt (12)) - zeroBase); + minute = + 10*(((int) timestamp.charAt (14)) - zeroBase) + + (((int) timestamp.charAt (15)) - zeroBase); + second = + 10*(((int) timestamp.charAt (17)) - zeroBase) + + (((int) timestamp.charAt (18)) - zeroBase); + fraction = + 100000*(((int) timestamp.charAt (20)) - zeroBase) + + 10000*(((int) timestamp.charAt (21)) - zeroBase) + + 1000*(((int) timestamp.charAt (22)) - zeroBase) + + 100*(((int) timestamp.charAt (23)) - zeroBase) + + 10*(((int) timestamp.charAt (24)) - zeroBase) + + (((int) timestamp.charAt (25)) - zeroBase); + + if (recyclableTimestamp == null) + return new java.sql.Timestamp (year, month, day, hour, minute, second, fraction*1000); + else { + recyclableTimestamp.setYear (year); + recyclableTimestamp.setMonth (month); + recyclableTimestamp.setDate (day); + recyclableTimestamp.setHours (hour); + recyclableTimestamp.setMinutes (minute); + recyclableTimestamp.setSeconds (second); + recyclableTimestamp.setNanos (fraction*1000); + return recyclableTimestamp; + } + } + + // ******************************************************** + // ********** Input converters (class -> byte[]) ********** + // ******************************************************** + + /** + * The returned character representation is in JDBC date format: + * <code>yyyy-mm-dd</code> date format in + * DERBY string representation of a date. + * + */ + public static final int dateToDateBytes (byte[] buffer, + int offset, + java.sql.Date date + ) throws ConversionException + { + int year = date.getYear () + 1900; + if (year > 9999) throw new ConversionException ("Year exceeds the maximum \"9999\"."); + int month = date.getMonth () + 1; + int day = date.getDate (); + + char[] dateChars = new char[DateTime.dateRepresentationLength]; + int zeroBase = (int) '0'; + dateChars[0] = (char) (year/1000 + zeroBase); + dateChars[1] = (char) ((year%1000)/100 + zeroBase); + dateChars[2] = (char) ((year%100)/10 + zeroBase); + dateChars[3] = (char) (year%10 + + zeroBase); + dateChars[4] = '-'; + dateChars[5] = (char) (month/10 + zeroBase); + dateChars[6] = (char) (month%10 + zeroBase); + dateChars[7] = '-'; + dateChars[8] = (char) (day/10 + zeroBase); + dateChars[9] = (char) (day%10 + zeroBase); + byte[] dateBytes = (new String(dateChars)).getBytes (); + System.arraycopy(dateBytes, 0, buffer, offset, DateTime.dateRepresentationLength); + + return DateTime.dateRepresentationLength; + } + + /** + * The returned character representation is in JDBC time escape format: + * <code>hh:mm:ss</code>, which is the same as JIS time format in + * DERBY string representation of a time. + * + */ + public static final int timeToTimeBytes (byte[] buffer, + int offset, + java.sql.Time time) + { + int hour = time.getHours(); + int minute = time.getMinutes(); + int second = time.getSeconds(); + + char[] timeChars = new char[DateTime.timeRepresentationLength]; + int zeroBase = (int) '0'; + timeChars[0] = (char) (hour/10 + zeroBase); + timeChars[1] = (char) (hour%10 + + zeroBase); + timeChars[2] = ':'; + timeChars[3] = (char) (minute/10 + zeroBase); + timeChars[4] = (char) (minute%10 + zeroBase); + timeChars[5] = ':'; + timeChars[6] = (char) (second/10 + zeroBase); + timeChars[7] = (char) (second%10 + zeroBase); + byte[] timeBytes = (new String(timeChars)).getBytes (); + System.arraycopy(timeBytes, 0, buffer, offset, DateTime.timeRepresentationLength); + + return DateTime.timeRepresentationLength; + } + + /** + * The returned character representation is in DERBY string representation of + * a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + */ + public static final int timestampToTimestampBytes (byte[] buffer, + int offset, + java.sql.Timestamp timestamp + ) throws ConversionException + { + int year = timestamp.getYear () + 1900; + if (year > 9999) throw new ConversionException ("Year exceeds the maximum \"9999\"."); + int month = timestamp.getMonth () + 1; + int day = timestamp.getDate (); + int hour = timestamp.getHours(); + int minute = timestamp.getMinutes(); + int second = timestamp.getSeconds(); + int microsecond = timestamp.getNanos()/1000; + + char[] timestampChars = new char[DateTime.timestampRepresentationLength]; + int zeroBase = (int) '0'; + timestampChars[0] = (char) (year/1000 + zeroBase); + timestampChars[1] = (char) ((year%1000)/100 + zeroBase); + timestampChars[2] = (char) ((year%100)/10 + zeroBase); + timestampChars[3] = (char) (year%10 + + zeroBase); + timestampChars[4] = '-'; + timestampChars[5] = (char) (month/10 + zeroBase); + timestampChars[6] = (char) (month%10 + zeroBase); + timestampChars[7] = '-'; + timestampChars[8] = (char) (day/10 + zeroBase); + timestampChars[9] = (char) (day%10 + zeroBase); + timestampChars[10] = '-'; + timestampChars[11] = (char) (hour/10 + zeroBase); + timestampChars[12] = (char) (hour%10 + zeroBase); + timestampChars[13] = '.'; + timestampChars[14] = (char) (minute/10 + zeroBase); + timestampChars[15] = (char) (minute%10 + zeroBase); + timestampChars[16] = '.'; + timestampChars[17] = (char) (second/10 + zeroBase); + timestampChars[18] = (char) (second%10 + zeroBase); + timestampChars[19] = '.'; + timestampChars[20] = (char) (microsecond/100000 + zeroBase); + timestampChars[21] = (char) ((microsecond%100000)/10000 + zeroBase); + timestampChars[22] = (char) ((microsecond%10000)/1000 + zeroBase); + timestampChars[23] = (char) ((microsecond%1000)/100 + zeroBase); + timestampChars[24] = (char) ((microsecond%100)/10 + zeroBase); + timestampChars[25] = (char) (microsecond%10 + zeroBase); + + byte[] timestampBytes = (new String(timestampChars)).getBytes (); + System.arraycopy(timestampBytes, 0, buffer, offset, DateTime.timestampRepresentationLength); + + return DateTime.timestampRepresentationLength; + } + + // ********************************************************* + // ******* CROSS output converters (byte[] -> class) ******* + // ********************************************************* + + /** + * Expected character representation is DERBY string representation + * of a date, which is in one of the following format. + */ + public static final java.sql.Timestamp dateBytesToTimestamp (byte[] buffer, + int offset, + java.sql.Timestamp recyclableTimestamp) + { + int year, month, day; + + String date = new String (buffer, offset, DateTime.dateRepresentationLength); + int yearIndx, monthIndx, dayIndx; + + yearIndx = 0; + monthIndx = 5; + dayIndx = 8; + + int zeroBase = ((int) '0'); + // Character arithmetic is used rather than + // the less efficient Integer.parseInt (date.substring()). + year = + 1000*(((int) date.charAt (yearIndx)) - zeroBase) + + 100*(((int) date.charAt (yearIndx+1)) - zeroBase) + + 10*(((int) date.charAt (yearIndx+2)) - zeroBase) + + (((int) date.charAt (yearIndx+3)) - zeroBase) - + 1900; + month = + 10*(((int) date.charAt (monthIndx)) - zeroBase) + + (((int) date.charAt (monthIndx+1)) - zeroBase) - + 1; + day = + 10*(((int) date.charAt (dayIndx)) - zeroBase) + + (((int) date.charAt (dayIndx+1)) - zeroBase); + + if (recyclableTimestamp == null) + return new java.sql.Timestamp (year, month, day, 0, 0, 0, 0); + else { + recyclableTimestamp.setYear (year); + recyclableTimestamp.setMonth (month); + recyclableTimestamp.setDate (day); + recyclableTimestamp.setHours (0); + recyclableTimestamp.setMinutes (0); + recyclableTimestamp.setSeconds (0); + recyclableTimestamp.setNanos (0); + return recyclableTimestamp; + } + } + + /** + * Expected character representation is DERBY string representation + * of a time, which is in one of the following format. + */ + public static final java.sql.Timestamp timeBytesToTimestamp (byte[] buffer, + int offset, + java.sql.Timestamp recyclableTimestamp) + { + int hour, minute, second; + + String time = new String (buffer, offset, DateTime.timeRepresentationLength); + int zeroBase = ((int) '0'); + + // compute hour. + hour = + 10*(((int) time.charAt (0)) - zeroBase) + + (((int) time.charAt (1)) - zeroBase); + // compute minute. + minute = + 10*(((int) time.charAt (3)) - zeroBase) + + (((int) time.charAt (4)) - zeroBase); + // compute second JIS format: hh:mm:ss. + second = + 10*(((int) time.charAt (6)) - zeroBase) + + (((int) time.charAt (7)) - zeroBase); + + if (recyclableTimestamp == null) + return new java.sql.Timestamp (0, 0, 1, hour, minute, second, 0); + else { + recyclableTimestamp.setYear (0); + recyclableTimestamp.setMonth (0); + recyclableTimestamp.setDate (1); + recyclableTimestamp.setHours (hour); + recyclableTimestamp.setMinutes (minute); + recyclableTimestamp.setSeconds (second); + recyclableTimestamp.setNanos (0); + return recyclableTimestamp; + } + } + + /** + * Expected character representation is DERBY string representation + * of a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + */ + public static final java.sql.Date timestampBytesToDate (byte[] buffer, + int offset, + java.sql.Date recyclableDate) + { + int year, month, day; + + String timestamp = new String (buffer, offset, DateTime.timestampRepresentationLength); + int zeroBase = ((int) '0'); + + year = + 1000*(((int) timestamp.charAt (0)) - zeroBase) + + 100*(((int) timestamp.charAt (1)) - zeroBase) + + 10*(((int) timestamp.charAt (2)) - zeroBase) + + (((int) timestamp.charAt (3)) - zeroBase) - + 1900; + month = + 10*(((int) timestamp.charAt (5)) - zeroBase) + + (((int) timestamp.charAt (6)) - zeroBase) - + 1; + day = + 10*(((int) timestamp.charAt (8)) - zeroBase) + + (((int) timestamp.charAt (9)) - zeroBase); + + if (recyclableDate == null) + return new java.sql.Date (year, month, day); + else { + recyclableDate.setYear (year); + recyclableDate.setMonth (month); + recyclableDate.setDate (day); + return recyclableDate; + } + } + + /** + * Expected character representation is DERBY string representation + * of a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + */ + public static final java.sql.Time timestampBytesToTime (byte[] buffer, + int offset, + java.sql.Time recyclableTime) + { + int hour, minute, second; + + String timestamp = new String (buffer, offset, DateTime.timestampRepresentationLength); + int zeroBase = ((int) '0'); + + hour = + 10*(((int) timestamp.charAt (11)) - zeroBase) + + (((int) timestamp.charAt (12)) - zeroBase); + minute = + 10*(((int) timestamp.charAt (14)) - zeroBase) + + (((int) timestamp.charAt (15)) - zeroBase); + second = + 10*(((int) timestamp.charAt (17)) - zeroBase) + + (((int) timestamp.charAt (18)) - zeroBase); + + if (recyclableTime == null) + return new java.sql.Time (hour, minute, second); + else { + recyclableTime.setYear (hour); + recyclableTime.setMonth (minute); + recyclableTime.setDate (second); + return recyclableTime; + } + } + + // ********************************************************* + // ******* CROSS input converters (class -> byte[]) ******** + // ********************************************************* + + /** + * The returned character representation is in JDBC date escape format: + * <code>yyyy-mm-dd</code>, which is the same as JIS date format in + * DERBY string representation of a date. + * + */ + public static final int timestampToDateBytes (byte[] buffer, + int offset, + java.sql.Timestamp timestamp + ) throws ConversionException + { + int year = timestamp.getYear () + 1900; + if (year > 9999) throw new ConversionException ("Year exceeds the maximum \"9999\"."); + int month = timestamp.getMonth () + 1; + int day = timestamp.getDate (); + + char[] dateChars = new char[DateTime.dateRepresentationLength]; + int zeroBase = (int) '0'; + dateChars[0] = (char) (year/1000 + zeroBase); + dateChars[1] = (char) ((year%1000)/100 + zeroBase); + dateChars[2] = (char) ((year%100)/10 + zeroBase); + dateChars[3] = (char) (year%10 + + zeroBase); + dateChars[4] = '-'; + dateChars[5] = (char) (month/10 + zeroBase); + dateChars[6] = (char) (month%10 + zeroBase); + dateChars[7] = '-'; + dateChars[8] = (char) (day/10 + zeroBase); + dateChars[9] = (char) (day%10 + zeroBase); + byte[] dateBytes = (new String(dateChars)).getBytes (); + System.arraycopy(dateBytes, 0, buffer, offset, DateTime.dateRepresentationLength); + + return DateTime.dateRepresentationLength; + } + + /** + * The returned character representation is in JDBC time escape format: + * <code>hh:mm:ss</code>, which is the same as JIS time format in + * DERBY string representation of a time. + * + */ + public static final int timestampToTimeBytes (byte[] buffer, + int offset, + java.sql.Timestamp timestamp) + { + int hour = timestamp.getHours(); + int minute = timestamp.getMinutes(); + int second = timestamp.getSeconds(); + + char[] timeChars = new char[DateTime.timeRepresentationLength]; + int zeroBase = (int) '0'; + timeChars[0] = (char) (hour/10 + zeroBase); + timeChars[1] = (char) (hour%10 + + zeroBase); + timeChars[2] = ':'; + timeChars[3] = (char) (minute/10 + zeroBase); + timeChars[4] = (char) (minute%10 + zeroBase); + timeChars[5] = ':'; + timeChars[6] = (char) (second/10 + zeroBase); + timeChars[7] = (char) (second%10 + zeroBase); + byte[] timeBytes = (new String(timeChars)).getBytes (); + System.arraycopy(timeBytes, 0, buffer, offset, DateTime.timeRepresentationLength); + + return DateTime.timeRepresentationLength; + } + + /** + * The returned character representation is in DERBY string representation of + * a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + * + */ + public static final int dateToTimestampBytes (byte[] buffer, + int offset, + java.sql.Date date + ) throws ConversionException + { + int year = date.getYear () + 1900; + if (year > 9999) throw new ConversionException ("Year exceeds the maximum \"9999\"."); + int month = date.getMonth () + 1; + int day = date.getDate (); + + char[] timestampChars = new char[DateTime.timestampRepresentationLength]; + int zeroBase = (int) '0'; + timestampChars[0] = (char) (year/1000 + zeroBase); + timestampChars[1] = (char) ((year%1000)/100 + zeroBase); + timestampChars[2] = (char) ((year%100)/10 + zeroBase); + timestampChars[3] = (char) (year%10 + + zeroBase); + timestampChars[4] = '-'; + timestampChars[5] = (char) (month/10 + zeroBase); + timestampChars[6] = (char) (month%10 + zeroBase); + timestampChars[7] = '-'; + timestampChars[8] = (char) (day/10 + zeroBase); + timestampChars[9] = (char) (day%10 + zeroBase); + timestampChars[10] = '-'; + timestampChars[11] = '0'; + timestampChars[12] = '0'; + timestampChars[13] = '.'; + timestampChars[14] = '0'; + timestampChars[15] = '0'; + timestampChars[16] = '.'; + timestampChars[17] = '0'; + timestampChars[18] = '0'; + timestampChars[19] = '.'; + timestampChars[20] = '0'; + timestampChars[21] = '0'; + timestampChars[22] = '0'; + timestampChars[23] = '0'; + timestampChars[24] = '0'; + timestampChars[25] = '0'; + + byte[] timestampBytes = (new String(timestampChars)).getBytes (); + System.arraycopy(timestampBytes, 0, buffer, offset, DateTime.timestampRepresentationLength); + + return DateTime.timestampRepresentationLength; + } + + /** + * The returned character representation is in DERBY string representation of + * a timestamp: <code>yyyy-mm-dd-hh.mm.ss.ffffff</code>. + * + */ + public static final int timeToTimestampBytes (byte[] buffer, + int offset, + java.sql.Time time + ) + { + int hour = time.getHours(); + int minute = time.getMinutes(); + int second = time.getSeconds(); + + char[] timestampChars = new char[DateTime.timestampRepresentationLength]; + int zeroBase = (int) '0'; + timestampChars[0] = '1'; + timestampChars[1] = '9'; + timestampChars[2] = '0'; + timestampChars[3] = '0'; + timestampChars[4] = '-'; + timestampChars[5] = '0'; + timestampChars[6] = '1'; + timestampChars[7] = '-'; + timestampChars[8] = '0'; + timestampChars[9] = '1'; + timestampChars[10] = '-'; + timestampChars[11] = (char) (hour/10 + zeroBase); + timestampChars[12] = (char) (hour%10 + zeroBase); + timestampChars[13] = '.'; + timestampChars[14] = (char) (minute/10 + zeroBase); + timestampChars[15] = (char) (minute%10 + zeroBase); + timestampChars[16] = '.'; + timestampChars[17] = (char) (second/10 + zeroBase); + timestampChars[18] = (char) (second%10 + zeroBase); + timestampChars[19] = '.'; + timestampChars[20] = '0'; + timestampChars[21] = '0'; + timestampChars[22] = '0'; + timestampChars[23] = '0'; + timestampChars[24] = '0'; + timestampChars[25] = '0'; + + byte[] timestampBytes = (new String(timestampChars)).getBytes (); + System.arraycopy(timestampBytes, 0, buffer, offset, DateTime.timestampRepresentationLength); + + return DateTime.timestampRepresentationLength; + } +} +
Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DateTime.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Decimal.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Decimal.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Decimal.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Decimal.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,489 @@ +/* + + Derby - Class org.apache.derby.client.am.Decimal + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package org.apache.derby.client.am; + +/** + * Converters from fixed point decimal bytes to <code>java.math.BigDecimal</code>, + * <code>double</code>, or <code>long</code>. + */ +public class Decimal +{ + /** + * Packed Decimal representation + */ + public final static int PACKED_DECIMAL = 0x30; + + //--------------------------private constants--------------------------------- + + private static final int[][] tenRadixMagnitude = { + { 0x3b9aca00 }, // 10^9 + { 0x0de0b6b3, 0xa7640000 }, // 10^18 + { 0x033b2e3c, 0x9fd0803c, 0xe8000000 }, // 10^27 + }; + + //--------------------------constructors-------------------------------------- + + // Hide the default constructor, this is a static class. + private Decimal() {} + + //--------------------------private helper methods---------------------------- + + /** + * Convert a range of packed nybbles (up to 9 digits without overflow) to an int. + * Note that for performance purpose, it does not do array-out-of-bound checking. + */ + private static final int packedNybblesToInt (byte[] buffer, + int offset, + int startNybble, + int numberOfNybbles) + { + int value = 0; + + int i = startNybble / 2; + if ((startNybble % 2) != 0) { + // process low nybble of the first byte if necessary. + value += buffer[offset+i] & 0x0F; + i++; + } + + int endNybble = startNybble + numberOfNybbles -1; + for (; i<(endNybble+1)/2; i++) { + value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); // high nybble. + value = value*10 + (buffer[offset+i] & 0x0F); // low nybble. + } + + if ((endNybble % 2) == 0) { + // process high nybble of the last byte if necessary. + value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); + } + + return value; + } + + /** + * Convert a range of packed nybbles (up to 18 digits without overflow) to a long. + * Note that for performance purpose, it does not do array-out-of-bound checking. + */ + private static final long packedNybblesToLong (byte[] buffer, + int offset, + int startNybble, + int numberOfNybbles) + { + long value = 0; + + int i = startNybble / 2; + if ((startNybble % 2) != 0) { + // process low nybble of the first byte if necessary. + value += buffer[offset+i] & 0x0F; + i++; + } + + int endNybble = startNybble + numberOfNybbles -1; + for (; i<(endNybble+1)/2; i++) { + value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); // high nybble. + value = value*10 + (buffer[offset+i] & 0x0F); // low nybble. + } + + if ((endNybble % 2) == 0) { + // process high nybble of the last byte if necessary. + value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); + } + + return value; + } + + /** + * Compute the int array of magnitude from input value segments. + */ + private static final int[] computeMagnitude(int[] input) + { + int length = input.length; + int[] mag = new int[length]; + + mag[length-1] = input[length-1]; + for (int i=0; i<length-1; i++) { + int carry = 0; + int j = tenRadixMagnitude[i].length-1; + int k = length-1; + for (; j>=0; j--, k--) { + long product = (input[length-2-i] & 0xFFFFFFFFL) * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL) + + (mag[k] & 0xFFFFFFFFL) // add previous value + + (carry & 0xFFFFFFFFL); // add carry + carry = (int) (product >>> 32); + mag[k] = (int) (product & 0xFFFFFFFFL); + } + mag[k] = (int) carry; + } + return mag; + } + + //--------------entry points for runtime representation----------------------- + + /** + * Build a <code>java.math.BigDecimal</code> from a fixed point decimal byte representation. + * + * @exception IllegalArgumentException if the specified representation is not recognized. + */ + public static final java.math.BigDecimal getBigDecimal (byte[] buffer, + int offset, + int precision, + int scale + ) throws java.io.UnsupportedEncodingException + { + // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code> + int length = precision / 2 + 1; + + // check for sign. + int signum; + if ((buffer[offset+length-1] & 0x0F) == 0x0D) + signum = -1; + else + signum = 1; + + if (precision <= 9) { + // can be handled by int without overflow. + int value = packedNybblesToInt(buffer, offset, 0, length*2-1); + + // convert value to a byte array of magnitude. + byte[] magnitude = new byte[4]; + magnitude[0] = (byte)(value >>> 24); + magnitude[1] = (byte)(value >>> 16); + magnitude[2] = (byte)(value >>> 8); + magnitude[3] = (byte)(value); + + return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale); + } + else if (precision <= 18) { + // can be handled by long without overflow. + long value = packedNybblesToLong(buffer, offset, 0, length*2-1); + + // convert value to a byte array of magnitude. + byte[] magnitude = new byte[8]; + magnitude[0] = (byte)(value >>> 56); + magnitude[1] = (byte)(value >>> 48); + magnitude[2] = (byte)(value >>> 40); + magnitude[3] = (byte)(value >>> 32); + magnitude[4] = (byte)(value >>> 24); + magnitude[5] = (byte)(value >>> 16); + magnitude[6] = (byte)(value >>> 8); + magnitude[7] = (byte)(value); + + return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale); + } + else if (precision <= 27) { + // get the value of last 9 digits (5 bytes). + int lo = packedNybblesToInt(buffer, offset, (length-5)*2, 9); + // get the value of another 9 digits (5 bytes). + int me = packedNybblesToInt(buffer, offset, (length-10)*2+1, 9); + // get the value of the rest digits. + int hi = packedNybblesToInt(buffer, offset, 0, (length-10)*2+1); + + // compute the int array of magnitude. + int[] value = computeMagnitude(new int[] {hi, me, lo}); + + // convert value to a byte array of magnitude. + byte[] magnitude = new byte[12]; + magnitude[0] = (byte)(value[0] >>> 24); + magnitude[1] = (byte)(value[0] >>> 16); + magnitude[2] = (byte)(value[0] >>> 8); + magnitude[3] = (byte)(value[0]); + magnitude[4] = (byte)(value[1] >>> 24); + magnitude[5] = (byte)(value[1] >>> 16); + magnitude[6] = (byte)(value[1] >>> 8); + magnitude[7] = (byte)(value[1]); + magnitude[8] = (byte)(value[2] >>> 24); + magnitude[9] = (byte)(value[2] >>> 16); + magnitude[10] = (byte)(value[2] >>> 8); + magnitude[11] = (byte)(value[2]); + + return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale); + } + else if (precision <= 31) { + // get the value of last 9 digits (5 bytes). + int lo = packedNybblesToInt(buffer, offset, (length-5)*2, 9); + // get the value of another 9 digits (5 bytes). + int meLo = packedNybblesToInt(buffer, offset, (length-10)*2+1, 9); + // get the value of another 9 digits (5 bytes). + int meHi = packedNybblesToInt(buffer, offset, (length-14)*2, 9); + // get the value of the rest digits. + int hi = packedNybblesToInt(buffer, offset, 0, (length-14)*2); + + // compute the int array of magnitude. + int[] value = computeMagnitude(new int[] {hi, meHi, meLo, lo}); + + // convert value to a byte array of magnitude. + byte[] magnitude = new byte[16]; + magnitude[0] = (byte)(value[0] >>> 24); + magnitude[1] = (byte)(value[0] >>> 16); + magnitude[2] = (byte)(value[0] >>> 8); + magnitude[3] = (byte)(value[0]); + magnitude[4] = (byte)(value[1] >>> 24); + magnitude[5] = (byte)(value[1] >>> 16); + magnitude[6] = (byte)(value[1] >>> 8); + magnitude[7] = (byte)(value[1]); + magnitude[8] = (byte)(value[2] >>> 24); + magnitude[9] = (byte)(value[2] >>> 16); + magnitude[10] = (byte)(value[2] >>> 8); + magnitude[11] = (byte)(value[2]); + magnitude[12] = (byte)(value[3] >>> 24); + magnitude[13] = (byte)(value[3] >>> 16); + magnitude[14] = (byte)(value[3] >>> 8); + magnitude[15] = (byte)(value[3]); + + return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale); + } + else { + // throw an exception here if nibbles is greater than 31 + throw new java.lang.IllegalArgumentException("Decimal may only be up to 31 digits!"); + } + } + + /** + * Build a Java <code>double</code> from a fixed point decimal byte representation. + * + * @exception IllegalArgumentException if the specified representation is not recognized. + */ + public static final double getDouble (byte[] buffer, + int offset, + int precision, + int scale + ) throws java.io.UnsupportedEncodingException + { + // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code> + int length = precision / 2 + 1; + + // check for sign. + int signum; + if ((buffer[offset+length-1] & 0x0F) == 0x0D) + signum = -1; + else + signum = 1; + + if (precision <= 9) { + // can be handled by int without overflow. + int value = packedNybblesToInt(buffer, offset, 0, length*2-1); + + return signum * value / Math.pow(10, scale); + } + else if (precision <= 18) { + // can be handled by long without overflow. + long value = packedNybblesToLong(buffer, offset, 0, length*2-1); + + return signum * value / Math.pow(10, scale); + } + else if (precision <= 27) { + // get the value of last 9 digits (5 bytes). + int lo = packedNybblesToInt(buffer, offset, (length-5)*2, 9); + // get the value of another 9 digits (5 bytes). + int me = packedNybblesToInt(buffer, offset, (length-10)*2+1, 9); + // get the value of the rest digits. + int hi = packedNybblesToInt(buffer, offset, 0, (length-10)*2+1); + + return signum * (lo / Math.pow(10, scale) + + me * Math.pow(10, 9-scale) + + hi * Math.pow(10, 18-scale)); + } + else if (precision <= 31) { + // get the value of last 9 digits (5 bytes). + int lo = packedNybblesToInt(buffer, offset, (length-5)*2, 9); + // get the value of another 9 digits (5 bytes). + int meLo = packedNybblesToInt(buffer, offset, (length-10)*2+1, 9); + // get the value of another 9 digits (5 bytes). + int meHi = packedNybblesToInt(buffer, offset, (length-14)*2, 9); + // get the value of the rest digits. + int hi = packedNybblesToInt(buffer, offset, 0, (length-14)*2); + + return signum * (lo / Math.pow(10, scale) + + meLo * Math.pow(10, 9-scale) + + meHi * Math.pow(10, 18-scale) + + hi * Math.pow(10, 27-scale)); + } + else { + // throw an exception here if nibbles is greater than 31 + throw new java.lang.IllegalArgumentException ("Decimal may only be up to 31 digits!"); + } + } + + /** + * Build a Java <code>long</code> from a fixed point decimal byte representation. + * + * @exception IllegalArgumentException if the specified representation is not recognized. + */ + public static final long getLong (byte[] buffer, + int offset, + int precision, + int scale + ) throws java.io.UnsupportedEncodingException + { + if (precision > 31) { + // throw an exception here if nibbles is greater than 31 + throw new java.lang.IllegalArgumentException ("Decimal may only be up to 31 digits!"); + } + + // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code> + int length = precision / 2 + 1; + + // check for sign. + int signum; + if ((buffer[offset+length-1] & 0x0F) == 0x0D) + signum = -1; + else + signum = 1; + + // compute the integer part only. + int leftOfDecimalPoint = length*2-1-scale; + long integer = 0; + if (leftOfDecimalPoint > 0) { + int i = 0; + for (; i<leftOfDecimalPoint/2; i++) { + integer = integer*10 + signum*((buffer[offset+i] & 0xF0) >>> 4); // high nybble. + integer = integer*10 + signum* (buffer[offset+i] & 0x0F); // low nybble. + } + if ((leftOfDecimalPoint % 2) == 1) { + // process high nybble of the last byte if necessary. + integer = integer*10 + signum*((buffer[offset+i] & 0xF0) >>> 4); + } + } + + return integer; + } + + //--------------entry points for runtime representation----------------------- + + /** + Write a Java <code>java.math.BigDecimal</code> to packed decimal bytes. + */ + public static final int bigDecimalToPackedDecimalBytes (byte[] buffer, + int offset, + java.math.BigDecimal b, + int declaredPrecision, + int declaredScale) + throws ConversionException + { + // packed decimal may only be up to 31 digits. + if (declaredPrecision > 31) + throw new ConversionException ("Packed decimal may only be up to 31 digits!"); + + // get absolute unscaled value of the BigDecimal as a String. + String unscaledStr = b.unscaledValue().abs().toString(); + + // get precision of the BigDecimal. + int bigPrecision = unscaledStr.length(); + + if (bigPrecision > 31) + throw new ConversionException ("The numeric literal \"" + + b.toString() + + "\" is not valid because its value is out of range.", + "42820", + -405); + + int bigScale = b.scale(); + int bigWholeIntegerLength = bigPrecision - bigScale; + if ( (bigWholeIntegerLength > 0) && (!unscaledStr.equals ("0")) ) { + // if whole integer part exists, check if overflow. + int declaredWholeIntegerLength = declaredPrecision - declaredScale; + if (bigWholeIntegerLength > declaredWholeIntegerLength) + throw new ConversionException ("Overflow occurred during numeric data type conversion of \"" + + b.toString() + + "\".", + "22003", + -413); + } + + // convert the unscaled value to a packed decimal bytes. + + // get unicode '0' value. + int zeroBase = '0'; + + // start index in target packed decimal. + int packedIndex = declaredPrecision-1; + + // start index in source big decimal. + int bigIndex; + + if (bigScale >= declaredScale) { + // If target scale is less than source scale, + // discard excessive fraction. + + // set start index in source big decimal to ignore excessive fraction. + bigIndex = bigPrecision-1-(bigScale-declaredScale); + + if (bigIndex < 0) { + // all digits are discarded, so only process the sign nybble. + buffer[offset+(packedIndex+1)/2] = + (byte) ( (b.signum()>=0)?12:13 ); // sign nybble + } + else { + // process the last nybble together with the sign nybble. + buffer[offset+(packedIndex+1)/2] = + (byte) ( ( (unscaledStr.charAt(bigIndex)-zeroBase) << 4 ) + // last nybble + ( (b.signum()>=0)?12:13 ) ); // sign nybble + } + packedIndex-=2; + bigIndex-=2; + } + else { + // If target scale is greater than source scale, + // pad the fraction with zero. + + // set start index in source big decimal to pad fraction with zero. + bigIndex = declaredScale-bigScale-1; + + // process the sign nybble. + buffer[offset+(packedIndex+1)/2] = + (byte) ( (b.signum()>=0)?12:13 ); // sign nybble + + for (packedIndex-=2, bigIndex-=2; bigIndex>=0; packedIndex-=2, bigIndex-=2) + buffer[offset+(packedIndex+1)/2] = (byte) 0; + + if (bigIndex == -1) { + buffer[offset+(packedIndex+1)/2] = + (byte) ( (unscaledStr.charAt(bigPrecision-1)-zeroBase) << 4 ); // high nybble + + packedIndex-=2; + bigIndex = bigPrecision-3; + } + else { + bigIndex = bigPrecision-2; + } + } + + // process the rest. + for (; bigIndex>=0; packedIndex-=2, bigIndex-=2) { + buffer[offset+(packedIndex+1)/2] = + (byte) ( ( (unscaledStr.charAt(bigIndex)-zeroBase) << 4 ) + // high nybble + ( unscaledStr.charAt(bigIndex+1)-zeroBase ) ); // low nybble + } + + // process the first nybble when there is one left. + if (bigIndex == -1) { + buffer[offset+(packedIndex+1)/2] = + (byte) (unscaledStr.charAt(0) - zeroBase); + + packedIndex-=2; + } + + // pad zero in front of the big decimal if necessary. + for (; packedIndex>=-1; packedIndex-=2) + buffer[offset+(packedIndex+1)/2] = (byte) 0; + + return declaredPrecision/2 + 1; + } +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Decimal.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Diagnosable.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Diagnosable.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Diagnosable.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Diagnosable.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,28 @@ +/* + + Derby - Class org.apache.derby.client.am.Diagnosable + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.am; + +public interface Diagnosable +{ + public Sqlca getSqlca(); + public java.lang.Throwable getThrowable (); + public void printTrace (java.io.PrintWriter printWriter, String messageHeader); +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Diagnosable.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DisconnectException.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DisconnectException.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DisconnectException.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DisconnectException.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,72 @@ +/* + + Derby - Class org.apache.derby.client.am.DisconnectException + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.am; + +public class DisconnectException extends SqlException +{ + + public DisconnectException (Agent agent, String reason, SqlState sqlstate, SqlCode sqlcode) + { + super (agent.logWriter_, reason, sqlstate, sqlcode); + } + + public DisconnectException (Agent agent, String reason, SqlState sqlstate) + { + super (agent.logWriter_, reason, sqlstate, SqlCode.disconnectError); + // make the call to close the streams and socket. + if (agent != null) agent.disconnectEvent(); + } + + public DisconnectException (java.lang.Throwable throwable, Agent agent, String reason, SqlState sqlstate) + { + super (agent.logWriter_, throwable, reason, sqlstate, SqlCode.disconnectError); + // make the call to close the streams and socket. + if (agent != null) agent.disconnectEvent(); + } + + public DisconnectException (Agent agent) + { + this (agent, null, SqlState.undefined); + } + + public DisconnectException (java.lang.Throwable throwable, Agent agent) + { + this (throwable, agent, null, SqlState.undefined); + } + + public DisconnectException (Agent agent, String reason) + { + this (agent, reason, SqlState.undefined); + } + + public DisconnectException (Throwable throwable, Agent agent, String reason) + { + this (throwable, agent, reason, SqlState.undefined); + } + + public DisconnectException (Agent agent, SqlException e) + { + this (agent, e.getMessage()); + setNextException (e); + } +} + + Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/DisconnectException.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,528 @@ +/* + + Derby - Class org.apache.derby.client.am.EncryptionManager + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.am; +import java.security.Security; +import java.security.Provider; + +// This class is get used when using encrypted password and/or userid mechanism. +// The <b>EncryptionManager</b> classs uses Diffie_Hellman algorithm to get the publick key and +// secret key, and then DES encryption is done using certain token (based on security +// mechanism) and server side's public key. Basically, this class is called when using +// security mechanism User ID and encrypted password (usrencpwd) and Encrypted user ID and password +// (eusridpwd). +// This class uses JCE provider to do Diffie_Hellman algorithm and DES encryption, +// obtainPublicKey(), calculateEncryptionToken(int, byte[]) and encryptData(byte[], int, byte[], byte[]) +// The agreed public value for the Diffie-Hellman prime is 256 bits +// and hence the encrytion will work only if the jce provider supports a 256 bits prime + +public class EncryptionManager +{ + transient Agent agent_; // for obtaining an exception log writer only + + // PROTOCOL's Diffie-Hellman agreed public value: prime. + private static final byte modulusBytes__[] = { + (byte)0xC6, (byte)0x21, (byte)0x12, (byte)0xD7, + (byte)0x3E, (byte)0xE6, (byte)0x13, (byte)0xF0, + (byte)0x94, (byte)0x7A, (byte)0xB3, (byte)0x1F, + (byte)0x0F, (byte)0x68, (byte)0x46, (byte)0xA1, + (byte)0xBF, (byte)0xF5, (byte)0xB3, (byte)0xA4, + (byte)0xCA, (byte)0x0D, (byte)0x60, (byte)0xBC, + (byte)0x1E, (byte)0x4C, (byte)0x7A, (byte)0x0D, + (byte)0x8C, (byte)0x16, (byte)0xB3, (byte)0xE3 + }; + + //the prime value in BigInteger form. It has to be in BigInteger form because this + //is the form used in JCE library. + private static final java.math.BigInteger modulus__ + = new java.math.BigInteger (1, modulusBytes__); + + // PROTOCOL's Diffie-Hellman agreed public value: base. + private static final byte baseBytes__[] = { + (byte)0x46, (byte)0x90, (byte)0xFA, (byte)0x1F, + (byte)0x7B, (byte)0x9E, (byte)0x1D, (byte)0x44, + (byte)0x42, (byte)0xC8, (byte)0x6C, (byte)0x91, + (byte)0x14, (byte)0x60, (byte)0x3F, (byte)0xDE, + (byte)0xCF, (byte)0x07, (byte)0x1E, (byte)0xDC, + (byte)0xEC, (byte)0x5F, (byte)0x62, (byte)0x6E, + (byte)0x21, (byte)0xE2, (byte)0x56, (byte)0xAE, + (byte)0xD9, (byte)0xEA, (byte)0x34, (byte)0xE4 + }; + + // The base value in BigInteger form. + private static final java.math.BigInteger base__ = + new java.math.BigInteger (1, baseBytes__); + + //PROTOCOL's Diffie-Hellman agreed exponential length + private static final int exponential_length__ = 255; + + private javax.crypto.spec.DHParameterSpec paramSpec_; + private java.security.KeyPairGenerator keyPairGenerator_; + private java.security.KeyPair keyPair_; + private javax.crypto.KeyAgreement keyAgreement_; + + private byte[] token_; // init vector + private byte[] secKey_; // security key + private javax.crypto.SecretKeyFactory secretKeyFactory_ = null; + private String providerName; // security provider name + private Provider provider; + + // EncryptionManager constructor. In this constructor,DHParameterSpec, + // KeyPairGenerator, KeyPair, and KeyAgreement are initialized. + public EncryptionManager (Agent agent) throws SqlException + { + agent_ = agent; + try + { + // get a security provider that supports the diffie helman key agreement algorithm + Provider[] list = Security.getProviders("KeyAgreement.DH"); + if(list == null) + throw new java.security.NoSuchProviderException(); + provider = list[0]; + providerName = provider.getName(); + + java.security.Security.addProvider ((java.security.Provider) provider); + + paramSpec_ = new javax.crypto.spec.DHParameterSpec (modulus__, base__, exponential_length__); + keyPairGenerator_ = java.security.KeyPairGenerator.getInstance ("DH", providerName); + keyPairGenerator_.initialize (paramSpec_); + keyPair_ = keyPairGenerator_.generateKeyPair(); + keyAgreement_ = javax.crypto.KeyAgreement.getInstance ("DH", providerName); + keyAgreement_.init (keyPair_.getPrivate()); + } + catch (java.security.NoSuchProviderException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchProviderException is caught" + + " when initializing EncryptionManager '" + e.getMessage() + "'"); + } + catch (java.security.NoSuchAlgorithmException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchAlgorithmException is caught" + + " when initializing EncryptionManager '" + e.getMessage() + "'"); + } + catch (java.security.InvalidAlgorithmParameterException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidAlgorithmParameterException is caught" + + " when initializing EncryptionManager '" + e.getMessage() + "'"); + } + + catch (java.security.InvalidKeyException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidKeyException is caught" + + " when initializing EncryptionManager '" + e.getMessage() + "'"); + } + } + + // This method generates the public key and returns it. This + // shared public key is the application requester's connection key and will + // be exchanged with the application server's connection key. This connection + // key will be put in the sectkn in ACCSEC command and send to the application + // server. + // @param null + // @return a byte array that is the application requester's public key + public byte[] obtainPublicKey () + { + + //we need to get the plain form public key because PROTOCOL accepts plain form + //public key only. + java.math.BigInteger aPub = ((javax.crypto.interfaces.DHPublicKey) keyPair_.getPublic()).getY(); + byte[] aPubKey = aPub.toByteArray(); + + //the following lines of code is to adjust the length of the key. PublicKey + //in JCE is in the form of BigInteger and it's a signed value. When tranformed + //to a Byte array form, normally this array is 32 bytes. However, if the + //value happens to take up all 32 X 8 bits and it is positive, an extra + //bit is needed and then a 33 byte array will be returned. Since PROTOCOL can't + //recogize the 33 byte key, we check the length here, if the length is 33, + //we will just trim off the first byte (0) and get the rest of 32 bytes. + if (aPubKey.length == 33 && aPubKey[0]==0) { + //System.out.println ("Adjust length"); + byte[] newKey = new byte[32]; + for (int i=0; i < newKey.length; i++) + newKey[i] = aPubKey[i+1]; + return newKey; + } + + //the following lines of code is to adjust the length of the key. Occasionally, + //the length of the public key is less than 32, the reason of this is that the 0 byte + //in the beginning is somehow not returned. So we check the length here, if the length + //is less than 32, we will pad 0 in the beginning to make the public key 32 bytes + if (aPubKey.length < 32) { + byte[] newKey = new byte[32]; + int i; + for (i=0; i < 32-aPubKey.length; i++) { + newKey[i] = 0; + } + for (int j=i; j<newKey.length; j++) + newKey[j] = aPubKey[j-i]; + return newKey; + } + return aPubKey; + } + + // This method is used to calculate the encryption token. DES encrypts the + // data using a token and the generated shared private key. The token used + // depends on the type of security mechanism being used: + // USRENCPWD - The userid is used as the token. The USRID is zero-padded to + // 8 bytes if less than 8 bytes or truncated to 8 bytes if greater than 8 bytes. + // EUSRIDPWD - The middle 8 bytes of the server's connection key is used as + // the token. + // @param int securityMechanism + // @param byte[] userid or server's connection key + // @return byte[] the encryption token + private byte[] calculateEncryptionToken (int securityMechanism, byte[] initVector) + { + byte[] token = new byte[8]; + + //USRENCPWD, the userid is used as token + if (securityMechanism == 7) { + if (initVector.length < 8) { //shorter than 8 bytes, zero padded to 8 bytes + for (int i=0; i<initVector.length; i++) + token[i] = initVector[i]; + for (int i=initVector.length; i<8; i++) + token[i] = 0; + } + else { //longer than 8 bytes, truncated to 8 bytes + for (int i=0; i<8; i++) + token[i] = initVector[i]; + } + } + //EUSRIDPWD - The middle 8 bytes of the server's connection key is used as + //the token. + else if (securityMechanism == 9) { + for (int i = 0; i < 8; i++) { + token[i] = initVector[i + 12]; + } + } + return token; + } + + //JDK 1.4 has a parity check on the DES encryption key. Each byte needs to have an odd number + //of "1"s in it, and this is required by DES. Otherwise JDK 1.4 throws InvalidKeyException. + //Older JDK doesn't check this. In order to make encryption work with JDK1.4, we are going to + //check each of the 8 byte of our key and flip the last bit if it has even number of 1s. + private void keyParityCheck(byte[] key) throws SqlException + { + byte temp; + int changeParity; + if (key.length!=8) + throw new SqlException (agent_.logWriter_, "DES key has the wrong length"); + for (int i=0; i<8; i++) + { + temp = key[i]; + changeParity = 1; + for (int j=0; j<8; j++) + { + if (temp < 0) + changeParity = 1 - changeParity; + temp = (byte) (temp << 1); + } + if (changeParity == 1) + { + if ((key[i] & 1) != 0) + key[i] &= 0xfe; + else + key[i] |= 1; + } + } + } + + // This method generates a secret key using the application server's + // public key + private byte[] generatePrivateKey (byte[] targetPublicKey) throws SqlException + { + try { + + //initiate a Diffie_Hellman KeyFactory object. + java.security.KeyFactory keyFac = java.security.KeyFactory.getInstance ("DH", provider); + + //Use server's public key to initiate a DHPublicKeySpec and then use + //this DHPublicKeySpec to initiate a publicKey object + java.math.BigInteger publicKey = new java.math.BigInteger (1, targetPublicKey); + javax.crypto.spec.DHPublicKeySpec dhKeySpec = + new javax.crypto.spec.DHPublicKeySpec (publicKey, modulus__, base__); + java.security.PublicKey pubKey = keyFac.generatePublic (dhKeySpec); + + //Execute the first phase of DH keyagreement protocal. + keyAgreement_.doPhase (pubKey, true); + + //generate the shared secret key. The application requestor's shared secret + //key should be exactly the same as the application server's shared secret + //key + byte[] sharedSecret = keyAgreement_.generateSecret(); + byte[] newKey = new byte[32]; + + //We adjust the length here. If the length of secret key is 33 and the first byte is 0, + //we trim off the frist byte. If the length of secret key is less than 32, we will + //pad 0 to the beginning of the byte array tho make the secret key 32 bytes. + if (sharedSecret.length == 33 && sharedSecret[0] == 0) { + for (int i=0; i<newKey.length; i++) + newKey[i] = sharedSecret[i+1]; + + } + if (sharedSecret.length < 32) { + int i; + for (i=0; i<(32 - sharedSecret.length); i++) { + newKey[i] = 0; + } + for (int j=i; j<sharedSecret.length; j++) + newKey[j] = sharedSecret[j-i]; + } + + //The Data Encryption Standard (DES) is going to be used to encrypt userid + //and password. DES is a block cipher; it encrypts data in 64-bit blocks. + //PROTOCOL encryption uses DES CBC mode as defined by the FIPS standard + //DES CBC requires an encryption key and an 8 byte token to encrypt the data. + //The middle 8 bytes of Diffie-Hellman shared private key is used as the + //encryption key. The following code retrieves middle 8 bytes of the shared + //private key. + byte[] key = new byte[8]; + + //if secret key is not 32, we will use the adjust length secret key + if (sharedSecret.length==32) { + for (int i=0; i< 8;i++) + key[i] = sharedSecret[i+12]; + } + else if (sharedSecret.length==33 || sharedSecret.length < 32) { + for (int i=0; i< 8;i++) + key[i] = newKey[i+12]; + } + else + throw new SqlException (agent_.logWriter_, "sharedSecret key length error " + sharedSecret.length); + + //we do parity check here and flip the parity bit if the byte has even number of 1s + keyParityCheck(key); + return key; + }/* + catch (java.security.NoSuchProviderException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchProviderException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + }*/ + catch (java.security.NoSuchAlgorithmException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchAlgorithmException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.spec.InvalidKeySpecException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidKeySpecException is caught " + + "when encrypting data"); + } + catch (java.security.InvalidKeyException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidKeyException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + + + } + + // This method encrypts the usreid/password with the middle 8 bytes of + // the generated secret key and an encryption token. Then it returns the + // encrypted data in a byte array. + // plainText The byte array form userid/password to encrypt. + // initVector The byte array which is used to calculate the + // encryption token. + // targetPublicKey DERBY' public key. + // Returns the encrypted data in a byte array. + public byte[] encryptData (byte[] plainText, + int securityMechanism, + byte[] initVector, + byte[] targetPublicKey) throws SqlException + { + + byte[] cipherText = null; + java.security.Key key = null; + + if (token_ == null) + token_ = calculateEncryptionToken (securityMechanism, initVector); + + try{ + if (secKey_ == null) + { + //use this encryption key to initiate a SecretKeySpec object + secKey_ = generatePrivateKey (targetPublicKey); + javax.crypto.spec.SecretKeySpec desKey = new javax.crypto.spec.SecretKeySpec (secKey_, "DES"); + key = desKey; + } + else + { + //use this encryption key to initiate a SecretKeySpec object + javax.crypto.spec.DESKeySpec desKey = new javax.crypto.spec.DESKeySpec (secKey_); + if (secretKeyFactory_ == null) + secretKeyFactory_ = javax.crypto.SecretKeyFactory.getInstance("DES", providerName); + key = secretKeyFactory_.generateSecret(desKey); + } + + //We use DES in CBC mode because this is the mode used in PROTOCOL. The + //encryption mode has to be consistent for encryption and decryption. + //CBC mode requires an initialization vector(IV) parameter. In CBC mode + //we need to initialize the Cipher object with an IV, which can be supplied + // using the javax.crypto.spec.IvParameterSpec class. + javax.crypto.Cipher cipher= javax.crypto.Cipher.getInstance ("DES/CBC/PKCS5Padding", providerName); + + //generate a IVParameterSpec object and use it to initiate the + //Cipher object. + javax.crypto.spec.IvParameterSpec ivParam = new javax.crypto.spec.IvParameterSpec (token_); + + //initiate the Cipher using encryption mode, encryption key and the + //IV parameter. + cipher.init (javax.crypto.Cipher.ENCRYPT_MODE, key, ivParam); + + //Execute the final phase of encryption + cipherText = cipher.doFinal (plainText); + } + catch (java.security.NoSuchProviderException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchProviderException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.NoSuchAlgorithmException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchAlgorithmException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.InvalidKeyException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidKeyException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.NoSuchPaddingException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.NoSuchPaddingException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.BadPaddingException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.BadPaddingException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.InvalidAlgorithmParameterException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidAlgorithmParameterException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.IllegalBlockSizeException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.IllegalBlockSizeException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.spec.InvalidKeySpecException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.IllegalBlockSizeException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + return cipherText; + } + + + // This method decrypts the usreid/password with the middle 8 bytes of + // the generated secret key and an encryption token. Then it returns the + // decrypted data in a byte array. + // plainText The byte array form userid/password to encrypt. + // initVector The byte array which is used to calculate the + // encryption token. + // targetPublicKey DERBY' public key. + // Returns the decrypted data in a byte array. + public byte[] decryptData (byte[] cipherText, + int securityMechanism, + byte[] initVector, + byte[] targetPublicKey) throws SqlException + { + + byte[] plainText = null; + java.security.Key key = null; + + if (token_ == null) + token_ = calculateEncryptionToken (securityMechanism, initVector); + + try{ + if (secKey_ == null) + { + //use this encryption key to initiate a SecretKeySpec object + secKey_ = generatePrivateKey (targetPublicKey); + javax.crypto.spec.SecretKeySpec desKey = new javax.crypto.spec.SecretKeySpec (secKey_, "DES"); + key = desKey; + } + else + { + //use this encryption key to initiate a SecretKeySpec object + javax.crypto.spec.DESKeySpec desKey = new javax.crypto.spec.DESKeySpec (secKey_); + if (secretKeyFactory_ == null) + secretKeyFactory_ = javax.crypto.SecretKeyFactory.getInstance("DES", providerName); + key = secretKeyFactory_.generateSecret(desKey); + } + + //We use DES in CBC mode because this is the mode used in PROTOCOL. The + //encryption mode has to be consistent for encryption and decryption. + //CBC mode requires an initialization vector(IV) parameter. In CBC mode + //we need to initialize the Cipher object with an IV, which can be supplied + // using the javax.crypto.spec.IvParameterSpec class. + javax.crypto.Cipher cipher= javax.crypto.Cipher.getInstance ("DES/CBC/PKCS5Padding", providerName); + + //generate a IVParameterSpec object and use it to initiate the + //Cipher object. + javax.crypto.spec.IvParameterSpec ivParam = new javax.crypto.spec.IvParameterSpec (token_); + + //initiate the Cipher using encryption mode, encryption key and the + //IV parameter. + cipher.init (javax.crypto.Cipher.DECRYPT_MODE, key,ivParam); + + //Execute the final phase of encryption + plainText = cipher.doFinal (cipherText); + } + catch (java.security.NoSuchProviderException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchProviderException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.NoSuchAlgorithmException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.NoSuchAlgorithmException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.InvalidKeyException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidKeyException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.NoSuchPaddingException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.NoSuchPaddingException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.BadPaddingException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.BadPaddingException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.InvalidAlgorithmParameterException e) { + throw new SqlException (agent_.logWriter_, e, "java.security.InvalidAlgorithmParameterException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (javax.crypto.IllegalBlockSizeException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.IllegalBlockSizeException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + catch (java.security.spec.InvalidKeySpecException e) { + throw new SqlException (agent_.logWriter_, e, "javax.crypto.IllegalBlockSizeException is caught " + + "when encrypting data '" + e.getMessage() + "'"); + } + return plainText; + } + + public void setInitVector(byte[] initVector) + { + token_ = initVector; + } + + public void setSecKey(byte[] secKey) + { + secKey_ = secKey; + } + + public void resetSecurityKeys() + { + token_ = null; + secKey_ = null; + } + +} + Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/EncryptionManager.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ErrorKey.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ErrorKey.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ErrorKey.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ErrorKey.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,49 @@ +/* + + Derby - Class org.apache.derby.client.am.ErrorKey + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.am; + + +// This class associates the SQL states and error codes with every possible exception +// as distinguished by a unique resourceKey. +public class ErrorKey +{ + private String resourceKey_; + private String sqlState_; + private int errorCode_; + + + String getResourceKey () + { + return resourceKey_; + } + + String getSQLState () + { + return sqlState_; + } + + int getErrorCode () + { + return errorCode_; + } +} + + Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ErrorKey.java ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ExceptionFormatter.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ExceptionFormatter.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ExceptionFormatter.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ExceptionFormatter.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,214 @@ +/* + + Derby - Class org.apache.derby.client.am.ExceptionFormatter + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package org.apache.derby.client.am; + +public class ExceptionFormatter +{ + // returnTokensOnly is true only when exception tracing is enabled so + // that we don't try to go to the server for a message while we're in + // the middle of parsing an Sqlca reply. + // Without this, if e.getMessage() fails, we would have infinite recursion + // when TRACE_DIAGNOSTICS is on because tracing occurs within the exception constructor. + static public void printTrace (java.sql.SQLException e, + java.io.PrintWriter printWriter, + String messageHeader, + boolean returnTokensOnly) + { + String header; + synchronized (printWriter) { + while (e != null) { + if (e instanceof java.sql.DataTruncation) { + header = messageHeader + "[" + "DataTruncation@" + Integer.toHexString (e.hashCode()) + "]"; + printWriter.println (header + " java.sql.DataTruncation"); + } + else if (e instanceof java.sql.SQLWarning) { + header = messageHeader + "[" + "SQLWarning@" + Integer.toHexString (e.hashCode()) + "]"; + printWriter.println (header + " java.sql.SQLWarning"); + } + else if (e instanceof java.sql.BatchUpdateException) { + header = messageHeader + "[" + "BatchUpdateException@" + Integer.toHexString (e.hashCode()) + "]"; + printWriter.println (header + " java.sql.BatchUpdateException"); + } + else { // e instanceof java.sql.SQLException + header = messageHeader + "[" + "SQLException@" + Integer.toHexString (e.hashCode()) + "]"; + printWriter.println (header + " java.sql.SQLException"); + } + + if (e instanceof Diagnosable) { + java.lang.Throwable throwable = null; + try { + throwable = ((Diagnosable) e).getThrowable(); + } + catch (java.lang.NoSuchMethodError doNothing) { + } + if (throwable != null) { + printTrace (throwable, printWriter, header); + } + Sqlca sqlca = ((Diagnosable) e).getSqlca(); + if (sqlca != null) { + printTrace (sqlca, printWriter, header); + // JDK stack trace calls e.getMessage(), so we must set some state on the sqlca that says return tokens only. + ((Sqlca) sqlca).returnTokensOnlyInMessageText (returnTokensOnly); + } + } + + printWriter.println (header + " SQL state = " + e.getSQLState ()); + printWriter.println (header + " Error code = " + String.valueOf (e.getErrorCode ())); + if (!(e instanceof Diagnosable)) { + printWriter.println (header + " Message = " + e.getMessage()); + } + else { + if (((Diagnosable) e).getSqlca() == null) + { // Too much has changed, so escape out here. + printWriter.println (header + " Message = " + e.getMessage()); + } + else { // This is server-side error. + Sqlca sqlca = (Sqlca) ((Diagnosable) e).getSqlca(); + if (returnTokensOnly) { + // print message tokens directly. + printWriter.println (header + " Tokens = " + sqlca.getSqlErrmc()); // a string containing error tokens only + } + else { + // Try to get message text from server. + String message = e.getMessage(); + if (!sqlca.messageTextRetrievedContainsTokensOnly_) { // got the message text. + printWriter.println (header + " Message = " + message); + } + else { // got only message tokens. + java.sql.SQLException mysteryException = sqlca.exceptionThrownOnStoredProcInvocation_; + if (mysteryException != null && + (mysteryException.getErrorCode() == -440 || mysteryException.getErrorCode() == -444)) { + printWriter.println (header + " Unable to obtain message text from server." + + " Only message tokens are available." + + " The stored procedure SYSIBM.SQLCAMESSAGE is not installed on server." + + " Contact your DBA."); + } + else { + printWriter.println (header + " Error occurred while trying to obtain message text from server. " + + "Only message tokens are available."); + } + printWriter.println (header + " Tokens = " + message); + } + } + } + } + + if (e instanceof java.sql.DataTruncation) { + printWriter.println (header + " Index = " + ((java.sql.DataTruncation) e).getIndex()); + printWriter.println (header + " Parameter = " + ((java.sql.DataTruncation) e).getParameter()); + printWriter.println (header + " Read = " + ((java.sql.DataTruncation) e).getRead()); + printWriter.println (header + " Data size = " + ((java.sql.DataTruncation) e).getDataSize()); + printWriter.println (header + " Transfer size = " + ((java.sql.DataTruncation) e).getTransferSize()); + } + + if (e instanceof java.sql.BatchUpdateException) { + printWriter.println (header + " Update counts = " + Utils.getStringFromInts (((java.sql.BatchUpdateException) e).getUpdateCounts())); + } + + printWriter.println (header + " Stack trace follows"); + e.printStackTrace (printWriter); + + if (e instanceof Diagnosable) { + Sqlca sqlca = (Sqlca) ((Diagnosable) e).getSqlca(); + if (sqlca != null) { + // JDK stack trace calls e.getMessage(), now that it is finished, + // we can reset the state on the sqlca that says return tokens only. + sqlca.returnTokensOnlyInMessageText (false); + } + } + + e = e.getNextException (); + } + + printWriter.flush(); + } + } + + static public void printTrace (Sqlca sqlca, + java.io.PrintWriter printWriter, + String messageHeader) + { + String header = messageHeader + "[" + "Sqlca@" + Integer.toHexString (sqlca.hashCode()) + "]"; + synchronized (printWriter) { + printWriter.println (header + " DERBY SQLCA from server"); + printWriter.println (header + " SqlCode = " + sqlca.getSqlCode()); + printWriter.println (header + " SqlErrd = " + Utils.getStringFromInts (sqlca.getSqlErrd())); + printWriter.println (header + " SqlErrmc = " + sqlca.getSqlErrmc()); + printWriter.println (header + " SqlErrmcTokens = " + Utils.getStringFromStrings (sqlca.getSqlErrmcTokens())); + printWriter.println (header + " SqlErrp = " + sqlca.getSqlErrp()); + printWriter.println (header + " SqlState = " + sqlca.getSqlState()); + printWriter.println (header + " SqlWarn = " + new String (sqlca.getSqlWarn())); + } + } + + static public void printTrace (java.lang.Throwable e, + java.io.PrintWriter printWriter, + String messageHeader) + { + String header = messageHeader + "[" + "Throwable@" + Integer.toHexString (e.hashCode()) + "]"; + synchronized (printWriter) { + printWriter.println (header + " " + e.getClass().getName()); + printWriter.println (header + " Message = " + e.getMessage ()); + printWriter.println (header + " Stack trace follows"); + e.printStackTrace (printWriter); + } + } + + static public void printTrace (javax.transaction.xa.XAException e, + java.io.PrintWriter printWriter, + String messageHeader) + { + String header = messageHeader + "[" + "XAException@" + Integer.toHexString (e.hashCode()) + "]"; + synchronized (printWriter) { + printWriter.println (header + " javax.transaction.xa.XAException"); + printWriter.println (header + " Message = " + e.getMessage ()); + printWriter.println (header + " Stack trace follows"); + + e.printStackTrace (printWriter); + + if(! ((org.apache.derby.client.am.Configuration.jreLevelMajor == 1) && + (org.apache.derby.client.am.Configuration.jreLevelMinor >= 4)) || + (org.apache.derby.client.am.Configuration.jreLevelMajor > 1) ) + { // If not jre 1.4 or above, we need to print the cause if there is one + // For jre 1.4 or above, e.printStackTrace() will print the cause automatically + if (e instanceof Diagnosable) { + java.lang.Throwable throwable = null; + try { + throwable = ((Diagnosable) e).getThrowable(); + } + catch (java.lang.NoSuchMethodError doNothing) { + } + if (throwable != null) + { + printWriter.print ("Caused by: "); + if (throwable instanceof java.sql.SQLException) + { + throwable.printStackTrace (printWriter); + } + else + { + printTrace (throwable, printWriter, header); + } + } + } + } + } + } +} Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/ExceptionFormatter.java ------------------------------------------------------------------------------ svn:eol-style = native