2
Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; version 2 of the License.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
#include <NdbSqlUtil.hpp>
19
#include <ndb_version.h>
23
* Data types. The entries must be in the numerical order.
26
const NdbSqlUtil::Type
27
NdbSqlUtil::m_typeList[] = {
197
Type::Olddecimalunsigned,
198
cmpOlddecimalunsigned,
209
Type::Decimalunsigned,
216
const NdbSqlUtil::Type&
217
NdbSqlUtil::getType(Uint32 typeId)
219
if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) &&
220
m_typeList[typeId].m_typeId != Type::Undefined) {
221
return m_typeList[typeId];
223
return m_typeList[Type::Undefined];
227
* Comparison functions.
231
NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
233
assert(info == 0 && n1 == 1 && n2 == 1);
243
NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
245
assert(info == 0 && n1 == 1 && n2 == 1);
255
NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
257
assert(info == 0 && n1 == 2 && n2 == 2);
267
NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
269
assert(info == 0 && n1 == 2 && n2 == 2);
279
NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
281
assert(info == 0 && n1 == 3 && n2 == 3);
288
int w1 = (int)sint3korr(b1);
289
int w2 = (int)sint3korr(b2);
294
NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
296
assert(info == 0 && n1 == 3 && n2 == 3);
303
int w1 = (int)uint3korr(b1);
304
int w2 = (int)uint3korr(b2);
309
NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
311
assert(info == 0 && n1 == 4 && n2 == 4);
323
NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
325
assert(info == 0 && n1 == 4 && n2 == 4);
337
NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
339
assert(info == 0 && n1 == 8 && n2 == 8);
351
NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
353
assert(info == 0 && n1 == 8 && n2 == 8);
365
NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
367
assert(info == 0 && n1 == 4 && n2 == 4);
371
require(!isnan(v1) && !isnan(v2));
380
NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
382
assert(info == 0 && n1 == 8 && n2 == 8);
386
require(!isnan(v1) && !isnan(v2));
395
NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
397
assert(info == 0 && n1 == n2);
398
const uchar* v1 = (const uchar*)p1;
399
const uchar* v2 = (const uchar*)p2;
408
} else if (c1 == '-') {
410
} else if (c2 == '-') {
412
} else if (c1 < c2) {
423
NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
425
return cmpOlddecimal(info, p1, n1, p2, n2);
429
NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
431
return cmpBinary(info, p1, n1, p2, n2);
435
NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
437
return cmpBinary(info, p1, n1, p2, n2);
441
NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
443
// allow different lengths
445
const uchar* v1 = (const uchar*)p1;
446
const uchar* v2 = (const uchar*)p2;
447
CHARSET_INFO* cs = (CHARSET_INFO*)info;
448
// compare with space padding
449
int k = (*cs->coll->strnncollsp)(cs, v1, n1, v2, n2, false);
454
NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
458
const uchar* v1 = (const uchar*)p1;
459
const uchar* v2 = (const uchar*)p2;
462
require(lb + m1 <= n1 && lb + m2 <= n2);
463
CHARSET_INFO* cs = (CHARSET_INFO*)info;
464
// compare with space padding
465
int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
470
NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
472
// allow different lengths
474
const uchar* v1 = (const uchar*)p1;
475
const uchar* v2 = (const uchar*)p2;
478
k = memcmp(v1, v2, n1);
481
} else if (n1 > n2) {
482
k = memcmp(v1, v2, n2);
486
k = memcmp(v1, v2, n1);
492
NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
496
const uchar* v1 = (const uchar*)p1;
497
const uchar* v2 = (const uchar*)p2;
500
require(lb + m1 <= n1 && lb + m2 <= n2);
501
int k = cmpBinary(info, v1 + lb, m1, v2 + lb, m2);
506
NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
508
assert(info == 0 && n1 == 8 && n2 == 8);
510
memcpy(&v1, p1, sizeof(Int64));
511
memcpy(&v2, p2, sizeof(Int64));
520
NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
522
assert(info == 0 && n1 == 3 && n2 == 3);
529
// from Field_newdate::val_int
530
int w1 = (int)uint3korr(b1);
531
int w2 = (int)uint3korr(b2);
537
NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
545
NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
552
NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
554
/* Bitfields are stored as 32-bit words
555
* This means that a byte-by-byte comparison will not work on all platforms
556
* We do a word-wise comparison of the significant bytes.
557
* It is assumed that insignificant bits (but not bytes) are zeroed in the
560
const Uint32 bytes= MIN(n1, n2);
561
Uint32 words= (bytes + 3) >> 2;
563
/* Don't expect either value to be length zero */
566
/* Check ptr alignment */
567
if (unlikely(((((UintPtr)p1) & 3) != 0) ||
568
((((UintPtr)p2) & 3) != 0)))
570
Uint32 copyP1[ MAX_TUPLE_SIZE_IN_WORDS ];
571
Uint32 copyP2[ MAX_TUPLE_SIZE_IN_WORDS ];
572
memcpy(copyP1, p1, words << 2);
573
memcpy(copyP2, p2, words << 2);
575
return cmpBit(info, copyP1, bytes, copyP2, bytes);
578
const Uint32* wp1= (const Uint32*) p1;
579
const Uint32* wp2= (const Uint32*) p2;
584
if (*(wp1++) > *(wp2++))
588
/* For the last word, we mask out any insignificant bytes */
589
const Uint32 sigBytes= bytes & 3; // 0..3; 0 == all bytes significant
590
const Uint32 mask= sigBytes?
591
(1 << (sigBytes *8)) -1 :
593
const Uint32 lastWord1= *wp1 & mask;
594
const Uint32 lastWord2= *wp2 & mask;
596
if (lastWord1 < lastWord2)
598
if (lastWord1 > lastWord2)
606
NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
608
assert(info == 0 && n1 == 3 && n2 == 3);
615
// from Field_time::val_int
616
int j1 = (int)sint3korr(b1);
617
int j2 = (int)sint3korr(b2);
628
NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
632
const uchar* v1 = (const uchar*)p1;
633
const uchar* v2 = (const uchar*)p2;
634
uint m1 = v1[0] | (v1[1] << 8);
635
uint m2 = v2[0] | (v2[1] << 8);
636
require(lb + m1 <= n1 && lb + m2 <= n2);
637
CHARSET_INFO* cs = (CHARSET_INFO*)info;
638
// compare with space padding
639
int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
644
NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
648
const uchar* v1 = (const uchar*)p1;
649
const uchar* v2 = (const uchar*)p2;
650
uint m1 = v1[0] | (v1[1] << 8);
651
uint m2 = v2[0] | (v2[1] << 8);
652
require(lb + m1 <= n1 && lb + m2 <= n2);
653
int k = cmpBinary(info, v1 + lb, m1, v2 + lb, m2);
658
NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
660
assert(info == 0 && n1 == 1 && n2 == 1);
670
NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
672
assert(info == 0 && n1 == 4 && n2 == 4);
685
static const int ndb_wild_prefix = '\\';
686
static const int ndb_wild_one = '_';
687
static const int ndb_wild_many = '%';
690
NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
692
const char* v1 = (const char*)p1;
693
const char* v2 = (const char*)p2;
694
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
695
// strip end spaces to match (incorrect) MySQL behaviour
696
n1 = (*cs->cset->lengthsp)(cs, v1, n1);
697
int k = (*cs->coll->wildcmp)(cs, v1, v1 + n1, v2, v2 + n2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
698
return k == 0 ? 0 : +1;
702
NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
705
return likeChar(&my_charset_bin, p1, n1, p2, n2);
709
NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
711
const unsigned lb = 1;
713
const uchar* v1 = (const uchar*)p1;
714
const uchar* v2 = (const uchar*)p2;
718
const char* w1 = (const char*)v1 + lb;
719
const char* w2 = (const char*)v2;
720
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
721
int k = (*cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
722
return k == 0 ? 0 : +1;
729
NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
732
return likeVarchar(&my_charset_bin, p1, n1, p2, n2);
736
NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
738
const unsigned lb = 2;
740
const uchar* v1 = (const uchar*)p1;
741
const uchar* v2 = (const uchar*)p2;
742
unsigned m1 = uint2korr(v1);
745
const char* w1 = (const char*)v1 + lb;
746
const char* w2 = (const char*)v2;
747
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
748
int k = (*cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
749
return k == 0 ? 0 : +1;
756
NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
759
return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2);
766
NdbSqlUtil::maskBit(const void* data, unsigned dataLen, const void* mask, unsigned maskLen, bool cmpZero)
768
/* Bitfields are stored in word oriented form, so we must compare them in that
770
* It is assumed that insignificant bits (but not bytes) in the passed values
773
const Uint32 bytes = MIN(dataLen, maskLen);
774
Uint32 words = (bytes + 3) >> 2;
776
/* Don't expect either value to be length zero */
779
/* Check ptr alignment */
780
if (unlikely(((((UintPtr)data) & 3) != 0) ||
781
((((UintPtr)mask) & 3) != 0)))
783
Uint32 copydata[ MAX_TUPLE_SIZE_IN_WORDS ];
784
Uint32 copymask[ MAX_TUPLE_SIZE_IN_WORDS ];
785
memcpy(copydata, data, words << 2);
786
memcpy(copymask, mask, words << 2);
788
return maskBit(data, bytes, mask, bytes, cmpZero);
791
const Uint32* wdata= (const Uint32*) data;
792
const Uint32* wmask= (const Uint32*) mask;
798
if ((*(wdata++) & *(wmask++)) != 0)
802
/* For the last word, we mask out any insignificant bytes */
803
const Uint32 sigBytes= bytes & 3; // 0..3; 0 == all bytes significant
804
const Uint32 comparisonMask= sigBytes?
805
(1 << (sigBytes *8)) -1 :
807
const Uint32 lastDataWord= *wdata & comparisonMask;
808
const Uint32 lastMaskWord= *wmask & comparisonMask;
810
if ((lastDataWord & lastMaskWord) != 0)
819
if ((*(wdata++) & *wmask) != *wmask)
825
/* For the last word, we mask out any insignificant bytes */
826
const Uint32 sigBytes= bytes & 3; // 0..3; 0 == all bytes significant
827
const Uint32 comparisonMask= sigBytes?
828
(1 << (sigBytes *8)) -1 :
830
const Uint32 lastDataWord= *wdata & comparisonMask;
831
const Uint32 lastMaskWord= *wmask & comparisonMask;
833
if ((lastDataWord & lastMaskWord) != lastMaskWord)
844
NdbSqlUtil::check_column_for_pk(Uint32 typeId, const void* info)
846
const Type& type = getType(typeId);
847
switch (type.m_typeId) {
850
case Type::Longvarchar:
852
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
856
cs->coll->strnxfrm != 0 &&
857
cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
863
case Type::Undefined:
875
NdbSqlUtil::check_column_for_hash_index(Uint32 typeId, const void* info)
877
return check_column_for_pk(typeId, info);
881
NdbSqlUtil::check_column_for_ordered_index(Uint32 typeId, const void* info)
883
const Type& type = getType(typeId);
884
if (type.m_cmp == NULL)
886
switch (type.m_typeId) {
889
case Type::Longvarchar:
891
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
895
cs->coll->strnxfrm != 0 &&
896
cs->coll->strnncollsp != 0 &&
897
cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
903
case Type::Undefined:
906
case Type::Bit: // can be fixed
917
NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len)
919
const unsigned char* const src = (const unsigned char*)p;
921
case NdbSqlUtil::Type::Varchar:
922
case NdbSqlUtil::Type::Varbinary:
926
if (attrlen >= lb + len)
930
case NdbSqlUtil::Type::Longvarchar:
931
case NdbSqlUtil::Type::Longvarbinary:
934
len = src[0] + (src[1] << 8);
935
if (attrlen >= lb + len)
950
NdbSqlUtil::ndb_strnxfrm(struct charset_info_st * cs,
951
uchar *dst, size_t dstlen,
952
const uchar *src, size_t srclen)
954
#if NDB_MYSQL_VERSION_D < NDB_MAKE_VERSION(5,6,0)
955
return (*cs->coll->strnxfrm)(cs, dst, dstlen, src, srclen);
958
strnxfrm has got two new parameters in 5.6, we are using the
959
defaults for those and can thus easily calculate them from
962
return (*cs->coll->strnxfrm)(cs, dst, dstlen, dstlen,
963
src, srclen, MY_STRXFRM_PAD_WITH_SPACE);
970
NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen)
972
unsigned char nsp[20]; // native space char
973
unsigned char xsp[20]; // strxfrm-ed space char
975
memset(nsp, 0x1f, sizeof(nsp));
976
memset(xsp, 0x1f, sizeof(xsp));
978
// convert from unicode codepoint for space
979
int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp));
983
int n2 = ndb_strnxfrm(cs, xsp, sizeof(xsp), nsp, n1);
986
// XXX bug workaround - strnxfrm may not write full string
987
memset(dst, 0x0, dstLen);
988
// strxfrm argument string - returns no error indication
989
int n3 = ndb_strnxfrm(cs, dst, dstLen, src, srcLen);
990
// pad with strxfrm-ed space chars
992
while (n4 < (int)dstLen) {
993
dst[n4] = xsp[(n4 - n3) % n2];
996
// no check for partial last
1000
#if defined(WORDS_BIGENDIAN) || defined (VM_TRACE)
1003
void determineParams(Uint32 typeId,
1004
Uint32 typeLog2Size,
1007
Uint32 dataByteSize,
1011
/* Some types need 'normal behaviour' over-ridden in
1012
* terms of endian-ness conversions
1018
case NdbSqlUtil::Type::Datetime:
1020
// Datetime is stored as 8x8, should be twiddled as 64 bit
1021
assert(typeLog2Size == 3);
1022
assert(arraySize == 8);
1023
assert(dataByteSize == 8);
1028
case NdbSqlUtil::Type::Timestamp:
1030
// Timestamp is stored as 4x8, should be twiddled as 32 bit
1031
assert(typeLog2Size == 3);
1032
assert(arraySize == 4);
1033
assert(dataByteSize == 4);
1038
case NdbSqlUtil::Type::Bit:
1040
// Bit is stored as bits, should be twiddled as 32 bit
1041
assert(typeLog2Size == 0);
1043
convLen = (arraySize + 31)/32;
1046
case NdbSqlUtil::Type::Blob:
1047
case NdbSqlUtil::Type::Text:
1049
if (arrayType == NDB_ARRAYTYPE_FIXED)
1051
// Length of fixed size blob which is stored in first 64 bit's
1052
// has to be twiddled, the remaining byte stream left as is
1053
assert(typeLog2Size == 3);
1054
assert(arraySize > 8);
1055
assert(dataByteSize > 8);
1060
// Fall through for Blob v2
1063
/* Default determined by meta-info */
1064
convSize = 1 << typeLog2Size;
1065
convLen = arraySize;
1069
const Uint32 unitBytes = (convSize >> 3);
1071
if (dataByteSize < (unitBytes * convLen))
1073
/* Actual data is shorter than expected, could
1074
* be VAR type or bad FIXED data (which some other
1075
* code should detect + handle)
1076
* We reduce convLen to avoid trampling
1078
assert((dataByteSize % unitBytes) == 0);
1079
convLen = dataByteSize / unitBytes;
1084
assert(dataByteSize >= (unitBytes * convLen));
1088
void doConvert(Uint32 convSize,
1095
/* Nothing to swap */
1099
Uint16* ptr = (Uint16*)data;
1100
for (Uint32 i = 0; i < convLen; i++){
1102
((*ptr & 0xFF00) >> 8) |
1103
((*ptr & 0x00FF) << 8);
1111
Uint32* ptr = (Uint32*)data;
1112
for (Uint32 i = 0; i < convLen; i++){
1114
((*ptr & 0xFF000000) >> 24) |
1115
((*ptr & 0x00FF0000) >> 8) |
1116
((*ptr & 0x0000FF00) << 8) |
1117
((*ptr & 0x000000FF) << 24);
1125
Uint64* ptr = (Uint64*)data;
1126
for (Uint32 i = 0; i < convLen; i++){
1128
((*ptr & (Uint64)0xFF00000000000000LL) >> 56) |
1129
((*ptr & (Uint64)0x00FF000000000000LL) >> 40) |
1130
((*ptr & (Uint64)0x0000FF0000000000LL) >> 24) |
1131
((*ptr & (Uint64)0x000000FF00000000LL) >> 8) |
1132
((*ptr & (Uint64)0x00000000FF000000LL) << 8) |
1133
((*ptr & (Uint64)0x0000000000FF0000LL) << 24) |
1134
((*ptr & (Uint64)0x000000000000FF00LL) << 40) |
1135
((*ptr & (Uint64)0x00000000000000FFLL) << 56);
1149
* Convert attribute byte order if necessary
1152
NdbSqlUtil::convertByteOrder(Uint32 typeId,
1153
Uint32 typeLog2Size,
1157
Uint32 dataByteSize)
1159
#if defined(WORDS_BIGENDIAN) || defined (VM_TRACE)
1162
determineParams(typeId,
1170
size_t mask = (((size_t) convSize) >> 3) -1; // Bottom 0,1,2,3 bits set
1171
bool aligned = (((size_t) data) & mask) == 0;
1172
uchar* dataPtr = data;
1173
const Uint32 bufSize = (MAX_TUPLE_SIZE_IN_WORDS + 1)/2;
1174
Uint64 alignedBuf[bufSize];
1178
assert(dataByteSize <= 4 * MAX_TUPLE_SIZE_IN_WORDS);
1179
memcpy(alignedBuf, data, dataByteSize);
1180
dataPtr = (uchar*) alignedBuf;
1183
/* Now have convSize and convLen, do the conversion */
1189
#ifndef WORDS_BIGENDIAN
1190
// VM trace on little-endian performs double-convert
1199
memcpy(data, alignedBuf, dataByteSize);