1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include <NdbSqlUtil.hpp>
21
* Data types. The entries must be in the numerical order.
24
const NdbSqlUtil::Type
25
NdbSqlUtil::m_typeList[] = {
167
Type::Olddecimalunsigned,
168
cmpOlddecimalunsigned,
177
Type::Decimalunsigned,
183
const NdbSqlUtil::Type&
184
NdbSqlUtil::getType(Uint32 typeId)
186
if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) &&
187
m_typeList[typeId].m_typeId != Type::Undefined) {
188
return m_typeList[typeId];
190
return m_typeList[Type::Undefined];
193
const NdbSqlUtil::Type&
194
NdbSqlUtil::getTypeBinary(Uint32 typeId)
200
case Type::Varbinary:
201
case Type::Longvarchar:
202
case Type::Longvarbinary:
203
typeId = Type::Binary;
211
return getType(typeId);
215
* Comparison functions.
219
NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
221
if (n2 >= sizeof(Int8)) {
223
memcpy(&v1, p1, sizeof(Int8));
224
memcpy(&v2, p2, sizeof(Int8));
236
NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
238
if (n2 >= sizeof(Uint8)) {
240
memcpy(&v1, p1, sizeof(Uint8));
241
memcpy(&v2, p2, sizeof(Uint8));
253
NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
255
if (n2 >= sizeof(Int16)) {
257
memcpy(&v1, p1, sizeof(Int16));
258
memcpy(&v2, p2, sizeof(Int16));
270
NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
272
if (n2 >= sizeof(Uint16)) {
274
memcpy(&v1, p1, sizeof(Uint16));
275
memcpy(&v2, p2, sizeof(Uint16));
287
NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
291
v1 = sint3korr((const uchar*)p1);
292
v2 = sint3korr((const uchar*)p2);
304
NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
308
v1 = uint3korr((const uchar*)p1);
309
v2 = uint3korr((const uchar*)p2);
321
NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
323
if (n2 >= sizeof(Int32)) {
325
memcpy(&v1, p1, sizeof(Int32));
326
memcpy(&v2, p2, sizeof(Int32));
338
NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
340
if (n2 >= sizeof(Uint32)) {
342
memcpy(&v1, p1, sizeof(Uint32));
343
memcpy(&v2, p2, sizeof(Uint32));
355
NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
357
if (n2 >= sizeof(Int64)) {
359
memcpy(&v1, p1, sizeof(Int64));
360
memcpy(&v2, p2, sizeof(Int64));
372
NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
374
if (n2 >= sizeof(Uint64)) {
376
memcpy(&v1, p1, sizeof(Uint64));
377
memcpy(&v2, p2, sizeof(Uint64));
389
NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
391
if (n2 >= sizeof(float)) {
393
memcpy(&v1, p1, sizeof(float));
394
memcpy(&v2, p2, sizeof(float));
406
NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
408
if (n2 >= sizeof(double)) {
410
memcpy(&v1, p1, sizeof(double));
411
memcpy(&v2, p2, sizeof(double));
423
NdbSqlUtil::cmp_olddecimal(const uchar* s1, const uchar* s2, unsigned n)
433
} else if (c1 == '-') {
435
} else if (c2 == '-') {
437
} else if (c1 < c2) {
448
NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
452
const uchar* v1 = (const uchar*)p1;
453
const uchar* v2 = (const uchar*)p2;
454
return cmp_olddecimal(v1, v2, n1);
460
NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
464
const uchar* v1 = (const uchar*)p1;
465
const uchar* v2 = (const uchar*)p2;
466
return cmp_olddecimal(v1, v2, n1);
472
NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
474
const uchar* v1 = (const uchar*)p1;
475
const uchar* v2 = (const uchar*)p2;
476
// compare as binary strings
477
unsigned n = (n1 <= n2 ? n1 : n2);
478
int k = memcmp(v1, v2, n);
480
k = (full ? n1 : n) - n2;
482
return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
486
NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
488
const uchar* v1 = (const uchar*)p1;
489
const uchar* v2 = (const uchar*)p2;
490
// compare as binary strings
491
unsigned n = (n1 <= n2 ? n1 : n2);
492
int k = memcmp(v1, v2, n);
494
k = (full ? n1 : n) - n2;
496
return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
500
NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
502
// collation does not work on prefix for some charsets
504
const uchar* v1 = (const uchar*)p1;
505
const uchar* v2 = (const uchar*)p2;
506
// not const in MySQL
507
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
508
// compare with space padding
509
int k = (*cs->coll->strnncollsp)(cs, v1, n1, v2, n2, false);
510
return k < 0 ? -1 : k > 0 ? +1 : 0;
514
NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
516
const unsigned lb = 1;
517
// collation does not work on prefix for some charsets
518
assert(full && n1 >= lb && n2 >= lb);
519
const uchar* v1 = (const uchar*)p1;
520
const uchar* v2 = (const uchar*)p2;
523
if (m1 <= n1 - lb && m2 <= n2 - lb) {
524
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
525
// compare with space padding
526
int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
527
return k < 0 ? -1 : k > 0 ? +1 : 0;
529
// treat bad data as NULL
530
if (m1 > n1 - lb && m2 <= n2 - lb)
532
if (m1 <= n1 - lb && m2 > n2 - lb)
538
NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
540
const uchar* v1 = (const uchar*)p1;
541
const uchar* v2 = (const uchar*)p2;
542
// compare as binary strings
543
unsigned n = (n1 <= n2 ? n1 : n2);
544
int k = memcmp(v1, v2, n);
546
k = (full ? n1 : n) - n2;
548
return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
552
NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
554
const unsigned lb = 1;
557
const uchar* v1 = (const uchar*)p1;
558
const uchar* v2 = (const uchar*)p2;
561
if (m1 <= n1 - lb && m2 <= n2 - lb) {
562
// compare as binary strings
563
unsigned m = (m1 <= m2 ? m1 : m2);
564
int k = memcmp(v1 + lb, v2 + lb, m);
566
k = (full ? m1 : m) - m2;
568
return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
570
// treat bad data as NULL
571
if (m1 > n1 - lb && m2 <= n2 - lb)
573
if (m1 <= n1 - lb && m2 > n2 - lb)
582
NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
584
if (n2 >= sizeof(Int64)) {
586
memcpy(&v1, p1, sizeof(Int64));
587
memcpy(&v2, p2, sizeof(Int64));
599
NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
601
#ifdef ndb_date_is_4_byte_native_int
602
if (n2 >= sizeof(Int32)) {
604
memcpy(&v1, p1, sizeof(Int32));
605
memcpy(&v2, p2, sizeof(Int32));
613
#ifdef ndb_date_sol9x86_cc_xO3_madness
615
const uchar* v1 = (const uchar*)p1;
616
const uchar* v2 = (const uchar*)p2;
617
// from Field_newdate::val_int
618
Uint64 j1 = uint3korr(v1);
619
Uint64 j2 = uint3korr(v2);
620
j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L;
621
j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L;
630
const uchar* v1 = (const uchar*)p1;
631
const uchar* v2 = (const uchar*)p2;
632
uint j1 = uint3korr(v1);
633
uint j2 = uint3korr(v2);
666
NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
674
NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
681
NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
683
Uint32 n = (n1 < n2) ? n1 : n2;
684
int ret = memcmp(p1, p2, n);
690
NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
693
const uchar* v1 = (const uchar*)p1;
694
const uchar* v2 = (const uchar*)p2;
695
// from Field_time::val_int
696
Int32 j1 = sint3korr(v1);
697
Int32 j2 = sint3korr(v2);
711
NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
713
const unsigned lb = 2;
714
// collation does not work on prefix for some charsets
715
assert(full && n1 >= lb && n2 >= lb);
716
const uchar* v1 = (const uchar*)p1;
717
const uchar* v2 = (const uchar*)p2;
718
unsigned m1 = uint2korr(v1);
719
unsigned m2 = uint2korr(v2);
720
if (m1 <= n1 - lb && m2 <= n2 - lb) {
721
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
722
// compare with space padding
723
int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
724
return k < 0 ? -1 : k > 0 ? +1 : 0;
726
// treat bad data as NULL
727
if (m1 > n1 - lb && m2 <= n2 - lb)
729
if (m1 <= n1 - lb && m2 > n2 - lb)
735
NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
737
const unsigned lb = 2;
740
const uchar* v1 = (const uchar*)p1;
741
const uchar* v2 = (const uchar*)p2;
742
unsigned m1 = uint2korr(v1);
743
unsigned m2 = uint2korr(v2);
744
if (m1 <= n1 - lb && m2 <= n2 - lb) {
745
// compare as binary strings
746
unsigned m = (m1 <= m2 ? m1 : m2);
747
int k = memcmp(v1 + lb, v2 + lb, m);
749
k = (full ? m1 : m) - m2;
751
return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
753
// treat bad data as NULL
754
if (m1 > n1 - lb && m2 <= n2 - lb)
756
if (m1 <= n1 - lb && m2 > n2 - lb)
765
NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
767
if (n2 >= sizeof(Uint8)) {
769
memcpy(&v1, p1, sizeof(Uint8));
770
memcpy(&v2, p2, sizeof(Uint8));
782
NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
784
if (n2 >= sizeof(Uint32)) {
786
memcpy(&v1, p1, sizeof(Uint32));
787
memcpy(&v2, p2, sizeof(Uint32));
800
static const int ndb_wild_prefix = '\\';
801
static const int ndb_wild_one = '_';
802
static const int ndb_wild_many = '%';
805
NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
807
const char* v1 = (const char*)p1;
808
const char* v2 = (const char*)p2;
809
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
810
// strip end spaces to match (incorrect) MySQL behaviour
811
n1 = (*cs->cset->lengthsp)(cs, v1, n1);
812
int k = (*cs->coll->wildcmp)(cs, v1, v1 + n1, v2, v2 + n2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
813
return k == 0 ? 0 : +1;
817
NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
820
return likeChar(&my_charset_bin, p1, n1, p2, n2);
824
NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
826
const unsigned lb = 1;
828
const uchar* v1 = (const uchar*)p1;
829
const uchar* v2 = (const uchar*)p2;
833
const char* w1 = (const char*)v1 + lb;
834
const char* w2 = (const char*)v2;
835
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
836
int k = (*cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
837
return k == 0 ? 0 : +1;
844
NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
847
return likeVarchar(&my_charset_bin, p1, n1, p2, n2);
851
NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
853
const unsigned lb = 2;
855
const uchar* v1 = (const uchar*)p1;
856
const uchar* v2 = (const uchar*)p2;
857
unsigned m1 = uint2korr(v1);
860
const char* w1 = (const char*)v1 + lb;
861
const char* w2 = (const char*)v2;
862
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
863
int k = (*cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
864
return k == 0 ? 0 : +1;
871
NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
874
return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2);
880
NdbSqlUtil::check_column_for_pk(Uint32 typeId, const void* info)
882
const Type& type = getType(typeId);
883
switch (type.m_typeId) {
886
case Type::Longvarchar:
888
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
892
cs->coll->strnxfrm != 0 &&
893
cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
899
case Type::Undefined:
911
NdbSqlUtil::check_column_for_hash_index(Uint32 typeId, const void* info)
913
return check_column_for_pk(typeId, info);
917
NdbSqlUtil::check_column_for_ordered_index(Uint32 typeId, const void* info)
919
const Type& type = getType(typeId);
920
if (type.m_cmp == NULL)
922
switch (type.m_typeId) {
925
case Type::Longvarchar:
927
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
931
cs->coll->strnxfrm != 0 &&
932
cs->coll->strnncollsp != 0 &&
933
cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
939
case Type::Undefined:
942
case Type::Bit: // can be fixed
953
NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len)
955
const unsigned char* const src = (const unsigned char*)p;
957
case NdbSqlUtil::Type::Varchar:
958
case NdbSqlUtil::Type::Varbinary:
962
if (attrlen >= lb + len)
966
case NdbSqlUtil::Type::Longvarchar:
967
case NdbSqlUtil::Type::Longvarbinary:
970
len = src[0] + (src[1] << 8);
971
if (attrlen >= lb + len)
987
NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen)
989
unsigned char nsp[20]; // native space char
990
unsigned char xsp[20]; // strxfrm-ed space char
992
memset(nsp, 0x1f, sizeof(nsp));
993
memset(xsp, 0x1f, sizeof(xsp));
995
// convert from unicode codepoint for space
996
int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp));
1000
int n2 = (*cs->coll->strnxfrm)(cs, xsp, sizeof(xsp), nsp, n1);
1003
// XXX bug workaround - strnxfrm may not write full string
1004
memset(dst, 0x0, dstLen);
1005
// strxfrm argument string - returns no error indication
1006
int n3 = (*cs->coll->strnxfrm)(cs, dst, dstLen, src, srcLen);
1007
// pad with strxfrm-ed space chars
1009
while (n4 < (int)dstLen) {
1010
dst[n4] = xsp[(n4 - n3) % n2];
1013
// no check for partial last