MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbSqlUtil.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
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.
7 
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.
12 
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
16 */
17 
18 #include <NdbSqlUtil.hpp>
19 #include <ndb_version.h>
20 #include <math.h>
21 
22 /*
23  * Data types. The entries must be in the numerical order.
24  */
25 
26 const NdbSqlUtil::Type
27 NdbSqlUtil::m_typeList[] = {
28  { // 0
29  Type::Undefined,
30  NULL,
31  NULL,
32  NULL
33  },
34  { // 1
35  Type::Tinyint,
36  cmpTinyint,
37  NULL,
38  NULL
39  },
40  { // 2
41  Type::Tinyunsigned,
42  cmpTinyunsigned,
43  NULL,
44  NULL
45  },
46  { // 3
47  Type::Smallint,
48  cmpSmallint,
49  NULL,
50  NULL
51  },
52  { // 4
53  Type::Smallunsigned,
54  cmpSmallunsigned,
55  NULL,
56  NULL
57  },
58  { // 5
59  Type::Mediumint,
60  cmpMediumint,
61  NULL,
62  NULL
63  },
64  { // 6
65  Type::Mediumunsigned,
66  cmpMediumunsigned,
67  NULL,
68  NULL
69  },
70  { // 7
71  Type::Int,
72  cmpInt,
73  NULL,
74  NULL
75  },
76  { // 8
77  Type::Unsigned,
78  cmpUnsigned,
79  NULL,
80  NULL
81  },
82  { // 9
83  Type::Bigint,
84  cmpBigint,
85  NULL,
86  NULL
87  },
88  { // 10
89  Type::Bigunsigned,
90  cmpBigunsigned,
91  NULL,
92  NULL
93  },
94  { // 11
95  Type::Float,
96  cmpFloat,
97  NULL,
98  NULL
99  },
100  { // 12
101  Type::Double,
102  cmpDouble,
103  NULL,
104  NULL
105  },
106  { // 13
107  Type::Olddecimal,
108  cmpOlddecimal,
109  NULL,
110  NULL
111  },
112  { // 14
113  Type::Char,
114  cmpChar,
115  likeChar,
116  NULL
117  },
118  { // 15
119  Type::Varchar,
120  cmpVarchar,
121  likeVarchar,
122  NULL
123  },
124  { // 16
125  Type::Binary,
126  cmpBinary,
127  likeBinary,
128  NULL
129  },
130  { // 17
131  Type::Varbinary,
132  cmpVarbinary,
133  likeVarbinary,
134  NULL
135  },
136  { // 18
137  Type::Datetime,
138  cmpDatetime,
139  NULL,
140  NULL
141  },
142  { // 19
143  Type::Date,
144  cmpDate,
145  NULL,
146  NULL
147  },
148  { // 20
149  Type::Blob,
150  NULL,
151  NULL,
152  NULL
153  },
154  { // 21
155  Type::Text,
156  NULL,
157  NULL,
158  NULL
159  },
160  { // 22
161  Type::Bit,
162  cmpBit,
163  NULL,
164  maskBit
165  },
166  { // 23
167  Type::Longvarchar,
168  cmpLongvarchar,
169  likeLongvarchar,
170  NULL
171  },
172  { // 24
173  Type::Longvarbinary,
174  cmpLongvarbinary,
175  likeLongvarbinary,
176  NULL
177  },
178  { // 25
179  Type::Time,
180  cmpTime,
181  NULL,
182  NULL
183  },
184  { // 26
185  Type::Year,
186  cmpYear,
187  NULL,
188  NULL
189  },
190  { // 27
191  Type::Timestamp,
192  cmpTimestamp,
193  NULL,
194  NULL
195  },
196  { // 28
197  Type::Olddecimalunsigned,
198  cmpOlddecimalunsigned,
199  NULL,
200  NULL
201  },
202  { // 29
203  Type::Decimal,
204  cmpDecimal,
205  NULL,
206  NULL
207  },
208  { // 30
209  Type::Decimalunsigned,
210  cmpDecimalunsigned,
211  NULL,
212  NULL
213  }
214 };
215 
216 const NdbSqlUtil::Type&
217 NdbSqlUtil::getType(Uint32 typeId)
218 {
219  if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) &&
220  m_typeList[typeId].m_typeId != Type::Undefined) {
221  return m_typeList[typeId];
222  }
223  return m_typeList[Type::Undefined];
224 }
225 
226 /*
227  * Comparison functions.
228  */
229 
230 int
231 NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
232 {
233  assert(info == 0 && n1 == 1 && n2 == 1);
234  Int8 v1, v2;
235  memcpy(&v1, p1, 1);
236  memcpy(&v2, p2, 1);
237  int w1 = (int)v1;
238  int w2 = (int)v2;
239  return w1 - w2;
240 }
241 
242 int
243 NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
244 {
245  assert(info == 0 && n1 == 1 && n2 == 1);
246  Uint8 v1, v2;
247  memcpy(&v1, p1, 1);
248  memcpy(&v2, p2, 1);
249  int w1 = (int)v1;
250  int w2 = (int)v2;
251  return w1 - w2;
252 }
253 
254 int
255 NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
256 {
257  assert(info == 0 && n1 == 2 && n2 == 2);
258  Int16 v1, v2;
259  memcpy(&v1, p1, 2);
260  memcpy(&v2, p2, 2);
261  int w1 = (int)v1;
262  int w2 = (int)v2;
263  return w1 - w2;
264 }
265 
266 int
267 NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
268 {
269  assert(info == 0 && n1 == 2 && n2 == 2);
270  Uint16 v1, v2;
271  memcpy(&v1, p1, 2);
272  memcpy(&v2, p2, 2);
273  int w1 = (int)v1;
274  int w2 = (int)v2;
275  return w1 - w2;
276 }
277 
278 int
279 NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
280 {
281  assert(info == 0 && n1 == 3 && n2 == 3);
282  uchar b1[4];
283  uchar b2[4];
284  memcpy(b1, p1, 3);
285  b1[3] = 0;
286  memcpy(b2, p2, 3);
287  b2[3] = 0;
288  int w1 = (int)sint3korr(b1);
289  int w2 = (int)sint3korr(b2);
290  return w1 - w2;
291 }
292 
293 int
294 NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
295 {
296  assert(info == 0 && n1 == 3 && n2 == 3);
297  uchar b1[4];
298  uchar b2[4];
299  memcpy(b1, p1, 3);
300  b1[3] = 0;
301  memcpy(b2, p2, 3);
302  b2[3] = 0;
303  int w1 = (int)uint3korr(b1);
304  int w2 = (int)uint3korr(b2);
305  return w1 - w2;
306 }
307 
308 int
309 NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
310 {
311  assert(info == 0 && n1 == 4 && n2 == 4);
312  Int32 v1, v2;
313  memcpy(&v1, p1, 4);
314  memcpy(&v2, p2, 4);
315  if (v1 < v2)
316  return -1;
317  if (v1 > v2)
318  return +1;
319  return 0;
320 }
321 
322 int
323 NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
324 {
325  assert(info == 0 && n1 == 4 && n2 == 4);
326  Uint32 v1, v2;
327  memcpy(&v1, p1, 4);
328  memcpy(&v2, p2, 4);
329  if (v1 < v2)
330  return -1;
331  if (v1 > v2)
332  return +1;
333  return 0;
334 }
335 
336 int
337 NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
338 {
339  assert(info == 0 && n1 == 8 && n2 == 8);
340  Int64 v1, v2;
341  memcpy(&v1, p1, 8);
342  memcpy(&v2, p2, 8);
343  if (v1 < v2)
344  return -1;
345  if (v1 > v2)
346  return +1;
347  return 0;
348 }
349 
350 int
351 NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
352 {
353  assert(info == 0 && n1 == 8 && n2 == 8);
354  Uint64 v1, v2;
355  memcpy(&v1, p1, 8);
356  memcpy(&v2, p2, 8);
357  if (v1 < v2)
358  return -1;
359  if (v1 > v2)
360  return +1;
361  return 0;
362 }
363 
364 int
365 NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
366 {
367  assert(info == 0 && n1 == 4 && n2 == 4);
368  float v1, v2;
369  memcpy(&v1, p1, 4);
370  memcpy(&v2, p2, 4);
371  require(!isnan(v1) && !isnan(v2));
372  if (v1 < v2)
373  return -1;
374  if (v1 > v2)
375  return +1;
376  return 0;
377 }
378 
379 int
380 NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
381 {
382  assert(info == 0 && n1 == 8 && n2 == 8);
383  double v1, v2;
384  memcpy(&v1, p1, 8);
385  memcpy(&v2, p2, 8);
386  require(!isnan(v1) && !isnan(v2));
387  if (v1 < v2)
388  return -1;
389  if (v1 > v2)
390  return +1;
391  return 0;
392 }
393 
394 int
395 NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
396 {
397  assert(info == 0 && n1 == n2);
398  const uchar* v1 = (const uchar*)p1;
399  const uchar* v2 = (const uchar*)p2;
400  int sgn = +1;
401  unsigned i = 0;
402  while (i < n1) {
403  int c1 = v1[i];
404  int c2 = v2[i];
405  if (c1 == c2) {
406  if (c1 == '-')
407  sgn = -1;
408  } else if (c1 == '-') {
409  return -1;
410  } else if (c2 == '-') {
411  return +1;
412  } else if (c1 < c2) {
413  return -1 * sgn;
414  } else {
415  return +1 * sgn;
416  }
417  i++;
418  }
419  return 0;
420 }
421 
422 int
423 NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
424 {
425  return cmpOlddecimal(info, p1, n1, p2, n2);
426 }
427 
428 int
429 NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
430 {
431  return cmpBinary(info, p1, n1, p2, n2);
432 }
433 
434 int
435 NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
436 {
437  return cmpBinary(info, p1, n1, p2, n2);
438 }
439 
440 int
441 NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
442 {
443  // allow different lengths
444  assert(info != 0);
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);
450  return k;
451 }
452 
453 int
454 NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
455 {
456  assert(info != 0);
457  const uint lb = 1;
458  const uchar* v1 = (const uchar*)p1;
459  const uchar* v2 = (const uchar*)p2;
460  uint m1 = v1[0];
461  uint m2 = v2[0];
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);
466  return k;
467 }
468 
469 int
470 NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
471 {
472  // allow different lengths
473  assert(info == 0);
474  const uchar* v1 = (const uchar*)p1;
475  const uchar* v2 = (const uchar*)p2;
476  int k = 0;
477  if (n1 < n2) {
478  k = memcmp(v1, v2, n1);
479  if (k == 0)
480  k = -1;
481  } else if (n1 > n2) {
482  k = memcmp(v1, v2, n2);
483  if (k == 0)
484  k = +1;
485  } else {
486  k = memcmp(v1, v2, n1);
487  }
488  return k;
489 }
490 
491 int
492 NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
493 {
494  assert(info == 0);
495  const uint lb = 1;
496  const uchar* v1 = (const uchar*)p1;
497  const uchar* v2 = (const uchar*)p2;
498  uint m1 = v1[0];
499  uint m2 = v2[0];
500  require(lb + m1 <= n1 && lb + m2 <= n2);
501  int k = cmpBinary(info, v1 + lb, m1, v2 + lb, m2);
502  return k;
503 }
504 
505 int
506 NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
507 {
508  assert(info == 0 && n1 == 8 && n2 == 8);
509  Int64 v1, v2;
510  memcpy(&v1, p1, sizeof(Int64));
511  memcpy(&v2, p2, sizeof(Int64));
512  if (v1 < v2)
513  return -1;
514  if (v1 > v2)
515  return +1;
516  return 0;
517 }
518 
519 int
520 NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
521 {
522  assert(info == 0 && n1 == 3 && n2 == 3);
523  uchar b1[4];
524  uchar b2[4];
525  memcpy(b1, p1, 3);
526  b1[3] = 0;
527  memcpy(b2, p2, 3);
528  b2[3] = 0;
529  // from Field_newdate::val_int
530  int w1 = (int)uint3korr(b1);
531  int w2 = (int)uint3korr(b2);
532  return w1 - w2;
533 }
534 
535 // not supported
536 int
537 NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
538 {
539  assert(false);
540  return 0;
541 }
542 
543 // not supported
544 int
545 NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
546 {
547  assert(false);
548  return 0;
549 }
550 
551 int
552 NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
553 {
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
558  * passed values.
559  */
560  const Uint32 bytes= MIN(n1, n2);
561  Uint32 words= (bytes + 3) >> 2;
562 
563  /* Don't expect either value to be length zero */
564  assert(words);
565 
566  /* Check ptr alignment */
567  if (unlikely(((((UintPtr)p1) & 3) != 0) ||
568  ((((UintPtr)p2) & 3) != 0)))
569  {
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);
574 
575  return cmpBit(info, copyP1, bytes, copyP2, bytes);
576  }
577 
578  const Uint32* wp1= (const Uint32*) p1;
579  const Uint32* wp2= (const Uint32*) p2;
580  while (--words)
581  {
582  if (*wp1 < *wp2)
583  return -1;
584  if (*(wp1++) > *(wp2++))
585  return 1;
586  }
587 
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 :
592  ~0;
593  const Uint32 lastWord1= *wp1 & mask;
594  const Uint32 lastWord2= *wp2 & mask;
595 
596  if (lastWord1 < lastWord2)
597  return -1;
598  if (lastWord1 > lastWord2)
599  return 1;
600 
601  return 0;
602 }
603 
604 
605 int
606 NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
607 {
608  assert(info == 0 && n1 == 3 && n2 == 3);
609  uchar b1[4];
610  uchar b2[4];
611  memcpy(b1, p1, 3);
612  b1[3] = 0;
613  memcpy(b2, p2, 3);
614  b2[3] = 0;
615  // from Field_time::val_int
616  int j1 = (int)sint3korr(b1);
617  int j2 = (int)sint3korr(b2);
618  if (j1 < j2)
619  return -1;
620  if (j1 > j2)
621  return +1;
622  return 0;
623 }
624 
625 // not yet
626 
627 int
628 NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
629 {
630  assert(info != 0);
631  const uint lb = 2;
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);
640  return k;
641 }
642 
643 int
644 NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
645 {
646  assert(info == 0);
647  const uint lb = 2;
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);
654  return k;
655 }
656 
657 int
658 NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
659 {
660  assert(info == 0 && n1 == 1 && n2 == 1);
661  Uint8 v1, v2;
662  memcpy(&v1, p1, 1);
663  memcpy(&v2, p2, 1);
664  int w1 = (int)v1;
665  int w2 = (int)v2;
666  return w1 - w2;
667 }
668 
669 int
670 NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
671 {
672  assert(info == 0 && n1 == 4 && n2 == 4);
673  Uint32 v1, v2;
674  memcpy(&v1, p1, 4);
675  memcpy(&v2, p2, 4);
676  if (v1 < v2)
677  return -1;
678  if (v1 > v2)
679  return +1;
680  return 0;
681 }
682 
683 // like
684 
685 static const int ndb_wild_prefix = '\\';
686 static const int ndb_wild_one = '_';
687 static const int ndb_wild_many = '%';
688 
689 int
690 NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
691 {
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;
699 }
700 
701 int
702 NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
703 {
704  assert(info == 0);
705  return likeChar(&my_charset_bin, p1, n1, p2, n2);
706 }
707 
708 int
709 NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
710 {
711  const unsigned lb = 1;
712  if (n1 >= lb) {
713  const uchar* v1 = (const uchar*)p1;
714  const uchar* v2 = (const uchar*)p2;
715  unsigned m1 = *v1;
716  unsigned m2 = n2;
717  if (lb + m1 <= n1) {
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;
723  }
724  }
725  return -1;
726 }
727 
728 int
729 NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
730 {
731  assert(info == 0);
732  return likeVarchar(&my_charset_bin, p1, n1, p2, n2);
733 }
734 
735 int
736 NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
737 {
738  const unsigned lb = 2;
739  if (n1 >= lb) {
740  const uchar* v1 = (const uchar*)p1;
741  const uchar* v2 = (const uchar*)p2;
742  unsigned m1 = uint2korr(v1);
743  unsigned m2 = n2;
744  if (lb + m1 <= n1) {
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;
750  }
751  }
752  return -1;
753 }
754 
755 int
756 NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
757 {
758  assert(info == 0);
759  return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2);
760 }
761 
762 
763 // mask Functions
764 
765 int
766 NdbSqlUtil::maskBit(const void* data, unsigned dataLen, const void* mask, unsigned maskLen, bool cmpZero)
767 {
768  /* Bitfields are stored in word oriented form, so we must compare them in that
769  * style as well
770  * It is assumed that insignificant bits (but not bytes) in the passed values
771  * are zeroed
772  */
773  const Uint32 bytes = MIN(dataLen, maskLen);
774  Uint32 words = (bytes + 3) >> 2;
775 
776  /* Don't expect either value to be length zero */
777  assert(words);
778 
779  /* Check ptr alignment */
780  if (unlikely(((((UintPtr)data) & 3) != 0) ||
781  ((((UintPtr)mask) & 3) != 0)))
782  {
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);
787 
788  return maskBit(data, bytes, mask, bytes, cmpZero);
789  }
790 
791  const Uint32* wdata= (const Uint32*) data;
792  const Uint32* wmask= (const Uint32*) mask;
793 
794  if (cmpZero)
795  {
796  while (--words)
797  {
798  if ((*(wdata++) & *(wmask++)) != 0)
799  return 1;
800  }
801 
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 :
806  ~0;
807  const Uint32 lastDataWord= *wdata & comparisonMask;
808  const Uint32 lastMaskWord= *wmask & comparisonMask;
809 
810  if ((lastDataWord & lastMaskWord) != 0)
811  return 1;
812 
813  return 0;
814  }
815  else
816  {
817  while (--words)
818  {
819  if ((*(wdata++) & *wmask) != *wmask)
820  return 1;
821 
822  wmask++;
823  }
824 
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 :
829  ~0;
830  const Uint32 lastDataWord= *wdata & comparisonMask;
831  const Uint32 lastMaskWord= *wmask & comparisonMask;
832 
833  if ((lastDataWord & lastMaskWord) != lastMaskWord)
834  return 1;
835 
836  return 0;
837  }
838 }
839 
840 
841 // check charset
842 
843 uint
844 NdbSqlUtil::check_column_for_pk(Uint32 typeId, const void* info)
845 {
846  const Type& type = getType(typeId);
847  switch (type.m_typeId) {
848  case Type::Char:
849  case Type::Varchar:
850  case Type::Longvarchar:
851  {
852  const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
853  if(cs != 0 &&
854  cs->cset != 0 &&
855  cs->coll != 0 &&
856  cs->coll->strnxfrm != 0 &&
857  cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
858  return 0;
859  else
860  return 743;
861  }
862  break;
863  case Type::Undefined:
864  case Type::Blob:
865  case Type::Text:
866  case Type::Bit:
867  break;
868  default:
869  return 0;
870  }
871  return 906;
872 }
873 
874 uint
875 NdbSqlUtil::check_column_for_hash_index(Uint32 typeId, const void* info)
876 {
877  return check_column_for_pk(typeId, info);
878 }
879 
880 uint
881 NdbSqlUtil::check_column_for_ordered_index(Uint32 typeId, const void* info)
882 {
883  const Type& type = getType(typeId);
884  if (type.m_cmp == NULL)
885  return false;
886  switch (type.m_typeId) {
887  case Type::Char:
888  case Type::Varchar:
889  case Type::Longvarchar:
890  {
891  const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
892  if (cs != 0 &&
893  cs->cset != 0 &&
894  cs->coll != 0 &&
895  cs->coll->strnxfrm != 0 &&
896  cs->coll->strnncollsp != 0 &&
897  cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY)
898  return 0;
899  else
900  return 743;
901  }
902  break;
903  case Type::Undefined:
904  case Type::Blob:
905  case Type::Text:
906  case Type::Bit: // can be fixed
907  break;
908  default:
909  return 0;
910  }
911  return 906;
912 }
913 
914 // utilities
915 
916 bool
917 NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len)
918 {
919  const unsigned char* const src = (const unsigned char*)p;
920  switch (typeId) {
921  case NdbSqlUtil::Type::Varchar:
922  case NdbSqlUtil::Type::Varbinary:
923  lb = 1;
924  if (attrlen >= lb) {
925  len = src[0];
926  if (attrlen >= lb + len)
927  return true;
928  }
929  break;
930  case NdbSqlUtil::Type::Longvarchar:
931  case NdbSqlUtil::Type::Longvarbinary:
932  lb = 2;
933  if (attrlen >= lb) {
934  len = src[0] + (src[1] << 8);
935  if (attrlen >= lb + len)
936  return true;
937  }
938  break;
939  default:
940  lb = 0;
941  len = attrlen;
942  return true;
943  break;
944  }
945  return false;
946 }
947 
948 
949 size_t
951  uchar *dst, size_t dstlen,
952  const uchar *src, size_t srclen)
953 {
954 #if NDB_MYSQL_VERSION_D < NDB_MAKE_VERSION(5,6,0)
955  return (*cs->coll->strnxfrm)(cs, dst, dstlen, src, srclen);
956 #else
957  /*
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
960  existing params
961  */
962  return (*cs->coll->strnxfrm)(cs, dst, dstlen, dstlen,
963  src, srclen, MY_STRXFRM_PAD_WITH_SPACE);
964 #endif
965 }
966 
967 // workaround
968 
969 int
970 NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen)
971 {
972  unsigned char nsp[20]; // native space char
973  unsigned char xsp[20]; // strxfrm-ed space char
974 #ifdef VM_TRACE
975  memset(nsp, 0x1f, sizeof(nsp));
976  memset(xsp, 0x1f, sizeof(xsp));
977 #endif
978  // convert from unicode codepoint for space
979  int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp));
980  if (n1 <= 0)
981  return -1;
982  // strxfrm to binary
983  int n2 = ndb_strnxfrm(cs, xsp, sizeof(xsp), nsp, n1);
984  if (n2 <= 0)
985  return -1;
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
991  int n4 = n3;
992  while (n4 < (int)dstLen) {
993  dst[n4] = xsp[(n4 - n3) % n2];
994  n4++;
995  }
996  // no check for partial last
997  return dstLen;
998 }
999 
1000 #if defined(WORDS_BIGENDIAN) || defined (VM_TRACE)
1001 
1002 static
1003 void determineParams(Uint32 typeId,
1004  Uint32 typeLog2Size,
1005  Uint32 arrayType,
1006  Uint32 arraySize,
1007  Uint32 dataByteSize,
1008  Uint32& convSize,
1009  Uint32& convLen)
1010 {
1011  /* Some types need 'normal behaviour' over-ridden in
1012  * terms of endian-ness conversions
1013  */
1014  convSize = 0;
1015  convLen = 0;
1016  switch(typeId)
1017  {
1018  case NdbSqlUtil::Type::Datetime:
1019  {
1020  // Datetime is stored as 8x8, should be twiddled as 64 bit
1021  assert(typeLog2Size == 3);
1022  assert(arraySize == 8);
1023  assert(dataByteSize == 8);
1024  convSize = 64;
1025  convLen = 1;
1026  break;
1027  }
1028  case NdbSqlUtil::Type::Timestamp:
1029  {
1030  // Timestamp is stored as 4x8, should be twiddled as 32 bit
1031  assert(typeLog2Size == 3);
1032  assert(arraySize == 4);
1033  assert(dataByteSize == 4);
1034  convSize = 32;
1035  convLen = 1;
1036  break;
1037  }
1038  case NdbSqlUtil::Type::Bit:
1039  {
1040  // Bit is stored as bits, should be twiddled as 32 bit
1041  assert(typeLog2Size == 0);
1042  convSize = 32;
1043  convLen = (arraySize + 31)/32;
1044  break;
1045  }
1046  case NdbSqlUtil::Type::Blob:
1047  case NdbSqlUtil::Type::Text:
1048  {
1049  if (arrayType == NDB_ARRAYTYPE_FIXED)
1050  {
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);
1056  convSize = 64;
1057  convLen = 1;
1058  break;
1059  }
1060  // Fall through for Blob v2
1061  }
1062  default:
1063  /* Default determined by meta-info */
1064  convSize = 1 << typeLog2Size;
1065  convLen = arraySize;
1066  break;
1067  }
1068 
1069  const Uint32 unitBytes = (convSize >> 3);
1070 
1071  if (dataByteSize < (unitBytes * convLen))
1072  {
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
1077  */
1078  assert((dataByteSize % unitBytes) == 0);
1079  convLen = dataByteSize / unitBytes;
1080  }
1081 
1082  assert(convSize);
1083  assert(convLen);
1084  assert(dataByteSize >= (unitBytes * convLen));
1085 }
1086 
1087 static
1088 void doConvert(Uint32 convSize,
1089  Uint32 convLen,
1090  uchar* data)
1091 {
1092  switch(convSize)
1093  {
1094  case 8:
1095  /* Nothing to swap */
1096  break;
1097  case 16:
1098  {
1099  Uint16* ptr = (Uint16*)data;
1100  for (Uint32 i = 0; i < convLen; i++){
1101  Uint16 val =
1102  ((*ptr & 0xFF00) >> 8) |
1103  ((*ptr & 0x00FF) << 8);
1104  *ptr = val;
1105  ptr++;
1106  }
1107  break;
1108  }
1109  case 32:
1110  {
1111  Uint32* ptr = (Uint32*)data;
1112  for (Uint32 i = 0; i < convLen; i++){
1113  Uint32 val =
1114  ((*ptr & 0xFF000000) >> 24) |
1115  ((*ptr & 0x00FF0000) >> 8) |
1116  ((*ptr & 0x0000FF00) << 8) |
1117  ((*ptr & 0x000000FF) << 24);
1118  *ptr = val;
1119  ptr++;
1120  }
1121  break;
1122  }
1123  case 64:
1124  {
1125  Uint64* ptr = (Uint64*)data;
1126  for (Uint32 i = 0; i < convLen; i++){
1127  Uint64 val =
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);
1136  *ptr = val;
1137  ptr++;
1138  }
1139  break;
1140  }
1141  default:
1142  abort();
1143  break;
1144  }
1145 }
1146 #endif
1147 
1151 void
1153  Uint32 typeLog2Size,
1154  Uint32 arrayType,
1155  Uint32 arraySize,
1156  uchar* data,
1157  Uint32 dataByteSize)
1158 {
1159 #if defined(WORDS_BIGENDIAN) || defined (VM_TRACE)
1160  Uint32 convSize;
1161  Uint32 convLen;
1162  determineParams(typeId,
1163  typeLog2Size,
1164  arrayType,
1165  arraySize,
1166  dataByteSize,
1167  convSize,
1168  convLen);
1169 
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];
1175 
1176  if (!aligned)
1177  {
1178  assert(dataByteSize <= 4 * MAX_TUPLE_SIZE_IN_WORDS);
1179  memcpy(alignedBuf, data, dataByteSize);
1180  dataPtr = (uchar*) alignedBuf;
1181  }
1182 
1183  /* Now have convSize and convLen, do the conversion */
1184  doConvert(convSize,
1185  convLen,
1186  dataPtr);
1187 
1188 #ifdef VM_TRACE
1189 #ifndef WORDS_BIGENDIAN
1190  // VM trace on little-endian performs double-convert
1191  doConvert(convSize,
1192  convLen,
1193  dataPtr);
1194 #endif
1195 #endif
1196 
1197  if (!aligned)
1198  {
1199  memcpy(data, alignedBuf, dataByteSize);
1200  }
1201 #endif
1202 }
1203