1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2012-2015 Kouhei Sutou <kou@clear-code.com>
4   Copyright(C) 2013 Kentoku SHIBA
5 
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10 
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
19 */
20 
21 #include <mrn_mysql.h>
22 
23 #include "mrn_multiple_column_key_codec.hpp"
24 #include "mrn_field_normalizer.hpp"
25 #include "mrn_smart_grn_obj.hpp"
26 #include "mrn_time_converter.hpp"
27 #include "mrn_value_decoder.hpp"
28 
29 // for debug
30 #define MRN_CLASS_NAME "mrn::MultipleColumnKeyCodec"
31 
32 #ifdef WORDS_BIGENDIAN
33 #define mrn_byte_order_host_to_network(buf, key, size)  \
34 {                                                       \
35   uint32 size_ = (uint32)(size);                        \
36   uint8 *buf_ = (uint8 *)(buf);                         \
37   uint8 *key_ = (uint8 *)(key);                         \
38   while (size_--) { *buf_++ = *key_++; }                \
39 }
40 #define mrn_byte_order_network_to_host(buf, key, size)  \
41 {                                                       \
42   uint32 size_ = (uint32)(size);                        \
43   uint8 *buf_ = (uint8 *)(buf);                         \
44   uint8 *key_ = (uint8 *)(key);                         \
45   while (size_) { *buf_++ = *key_++; size_--; }         \
46 }
47 #else /* WORDS_BIGENDIAN */
48 #define mrn_byte_order_host_to_network(buf, key, size)  \
49 {                                                       \
50   uint32 size_ = (uint32)(size);                        \
51   uint8 *buf_ = (uint8 *)(buf);                         \
52   uint8 *key_ = (uint8 *)(key) + size_;                 \
53   while (size_--) { *buf_++ = *(--key_); }              \
54 }
55 #define mrn_byte_order_network_to_host(buf, key, size)  \
56 {                                                       \
57   uint32 size_ = (uint32)(size);                        \
58   uint8 *buf_ = (uint8 *)(buf);                         \
59   uint8 *key_ = (uint8 *)(key) + size_;                 \
60   while (size_) { *buf_++ = *(--key_); size_--; }       \
61 }
62 #endif /* WORDS_BIGENDIAN */
63 
64 namespace mrn {
MultipleColumnKeyCodec(grn_ctx * ctx,THD * thread,KEY * key_info)65   MultipleColumnKeyCodec::MultipleColumnKeyCodec(grn_ctx *ctx,
66                                                  THD *thread,
67                                                  KEY *key_info)
68     : ctx_(ctx),
69       thread_(thread),
70       key_info_(key_info) {
71   }
72 
~MultipleColumnKeyCodec()73   MultipleColumnKeyCodec::~MultipleColumnKeyCodec() {
74   }
75 
encode(const uchar * mysql_key,uint mysql_key_length,uchar * grn_key,uint * grn_key_length)76   int MultipleColumnKeyCodec::encode(const uchar *mysql_key,
77                                      uint mysql_key_length,
78                                      uchar *grn_key,
79                                      uint *grn_key_length) {
80     MRN_DBUG_ENTER_METHOD();
81     int error = 0;
82     const uchar *current_mysql_key = mysql_key;
83     const uchar *mysql_key_end = mysql_key + mysql_key_length;
84     uchar *current_grn_key = grn_key;
85 
86     int n_key_parts = KEY_N_KEY_PARTS(key_info_);
87     DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
88     *grn_key_length = 0;
89     for (int i = 0; i < n_key_parts && current_mysql_key < mysql_key_end; i++) {
90       KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
91       Field *field = key_part->field;
92       bool is_null = false;
93       DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
94 
95       if (field->null_bit) {
96         DBUG_PRINT("info", ("mroonga: field has null bit"));
97         *current_grn_key = 0;
98         is_null = *current_mysql_key;
99         current_mysql_key += 1;
100         current_grn_key += 1;
101         (*grn_key_length)++;
102       }
103 
104       DataType data_type = TYPE_UNKNOWN;
105       uint data_size = 0;
106       get_key_info(key_part, &data_type, &data_size);
107       uint grn_key_data_size = data_size;
108 
109       switch (data_type) {
110       case TYPE_UNKNOWN:
111         // TODO: This will not be happen. This is just for
112         // suppressing warnings by gcc -O2. :<
113         error = HA_ERR_UNSUPPORTED;
114         break;
115       case TYPE_LONG_LONG_NUMBER:
116         {
117           long long int long_long_value = 0;
118           long_long_value = sint8korr(current_mysql_key);
119           encode_long_long_int(long_long_value, current_grn_key);
120         }
121         break;
122       case TYPE_NUMBER:
123         {
124           Field_num *number_field = static_cast<Field_num *>(field);
125           encode_number(current_mysql_key,
126                         data_size,
127                         !number_field->unsigned_flag,
128                         current_grn_key);
129         }
130         break;
131       case TYPE_FLOAT:
132         {
133           float value;
134           value_decoder::decode(&value, current_mysql_key);
135           encode_float(value, data_size, current_grn_key);
136         }
137         break;
138       case TYPE_DOUBLE:
139         {
140           double value;
141           value_decoder::decode(&value, current_mysql_key);
142           encode_double(value, data_size, current_grn_key);
143         }
144         break;
145       case TYPE_DATETIME:
146         {
147           long long int mysql_datetime;
148 #ifdef WORDS_BIGENDIAN
149           if (field->table && field->table->s->db_low_byte_first) {
150             mysql_datetime = sint8korr(current_mysql_key);
151           } else
152 #endif
153           {
154             value_decoder::decode(&mysql_datetime, current_mysql_key);
155           }
156           TimeConverter time_converter;
157           bool truncated;
158           long long int grn_time =
159             time_converter.mysql_datetime_to_grn_time(mysql_datetime,
160                                                       &truncated);
161           encode_long_long_int(grn_time, current_grn_key);
162         }
163         break;
164 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
165       case TYPE_DATETIME2:
166         {
167           Field_datetimef *datetimef_field =
168             static_cast<Field_datetimef *>(field);
169           long long int mysql_datetime_packed = is_null ? 0 :
170             my_datetime_packed_from_binary(current_mysql_key,
171                                            datetimef_field->decimals());
172           MYSQL_TIME mysql_time;
173           TIME_from_longlong_datetime_packed(&mysql_time, mysql_datetime_packed);
174           TimeConverter time_converter;
175           bool truncated;
176           long long int grn_time =
177             time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
178           grn_key_data_size = 8;
179           encode_long_long_int(grn_time, current_grn_key);
180         }
181         break;
182 #endif
183       case TYPE_BYTE_SEQUENCE:
184         memcpy(current_grn_key, current_mysql_key, data_size);
185         break;
186       case TYPE_BYTE_REVERSE:
187         encode_reverse(current_mysql_key, data_size, current_grn_key);
188         break;
189       case TYPE_BYTE_BLOB:
190         encode_blob(current_mysql_key, &data_size, field, current_grn_key);
191         grn_key_data_size = data_size;
192         break;
193       }
194 
195       if (error) {
196         break;
197       }
198 
199       current_mysql_key += data_size;
200       current_grn_key += grn_key_data_size;
201       *grn_key_length += grn_key_data_size;
202     }
203 
204     DBUG_RETURN(error);
205   }
206 
decode(const uchar * grn_key,uint grn_key_length,uchar * mysql_key,uint * mysql_key_length)207   int MultipleColumnKeyCodec::decode(const uchar *grn_key,
208                                      uint grn_key_length,
209                                      uchar *mysql_key,
210                                      uint *mysql_key_length) {
211     MRN_DBUG_ENTER_METHOD();
212     int error = 0;
213     const uchar *current_grn_key = grn_key;
214     const uchar *grn_key_end = grn_key + grn_key_length;
215     uchar *current_mysql_key = mysql_key;
216 
217     int n_key_parts = KEY_N_KEY_PARTS(key_info_);
218     DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
219     *mysql_key_length = 0;
220     for (int i = 0; i < n_key_parts && current_grn_key < grn_key_end; i++) {
221       KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
222       Field *field = key_part->field;
223       DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
224 
225       if (field->null_bit) {
226         DBUG_PRINT("info", ("mroonga: field has null bit"));
227         *current_mysql_key = 0;
228         current_grn_key += 1;
229         current_mysql_key += 1;
230         (*mysql_key_length)++;
231       }
232 
233       DataType data_type = TYPE_UNKNOWN;
234       uint data_size = 0;
235       get_key_info(key_part, &data_type, &data_size);
236       uint grn_key_data_size = data_size;
237 
238       switch (data_type) {
239       case TYPE_UNKNOWN:
240         // TODO: This will not be happen. This is just for
241         // suppressing warnings by gcc -O2. :<
242         error = HA_ERR_UNSUPPORTED;
243         break;
244       case TYPE_LONG_LONG_NUMBER:
245         {
246           long long int value;
247           decode_long_long_int(current_grn_key, &value);
248           int8store(current_mysql_key, value);
249         }
250         break;
251       case TYPE_NUMBER:
252         {
253           Field_num *number_field = static_cast<Field_num *>(field);
254           decode_number(current_grn_key,
255                         grn_key_data_size,
256                         !number_field->unsigned_flag,
257                         current_mysql_key);
258         }
259         break;
260       case TYPE_FLOAT:
261         decode_float(current_grn_key, grn_key_data_size, current_mysql_key);
262         break;
263       case TYPE_DOUBLE:
264         decode_double(current_grn_key, grn_key_data_size, current_mysql_key);
265         break;
266       case TYPE_DATETIME:
267         {
268           long long int grn_time;
269           decode_long_long_int(current_grn_key, &grn_time);
270           TimeConverter time_converter;
271           long long int mysql_datetime =
272             time_converter.grn_time_to_mysql_datetime(grn_time);
273 #ifdef WORDS_BIGENDIAN
274           if (field->table && field->table->s->db_low_byte_first) {
275             int8store(current_mysql_key, mysql_datetime);
276           } else
277 #endif
278           {
279             longlongstore(current_mysql_key, mysql_datetime);
280           }
281         }
282         break;
283 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
284       case TYPE_DATETIME2:
285         {
286           Field_datetimef *datetimef_field =
287             static_cast<Field_datetimef *>(field);
288           long long int grn_time;
289           grn_key_data_size = 8;
290           decode_long_long_int(current_grn_key, &grn_time);
291           TimeConverter time_converter;
292           MYSQL_TIME mysql_time;
293           mysql_time.neg = FALSE;
294           mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME;
295           time_converter.grn_time_to_mysql_time(grn_time, &mysql_time);
296           long long int mysql_datetime_packed =
297             TIME_to_longlong_datetime_packed(&mysql_time);
298           my_datetime_packed_to_binary(mysql_datetime_packed,
299                                        current_mysql_key,
300                                        datetimef_field->decimals());
301         }
302         break;
303 #endif
304       case TYPE_BYTE_SEQUENCE:
305         memcpy(current_mysql_key, current_grn_key, grn_key_data_size);
306         break;
307       case TYPE_BYTE_REVERSE:
308         decode_reverse(current_grn_key, grn_key_data_size, current_mysql_key);
309         break;
310       case TYPE_BYTE_BLOB:
311         memcpy(current_mysql_key,
312                current_grn_key + data_size,
313                HA_KEY_BLOB_LENGTH);
314         memcpy(current_mysql_key + HA_KEY_BLOB_LENGTH,
315                current_grn_key,
316                data_size);
317         data_size += HA_KEY_BLOB_LENGTH;
318         grn_key_data_size = data_size;
319         break;
320       }
321 
322       if (error) {
323         break;
324       }
325 
326       current_grn_key += grn_key_data_size;
327       current_mysql_key += data_size;
328       *mysql_key_length += data_size;
329     }
330 
331     DBUG_RETURN(error);
332   }
333 
size()334   uint MultipleColumnKeyCodec::size() {
335     MRN_DBUG_ENTER_METHOD();
336 
337     int n_key_parts = KEY_N_KEY_PARTS(key_info_);
338     DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
339 
340     uint total_size = 0;
341     for (int i = 0; i < n_key_parts; ++i) {
342       KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
343       Field *field = key_part->field;
344       DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
345 
346       if (field->null_bit) {
347         DBUG_PRINT("info", ("mroonga: field has null bit"));
348         ++total_size;
349       }
350 
351       DataType data_type = TYPE_UNKNOWN;
352       uint data_size = 0;
353       get_key_info(key_part, &data_type, &data_size);
354       switch (data_type) {
355 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
356       case TYPE_DATETIME2:
357         data_size = 8;
358         break;
359 #endif
360       case TYPE_BYTE_BLOB:
361         data_size += HA_KEY_BLOB_LENGTH;
362         break;
363       default:
364         break;
365       }
366       total_size += data_size;
367     }
368 
369     DBUG_RETURN(total_size);
370   }
371 
get_key_info(KEY_PART_INFO * key_part,DataType * data_type,uint * data_size)372   void MultipleColumnKeyCodec::get_key_info(KEY_PART_INFO *key_part,
373                                             DataType *data_type,
374                                             uint *data_size) {
375     MRN_DBUG_ENTER_METHOD();
376 
377     *data_type = TYPE_UNKNOWN;
378     *data_size = 0;
379 
380     Field *field = key_part->field;
381     switch (field->real_type()) {
382     case MYSQL_TYPE_DECIMAL:
383       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DECIMAL"));
384       *data_type = TYPE_BYTE_SEQUENCE;
385       *data_size = key_part->length;
386       break;
387     case MYSQL_TYPE_TINY:
388     case MYSQL_TYPE_YEAR:
389       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TINY"));
390       *data_type = TYPE_NUMBER;
391       *data_size = 1;
392       break;
393     case MYSQL_TYPE_SHORT:
394       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_SHORT"));
395       *data_type = TYPE_NUMBER;
396       *data_size = 2;
397       break;
398     case MYSQL_TYPE_LONG:
399       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_LONG"));
400       *data_type = TYPE_NUMBER;
401       *data_size = 4;
402       break;
403     case MYSQL_TYPE_FLOAT:
404       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_FLOAT"));
405       *data_type = TYPE_FLOAT;
406       *data_size = 4;
407       break;
408     case MYSQL_TYPE_DOUBLE:
409       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DOUBLE"));
410       *data_type = TYPE_DOUBLE;
411       *data_size = 8;
412       break;
413     case MYSQL_TYPE_NULL:
414       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NULL"));
415       *data_type = TYPE_NUMBER;
416       *data_size = 1;
417       break;
418     case MYSQL_TYPE_TIMESTAMP:
419       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIMESTAMP"));
420       *data_type = TYPE_BYTE_REVERSE;
421       *data_size = key_part->length;
422       break;
423     case MYSQL_TYPE_DATE:
424       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATE"));
425       *data_type = TYPE_BYTE_REVERSE;
426       *data_size = key_part->length;
427       break;
428     case MYSQL_TYPE_DATETIME:
429       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATETIME"));
430       *data_type = TYPE_DATETIME;
431       *data_size = key_part->length;
432       break;
433     case MYSQL_TYPE_NEWDATE:
434       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NEWDATE"));
435       *data_type = TYPE_BYTE_REVERSE;
436       *data_size = key_part->length;
437       break;
438     case MYSQL_TYPE_LONGLONG:
439       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_LONGLONG"));
440       *data_type = TYPE_NUMBER;
441       *data_size = 8;
442       break;
443     case MYSQL_TYPE_INT24:
444       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_INT24"));
445       *data_type = TYPE_NUMBER;
446       *data_size = 3;
447       break;
448     case MYSQL_TYPE_TIME:
449       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIME"));
450       *data_type = TYPE_NUMBER;
451       *data_size = 3;
452       break;
453     case MYSQL_TYPE_VARCHAR:
454       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_VARCHAR"));
455       *data_type = TYPE_BYTE_BLOB;
456       *data_size = key_part->length;
457       break;
458     case MYSQL_TYPE_BIT:
459       // TODO
460       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_BIT"));
461       *data_type = TYPE_NUMBER;
462       *data_size = 1;
463       break;
464 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
465     case MYSQL_TYPE_TIMESTAMP2:
466       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIMESTAMP2"));
467       *data_type = TYPE_BYTE_SEQUENCE;
468       *data_size = key_part->length;
469       break;
470 #endif
471 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
472     case MYSQL_TYPE_DATETIME2:
473       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATETIME2"));
474       *data_type = TYPE_DATETIME2;
475       *data_size = key_part->length;
476       break;
477 #endif
478 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
479     case MYSQL_TYPE_TIME2:
480       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIME2"));
481       *data_type = TYPE_BYTE_SEQUENCE;
482       *data_size = key_part->length;
483       break;
484 #endif
485     case MYSQL_TYPE_NEWDECIMAL:
486       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NEWDECIMAL"));
487       *data_type = TYPE_BYTE_SEQUENCE;
488       *data_size = key_part->length;
489       break;
490     case MYSQL_TYPE_ENUM:
491       // TODO
492       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_ENUM"));
493       *data_type = TYPE_NUMBER;
494       *data_size = 1;
495       break;
496     case MYSQL_TYPE_SET:
497       // TODO
498       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_SET"));
499       *data_type = TYPE_NUMBER;
500       *data_size = 1;
501       break;
502     case MYSQL_TYPE_TINY_BLOB:
503     case MYSQL_TYPE_MEDIUM_BLOB:
504     case MYSQL_TYPE_LONG_BLOB:
505     case MYSQL_TYPE_BLOB:
506       // TODO
507       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_BLOB"));
508       *data_type = TYPE_BYTE_BLOB;
509       *data_size = key_part->length;
510       break;
511     case MYSQL_TYPE_VAR_STRING:
512     case MYSQL_TYPE_STRING:
513       // TODO
514       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_STRING"));
515       *data_type = TYPE_BYTE_SEQUENCE;
516       *data_size = key_part->length;
517       break;
518     case MYSQL_TYPE_GEOMETRY:
519       // TODO
520       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_GEOMETRY"));
521       *data_type = TYPE_BYTE_SEQUENCE;
522       *data_size = key_part->length;
523       break;
524     case MYSQL_TYPE_VARCHAR_COMPRESSED:
525     case MYSQL_TYPE_BLOB_COMPRESSED:
526       DBUG_ASSERT(0);
527 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
528     case MYSQL_TYPE_JSON:
529       // TODO
530       DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_JSON"));
531       *data_type = TYPE_BYTE_SEQUENCE;
532       *data_size = key_part->length;
533       break;
534 #endif
535     }
536     DBUG_VOID_RETURN;
537   }
538 
encode_number(const uchar * mysql_key,uint mysql_key_size,bool is_signed,uchar * grn_key)539   void MultipleColumnKeyCodec::encode_number(const uchar *mysql_key,
540                                              uint mysql_key_size,
541                                              bool is_signed,
542                                              uchar *grn_key) {
543     MRN_DBUG_ENTER_METHOD();
544     mrn_byte_order_host_to_network(grn_key, mysql_key, mysql_key_size);
545     if (is_signed) {
546       grn_key[0] ^= 0x80;
547     }
548     DBUG_VOID_RETURN;
549   }
550 
decode_number(const uchar * grn_key,uint grn_key_size,bool is_signed,uchar * mysql_key)551   void MultipleColumnKeyCodec::decode_number(const uchar *grn_key,
552                                              uint grn_key_size,
553                                              bool is_signed,
554                                              uchar *mysql_key) {
555     MRN_DBUG_ENTER_METHOD();
556     uchar buffer[8];
557     memcpy(buffer, grn_key, grn_key_size);
558     if (is_signed) {
559       buffer[0] ^= 0x80;
560     }
561     mrn_byte_order_network_to_host(mysql_key, buffer, grn_key_size);
562     DBUG_VOID_RETURN;
563   }
564 
encode_long_long_int(volatile long long int value,uchar * grn_key)565   void MultipleColumnKeyCodec::encode_long_long_int(volatile long long int value,
566                                                     uchar *grn_key) {
567     MRN_DBUG_ENTER_METHOD();
568     uint value_size = 8;
569     mrn_byte_order_host_to_network(grn_key, &value, value_size);
570     grn_key[0] ^= 0x80;
571     DBUG_VOID_RETURN;
572   }
573 
decode_long_long_int(const uchar * grn_key,long long int * value)574   void MultipleColumnKeyCodec::decode_long_long_int(const uchar *grn_key,
575                                                     long long int *value) {
576     MRN_DBUG_ENTER_METHOD();
577     uint grn_key_size = 8;
578     uchar buffer[8];
579     memcpy(buffer, grn_key, grn_key_size);
580     buffer[0] ^= 0x80;
581     mrn_byte_order_network_to_host(value, buffer, grn_key_size);
582     DBUG_VOID_RETURN;
583   }
584 
encode_float(volatile float value,uint value_size,uchar * grn_key)585   void MultipleColumnKeyCodec::encode_float(volatile float value,
586                                             uint value_size,
587                                             uchar *grn_key) {
588     MRN_DBUG_ENTER_METHOD();
589     int n_bits = (value_size * 8 - 1);
590     volatile int *int_value_pointer = (int *)(&value);
591     int int_value = *int_value_pointer;
592     int_value ^= ((int_value >> n_bits) | (1 << n_bits));
593     mrn_byte_order_host_to_network(grn_key, &int_value, value_size);
594     DBUG_VOID_RETURN;
595   }
596 
decode_float(const uchar * grn_key,uint grn_key_size,uchar * mysql_key)597   void MultipleColumnKeyCodec::decode_float(const uchar *grn_key,
598                                             uint grn_key_size,
599                                             uchar *mysql_key) {
600     MRN_DBUG_ENTER_METHOD();
601     int int_value;
602     mrn_byte_order_network_to_host(&int_value, grn_key, grn_key_size);
603     int max_bit = (grn_key_size * 8 - 1);
604     *((int *)mysql_key) =
605       int_value ^ (((int_value ^ (1 << max_bit)) >> max_bit) |
606                    (1 << max_bit));
607     DBUG_VOID_RETURN;
608   }
609 
encode_double(volatile double value,uint value_size,uchar * grn_key)610   void MultipleColumnKeyCodec::encode_double(volatile double value,
611                                              uint value_size,
612                                              uchar *grn_key) {
613     MRN_DBUG_ENTER_METHOD();
614     int n_bits = (value_size * 8 - 1);
615     volatile long long int *long_long_value_pointer = (long long int *)(&value);
616     volatile long long int long_long_value = *long_long_value_pointer;
617     long_long_value ^= ((long_long_value >> n_bits) | (1LL << n_bits));
618     mrn_byte_order_host_to_network(grn_key, &long_long_value, value_size);
619     DBUG_VOID_RETURN;
620   }
621 
decode_double(const uchar * grn_key,uint grn_key_size,uchar * mysql_key)622   void MultipleColumnKeyCodec::decode_double(const uchar *grn_key,
623                                              uint grn_key_size,
624                                              uchar *mysql_key) {
625     MRN_DBUG_ENTER_METHOD();
626     long long int long_long_value;
627     mrn_byte_order_network_to_host(&long_long_value, grn_key, grn_key_size);
628     int max_bit = (grn_key_size * 8 - 1);
629     long_long_value =
630       long_long_value ^ (((long_long_value ^ (1LL << max_bit)) >> max_bit) |
631                          (1LL << max_bit));
632     memcpy(mysql_key, &long_long_value, sizeof(long_long_value));
633     DBUG_VOID_RETURN;
634   }
635 
encode_reverse(const uchar * mysql_key,uint mysql_key_size,uchar * grn_key)636   void MultipleColumnKeyCodec::encode_reverse(const uchar *mysql_key,
637                                               uint mysql_key_size,
638                                               uchar *grn_key) {
639     MRN_DBUG_ENTER_METHOD();
640     for (uint i = 0; i < mysql_key_size; i++) {
641       grn_key[i] = mysql_key[mysql_key_size - i - 1];
642     }
643     DBUG_VOID_RETURN;
644   }
645 
decode_reverse(const uchar * grn_key,uint grn_key_size,uchar * mysql_key)646   void MultipleColumnKeyCodec::decode_reverse(const uchar *grn_key,
647                                               uint grn_key_size,
648                                               uchar *mysql_key) {
649     MRN_DBUG_ENTER_METHOD();
650     for (uint i = 0; i < grn_key_size; i++) {
651       mysql_key[i] = grn_key[grn_key_size - i - 1];
652     }
653     DBUG_VOID_RETURN;
654   }
655 
encode_blob(const uchar * mysql_key,uint * mysql_key_size,Field * field,uchar * grn_key)656   void MultipleColumnKeyCodec::encode_blob(const uchar *mysql_key,
657                                            uint *mysql_key_size,
658                                            Field *field,
659                                            uchar *grn_key) {
660     MRN_DBUG_ENTER_METHOD();
661     FieldNormalizer normalizer(ctx_, thread_, field);
662     if (normalizer.should_normalize()) {
663 #if HA_KEY_BLOB_LENGTH != 2
664 #  error "TODO: support HA_KEY_BLOB_LENGTH != 2 case if it is needed"
665 #endif
666       const char *blob_data =
667         reinterpret_cast<const char *>(mysql_key + HA_KEY_BLOB_LENGTH);
668       uint16 blob_data_length = *((uint16 *)(mysql_key));
669       grn_obj *grn_string = normalizer.normalize(blob_data,
670                                                  blob_data_length);
671       mrn::SmartGrnObj smart_grn_string(ctx_, grn_string);
672       const char *normalized;
673       unsigned int normalized_length = 0;
674       grn_string_get_normalized(ctx_, grn_string,
675                                 &normalized, &normalized_length, NULL);
676       uint16 new_blob_data_length;
677       if (normalized_length <= UINT_MAX16) {
678         if (normalized_length)
679           memcpy(grn_key, normalized, normalized_length);
680         if (normalized_length < *mysql_key_size) {
681           memset(grn_key + normalized_length,
682                  '\0', *mysql_key_size - normalized_length);
683         }
684         new_blob_data_length = normalized_length;
685       } else {
686         push_warning_printf(thread_,
687                             MRN_SEVERITY_WARNING,
688                             MRN_ERROR_CODE_DATA_TRUNCATE(thread_),
689                             "normalized data truncated "
690                             "for multiple column index: "
691                             "normalized-data-size: <%u> "
692                             "max-data-size: <%u> "
693                             "column-name: <%s> "
694                             "data: <%.*s>",
695                             normalized_length,
696                             UINT_MAX16,
697                             field->field_name,
698                             blob_data_length, blob_data);
699         memcpy(grn_key, normalized, blob_data_length);
700         new_blob_data_length = blob_data_length;
701       }
702       memcpy(grn_key + *mysql_key_size,
703              &new_blob_data_length,
704              HA_KEY_BLOB_LENGTH);
705     } else {
706       memcpy(grn_key + *mysql_key_size, mysql_key, HA_KEY_BLOB_LENGTH);
707       memcpy(grn_key, mysql_key + HA_KEY_BLOB_LENGTH, *mysql_key_size);
708     }
709     *mysql_key_size += HA_KEY_BLOB_LENGTH;
710     DBUG_VOID_RETURN;
711   }
712 }
713