18 package com.mysql.clusterj.tie;
20 import java.lang.reflect.Method;
21 import java.math.BigDecimal;
22 import java.math.BigInteger;
23 import java.math.RoundingMode;
24 import java.nio.ByteBuffer;
25 import java.nio.ByteOrder;
26 import java.nio.CharBuffer;
27 import java.nio.charset.CharacterCodingException;
28 import java.nio.charset.Charset;
29 import java.nio.charset.CharsetDecoder;
30 import java.nio.charset.CharsetEncoder;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Calendar;
34 import java.util.HashSet;
35 import java.util.List;
38 import java.util.TreeMap;
40 import com.mysql.ndbjtie.mysql.CharsetMap;
41 import com.mysql.ndbjtie.mysql.CharsetMapConst;
42 import com.mysql.ndbjtie.mysql.Utils;
43 import com.mysql.ndbjtie.ndbapi.NdbErrorConst;
44 import com.mysql.ndbjtie.ndbapi.NdbRecAttr;
45 import com.mysql.clusterj.ClusterJDatastoreException;
46 import com.mysql.clusterj.ClusterJFatalInternalException;
47 import com.mysql.clusterj.ClusterJUserException;
48 import com.mysql.clusterj.core.store.Column;
49 import com.mysql.clusterj.core.util.I18NHelper;
50 import com.mysql.clusterj.core.util.Logger;
51 import com.mysql.clusterj.core.util.LoggerFactoryService;
52 import com.mysql.clusterj.tie.DbImpl.BufferManager;
68 static CharsetEncoder charsetEncoder = Charset.forName(
"windows-1252").newEncoder();
71 static CharsetDecoder charsetDecoder = Charset.forName(
"windows-1252").newDecoder();
73 static final long ooooooooooooooff = 0x00000000000000ffL;
74 static final long ooooooooooooffoo = 0x000000000000ff00L;
75 static final long ooooooooooffoooo = 0x0000000000ff0000L;
76 static final long ooooooooffoooooo = 0x00000000ff000000L;
77 static final long ooooooffoooooooo = 0x000000ff00000000L;
78 static final long ooooffoooooooooo = 0x0000ff0000000000L;
79 static final long ooffoooooooooooo = 0x00ff000000000000L;
80 static final long ffoooooooooooooo = 0xff00000000000000L;
81 static final long ooooooooffffffff = 0x00000000ffffffffL;
82 static final int ooooooff = 0x000000ff;
83 static final int ooooffff = 0x0000ffff;
84 static final int ooooffoo = 0x0000ff00;
85 static final int ooffoooo = 0x00ff0000;
87 static final char[] SPACE_PAD =
new char[255];
89 for (
int i = 0;
i < 255; ++
i) {
94 static final byte[] ZERO_PAD =
new byte[255];
96 for (
int i = 0;
i < 255; ++
i) {
97 ZERO_PAD[
i] = (byte)0;
101 static final byte[] EMPTY_BYTE_ARRAY =
new byte[0];
105 static Class<?> charsetMapClass = loadClass(
"com.mysql.ndbjtie.mysql.CharsetMap");
106 static Class<?> loadClass(
String className) {
108 return Class.forName(className);
109 }
catch (ClassNotFoundException e) {
120 static CharsetMap charsetMap = createCharsetMap();
125 StringBuilder builder =
new StringBuilder();
129 }
catch (Throwable t1) {
130 builder.append(
"CharsetMap.create() threw " + t1.getClass().getName() +
":" + t1.getMessage());
132 Method charsetMapCreateMethod = charsetMapClass.getMethod(
"create", (Class[])null);
133 result = (
CharsetMap)charsetMapCreateMethod.invoke(null, (Object[])null);
134 builder.append(
"charsetMapCreateMethod.invoke() succeeded:" + result);
135 }
catch (Throwable t2) {
136 builder.append(
"charsetMapCreateMethod.invoke() threw " + t2.getClass().getName() +
":" + t2.getMessage());
143 static int MAXIMUM_MYSQL_COLLATION_NUMBER = 256;
146 static int collationLatin1 = charsetMap.getCharsetNumber(
"latin1");
157 private static Map<String, int[]> collationPeersMap =
new TreeMap<String, int[]>();
160 private static CharsetConverter charsetConverterMultibyte =
new MultiByteCharsetConverter();
163 private static CharsetConverter[] charsetConverters =
164 new CharsetConverter[MAXIMUM_MYSQL_COLLATION_NUMBER + 1];
168 Map<String, List<Integer>> workingCollationPeersMap =
new TreeMap<String, List<Integer>>();
169 for (
int collation = 1; collation <= MAXIMUM_MYSQL_COLLATION_NUMBER; ++collation) {
170 String mysqlName = charsetMap.getMysqlName(collation);
171 if (mysqlName != null) {
172 if ((isMultibyteCollation(collation))) {
174 charsetConverters[collation] = charsetConverterMultibyte;
177 List<Integer> collations = workingCollationPeersMap.get(mysqlName);
178 if (collations == null) {
180 collations =
new ArrayList<Integer>(8);
181 collations.add(collation);
182 workingCollationPeersMap.put(mysqlName, collations);
185 collations.add(collation);
191 for (Map.Entry<
String,
List<Integer>> workingCollationPeers: workingCollationPeersMap.entrySet()) {
192 String mysqlName = workingCollationPeers.getKey();
194 int[] collationArray =
new int[collations.size()];
196 for (Integer collation: collations) {
197 collationArray[i++] = collation;
199 collationPeersMap.put(mysqlName, collationArray);
201 if (logger.isDetailEnabled()) {
202 for (Map.Entry<
String,
int[]> collationEntry: collationPeersMap.entrySet()) {
203 logger.detail(
"Utility collationMap " + collationEntry.getKey()
204 +
" collations : " + Arrays.toString(collationEntry.getValue()));
208 addCollation(collationLatin1);
216 return NdbErrorConst.Status.TemporaryError == ex.getStatus();
219 private final static EndianManager endianManager = ByteOrder.BIG_ENDIAN.equals(ByteOrder.nativeOrder())?
223 new EndianManager() {
226 switch (storeColumn.
getType()) {
228 return ndbRecAttr.int32_value() == 1;
230 return ndbRecAttr.int8_value() == 1;
233 local.
message(
"ERR_Unsupported_Mapping", storeColumn.
getType(),
"boolean"));
238 switch (storeColumn.getType()) {
245 throw new ClusterJUserException(
246 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"byte"));
250 switch (storeColumn.getType()) {
256 throw new ClusterJUserException(
257 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
261 switch (storeColumn.getType()) {
271 throw new ClusterJUserException(
272 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"int"));
276 switch (storeColumn.getType()) {
279 return (rawValue >>> 32) | (rawValue << 32);
286 return (((
long)ndbRecAttr.
int32_value()) & ooooooooffffffff) * 1000L;
292 throw new ClusterJUserException(
293 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
302 public void put3byteInt(ByteBuffer byteBuffer,
int value) {
303 byteBuffer.put((byte)(value));
304 byteBuffer.put((byte)(value >> 8));
305 byteBuffer.put((byte)(value >> 16));
308 public ByteBuffer
convertValue(Column storeColumn, byte value) {
310 switch (storeColumn.getType()) {
312 result = ByteBuffer.allocateDirect(4);
314 result.order(ByteOrder.BIG_ENDIAN);
315 result.putInt(value & 0xff);
320 result = ByteBuffer.allocateDirect(1);
325 throw new ClusterJUserException(local.
message(
326 "ERR_Unsupported_Mapping", storeColumn.getType(),
"byte"));
330 public ByteBuffer
convertValue(Column storeColumn,
short value) {
332 switch (storeColumn.getType()) {
334 result = ByteBuffer.allocateDirect(4);
336 result.order(ByteOrder.BIG_ENDIAN);
337 result.putInt(value & 0xffff);
341 result = ByteBuffer.allocateDirect(2);
342 result.order(ByteOrder.BIG_ENDIAN);
343 result.putShort(value);
347 throw new ClusterJUserException(local.
message(
348 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
352 public ByteBuffer
convertValue(Column storeColumn,
int value) {
353 ByteBuffer result = ByteBuffer.allocateDirect(4);
354 switch (storeColumn.getType()) {
357 result.order(ByteOrder.BIG_ENDIAN);
360 throw new ClusterJUserException(local.
message(
361 "ERR_Unsupported_Mapping", storeColumn.getType(),
"int"));
363 result.putInt(value);
368 public ByteBuffer
convertValue(Column storeColumn,
long value) {
369 ByteBuffer result = ByteBuffer.allocateDirect(8);
373 public ByteBuffer
convertValue(Column storeColumn,
long value, ByteBuffer result) {
374 switch (storeColumn.getType()) {
377 result.order(ByteOrder.BIG_ENDIAN);
378 result.putInt((
int)((value)));
379 result.putInt((
int)((value >>> 32)));
384 result.order(ByteOrder.BIG_ENDIAN);
385 result.putLong(value);
389 result.order(ByteOrder.LITTLE_ENDIAN);
390 put3byteInt(result, packDate(value));
394 result.order(ByteOrder.BIG_ENDIAN);
399 result.order(ByteOrder.LITTLE_ENDIAN);
400 put3byteInt(result, packTime(value));
404 result.order(ByteOrder.BIG_ENDIAN);
405 result.putInt((
int)(value/1000L));
409 throw new ClusterJUserException(local.
message(
410 "ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
416 switch (storeColumn.getType()) {
419 result |= (value >>> 32);
420 result |= (value << 32);
428 long packDate = packDate(value);
429 result |= (packDate & ooooooff) << 56;
430 result |= (packDate & ooooffoo) << 40;
431 result |= (packDate & ooffoooo) << 24;
438 long packTime = packTime(value);
439 result |= (packTime & ooooooff) << 56;
440 result |= (packTime & ooooffoo) << 40;
441 result |= (packTime & ooffoooo) << 24;
446 return (value/1000L) << 32;
448 throw new ClusterJUserException(local.
message(
449 "ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
454 switch (storeColumn.getType()) {
457 return value & ooooooff;
463 throw new ClusterJUserException(local.
message(
464 "ERR_Unsupported_Mapping", storeColumn.getType(),
"byte"));
469 switch (storeColumn.getType()) {
472 return value & ooooffff;
477 throw new ClusterJUserException(local.
message(
478 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
486 new EndianManager() {
489 switch (storeColumn.getType()) {
495 throw new ClusterJUserException(
496 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"boolean"));
501 switch (storeColumn.getType()) {
507 throw new ClusterJUserException(
508 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"byte"));
512 switch (storeColumn.getType()) {
517 throw new ClusterJUserException(
518 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
522 switch (storeColumn.getType()) {
532 throw new ClusterJUserException(
533 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"int"));
537 switch (storeColumn.getType()) {
551 throw new ClusterJUserException(
552 local.
message(
"ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
562 public void put3byteInt(ByteBuffer byteBuffer,
int value) {
563 byteBuffer.putInt(value);
567 public ByteBuffer
convertValue(Column storeColumn, byte value) {
569 switch (storeColumn.getType()) {
572 result = ByteBuffer.allocateDirect(4);
573 result.order(ByteOrder.nativeOrder());
574 result.putInt(value & 0xff);
579 result = ByteBuffer.allocateDirect(1);
580 result.order(ByteOrder.nativeOrder());
585 throw new ClusterJUserException(local.
message(
586 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
590 public ByteBuffer
convertValue(Column storeColumn,
short value) {
591 switch (storeColumn.getType()) {
594 ByteBuffer result = ByteBuffer.allocateDirect(2);
595 result.order(ByteOrder.nativeOrder());
596 result.putShort(value);
600 throw new ClusterJUserException(local.
message(
601 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
605 public ByteBuffer
convertValue(Column storeColumn,
int value) {
606 switch (storeColumn.getType()) {
609 ByteBuffer result = ByteBuffer.allocateDirect(4);
610 result.order(ByteOrder.nativeOrder());
611 result.putInt(value);
615 throw new ClusterJUserException(local.
message(
616 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
620 public ByteBuffer
convertValue(Column storeColumn,
long value) {
621 ByteBuffer result = ByteBuffer.allocateDirect(8);
625 public ByteBuffer
convertValue(Column storeColumn,
long value, ByteBuffer result) {
626 switch (storeColumn.getType()) {
630 result.order(ByteOrder.LITTLE_ENDIAN);
631 result.putLong(value);
635 result.order(ByteOrder.LITTLE_ENDIAN);
640 result.order(ByteOrder.LITTLE_ENDIAN);
641 result.putInt((
int)(value/1000L));
645 result.order(ByteOrder.LITTLE_ENDIAN);
646 put3byteInt(result, packDate(value));
650 result.order(ByteOrder.LITTLE_ENDIAN);
651 put3byteInt(result, packTime(value));
655 throw new ClusterJUserException(local.
message(
656 "ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
661 switch (storeColumn.getType()) {
671 return packDate(value);
673 return packTime(value);
675 throw new ClusterJUserException(local.
message(
676 "ERR_Unsupported_Mapping", storeColumn.getType(),
"long"));
681 switch (storeColumn.getType()) {
686 return value & ooooooff;
688 throw new ClusterJUserException(local.
message(
689 "ERR_Unsupported_Mapping", storeColumn.getType(),
"byte"));
694 switch (storeColumn.getType()) {
698 return value & ooooffff;
700 throw new ClusterJUserException(local.
message(
701 "ERR_Unsupported_Mapping", storeColumn.getType(),
"short"));
708 private static Set<Integer> NonSevereErrorCodes =
new HashSet<Integer>();
711 NonSevereErrorCodes.add(4203);
712 NonSevereErrorCodes.add(4243);
713 NonSevereErrorCodes.add(626);
716 protected static interface EndianManager {
717 public void put3byteInt(ByteBuffer byteBuffer,
int value);
722 public ByteBuffer
convertValue(Column storeColumn, byte value);
723 public ByteBuffer
convertValue(Column storeColumn,
short value);
724 public ByteBuffer
convertValue(Column storeColumn,
int value);
725 public ByteBuffer
convertValue(Column storeColumn,
long value);
737 protected static short swap(
short value) {
738 return (
short)((0x00ff & (value >>> 8)) |
739 (0xff00 & (value << 8)));
747 protected static int swap(
int value) {
748 return 0x000000ff & (value >>> 24) |
749 (0x0000ff00 & (value >>> 8)) |
750 (0x00ff0000 & (value << 8)) |
751 (0xff000000 & (value << 24));
759 protected static long swap(
long value) {
760 return ooooooooooooooff & (value >>> 56) |
761 (ooooooooooooffoo & (value >>> 40)) |
762 (ooooooooooffoooo & (value >>> 24)) |
763 (ooooooooffoooooo & (value >>> 8)) |
764 (ooooooffoooooooo & (value << 8)) |
765 (ooooffoooooooooo & (value << 24)) |
766 (ooffoooooooooooo & (value << 40)) |
767 (ffoooooooooooooo & (value << 56));
770 protected static void throwError(Object returnCode,
NdbErrorConst ndbError) {
771 throwError(returnCode, ndbError,
"");
774 protected static void throwError(Object returnCode, NdbErrorConst ndbError,
String extra) {
776 int code = ndbError.code();
777 int mysqlCode = ndbError.mysql_code();
778 int status = ndbError.status();
779 int classification = ndbError.classification();
781 status, classification, message, extra);
782 if (!NonSevereErrorCodes .contains(code)) {
785 throw new ClusterJDatastoreException(msg, code, mysqlCode, status, classification);
795 int dataLength = value.length;
798 switch (prefixLength) {
801 if (dataLength > requiredLength) {
803 local.
message(
"ERR_Data_Too_Long",
804 storeColumn.
getName(), requiredLength, dataLength));
806 result = ByteBuffer.allocateDirect(requiredLength);
807 result.order(ByteOrder.nativeOrder());
809 if (dataLength < requiredLength) {
811 result.put(ZERO_PAD, 0, requiredLength - dataLength);
816 if (dataLength > 255) {
818 local.
message(
"ERR_Data_Too_Long",
819 storeColumn.
getName(),
"255", dataLength));
821 result = ByteBuffer.allocateDirect(prefixLength + dataLength);
822 result.order(ByteOrder.nativeOrder());
823 result.put((byte)dataLength);
827 if (dataLength > 8000) {
829 local.
message(
"ERR_Data_Too_Long",
830 storeColumn.
getName(),
"8000", dataLength));
832 result = ByteBuffer.allocateDirect(prefixLength + dataLength);
833 result.order(ByteOrder.nativeOrder());
834 result.put((byte)(dataLength%256));
835 result.put((byte)(dataLength/256));
840 local.
message(
"ERR_Unknown_Prefix_Length",
841 prefixLength, storeColumn.
getName()));
858 ByteBuffer result = ByteBuffer.allocateDirect(bytesNeeded);
860 BigDecimal scaledValue = value.setScale(scale, RoundingMode.HALF_UP);
862 String stringRepresentation = scaledValue.toPlainString();
863 int length = stringRepresentation.length();
864 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(length);
865 CharBuffer charBuffer = CharBuffer.wrap(stringRepresentation);
867 charsetEncoder.encode(charBuffer, byteBuffer,
true);
869 int returnCode =
Utils.decimal_str2bin(
870 byteBuffer, length, precision, scale, result, bytesNeeded);
872 if (returnCode != 0) {
874 local.
message(
"ERR_String_To_Binary_Decimal",
875 returnCode, scaledValue, storeColumn.
getName(), precision, scale));
891 ByteBuffer result = ByteBuffer.allocateDirect(bytesNeeded);
892 String stringRepresentation = value.toString();
893 int length = stringRepresentation.length();
894 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(length);
895 CharBuffer charBuffer = CharBuffer.wrap(stringRepresentation);
897 charsetEncoder.encode(charBuffer, byteBuffer,
true);
899 int returnCode =
Utils.decimal_str2bin(
900 byteBuffer, length, precision, scale, result, bytesNeeded);
902 if (returnCode != 0) {
904 local.
message(
"ERR_String_To_Binary_Decimal",
905 returnCode, stringRepresentation, storeColumn.
getName(), precision, scale));
917 ByteBuffer result = ByteBuffer.allocateDirect(8);
918 result.order(ByteOrder.nativeOrder());
919 result.putDouble(value);
931 ByteBuffer result = ByteBuffer.allocateDirect(4);
932 result.order(ByteOrder.nativeOrder());
933 result.putFloat(value);
945 return endianManager.convertValue(storeColumn, value);
955 return endianManager.convertValue(storeColumn, value);
965 return endianManager.convertValue(storeColumn, value);
975 return endianManager.convertValue(storeColumn, value);
989 CharSequence chars = value;
992 chars = padString(value, storeColumn);
996 if (logger.isDetailEnabled()) dumpBytesToLog(byteBuffer, byteBuffer.limit());
1007 if (value == null) {
1010 CharSequence chars = value;
1012 if (logger.isDetailEnabled()) dumpBytesToLog(byteBuffer, byteBuffer.limit());
1023 if (value == null) {
1024 value = EMPTY_BYTE_ARRAY;
1026 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(value.length);
1027 byteBuffer.put(value);
1029 if (logger.isDetailEnabled()) dumpBytesToLog(byteBuffer, byteBuffer.limit());
1038 private static CharSequence padString(CharSequence value,
Column storeColumn) {
1039 CharSequence chars = value;
1040 int suppliedLength = value.length();
1042 if (suppliedLength > requiredLength) {
1044 storeColumn.
getName(), requiredLength, suppliedLength));
1045 }
else if (suppliedLength < requiredLength) {
1047 StringBuilder buffer =
new StringBuilder(requiredLength);
1048 buffer.append(value);
1049 buffer.append(SPACE_PAD, 0, requiredLength - suppliedLength);
1061 int limit = byteBuffer.limit();
1064 int length = limit -
offset;
1065 byteBuffer.position(0);
1072 length, columnName));
1074 byteBuffer.put((byte)(length % 256));
1077 if (length > 65535) {
1079 length, columnName));
1081 byteBuffer.put((byte)(length % 256));
1082 byteBuffer.put((byte)(length / 256));
1086 byteBuffer.position(0);
1087 byteBuffer.limit(limit);
1097 private static int packDate(
long millis) {
1098 Calendar calendar = Calendar.getInstance();
1100 calendar.setTimeInMillis(millis);
1101 int year = calendar.get(Calendar.YEAR);
1102 int month = calendar.get(Calendar.MONTH);
1103 int day = calendar.get(Calendar.DATE);
1104 int date = (year * 512) + ((month + 1) * 32) + day;
1115 private static int packTime(
long millis) {
1116 Calendar calendar = Calendar.getInstance();
1118 calendar.setTimeInMillis(millis);
1119 int year = calendar.get(Calendar.YEAR);
1120 int month = calendar.get(Calendar.MONTH);
1121 int day = calendar.get(Calendar.DATE);
1122 int hour = calendar.get(Calendar.HOUR);
1123 int minute = calendar.get(Calendar.MINUTE);
1124 int second = calendar.get(Calendar.SECOND);
1127 local.
message(
"ERR_Write_Time_Domain",
new java.sql.Time(millis), millis, year, month, day, hour, minute, second));
1129 int time = ((day - 1) * 240000) + (hour * 10000) + (minute * 100) + second;
1141 Calendar calendar = Calendar.getInstance();
1143 calendar.setTimeInMillis(value);
1144 long year = calendar.get(Calendar.YEAR);
1145 long month = calendar.get(Calendar.MONTH) + 1;
1146 long day = calendar.get(Calendar.DATE);
1147 long hour = calendar.get(Calendar.HOUR);
1148 long minute = calendar.get(Calendar.MINUTE);
1149 long second = calendar.get(Calendar.SECOND);
1150 long packedDatetime = (year * 10000000000L) + (month * 100000000L) + (day * 1000000L)
1151 + (hour * 10000L) + (minute * 100) + second;
1152 return packedDatetime;
1162 buffer.append(bytes.length);
1163 buffer.append(
"]: [");
1164 for (
int i = 0; i < bytes.length; ++
i) {
1165 buffer.append((
int)bytes[i]);
1169 return buffer.toString();
1179 int length = byteBuffer.limit() - byteBuffer.position();
1180 byte[] dst =
new byte[length];
1181 byteBuffer.get(dst);
1186 private static void dumpBytesToLog(ByteBuffer byteBuffer,
int limit) {
1188 message.append(byteBuffer.position());
1189 message.append(
" limit: ");
1190 message.append(byteBuffer.limit());
1191 message.append(
" data [");
1192 while (byteBuffer.hasRemaining()) {
1193 message.append((
int)byteBuffer.get());
1194 message.append(
" ");
1196 message.append(
"]");
1197 logger.detail(message.toString());
1198 byteBuffer.position(0);
1199 byteBuffer.limit(limit);
1202 public static BigDecimal getDecimal(ByteBuffer byteBuffer,
int length,
int precision,
int scale) {
1206 return new BigDecimal(decimal);
1207 }
catch (NumberFormatException nfe) {
1208 throw new ClusterJUserException(
1209 local.
message(
"ERR_Number_Format", decimal, dump(decimal)));
1213 public static BigInteger getBigInteger(ByteBuffer byteBuffer,
int length,
int precision,
int scale) {
1217 return new BigInteger(decimal);
1218 }
catch (NumberFormatException nfe) {
1219 throw new ClusterJUserException(
1220 local.
message(
"ERR_Number_Format", decimal, dump(decimal)));
1234 int capacity = precision + 3;
1235 ByteBuffer digits = ByteBuffer.allocateDirect(capacity);
1236 int returnCode =
Utils.decimal_bin2str(byteBuffer, length, precision, scale, digits, capacity);
1237 if (returnCode != 0) {
1239 local.
message(
"ERR_Binary_Decimal_To_String",
1240 returnCode, precision, scale,
dumpBytes(byteBuffer)));
1244 for (
int i = 0; i < digits.limit(); ++
i) {
1245 if (digits.get(i) == 0) {
1253 CharBuffer charBuffer = charsetDecoder.decode(digits);
1254 string = charBuffer.toString();
1256 }
catch (CharacterCodingException e) {
1258 local.
message(
"ERR_Character_Encoding",
string));
1269 int date = packedDate & 0x1f;
1270 packedDate = packedDate >>> 5;
1271 int month = (packedDate & 0x0f) - 1;
1272 int year = packedDate >>> 4;
1273 Calendar calendar = Calendar.getInstance();
1275 calendar.set(year, month, date);
1276 return calendar.getTimeInMillis();
1285 int second = packedTime % 100;
1287 int minute = packedTime % 100;
1289 int hour = packedTime % 24;
1290 int date = (packedTime / 24) + 1;
1293 local.
message(
"ERR_Read_Time_Domain", packedTime, date, hour, minute, second));
1295 Calendar calendar = Calendar.getInstance();
1297 calendar.set(Calendar.DATE, date);
1298 calendar.set(Calendar.HOUR, hour);
1299 calendar.set(Calendar.MINUTE, minute);
1300 calendar.set(Calendar.SECOND, second);
1301 calendar.set(Calendar.MILLISECOND, 0);
1302 return calendar.getTimeInMillis();
1313 int second = (int)(packedDatetime % 100);
1314 packedDatetime /= 100;
1315 int minute = (int)(packedDatetime % 100);
1316 packedDatetime /= 100;
1317 int hour = (int)(packedDatetime % 100);
1318 packedDatetime /= 100;
1319 int day = (int)(packedDatetime % 100);
1320 packedDatetime /= 100;
1321 int month = (int)(packedDatetime % 100) - 1;
1322 int year = (int)(packedDatetime / 100);
1323 Calendar calendar = Calendar.getInstance();
1325 calendar.set(Calendar.YEAR, year);
1326 calendar.set(Calendar.MONTH, month);
1327 calendar.set(Calendar.DATE, day);
1328 calendar.set(Calendar.HOUR, hour);
1329 calendar.set(Calendar.MINUTE, minute);
1330 calendar.set(Calendar.SECOND, second);
1331 calendar.set(Calendar.MILLISECOND, 0);
1332 return calendar.getTimeInMillis();
1344 if (array == null)
return null;
1345 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(array.length);
1346 byteBuffer.put(array);
1348 int inputLength = array.length;
1350 int outputLength = inputLength * 4;
1351 ByteBuffer outputByteBuffer = ByteBuffer.allocateDirect(outputLength);
1352 int[] lengths =
new int[] {inputLength, outputLength};
1353 int returnCode = charsetMap.recode(lengths, collation,
collationUTF16,
1354 byteBuffer, outputByteBuffer);
1355 switch (returnCode) {
1357 outputByteBuffer.limit(lengths[1]);
1358 CharBuffer charBuffer = outputByteBuffer.asCharBuffer();
1359 return charBuffer.toString();
1365 collation, lengths[0]));
1368 collation, inputLength, outputLength, lengths[0], lengths[1]));
1382 protected static String decode(ByteBuffer inputByteBuffer,
int collation) {
1383 int inputLength = inputByteBuffer.limit() - inputByteBuffer.position();
1384 int outputLength = inputLength * 2;
1385 ByteBuffer outputByteBuffer = ByteBuffer.allocateDirect(outputLength);
1386 int[] lengths =
new int[] {inputLength, outputLength};
1387 int returnCode = charsetMap.recode(lengths, collation,
collationUTF16,
1388 inputByteBuffer, outputByteBuffer);
1389 switch (returnCode) {
1391 outputByteBuffer.limit(lengths[1]);
1392 CharBuffer charBuffer = outputByteBuffer.asCharBuffer();
1393 return charBuffer.toString();
1399 collation, lengths[0]));
1402 collation, inputLength, outputLength, lengths[0], lengths[1]));
1419 int length = encoded.limit();
1420 byte[] result =
new byte[length];
1421 encoded.get(result);
1434 if (
string == null)
return null;
1435 int inputLength = (
string.length() * 2);
1436 ByteBuffer inputByteBuffer = ByteBuffer.allocateDirect(inputLength);
1437 CharBuffer charBuffer = inputByteBuffer.asCharBuffer();
1438 charBuffer.append(
string);
1439 int outputLength = (2 * inputLength) + prefixLength;
1440 ByteBuffer outputByteBuffer = ByteBuffer.allocateDirect(outputLength);
1441 outputByteBuffer.position(prefixLength);
1442 int[] lengths =
new int[] {inputLength, outputLength - prefixLength};
1443 int returnCode = charsetMap.recode(lengths,
collationUTF16, collation,
1444 inputByteBuffer, outputByteBuffer);
1446 switch (returnCode) {
1448 outputByteBuffer.limit(prefixLength + lengths[1]);
1449 return outputByteBuffer;
1455 collation, lengths[0]));
1458 collation, inputLength, outputLength, lengths[0], lengths[1]));
1475 CharSequence chars = input;
1477 if (prefixLength == 0) {
1478 chars = padString(input, storeColumn);
1480 return charsetConverter.encode(storeColumn.
getName(), chars, collation, prefixLength, bufferManager);
1493 return charsetConverter.decode(inputByteBuffer, collation, bufferManager);
1501 private static CharsetConverter getCharsetConverter(
int collation) {
1505 synchronized (charsetConverters) {
1506 if (collation + 1 > charsetConverters.length) {
1508 String charsetName = charsetMap.getName(collation);
1509 logger.warn(local.
message(
"ERR_Charset_Number_Too_Big", collation, charsetName,
1510 MAXIMUM_MYSQL_COLLATION_NUMBER));
1511 return charsetConverterMultibyte;
1513 CharsetConverter result = charsetConverters[collation];
1514 if (result == null) {
1515 result = addCollation(collation);
1527 private static CharsetConverter addCollation(
int collation) {
1528 if (isMultibyteCollation(collation)) {
1529 return charsetConverters[collation] = charsetConverterMultibyte;
1531 String charsetName = charsetMap.getMysqlName(collation);
1532 CharsetConverter charsetConverter =
new SingleByteCharsetConverter(collation);
1533 int[] collations = collationPeersMap.get(charsetName);
1534 if (collations == null) {
1536 collations =
new int[] {collation};
1537 collationPeersMap.put(charsetName, collations);
1538 logger.warn(local.
message(
"WARN_Unknown_Collation", collation, charsetName));
1539 return charsetConverter;
1541 for (
int peer: collations) {
1543 logger.info(
"Adding charset converter " + charsetName +
" for collation " + peer);
1544 charsetConverters[peer] = charsetConverter;
1546 return charsetConverter;
1555 private static Boolean isMultibyteCollation(
int collation) {
1556 boolean[] multibyte = charsetMap.isMultibyte(collation);
1557 return (multibyte == null)?null:multibyte[0];
1564 ByteBuffer encode(
String columnName, CharSequence input,
int collation,
int prefixLength,
BufferManager bufferManager);
1572 protected static class MultiByteCharsetConverter
implements CharsetConverter {
1583 public ByteBuffer
encode(
String columnName, CharSequence input,
int collation,
int prefixLength,
BufferManager bufferManager) {
1585 int inputLength = input.length() * 2;
1587 boolean done =
false;
1589 int sizeNeeded = inputLength;
1591 ByteBuffer outputByteBuffer = bufferManager.getStringStorageBuffer(sizeNeeded);
1592 int outputLength = outputByteBuffer.limit();
1593 outputByteBuffer.position(prefixLength);
1594 int[] lengths =
new int[] {inputLength, outputLength - prefixLength};
1595 int returnCode = charsetMap.recode(lengths,
collationUTF16, collation,
1596 inputByteBuffer, outputByteBuffer);
1597 switch (returnCode) {
1599 outputByteBuffer.limit(prefixLength + lengths[1]);
1600 outputByteBuffer.position(0);
1602 return outputByteBuffer;
1608 collation, lengths[0]));
1611 sizeNeeded = sizeNeeded * 3 / 2;
1630 public String decode(ByteBuffer inputByteBuffer,
int collation, BufferManager bufferManager) {
1631 int inputLength = inputByteBuffer.limit() - inputByteBuffer.position();
1632 int sizeNeeded = inputLength * 4;
1633 boolean done =
false;
1635 ByteBuffer outputByteBuffer = bufferManager.getStringByteBuffer(sizeNeeded);
1636 CharBuffer outputCharBuffer = bufferManager.getStringCharBuffer();
1637 int outputLength = outputByteBuffer.capacity();
1638 outputByteBuffer.position(0);
1639 outputByteBuffer.limit(outputLength);
1640 int[] lengths =
new int[] {inputLength, outputLength};
1641 int returnCode = charsetMap.recode(lengths, collation,
collationUTF16,
1642 inputByteBuffer, outputByteBuffer);
1643 switch (returnCode) {
1644 case CharsetMapConst.RecodeStatus.RECODE_OK:
1645 outputCharBuffer.position(0);
1647 outputCharBuffer.limit(lengths[1] / 2);
1648 return outputCharBuffer.toString();
1649 case CharsetMapConst.RecodeStatus.RECODE_BAD_CHARSET:
1650 throw new ClusterJFatalInternalException(local.message(
"ERR_Decode_Bad_Charset",
1652 case CharsetMapConst.RecodeStatus.RECODE_BAD_SRC:
1653 throw new ClusterJFatalInternalException(local.message(
"ERR_Decode_Bad_Source",
1654 collation, lengths[0]));
1655 case CharsetMapConst.RecodeStatus.RECODE_BUFF_TOO_SMALL:
1657 sizeNeeded = sizeNeeded * 3 / 2;
1660 throw new ClusterJFatalInternalException(local.message(
"ERR_Decode_Bad_Return_Code",
1670 protected static class SingleByteCharsetConverter
implements CharsetConverter {
1672 private static final int BYTE_RANGE = (1 + Byte.MAX_VALUE) - Byte.MIN_VALUE;
1673 private static byte[] allBytes =
new byte[BYTE_RANGE];
1677 private static byte[] unknownCharsMap =
new byte[65536];
1681 for (
int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
1682 allBytes[i - Byte.MIN_VALUE] = (byte) i;
1685 for (
int i = 0; i < unknownCharsMap.length; i++) {
1686 unknownCharsMap[
i] = (byte)
'?';
1691 private char[] byteToChars =
new char[BYTE_RANGE];
1694 private byte[] charToBytes =
new byte[65536];
1700 public SingleByteCharsetConverter(
int collation) {
1701 ByteBuffer allBytesByteBuffer = ByteBuffer.allocateDirect(256);
1702 allBytesByteBuffer.put(allBytes);
1703 allBytesByteBuffer.flip();
1704 String allBytesString = Utility.decode(allBytesByteBuffer, collation);
1705 if (allBytesString.length() != 256) {
1706 String charsetName = charsetMap.getName(collation);
1707 throw new ClusterJFatalInternalException(local.
message(
"ERR_Bad_Charset_Decode_All_Chars",
1708 collation, charsetName, allBytesString.length()));
1710 int allBytesLen = allBytesString.length();
1712 System.arraycopy(unknownCharsMap, 0, this.charToBytes, 0,
1713 this.charToBytes.length);
1715 for (
int i = 0; i < BYTE_RANGE && i < allBytesLen; i++) {
1716 char c = allBytesString.charAt(i);
1717 this.byteToChars[
i] = c;
1718 this.charToBytes[c] = allBytes[
i];
1730 public ByteBuffer
encode(
String columnName, CharSequence input,
int collation,
int prefixLength, BufferManager bufferManager) {
1731 int length = input.length();
1732 byte[] outputBytes =
new byte[length];
1733 for (
int position = 0; position < length; ++position) {
1734 outputBytes[position] = charToBytes[input.charAt(position)];
1737 ByteBuffer outputByteBuffer = bufferManager.getStringStorageBuffer(length + prefixLength);
1739 outputByteBuffer.position(prefixLength);
1740 outputByteBuffer.put(outputBytes);
1741 outputByteBuffer.flip();
1744 return outputByteBuffer;
1756 public String decode(ByteBuffer inputByteBuffer,
int collation, BufferManager bufferManager) {
1757 int inputLimit = inputByteBuffer.limit();
1758 int inputPosition = inputByteBuffer.position();
1759 int inputSize = inputLimit- inputPosition;
1760 byte[] inputBytes =
new byte[inputSize];
1761 inputByteBuffer.get(inputBytes);
1762 char[] outputChars =
new char[inputSize];
1763 for (
int position = 0; position < inputSize; ++position) {
1764 outputChars[position] = byteToChars[inputBytes[position] - Byte.MIN_VALUE];
1774 for (
int i = 0; i <
string.length(); ++
i) {
1775 int theCharacter =
string.charAt(i);
1776 buffer.append(theCharacter);
1780 return buffer.toString();
1790 static int[] howManyBytesNeeded =
new int[] {0, 1, 1, 2, 2, 3, 3, 4, 4, 4,
1791 5, 5, 6, 6, 7, 7, 8, 8, 8,
1792 9, 9, 10, 10, 11, 11, 12, 12, 12,
1793 13, 13, 14, 14, 15, 15, 16, 16, 16,
1794 17, 17, 18, 18, 19, 19, 20, 20, 20,
1795 21, 21, 22, 22, 23, 23, 24, 24, 24,
1796 25, 25, 26, 26, 27, 27, 28, 28, 28,
1805 int howManyBytesNeededForIntegral = howManyBytesNeeded[precision - scale];
1806 int howManyBytesNeededForFraction = howManyBytesNeeded[scale];
1807 int result = howManyBytesNeededForIntegral + howManyBytesNeededForFraction;
1818 return endianManager.getBoolean(storeColumn, ndbRecAttr);
1828 return endianManager.getByte(storeColumn, ndbRecAttr);
1838 return endianManager.getShort(storeColumn, ndbRecAttr);
1848 return endianManager.getInt(storeColumn, ndbRecAttr);
1858 return endianManager.getLong(storeColumn, ndbRecAttr);
1870 return endianManager.convertLongValueForStorage(storeColumn, value);
1882 return endianManager.convertByteValueForStorage(storeColumn, value);
1893 public static int convertShortValueForStorage(
Column storeColumn,
1895 return endianManager.convertShortValueForStorage(storeColumn, value);