NdbSqlUtil.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:19k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include <NdbSqlUtil.hpp>
  14. int
  15. NdbSqlUtil::char_compare(const char* s1, unsigned n1,
  16.                          const char* s2, unsigned n2, bool padded)
  17. {
  18.   int c1 = 0;
  19.   int c2 = 0;
  20.   unsigned i = 0;
  21.   while (i < n1 || i < n2) {
  22.     c1 = i < n1 ? s1[i] : padded ? 0x20 : 0;
  23.     c2 = i < n2 ? s2[i] : padded ? 0x20 : 0;
  24.     if (c1 != c2)
  25.       break;
  26.     i++;
  27.   }
  28.   return c1 - c2;
  29. }
  30. bool
  31. NdbSqlUtil::char_like(const char* s1, unsigned n1,
  32.                       const char* s2, unsigned n2, bool padded)
  33. {
  34.   int c1 = 0;
  35.   int c2 = 0;
  36.   unsigned i1 = 0;
  37.   unsigned i2 = 0;
  38.   while (i1 < n1 || i2 < n2) {
  39.     c1 = i1 < n1 ? s1[i1] : padded ? 0x20 : 0;
  40.     c2 = i2 < n2 ? s2[i2] : padded ? 0x20 : 0;
  41.     if (c2 == '%') {
  42.       while (i2 + 1 < n2 && s2[i2 + 1] == '%') {
  43.         i2++;
  44.       }
  45.       unsigned m = 0;
  46.       while (m <= n1 - i1) {
  47.         if (char_like(s1 + i1 + m, n1 -i1 - m,
  48.                       s2 + i2 + 1, n2 - i2 - 1, padded))
  49.         return true;
  50.         m++;
  51.       }
  52.       return false;
  53.     }
  54.     if (c2 == '_') {
  55.       if (c1 == 0)
  56.         return false;
  57.     } else {
  58.       if (c1 != c2)
  59.         return false;
  60.     }
  61.     i1++;
  62.     i2++;
  63.   }
  64.   return i1 == n2 && i2 == n2;
  65. }
  66. /**
  67.  * Data types.
  68.  */
  69. const NdbSqlUtil::Type
  70. NdbSqlUtil::m_typeList[] = {
  71.   { // 0
  72.     Type::Undefined,
  73.     NULL
  74.   },
  75.   { // 1
  76.     Type::Tinyint,
  77.     cmpTinyint
  78.   },
  79.   { // 2
  80.     Type::Tinyunsigned,
  81.     cmpTinyunsigned
  82.   },
  83.   { // 3
  84.     Type::Smallint,
  85.     cmpSmallint
  86.   },
  87.   { // 4
  88.     Type::Smallunsigned,
  89.     cmpSmallunsigned
  90.   },
  91.   { // 5
  92.     Type::Mediumint,
  93.     cmpMediumint
  94.   },
  95.   { // 6
  96.     Type::Mediumunsigned,
  97.     cmpMediumunsigned
  98.   },
  99.   { // 7
  100.     Type::Int,
  101.     cmpInt
  102.   },
  103.   { // 8
  104.     Type::Unsigned,
  105.     cmpUnsigned
  106.   },
  107.   { // 9
  108.     Type::Bigint,
  109.     cmpBigint
  110.   },
  111.   { // 10
  112.     Type::Bigunsigned,
  113.     cmpBigunsigned
  114.   },
  115.   { // 11
  116.     Type::Float,
  117.     cmpFloat
  118.   },
  119.   { // 12
  120.     Type::Double,
  121.     cmpDouble
  122.   },
  123.   { // 13
  124.     Type::Olddecimal,
  125.     cmpOlddecimal
  126.   },
  127.   { // 14
  128.     Type::Char,
  129.     cmpChar
  130.   },
  131.   { // 15
  132.     Type::Varchar,
  133.     cmpVarchar
  134.   },
  135.   { // 16
  136.     Type::Binary,
  137.     cmpBinary
  138.   },
  139.   { // 17
  140.     Type::Varbinary,
  141.     cmpVarbinary
  142.   },
  143.   { // 18
  144.     Type::Datetime,
  145.     cmpDatetime
  146.   },
  147.   { // 19
  148.     Type::Date,
  149.     cmpDate
  150.   },
  151.   { // 20
  152.     Type::Blob,
  153.     cmpBlob
  154.   },
  155.   { // 21
  156.     Type::Text,
  157.     cmpText
  158.   },
  159.   { // 22
  160.     Type::Undefined,    // 5.0 Bit
  161.     NULL
  162.   },
  163.   { // 23
  164.     Type::Undefined,    // 5.0 Longvarchar
  165.     NULL
  166.   },
  167.   { // 24
  168.     Type::Undefined,    // 5.0 Longvarbinary
  169.     NULL
  170.   },
  171.   { // 25
  172.     Type::Time,
  173.     cmpTime
  174.   },
  175.   { // 26
  176.     Type::Year,
  177.     cmpYear
  178.   },
  179.   { // 27
  180.     Type::Timestamp,
  181.     cmpTimestamp
  182.   },
  183.   { // 28
  184.     Type::Olddecimalunsigned,
  185.     cmpOlddecimalunsigned
  186.   }
  187. };
  188. const NdbSqlUtil::Type&
  189. NdbSqlUtil::getType(Uint32 typeId)
  190. {
  191.   if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) &&
  192.       m_typeList[typeId].m_typeId != Type::Undefined) {
  193.     return m_typeList[typeId];
  194.   }
  195.   return m_typeList[Type::Undefined];
  196. }
  197. const NdbSqlUtil::Type&
  198. NdbSqlUtil::getTypeBinary(Uint32 typeId)
  199. {
  200.   switch (typeId) {
  201.   case Type::Char:
  202.     typeId = Type::Binary;
  203.     break;
  204.   case Type::Varchar:
  205.     typeId = Type::Varbinary; 
  206.     break;
  207.   case Type::Text:
  208.     typeId = Type::Blob;
  209.     break;
  210.   default:
  211.     break;
  212.   }
  213.   return getType(typeId);
  214. }
  215. // compare
  216. int
  217. NdbSqlUtil::cmpTinyint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  218. {
  219.   assert(full >= size && size > 0);
  220.   union { Uint32 p[1]; Int8 v; } u1, u2;
  221.   u1.p[0] = p1[0];
  222.   u2.p[0] = p2[0];
  223.   if (u1.v < u2.v)
  224.     return -1;
  225.   if (u1.v > u2.v)
  226.     return +1;
  227.   return 0;
  228. }
  229. int
  230. NdbSqlUtil::cmpTinyunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  231. {
  232.   assert(full >= size && size > 0);
  233.   union { Uint32 p[1]; Uint8 v; } u1, u2;
  234.   u1.p[0] = p1[0];
  235.   u2.p[0] = p2[0];
  236.   if (u1.v < u2.v)
  237.     return -1;
  238.   if (u1.v > u2.v)
  239.     return +1;
  240.   return 0;
  241. }
  242. int
  243. NdbSqlUtil::cmpSmallint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  244. {
  245.   assert(full >= size && size > 0);
  246.   union { Uint32 p[1]; Int16 v; } u1, u2;
  247.   u1.p[0] = p1[0];
  248.   u2.p[0] = p2[0];
  249.   if (u1.v < u2.v)
  250.     return -1;
  251.   if (u1.v > u2.v)
  252.     return +1;
  253.   return 0;
  254. }
  255. int
  256. NdbSqlUtil::cmpSmallunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  257. {
  258.   assert(full >= size && size > 0);
  259.   union { Uint32 p[1]; Uint16 v; } u1, u2;
  260.   u1.p[0] = p1[0];
  261.   u2.p[0] = p2[0];
  262.   if (u1.v < u2.v)
  263.     return -1;
  264.   if (u1.v > u2.v)
  265.     return +1;
  266.   return 0;
  267. }
  268. int
  269. NdbSqlUtil::cmpMediumint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  270. {
  271.   assert(full >= size && size > 0);
  272.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  273.   u1.p = p1;
  274.   u2.p = p2;
  275.   Int32 v1 = sint3korr(u1.v);
  276.   Int32 v2 = sint3korr(u2.v);
  277.   if (v1 < v2)
  278.     return -1;
  279.   if (v1 > v2)
  280.     return +1;
  281.   return 0;
  282. }
  283. int
  284. NdbSqlUtil::cmpMediumunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  285. {
  286.   assert(full >= size && size > 0);
  287.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  288.   u1.p = p1;
  289.   u2.p = p2;
  290.   Uint32 v1 = uint3korr(u1.v);
  291.   Uint32 v2 = uint3korr(u2.v);
  292.   if (v1 < v2)
  293.     return -1;
  294.   if (v1 > v2)
  295.     return +1;
  296.   return 0;
  297. }
  298. int
  299. NdbSqlUtil::cmpInt(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  300. {
  301.   assert(full >= size && size > 0);
  302.   union { Uint32 p[1]; Int32 v; } u1, u2;
  303.   u1.p[0] = p1[0];
  304.   u2.p[0] = p2[0];
  305.   if (u1.v < u2.v)
  306.     return -1;
  307.   if (u1.v > u2.v)
  308.     return +1;
  309.   return 0;
  310. }
  311. int
  312. NdbSqlUtil::cmpUnsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  313. {
  314.   assert(full >= size && size > 0);
  315.   union { Uint32 p[1]; Uint32 v; } u1, u2;
  316.   u1.v = p1[0];
  317.   u2.v = p2[0];
  318.   if (u1.v < u2.v)
  319.     return -1;
  320.   if (u1.v > u2.v)
  321.     return +1;
  322.   return 0;
  323. }
  324. int
  325. NdbSqlUtil::cmpBigint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  326. {
  327.   assert(full >= size && size > 0);
  328.   if (size >= 2) {
  329.     union { Uint32 p[2]; Int64 v; } u1, u2;
  330.     u1.p[0] = p1[0];
  331.     u1.p[1] = p1[1];
  332.     u2.p[0] = p2[0];
  333.     u2.p[1] = p2[1];
  334.     if (u1.v < u2.v)
  335.       return -1;
  336.     if (u1.v > u2.v)
  337.       return +1;
  338.     return 0;
  339.   }
  340.   return CmpUnknown;
  341. }
  342. int
  343. NdbSqlUtil::cmpBigunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  344. {
  345.   assert(full >= size && size > 0);
  346.   if (size >= 2) {
  347.     union { Uint32 p[2]; Uint64 v; } u1, u2;
  348.     u1.p[0] = p1[0];
  349.     u1.p[1] = p1[1];
  350.     u2.p[0] = p2[0];
  351.     u2.p[1] = p2[1];
  352.     if (u1.v < u2.v)
  353.       return -1;
  354.     if (u1.v > u2.v)
  355.       return +1;
  356.     return 0;
  357.   }
  358.   return CmpUnknown;
  359. }
  360. int
  361. NdbSqlUtil::cmpFloat(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  362. {
  363.   assert(full >= size && size > 0);
  364.   union { Uint32 p[1]; float v; } u1, u2;
  365.   u1.p[0] = p1[0];
  366.   u2.p[0] = p2[0];
  367.   // no format check
  368.   if (u1.v < u2.v)
  369.     return -1;
  370.   if (u1.v > u2.v)
  371.     return +1;
  372.   return 0;
  373. }
  374. int
  375. NdbSqlUtil::cmpDouble(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  376. {
  377.   assert(full >= size && size > 0);
  378.   if (size >= 2) {
  379.     union { Uint32 p[2]; double v; } u1, u2;
  380.     u1.p[0] = p1[0];
  381.     u1.p[1] = p1[1];
  382.     u2.p[0] = p2[0];
  383.     u2.p[1] = p2[1];
  384.     // no format check
  385.     if (u1.v < u2.v)
  386.       return -1;
  387.     if (u1.v > u2.v)
  388.       return +1;
  389.     return 0;
  390.   }
  391.   return CmpUnknown;
  392. }
  393. int
  394. NdbSqlUtil::cmp_olddecimal(const uchar* s1, const uchar* s2, unsigned n)
  395. {
  396.   int sgn = +1;
  397.   unsigned i = 0;
  398.   while (i < n) {
  399.     int c1 = s1[i];
  400.     int c2 = s2[i];
  401.     if (c1 == c2) {
  402.       if (c1 == '-')
  403.         sgn = -1;
  404.     } else if (c1 == '-') {
  405.       return -1;
  406.     } else if (c2 == '-') {
  407.       return +1;
  408.     } else if (c1 < c2) {
  409.       return -1 * sgn;
  410.     } else {
  411.       return +1 * sgn;
  412.     }
  413.     i++;
  414.   }
  415.   return 0;
  416. }
  417. int
  418. NdbSqlUtil::cmpOlddecimal(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  419. {
  420.   assert(full >= size && size > 0);
  421.   if (full == size) {
  422.     union { const Uint32* p; const uchar* v; } u1, u2;
  423.     u1.p = p1;
  424.     u2.p = p2;
  425.     return cmp_olddecimal(u1.v, u2.v, full << 2);
  426.   }
  427.   return CmpUnknown;
  428. }
  429. int
  430. NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  431. {
  432.   assert(full >= size && size > 0);
  433.   if (full == size) {
  434.     union { const Uint32* p; const uchar* v; } u1, u2;
  435.     u1.p = p1;
  436.     u2.p = p2;
  437.     return cmp_olddecimal(u1.v, u2.v, full << 2);
  438.   }
  439.   return CmpUnknown;
  440. }
  441. int
  442. NdbSqlUtil::cmpChar(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  443. {
  444.   // collation does not work on prefix for some charsets
  445.   assert(full == size && size > 0);
  446.   /*
  447.    * Char is blank-padded to length and null-padded to word size.
  448.    */
  449.   union { const Uint32* p; const uchar* v; } u1, u2;
  450.   u1.p = p1;
  451.   u2.p = p2;
  452.   // not const in MySQL
  453.   CHARSET_INFO* cs = (CHARSET_INFO*)(info);
  454.   // length in bytes including null padding to Uint32
  455.   uint l1 = (full << 2);
  456.   int k = (*cs->coll->strnncollsp)(cs, u1.v, l1, u2.v, l1);
  457.   return k < 0 ? -1 : k > 0 ? +1 : 0;
  458. }
  459. int
  460. NdbSqlUtil::cmpVarchar(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  461. {
  462.   assert(full >= size && size > 0);
  463.   /*
  464.    * Varchar is not allowed to contain a null byte and the value is
  465.    * null-padded.  Therefore comparison does not need to use the length.
  466.    *
  467.    * Not used before MySQL 5.0.  Format is likely to change.  Handle
  468.    * only binary collation for now.
  469.    */
  470.   union { const Uint32* p; const char* v; } u1, u2;
  471.   u1.p = p1;
  472.   u2.p = p2;
  473.   // skip length in first 2 bytes
  474.   int k = strncmp(u1.v + 2, u2.v + 2, (size << 2) - 2);
  475.   return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
  476. }
  477. int
  478. NdbSqlUtil::cmpBinary(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  479. {
  480.   assert(full >= size && size > 0);
  481.   /*
  482.    * Binary data of full length.  Compare bytewise.
  483.    */
  484.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  485.   u1.p = p1;
  486.   u2.p = p2;
  487.   int k = memcmp(u1.v, u2.v, size << 2);
  488.   return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
  489. }
  490. int
  491. NdbSqlUtil::cmpVarbinary(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  492. {
  493.   assert(full >= size && size > 0);
  494.   /*
  495.    * Binary data of variable length padded with nulls.  The comparison
  496.    * does not need to use the length.
  497.    *
  498.    * Not used before MySQL 5.0.  Format is likely to change.
  499.    */
  500.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  501.   u1.p = p1;
  502.   u2.p = p2;
  503.   // skip length in first 2 bytes
  504.   int k = memcmp(u1.v + 2, u2.v + 2, (size << 2) - 2);
  505.   return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
  506. }
  507. int
  508. NdbSqlUtil::cmpDatetime(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  509. {
  510.   assert(full >= size && size > 0);
  511.   if (size >= 2) {
  512.     union { Uint32 p[2]; Int64 v; } u1, u2;
  513.     u1.p[0] = p1[0];
  514.     u1.p[1] = p1[1];
  515.     u2.p[0] = p2[0];
  516.     u2.p[1] = p2[1];
  517.     if (u1.v < u2.v)
  518.       return -1;
  519.     if (u1.v > u2.v)
  520.       return +1;
  521.     return 0;
  522.   }
  523.   return CmpUnknown;
  524. }
  525. int
  526. NdbSqlUtil::cmpDate(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  527. {
  528. #ifdef ndb_date_is_4_byte_native_int
  529.   assert(full >= size && size > 0);
  530.   union { Uint32 p[2]; Int32 v; } u1, u2;
  531.   u1.p[0] = p1[0];
  532.   u2.p[0] = p2[0];
  533.   if (u1.v < u2.v)
  534.     return -1;
  535.   if (u1.v > u2.v)
  536.     return +1;
  537.   return 0;
  538. #else
  539.   assert(full >= size && size > 0);
  540.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  541.   u1.p = p1;
  542.   u2.p = p2;
  543. #ifdef ndb_date_sol9x86_cc_xO3_madness
  544.   // from Field_newdate::val_int
  545.   Uint64 j1 = uint3korr(u1.v);
  546.   Uint64 j2 = uint3korr(u2.v);
  547.   j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L;
  548.   j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L;
  549.   if (j1 < j2)
  550.     return -1;
  551.   if (j1 > j2)
  552.     return +1;
  553.   return 0;
  554. #else
  555.   uint j1 = uint3korr(u1.v);
  556.   uint j2 = uint3korr(u2.v);
  557.   uint d1 = (j1 & 31);
  558.   uint d2 = (j2 & 31);
  559.   j1 = (j1 >> 5);
  560.   j2 = (j2 >> 5);
  561.   uint m1 = (j1 & 15);
  562.   uint m2 = (j2 & 15);
  563.   j1 = (j1 >> 4);
  564.   j2 = (j2 >> 4);
  565.   uint y1 = j1;
  566.   uint y2 = j2;
  567.   if (y1 < y2)
  568.     return -1;
  569.   if (y1 > y2)
  570.     return +1;
  571.   if (m1 < m2)
  572.     return -1;
  573.   if (m1 > m2)
  574.     return +1;
  575.   if (d1 < d2)
  576.     return -1;
  577.   if (d1 > d2)
  578.     return +1;
  579.   return 0;
  580. #endif
  581. #endif
  582. }
  583. int
  584. NdbSqlUtil::cmpBlob(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  585. {
  586.   assert(full >= size && size > 0);
  587.   /*
  588.    * Blob comparison is on the inline bytes (null padded).
  589.    */
  590.   const unsigned head = NDB_BLOB_HEAD_SIZE;
  591.   // skip blob head
  592.   if (size >= head + 1) {
  593.     union { const Uint32* p; const unsigned char* v; } u1, u2;
  594.     u1.p = p1 + head;
  595.     u2.p = p2 + head;
  596.     int k = memcmp(u1.v, u2.v, (size - head) << 2);
  597.     return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
  598.   }
  599.   return CmpUnknown;
  600. }
  601. int
  602. NdbSqlUtil::cmpText(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  603. {
  604.   // collation does not work on prefix for some charsets
  605.   assert(full == size && size > 0);
  606.   /*
  607.    * Text comparison is on the inline bytes (blank padded).  Currently
  608.    * not supported for multi-byte charsets.
  609.    */
  610.   const unsigned head = NDB_BLOB_HEAD_SIZE;
  611.   // skip blob head
  612.   if (size >= head + 1) {
  613.     union { const Uint32* p; const uchar* v; } u1, u2;
  614.     u1.p = p1 + head;
  615.     u2.p = p2 + head;
  616.     // not const in MySQL
  617.     CHARSET_INFO* cs = (CHARSET_INFO*)(info);
  618.     // length in bytes including null padding to Uint32
  619.     uint l1 = (full << 2);
  620.     int k = (*cs->coll->strnncollsp)(cs, u1.v, l1, u2.v, l1);
  621.     return k < 0 ? -1 : k > 0 ? +1 : 0;
  622.   }
  623.   return CmpUnknown;
  624. }
  625. int
  626. NdbSqlUtil::cmpTime(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  627. {
  628.   assert(full >= size && size > 0);
  629.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  630.   u1.p = p1;
  631.   u2.p = p2;
  632.   // from Field_time::val_int
  633.   Int32 j1 = sint3korr(u1.v);
  634.   Int32 j2 = sint3korr(u2.v);
  635.   if (j1 < j2)
  636.     return -1;
  637.   if (j1 > j2)
  638.     return +1;
  639.   return 0;
  640. }
  641. int
  642. NdbSqlUtil::cmpYear(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  643. {
  644.   assert(full >= size && size > 0);
  645.   union { const Uint32* p; const unsigned char* v; } u1, u2;
  646.   u1.p = p1;
  647.   u2.p = p2;
  648.   if (u1.v[0] < u2.v[0])
  649.     return -1;
  650.   if (u1.v[0] > u2.v[0])
  651.     return +1;
  652.   return 0;
  653. }
  654. int
  655. NdbSqlUtil::cmpTimestamp(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
  656. {
  657.   assert(full >= size && size > 0);
  658.   union { Uint32 p[1]; Uint32 v; } u1, u2;
  659.   u1.v = p1[0];
  660.   u2.v = p2[0];
  661.   if (u1.v < u2.v)
  662.     return -1;
  663.   if (u1.v > u2.v)
  664.     return +1;
  665.   return 0;
  666. }
  667. // check charset
  668. bool
  669. NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info)
  670. {
  671.   const Type& type = getType(typeId);
  672.   switch (type.m_typeId) {
  673.   case Type::Undefined:
  674.     break;
  675.   case Type::Char:
  676.     {
  677.       const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
  678.       return
  679.         cs != 0 &&
  680.         cs->cset != 0 &&
  681.         cs->coll != 0 &&
  682.         cs->coll->strnxfrm != 0 &&
  683.         cs->strxfrm_multiply <= 1; // current limitation
  684.     }
  685.     break;
  686.   case Type::Varchar:
  687.     return true; // Varchar not used via MySQL
  688.   case Type::Blob:
  689.   case Type::Text:
  690.     break;
  691.   default:
  692.     return true;
  693.   }
  694.   return false;
  695. }
  696. bool
  697. NdbSqlUtil::usable_in_hash_index(Uint32 typeId, const void* info)
  698. {
  699.   return usable_in_pk(typeId, info);
  700. }
  701. bool
  702. NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info)
  703. {
  704.   const Type& type = getType(typeId);
  705.   switch (type.m_typeId) {
  706.   case Type::Undefined:
  707.     break;
  708.   case Type::Char:
  709.     {
  710.       const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
  711.       return
  712.         cs != 0 &&
  713.         cs->cset != 0 &&
  714.         cs->coll != 0 &&
  715.         cs->coll->strnxfrm != 0 &&
  716.         cs->coll->strnncollsp != 0 &&
  717.         cs->strxfrm_multiply <= 1; // current limitation
  718.     }
  719.     break;
  720.   case Type::Varchar:
  721.     return true; // Varchar not used via MySQL
  722.   case Type::Text:
  723.     {
  724.       const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
  725.       return
  726.         cs != 0 &&
  727.         cs->mbmaxlen == 1 && // extra limitation
  728.         cs->cset != 0 &&
  729.         cs->coll != 0 &&
  730.         cs->coll->strnxfrm != 0 &&
  731.         cs->coll->strnncollsp != 0 &&
  732.         cs->strxfrm_multiply <= 1; // current limitation
  733.     }
  734.     break;
  735.   default:
  736.     return true;
  737.   }
  738.   return false;
  739. }
  740. #ifdef NDB_SQL_UTIL_TEST
  741. #include <NdbTick.h>
  742. #include <NdbOut.hpp>
  743. struct Testcase {
  744.   int op;       // 1=compare 2=like
  745.   int res;
  746.   const char* s1;
  747.   const char* s2;
  748.   int pad;
  749. };
  750. const Testcase testcase[] = {
  751.   { 2, 1, "abc", "abc", 0 },
  752.   { 2, 1, "abc", "abc%", 0 },
  753.   { 2, 1, "abcdef", "abc%", 0 },
  754.   { 2, 1, "abcdefabcdefabcdef", "abc%", 0 },
  755.   { 2, 1, "abcdefabcdefabcdef", "abc%f", 0 },
  756.   { 2, 0, "abcdefabcdefabcdef", "abc%z", 0 },
  757.   { 2, 1, "abcdefabcdefabcdef", "%f", 0 },
  758.   { 2, 1, "abcdef", "a%b%c%d%e%f", 0 },
  759.   { 0, 0, 0, 0 }
  760. };
  761. int
  762. main(int argc, char** argv)
  763. {
  764.   ndb_init(); // for charsets
  765.   unsigned count = argc > 1 ? atoi(argv[1]) : 1000000;
  766.   ndbout_c("count = %u", count);
  767.   assert(count != 0);
  768.   for (const Testcase* t = testcase; t->s1 != 0; t++) {
  769.     ndbout_c("%d = '%s' %s '%s' pad=%d",
  770.         t->res, t->s1, t->op == 1 ? "comp" : "like", t->s2);
  771.     NDB_TICKS x1 = NdbTick_CurrentMillisecond();
  772.     unsigned n1 = strlen(t->s1);
  773.     unsigned n2 = strlen(t->s2);
  774.     for (unsigned i = 0; i < count; i++) {
  775.       if (t->op == 1) {
  776.         int res = NdbSqlUtil::char_compare(t->s1, n1, t->s2, n2, t->pad);
  777.         assert(res == t->res);
  778.         continue;
  779.       }
  780.       if (t->op == 2) {
  781.         int res = NdbSqlUtil::char_like(t->s1, n1, t->s2, n2, t->pad);
  782.         assert(res == t->res);
  783.         continue;
  784.       }
  785.       assert(false);
  786.     }
  787.     NDB_TICKS x2 = NdbTick_CurrentMillisecond();
  788.     if (x2 < x1)
  789.       x2 = x1;
  790.     double usec = 1000000.0 * double(x2 - x1) / double(count);
  791.     ndbout_c("time %.0f usec per call", usec);
  792.   }
  793.   // quick check
  794.   for (unsigned i = 0; i < sizeof(m_typeList) / sizeof(m_typeList[0]); i++) {
  795.     const NdbSqlUtil::Type& t = m_typeList[i];
  796.     assert(t.m_typeId == i);
  797.   }
  798.   return 0;
  799. }
  800. #endif