1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2013-2017 Kouhei Sutou <kou@clear-code.com> |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with this library; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | #include "mrn_condition_converter.hpp" |
21 | #include "mrn_time_converter.hpp" |
22 | #include "mrn_smart_grn_obj.hpp" |
23 | |
24 | // for debug |
25 | #define MRN_CLASS_NAME "mrn::ConditionConverter" |
26 | |
27 | #ifdef MRN_ITEM_HAVE_ITEM_NAME |
28 | # define MRN_ITEM_FIELD_GET_NAME(item) ((item)->item_name.ptr()) |
29 | # define MRN_ITEM_FIELD_GET_NAME_LENGTH(item) ((item)->item_name.length()) |
30 | #else |
31 | # define MRN_ITEM_FIELD_GET_NAME(item) ((item)->name.str) |
32 | # define MRN_ITEM_FIELD_GET_NAME_LENGTH(item) ((item)->name.length) |
33 | #endif |
34 | |
35 | namespace mrn { |
36 | ConditionConverter::ConditionConverter(grn_ctx *ctx, grn_obj *table, |
37 | bool is_storage_mode) |
38 | : ctx_(ctx), |
39 | table_(table), |
40 | is_storage_mode_(is_storage_mode) { |
41 | GRN_TEXT_INIT(&column_name_, 0); |
42 | GRN_VOID_INIT(&value_); |
43 | } |
44 | |
45 | ConditionConverter::~ConditionConverter() { |
46 | grn_obj_unlink(ctx_, &column_name_); |
47 | grn_obj_unlink(ctx_, &value_); |
48 | } |
49 | |
50 | bool ConditionConverter::is_convertable(const Item *item) { |
51 | MRN_DBUG_ENTER_METHOD(); |
52 | |
53 | if (!item) { |
54 | DBUG_RETURN(false); |
55 | } |
56 | |
57 | switch (item->type()) { |
58 | case Item::COND_ITEM: |
59 | { |
60 | const Item_cond *cond_item = reinterpret_cast<const Item_cond *>(item); |
61 | bool convertable = is_convertable(cond_item); |
62 | DBUG_RETURN(convertable); |
63 | } |
64 | break; |
65 | case Item::FUNC_ITEM: |
66 | { |
67 | const Item_func *func_item = reinterpret_cast<const Item_func *>(item); |
68 | bool convertable = is_convertable(func_item); |
69 | DBUG_RETURN(convertable); |
70 | } |
71 | break; |
72 | default: |
73 | DBUG_RETURN(false); |
74 | break; |
75 | } |
76 | |
77 | DBUG_RETURN(false); |
78 | } |
79 | |
80 | bool ConditionConverter::is_convertable(const Item_cond *cond_item) { |
81 | MRN_DBUG_ENTER_METHOD(); |
82 | |
83 | if (!is_storage_mode_) { |
84 | DBUG_RETURN(false); |
85 | } |
86 | |
87 | if (cond_item->functype() != Item_func::COND_AND_FUNC) { |
88 | DBUG_RETURN(false); |
89 | } |
90 | |
91 | List<Item> *argument_list = |
92 | const_cast<Item_cond *>(cond_item)->argument_list(); |
93 | List_iterator<Item> iterator(*argument_list); |
94 | const Item *sub_item; |
95 | while ((sub_item = iterator++)) { |
96 | if (!is_convertable(sub_item)) { |
97 | DBUG_RETURN(false); |
98 | } |
99 | } |
100 | |
101 | DBUG_RETURN(true); |
102 | } |
103 | |
104 | bool ConditionConverter::is_convertable(const Item_func *func_item) { |
105 | MRN_DBUG_ENTER_METHOD(); |
106 | |
107 | switch (func_item->functype()) { |
108 | case Item_func::EQ_FUNC: |
109 | case Item_func::LT_FUNC: |
110 | case Item_func::LE_FUNC: |
111 | case Item_func::GE_FUNC: |
112 | case Item_func::GT_FUNC: |
113 | if (!is_storage_mode_) { |
114 | DBUG_RETURN(false); |
115 | } |
116 | { |
117 | Item **arguments = func_item->arguments(); |
118 | Item *left_item = arguments[0]; |
119 | Item *right_item = arguments[1]; |
120 | if (left_item->type() != Item::FIELD_ITEM) { |
121 | DBUG_RETURN(false); |
122 | } |
123 | if (!right_item->basic_const_item()) { |
124 | DBUG_RETURN(false); |
125 | } |
126 | |
127 | bool convertable = |
128 | is_convertable_binary_operation(static_cast<Item_field *>(left_item), |
129 | right_item, |
130 | func_item->functype()); |
131 | DBUG_RETURN(convertable); |
132 | } |
133 | break; |
134 | case Item_func::FT_FUNC: |
135 | DBUG_RETURN(true); |
136 | break; |
137 | case Item_func::BETWEEN: |
138 | if (!is_storage_mode_) { |
139 | DBUG_RETURN(false); |
140 | } |
141 | { |
142 | Item **arguments = func_item->arguments(); |
143 | Item *target_item = arguments[0]; |
144 | Item *min_item = arguments[1]; |
145 | Item *max_item = arguments[2]; |
146 | if (target_item->type() != Item::FIELD_ITEM) { |
147 | DBUG_RETURN(false); |
148 | } |
149 | if (!min_item->basic_const_item()) { |
150 | DBUG_RETURN(false); |
151 | } |
152 | if (!max_item->basic_const_item()) { |
153 | DBUG_RETURN(false); |
154 | } |
155 | |
156 | bool convertable = |
157 | is_convertable_between(static_cast<Item_field *>(target_item), |
158 | min_item, |
159 | max_item); |
160 | DBUG_RETURN(convertable); |
161 | } |
162 | default: |
163 | DBUG_RETURN(false); |
164 | break; |
165 | } |
166 | |
167 | DBUG_RETURN(true); |
168 | } |
169 | |
170 | bool ConditionConverter::is_convertable_binary_operation( |
171 | const Item_field *field_item, |
172 | Item *value_item, |
173 | Item_func::Functype func_type) { |
174 | MRN_DBUG_ENTER_METHOD(); |
175 | |
176 | bool convertable = false; |
177 | |
178 | enum_field_types field_type = field_item->field->real_type(); |
179 | NormalizedType normalized_type = normalize_field_type(field_type); |
180 | switch (normalized_type) { |
181 | case STRING_TYPE: |
182 | if (value_item->type() == Item::STRING_ITEM && |
183 | func_type == Item_func::EQ_FUNC) { |
184 | convertable = have_index(field_item, GRN_OP_EQUAL); |
185 | } |
186 | break; |
187 | case INT_TYPE: |
188 | if (field_type == MYSQL_TYPE_ENUM) { |
189 | convertable = (value_item->type() == Item::STRING_ITEM || |
190 | value_item->type() == Item::INT_ITEM); |
191 | } else { |
192 | convertable = value_item->type() == Item::INT_ITEM; |
193 | } |
194 | break; |
195 | case TIME_TYPE: |
196 | if (is_valid_time_value(field_item, value_item)) { |
197 | convertable = have_index(field_item, func_type); |
198 | } |
199 | break; |
200 | case UNSUPPORTED_TYPE: |
201 | break; |
202 | } |
203 | |
204 | DBUG_RETURN(convertable); |
205 | } |
206 | |
207 | bool ConditionConverter::is_convertable_between(const Item_field *field_item, |
208 | Item *min_item, |
209 | Item *max_item) { |
210 | MRN_DBUG_ENTER_METHOD(); |
211 | |
212 | bool convertable = false; |
213 | |
214 | enum_field_types field_type = field_item->field->type(); |
215 | NormalizedType normalized_type = normalize_field_type(field_type); |
216 | switch (normalized_type) { |
217 | case STRING_TYPE: |
218 | if (min_item->type() == Item::STRING_ITEM && |
219 | max_item->type() == Item::STRING_ITEM) { |
220 | convertable = have_index(field_item, GRN_OP_LESS); |
221 | } |
222 | break; |
223 | case INT_TYPE: |
224 | if (min_item->type() == Item::INT_ITEM && |
225 | max_item->type() == Item::INT_ITEM) { |
226 | convertable = have_index(field_item, GRN_OP_LESS); |
227 | } |
228 | break; |
229 | case TIME_TYPE: |
230 | if (is_valid_time_value(field_item, min_item) && |
231 | is_valid_time_value(field_item, max_item)) { |
232 | convertable = have_index(field_item, GRN_OP_LESS); |
233 | } |
234 | break; |
235 | case UNSUPPORTED_TYPE: |
236 | break; |
237 | } |
238 | |
239 | DBUG_RETURN(convertable); |
240 | } |
241 | |
242 | bool ConditionConverter::is_valid_time_value(const Item_field *field_item, |
243 | Item *value_item) { |
244 | MRN_DBUG_ENTER_METHOD(); |
245 | |
246 | MYSQL_TIME mysql_time; |
247 | bool error = get_time_value(field_item, value_item, &mysql_time); |
248 | |
249 | DBUG_RETURN(!error); |
250 | } |
251 | |
252 | bool ConditionConverter::get_time_value(const Item_field *field_item, |
253 | Item *value_item, |
254 | MYSQL_TIME *mysql_time) { |
255 | MRN_DBUG_ENTER_METHOD(); |
256 | |
257 | bool error; |
258 | Item *real_value_item = value_item->real_item(); |
259 | switch (field_item->field->type()) { |
260 | case MYSQL_TYPE_TIME: |
261 | error = real_value_item->get_time(mysql_time); |
262 | break; |
263 | case MYSQL_TYPE_YEAR: |
264 | mysql_time->year = static_cast<int>(value_item->val_int()); |
265 | mysql_time->month = 1; |
266 | mysql_time->day = 1; |
267 | mysql_time->hour = 0; |
268 | mysql_time->hour = 0; |
269 | mysql_time->minute = 0; |
270 | mysql_time->second_part = 0; |
271 | mysql_time->neg = false; |
272 | mysql_time->time_type = MYSQL_TIMESTAMP_DATE; |
273 | error = false; |
274 | break; |
275 | default: |
276 | error = real_value_item->get_date(mysql_time, TIME_FUZZY_DATE); |
277 | break; |
278 | } |
279 | |
280 | DBUG_RETURN(error); |
281 | } |
282 | |
283 | ConditionConverter::NormalizedType |
284 | ConditionConverter::normalize_field_type(enum_field_types field_type) { |
285 | MRN_DBUG_ENTER_METHOD(); |
286 | |
287 | NormalizedType type = UNSUPPORTED_TYPE; |
288 | |
289 | switch (field_type) { |
290 | case MYSQL_TYPE_DECIMAL: |
291 | type = STRING_TYPE; |
292 | break; |
293 | case MYSQL_TYPE_TINY: |
294 | case MYSQL_TYPE_SHORT: |
295 | case MYSQL_TYPE_LONG: |
296 | type = INT_TYPE; |
297 | break; |
298 | case MYSQL_TYPE_FLOAT: |
299 | case MYSQL_TYPE_DOUBLE: |
300 | type = UNSUPPORTED_TYPE; |
301 | break; |
302 | case MYSQL_TYPE_NULL: |
303 | type = UNSUPPORTED_TYPE; |
304 | break; |
305 | case MYSQL_TYPE_TIMESTAMP: |
306 | type = TIME_TYPE; |
307 | break; |
308 | case MYSQL_TYPE_LONGLONG: |
309 | case MYSQL_TYPE_INT24: |
310 | type = INT_TYPE; |
311 | break; |
312 | case MYSQL_TYPE_DATE: |
313 | case MYSQL_TYPE_TIME: |
314 | case MYSQL_TYPE_DATETIME: |
315 | case MYSQL_TYPE_YEAR: |
316 | case MYSQL_TYPE_NEWDATE: |
317 | type = TIME_TYPE; |
318 | break; |
319 | case MYSQL_TYPE_VARCHAR: |
320 | type = STRING_TYPE; |
321 | break; |
322 | case MYSQL_TYPE_BIT: |
323 | type = INT_TYPE; |
324 | break; |
325 | #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2 |
326 | case MYSQL_TYPE_TIMESTAMP2: |
327 | type = TIME_TYPE; |
328 | break; |
329 | #endif |
330 | #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2 |
331 | case MYSQL_TYPE_DATETIME2: |
332 | type = TIME_TYPE; |
333 | break; |
334 | #endif |
335 | #ifdef MRN_HAVE_MYSQL_TYPE_TIME2 |
336 | case MYSQL_TYPE_TIME2: |
337 | type = TIME_TYPE; |
338 | break; |
339 | #endif |
340 | case MYSQL_TYPE_NEWDECIMAL: |
341 | type = STRING_TYPE; |
342 | break; |
343 | case MYSQL_TYPE_ENUM: |
344 | type = INT_TYPE; |
345 | break; |
346 | case MYSQL_TYPE_SET: |
347 | type = INT_TYPE; |
348 | break; |
349 | case MYSQL_TYPE_TINY_BLOB: |
350 | case MYSQL_TYPE_MEDIUM_BLOB: |
351 | case MYSQL_TYPE_LONG_BLOB: |
352 | case MYSQL_TYPE_BLOB: |
353 | case MYSQL_TYPE_VAR_STRING: |
354 | case MYSQL_TYPE_STRING: |
355 | type = STRING_TYPE; |
356 | break; |
357 | case MYSQL_TYPE_GEOMETRY: |
358 | type = UNSUPPORTED_TYPE; |
359 | break; |
360 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
361 | case MYSQL_TYPE_BLOB_COMPRESSED: |
362 | DBUG_ASSERT(0); |
363 | #ifdef MRN_HAVE_MYSQL_TYPE_JSON |
364 | case MYSQL_TYPE_JSON: |
365 | type = STRING_TYPE; |
366 | break; |
367 | #endif |
368 | } |
369 | |
370 | DBUG_RETURN(type); |
371 | } |
372 | |
373 | bool ConditionConverter::have_index(const Item_field *field_item, |
374 | grn_operator _operator) { |
375 | MRN_DBUG_ENTER_METHOD(); |
376 | |
377 | grn_obj *column; |
378 | column = grn_obj_column(ctx_, table_, |
379 | MRN_ITEM_FIELD_GET_NAME(field_item), |
380 | MRN_ITEM_FIELD_GET_NAME_LENGTH(field_item)); |
381 | if (!column) { |
382 | DBUG_RETURN(false); |
383 | } |
384 | mrn::SmartGrnObj smart_column(ctx_, column); |
385 | |
386 | int n_indexes = grn_column_index(ctx_, column, _operator, NULL, 0, NULL); |
387 | bool convertable = (n_indexes > 0); |
388 | |
389 | DBUG_RETURN(convertable); |
390 | } |
391 | |
392 | bool ConditionConverter::have_index(const Item_field *field_item, |
393 | Item_func::Functype func_type) { |
394 | MRN_DBUG_ENTER_METHOD(); |
395 | |
396 | bool have = false; |
397 | switch (func_type) { |
398 | case Item_func::EQ_FUNC: |
399 | have = have_index(field_item, GRN_OP_EQUAL); |
400 | break; |
401 | case Item_func::LT_FUNC: |
402 | have = have_index(field_item, GRN_OP_LESS); |
403 | break; |
404 | case Item_func::LE_FUNC: |
405 | have = have_index(field_item, GRN_OP_LESS_EQUAL); |
406 | break; |
407 | case Item_func::GE_FUNC: |
408 | have = have_index(field_item, GRN_OP_GREATER_EQUAL); |
409 | break; |
410 | case Item_func::GT_FUNC: |
411 | have = have_index(field_item, GRN_OP_GREATER); |
412 | break; |
413 | default: |
414 | break; |
415 | } |
416 | |
417 | DBUG_RETURN(have); |
418 | } |
419 | |
420 | unsigned int ConditionConverter::count_match_against(const Item *item) { |
421 | MRN_DBUG_ENTER_METHOD(); |
422 | |
423 | if (!item) { |
424 | DBUG_RETURN(0); |
425 | } |
426 | |
427 | switch (item->type()) { |
428 | case Item::COND_ITEM: |
429 | if (is_storage_mode_) { |
430 | Item_cond *cond_item = (Item_cond *)item; |
431 | if (cond_item->functype() == Item_func::COND_AND_FUNC) { |
432 | unsigned int n_match_againsts = 0; |
433 | List_iterator<Item> iterator(*((cond_item)->argument_list())); |
434 | const Item *sub_item; |
435 | while ((sub_item = iterator++)) { |
436 | n_match_againsts += count_match_against(sub_item); |
437 | } |
438 | DBUG_RETURN(n_match_againsts); |
439 | } |
440 | } |
441 | break; |
442 | case Item::FUNC_ITEM: |
443 | { |
444 | const Item_func *func_item = (const Item_func *)item; |
445 | switch (func_item->functype()) { |
446 | case Item_func::FT_FUNC: |
447 | DBUG_RETURN(1); |
448 | break; |
449 | default: |
450 | break; |
451 | } |
452 | } |
453 | break; |
454 | default: |
455 | break; |
456 | } |
457 | |
458 | DBUG_RETURN(0); |
459 | } |
460 | |
461 | void ConditionConverter::convert(const Item *where, grn_obj *expression) { |
462 | MRN_DBUG_ENTER_METHOD(); |
463 | |
464 | if (!where || where->type() != Item::COND_ITEM) { |
465 | DBUG_VOID_RETURN; |
466 | } |
467 | |
468 | Item_cond *cond_item = (Item_cond *)where; |
469 | List_iterator<Item> iterator(*((cond_item)->argument_list())); |
470 | const Item *sub_item; |
471 | while ((sub_item = iterator++)) { |
472 | switch (sub_item->type()) { |
473 | case Item::FUNC_ITEM: |
474 | { |
475 | const Item_func *func_item = (const Item_func *)sub_item; |
476 | switch (func_item->functype()) { |
477 | case Item_func::EQ_FUNC: |
478 | convert_binary_operation(func_item, expression, GRN_OP_EQUAL); |
479 | break; |
480 | case Item_func::LT_FUNC: |
481 | convert_binary_operation(func_item, expression, GRN_OP_LESS); |
482 | break; |
483 | case Item_func::LE_FUNC: |
484 | convert_binary_operation(func_item, expression, GRN_OP_LESS_EQUAL); |
485 | break; |
486 | case Item_func::GE_FUNC: |
487 | convert_binary_operation(func_item, expression, |
488 | GRN_OP_GREATER_EQUAL); |
489 | break; |
490 | case Item_func::GT_FUNC: |
491 | convert_binary_operation(func_item, expression, GRN_OP_GREATER); |
492 | break; |
493 | case Item_func::BETWEEN: |
494 | convert_between(func_item, expression); |
495 | break; |
496 | default: |
497 | break; |
498 | } |
499 | } |
500 | break; |
501 | default: |
502 | break; |
503 | } |
504 | } |
505 | |
506 | DBUG_VOID_RETURN; |
507 | } |
508 | |
509 | void ConditionConverter::convert_binary_operation(const Item_func *func_item, |
510 | grn_obj *expression, |
511 | grn_operator _operator) { |
512 | Item **arguments = func_item->arguments(); |
513 | Item *left_item = arguments[0]; |
514 | Item *right_item = arguments[1]; |
515 | if (left_item->type() == Item::FIELD_ITEM) { |
516 | const Item_field *field_item = static_cast<const Item_field *>(left_item); |
517 | append_field_value(field_item, expression); |
518 | append_const_item(field_item, right_item, expression); |
519 | grn_expr_append_op(ctx_, expression, _operator, 2); |
520 | grn_expr_append_op(ctx_, expression, GRN_OP_AND, 2); |
521 | } |
522 | } |
523 | |
524 | void ConditionConverter::convert_between(const Item_func *func_item, |
525 | grn_obj *expression) { |
526 | MRN_DBUG_ENTER_METHOD(); |
527 | |
528 | Item **arguments = func_item->arguments(); |
529 | Item *target_item = arguments[0]; |
530 | Item *min_item = arguments[1]; |
531 | Item *max_item = arguments[2]; |
532 | |
533 | grn_obj *between_func = grn_ctx_get(ctx_, "between" , strlen("between" )); |
534 | grn_expr_append_obj(ctx_, expression, between_func, GRN_OP_PUSH, 1); |
535 | |
536 | const Item_field *field_item = static_cast<const Item_field *>(target_item); |
537 | append_field_value(field_item, expression); |
538 | |
539 | grn_obj include; |
540 | mrn::SmartGrnObj smart_include(ctx_, &include); |
541 | GRN_TEXT_INIT(&include, 0); |
542 | GRN_TEXT_PUTS(ctx_, &include, "include" ); |
543 | append_const_item(field_item, min_item, expression); |
544 | grn_expr_append_const(ctx_, expression, &include, GRN_OP_PUSH, 1); |
545 | append_const_item(field_item, max_item, expression); |
546 | grn_expr_append_const(ctx_, expression, &include, GRN_OP_PUSH, 1); |
547 | |
548 | grn_expr_append_op(ctx_, expression, GRN_OP_CALL, 5); |
549 | |
550 | grn_expr_append_op(ctx_, expression, GRN_OP_AND, 2); |
551 | |
552 | DBUG_VOID_RETURN; |
553 | } |
554 | |
555 | void ConditionConverter::append_field_value(const Item_field *field_item, |
556 | grn_obj *expression) { |
557 | MRN_DBUG_ENTER_METHOD(); |
558 | |
559 | GRN_BULK_REWIND(&column_name_); |
560 | GRN_TEXT_PUT(ctx_, &column_name_, |
561 | MRN_ITEM_FIELD_GET_NAME(field_item), |
562 | MRN_ITEM_FIELD_GET_NAME_LENGTH(field_item)); |
563 | grn_expr_append_const(ctx_, expression, &column_name_, |
564 | GRN_OP_PUSH, 1); |
565 | grn_expr_append_op(ctx_, expression, GRN_OP_GET_VALUE, 1); |
566 | |
567 | DBUG_VOID_RETURN; |
568 | } |
569 | |
570 | void ConditionConverter::append_const_item(const Item_field *field_item, |
571 | Item *const_item, |
572 | grn_obj *expression) { |
573 | MRN_DBUG_ENTER_METHOD(); |
574 | |
575 | enum_field_types field_type = field_item->field->real_type(); |
576 | NormalizedType normalized_type = normalize_field_type(field_type); |
577 | |
578 | switch (normalized_type) { |
579 | case STRING_TYPE: |
580 | grn_obj_reinit(ctx_, &value_, GRN_DB_TEXT, 0); |
581 | { |
582 | String *string; |
583 | string = const_item->val_str(NULL); |
584 | GRN_TEXT_SET(ctx_, &value_, string->ptr(), string->length()); |
585 | } |
586 | break; |
587 | case INT_TYPE: |
588 | grn_obj_reinit(ctx_, &value_, GRN_DB_INT64, 0); |
589 | if (field_type == MYSQL_TYPE_ENUM) { |
590 | if (const_item->type() == Item::STRING_ITEM) { |
591 | String *string; |
592 | string = const_item->val_str(NULL); |
593 | Field_enum *enum_field = static_cast<Field_enum *>(field_item->field); |
594 | int enum_value = find_type(string->c_ptr(), |
595 | enum_field->typelib, |
596 | FIND_TYPE_BASIC); |
597 | GRN_INT64_SET(ctx_, &value_, enum_value); |
598 | } else { |
599 | GRN_INT64_SET(ctx_, &value_, const_item->val_int()); |
600 | } |
601 | } else { |
602 | GRN_INT64_SET(ctx_, &value_, const_item->val_int()); |
603 | } |
604 | break; |
605 | case TIME_TYPE: |
606 | grn_obj_reinit(ctx_, &value_, GRN_DB_TIME, 0); |
607 | { |
608 | MYSQL_TIME mysql_time; |
609 | get_time_value(field_item, const_item, &mysql_time); |
610 | bool truncated = false; |
611 | TimeConverter time_converter; |
612 | long long int time = |
613 | time_converter.mysql_time_to_grn_time(&mysql_time, &truncated); |
614 | GRN_TIME_SET(ctx_, &value_, time); |
615 | } |
616 | break; |
617 | case UNSUPPORTED_TYPE: |
618 | // Should not be occurred. |
619 | DBUG_PRINT("error" , |
620 | ("mroonga: append_const_item: unsupported type: <%d> " |
621 | "This case should not be occurred." , |
622 | field_type)); |
623 | grn_obj_reinit(ctx_, &value_, GRN_DB_VOID, 0); |
624 | break; |
625 | } |
626 | grn_expr_append_const(ctx_, expression, &value_, GRN_OP_PUSH, 1); |
627 | |
628 | DBUG_VOID_RETURN; |
629 | } |
630 | } |
631 | |