1 21 package org.apache.derby.client.am; 22 23 import org.apache.derby.shared.common.reference.SQLState; 24 import org.apache.derby.shared.common.i18n.MessageUtil; 25 26 30 public class Decimal { 31 34 public final static int PACKED_DECIMAL = 0x30; 35 36 private static MessageUtil msgutil = SqlException.getMessageUtil(); 37 38 40 private static final int[][] tenRadixMagnitude = { 41 {0x3b9aca00}, {0x0de0b6b3, 0xa7640000}, {0x033b2e3c, 0x9fd0803c, 0xe8000000}, }; 45 46 48 private Decimal() { 50 } 51 52 54 58 private static final int packedNybblesToInt(byte[] buffer, 59 int offset, 60 int startNybble, 61 int numberOfNybbles) { 62 int value = 0; 63 64 int i = startNybble / 2; 65 if ((startNybble % 2) != 0) { 66 value += buffer[offset + i] & 0x0F; 68 i++; 69 } 70 71 int endNybble = startNybble + numberOfNybbles - 1; 72 for (; i < (endNybble + 1) / 2; i++) { 73 value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); value = value * 10 + (buffer[offset + i] & 0x0F); } 76 77 if ((endNybble % 2) == 0) { 78 value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); 80 } 81 82 return value; 83 } 84 85 89 private static final long packedNybblesToLong(byte[] buffer, 90 int offset, 91 int startNybble, 92 int numberOfNybbles) { 93 long value = 0; 94 95 int i = startNybble / 2; 96 if ((startNybble % 2) != 0) { 97 value += buffer[offset + i] & 0x0F; 99 i++; 100 } 101 102 int endNybble = startNybble + numberOfNybbles - 1; 103 for (; i < (endNybble + 1) / 2; i++) { 104 value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); value = value * 10 + (buffer[offset + i] & 0x0F); } 107 108 if ((endNybble % 2) == 0) { 109 value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); 111 } 112 113 return value; 114 } 115 116 119 private static final int[] computeMagnitude(int[] input) { 120 int length = input.length; 121 int[] mag = new int[length]; 122 123 mag[length - 1] = input[length - 1]; 124 for (int i = 0; i < length - 1; i++) { 125 int carry = 0; 126 int j = tenRadixMagnitude[i].length - 1; 127 int k = length - 1; 128 for (; j >= 0; j--, k--) { 129 long product = (input[length - 2 - i] & 0xFFFFFFFFL) * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL) 130 + (mag[k] & 0xFFFFFFFFL) + (carry & 0xFFFFFFFFL); carry = (int) (product >>> 32); 133 mag[k] = (int) (product & 0xFFFFFFFFL); 134 } 135 mag[k] = (int) carry; 136 } 137 return mag; 138 } 139 140 142 147 public static final java.math.BigDecimal getBigDecimal(byte[] buffer, 148 int offset, 149 int precision, 150 int scale) throws java.io.UnsupportedEncodingException { 151 int length = precision / 2 + 1; 153 154 int signum; 156 if ((buffer[offset + length - 1] & 0x0F) == 0x0D) { 157 signum = -1; 158 } else { 159 signum = 1; 160 } 161 162 if (precision <= 9) { 163 int value = packedNybblesToInt(buffer, offset, 0, length * 2 - 1); 165 166 byte[] magnitude = new byte[4]; 168 magnitude[0] = (byte) (value >>> 24); 169 magnitude[1] = (byte) (value >>> 16); 170 magnitude[2] = (byte) (value >>> 8); 171 magnitude[3] = (byte) (value); 172 173 return new java.math.BigDecimal (new java.math.BigInteger (signum, magnitude), scale); 174 } else if (precision <= 18) { 175 long value = packedNybblesToLong(buffer, offset, 0, length * 2 - 1); 177 178 byte[] magnitude = new byte[8]; 180 magnitude[0] = (byte) (value >>> 56); 181 magnitude[1] = (byte) (value >>> 48); 182 magnitude[2] = (byte) (value >>> 40); 183 magnitude[3] = (byte) (value >>> 32); 184 magnitude[4] = (byte) (value >>> 24); 185 magnitude[5] = (byte) (value >>> 16); 186 magnitude[6] = (byte) (value >>> 8); 187 magnitude[7] = (byte) (value); 188 189 return new java.math.BigDecimal (new java.math.BigInteger (signum, magnitude), scale); 190 } else if (precision <= 27) { 191 int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); 193 int me = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); 195 int hi = packedNybblesToInt(buffer, offset, 0, (length - 10) * 2 + 1); 197 198 int[] value = computeMagnitude(new int[]{hi, me, lo}); 200 201 byte[] magnitude = new byte[12]; 203 magnitude[0] = (byte) (value[0] >>> 24); 204 magnitude[1] = (byte) (value[0] >>> 16); 205 magnitude[2] = (byte) (value[0] >>> 8); 206 magnitude[3] = (byte) (value[0]); 207 magnitude[4] = (byte) (value[1] >>> 24); 208 magnitude[5] = (byte) (value[1] >>> 16); 209 magnitude[6] = (byte) (value[1] >>> 8); 210 magnitude[7] = (byte) (value[1]); 211 magnitude[8] = (byte) (value[2] >>> 24); 212 magnitude[9] = (byte) (value[2] >>> 16); 213 magnitude[10] = (byte) (value[2] >>> 8); 214 magnitude[11] = (byte) (value[2]); 215 216 return new java.math.BigDecimal (new java.math.BigInteger (signum, magnitude), scale); 217 } else if (precision <= 31) { 218 int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); 220 int meLo = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); 222 int meHi = packedNybblesToInt(buffer, offset, (length - 14) * 2, 9); 224 int hi = packedNybblesToInt(buffer, offset, 0, (length - 14) * 2); 226 227 int[] value = computeMagnitude(new int[]{hi, meHi, meLo, lo}); 229 230 byte[] magnitude = new byte[16]; 232 magnitude[0] = (byte) (value[0] >>> 24); 233 magnitude[1] = (byte) (value[0] >>> 16); 234 magnitude[2] = (byte) (value[0] >>> 8); 235 magnitude[3] = (byte) (value[0]); 236 magnitude[4] = (byte) (value[1] >>> 24); 237 magnitude[5] = (byte) (value[1] >>> 16); 238 magnitude[6] = (byte) (value[1] >>> 8); 239 magnitude[7] = (byte) (value[1]); 240 magnitude[8] = (byte) (value[2] >>> 24); 241 magnitude[9] = (byte) (value[2] >>> 16); 242 magnitude[10] = (byte) (value[2] >>> 8); 243 magnitude[11] = (byte) (value[2]); 244 magnitude[12] = (byte) (value[3] >>> 24); 245 magnitude[13] = (byte) (value[3] >>> 16); 246 magnitude[14] = (byte) (value[3] >>> 8); 247 magnitude[15] = (byte) (value[3]); 248 249 return new java.math.BigDecimal (new java.math.BigInteger (signum, magnitude), scale); 250 } else { 251 throw new java.lang.IllegalArgumentException ( 253 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS)); 254 } 255 } 256 257 262 public static final double getDouble(byte[] buffer, 263 int offset, 264 int precision, 265 int scale) throws java.io.UnsupportedEncodingException { 266 int length = precision / 2 + 1; 268 269 int signum; 271 if ((buffer[offset + length - 1] & 0x0F) == 0x0D) { 272 signum = -1; 273 } else { 274 signum = 1; 275 } 276 277 if (precision <= 9) { 278 int value = packedNybblesToInt(buffer, offset, 0, length * 2 - 1); 280 281 return signum * value / Math.pow(10, scale); 282 } else if (precision <= 18) { 283 long value = packedNybblesToLong(buffer, offset, 0, length * 2 - 1); 285 286 return signum * value / Math.pow(10, scale); 287 } else if (precision <= 27) { 288 int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); 290 int me = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); 292 int hi = packedNybblesToInt(buffer, offset, 0, (length - 10) * 2 + 1); 294 295 return signum * (lo / Math.pow(10, scale) + 296 me * Math.pow(10, 9 - scale) + 297 hi * Math.pow(10, 18 - scale)); 298 } else if (precision <= 31) { 299 int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); 301 int meLo = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); 303 int meHi = packedNybblesToInt(buffer, offset, (length - 14) * 2, 9); 305 int hi = packedNybblesToInt(buffer, offset, 0, (length - 14) * 2); 307 308 return signum * (lo / Math.pow(10, scale) + 309 meLo * Math.pow(10, 9 - scale) + 310 meHi * Math.pow(10, 18 - scale) + 311 hi * Math.pow(10, 27 - scale)); 312 } else { 313 throw new java.lang.IllegalArgumentException ( 315 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS)); 316 } 317 } 318 319 324 public static final long getLong(byte[] buffer, 325 int offset, 326 int precision, 327 int scale) throws java.io.UnsupportedEncodingException { 328 if (precision > 31) { 329 throw new java.lang.IllegalArgumentException ( 331 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS)); 332 } 333 334 int length = precision / 2 + 1; 336 337 int signum; 339 if ((buffer[offset + length - 1] & 0x0F) == 0x0D) { 340 signum = -1; 341 } else { 342 signum = 1; 343 } 344 345 int leftOfDecimalPoint = length * 2 - 1 - scale; 347 long integer = 0; 348 if (leftOfDecimalPoint > 0) { 349 int i = 0; 350 for (; i < leftOfDecimalPoint / 2; i++) { 351 integer = integer * 10 + signum * ((buffer[offset + i] & 0xF0) >>> 4); integer = integer * 10 + signum * (buffer[offset + i] & 0x0F); } 354 if ((leftOfDecimalPoint % 2) == 1) { 355 integer = integer * 10 + signum * ((buffer[offset + i] & 0xF0) >>> 4); 357 } 358 } 359 360 return integer; 361 } 362 363 365 368 public static final int bigDecimalToPackedDecimalBytes(byte[] buffer, 369 int offset, 370 java.math.BigDecimal b, 371 int declaredPrecision, 372 int declaredScale) 373 throws SqlException { 374 if (declaredPrecision > 31) { 376 throw new SqlException(null, 377 new ClientMessageId(SQLState.DECIMAL_TOO_MANY_DIGITS)); 378 } 379 380 String unscaledStr = b.unscaledValue().abs().toString(); 382 383 int bigPrecision = unscaledStr.length(); 385 386 if (bigPrecision > 31) { 387 throw new SqlException(null, 388 new ClientMessageId(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE), 389 "packed decimal", new SqlCode(-405)); 390 } 391 392 int bigScale = b.scale(); 393 int bigWholeIntegerLength = bigPrecision - bigScale; 394 if ((bigWholeIntegerLength > 0) && (!unscaledStr.equals("0"))) { 395 int declaredWholeIntegerLength = declaredPrecision - declaredScale; 397 if (bigWholeIntegerLength > declaredWholeIntegerLength) { 398 throw new SqlException(null, 399 new ClientMessageId(SQLState.NUMERIC_OVERFLOW), 400 b.toString(), "packed decimal", new SqlCode(-413)); 401 } 402 } 403 404 406 int zeroBase = '0'; 408 409 int packedIndex = declaredPrecision - 1; 411 412 int bigIndex; 414 415 if (bigScale >= declaredScale) { 416 419 bigIndex = bigPrecision - 1 - (bigScale - declaredScale); 421 422 if (bigIndex < 0) { 423 buffer[offset + (packedIndex + 1) / 2] = 425 (byte) ((b.signum() >= 0) ? 12 : 13); } else { 427 buffer[offset + (packedIndex + 1) / 2] = 429 (byte) (((unscaledStr.charAt(bigIndex) - zeroBase) << 4) + ((b.signum() >= 0) ? 12 : 13)); } 432 packedIndex -= 2; 433 bigIndex -= 2; 434 } else { 435 438 bigIndex = declaredScale - bigScale - 1; 440 441 buffer[offset + (packedIndex + 1) / 2] = 443 (byte) ((b.signum() >= 0) ? 12 : 13); 445 for (packedIndex -= 2, bigIndex -= 2; bigIndex >= 0; packedIndex -= 2, bigIndex -= 2) { 446 buffer[offset + (packedIndex + 1) / 2] = (byte) 0; 447 } 448 449 if (bigIndex == -1) { 450 buffer[offset + (packedIndex + 1) / 2] = 451 (byte) ((unscaledStr.charAt(bigPrecision - 1) - zeroBase) << 4); 453 packedIndex -= 2; 454 bigIndex = bigPrecision - 3; 455 } else { 456 bigIndex = bigPrecision - 2; 457 } 458 } 459 460 for (; bigIndex >= 0; packedIndex -= 2, bigIndex -= 2) { 462 buffer[offset + (packedIndex + 1) / 2] = 463 (byte) (((unscaledStr.charAt(bigIndex) - zeroBase) << 4) + (unscaledStr.charAt(bigIndex + 1) - zeroBase)); } 466 467 if (bigIndex == -1) { 469 buffer[offset + (packedIndex + 1) / 2] = 470 (byte) (unscaledStr.charAt(0) - zeroBase); 471 472 packedIndex -= 2; 473 } 474 475 for (; packedIndex >= -1; packedIndex -= 2) { 477 buffer[offset + (packedIndex + 1) / 2] = (byte) 0; 478 } 479 480 return declaredPrecision / 2 + 1; 481 } 482 } 483 | Popular Tags |