1 | /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. |
2 | Copyright (c) 2010, 2016, MariaDB |
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 | /** |
19 | @file |
20 | |
21 | @brief |
22 | Functions to copy data to or from fields |
23 | |
24 | This could be done with a single short function but opencoding this |
25 | gives much more speed. |
26 | */ |
27 | |
28 | #include "mariadb.h" |
29 | #include "sql_priv.h" |
30 | #include "sql_class.h" // THD |
31 | #include <m_ctype.h> |
32 | |
33 | static void do_field_eq(Copy_field *copy) |
34 | { |
35 | memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); |
36 | } |
37 | |
38 | static void do_field_1(Copy_field *copy) |
39 | { |
40 | copy->to_ptr[0]=copy->from_ptr[0]; |
41 | } |
42 | |
43 | static void do_field_2(Copy_field *copy) |
44 | { |
45 | copy->to_ptr[0]=copy->from_ptr[0]; |
46 | copy->to_ptr[1]=copy->from_ptr[1]; |
47 | } |
48 | |
49 | static void do_field_3(Copy_field *copy) |
50 | { |
51 | copy->to_ptr[0]=copy->from_ptr[0]; |
52 | copy->to_ptr[1]=copy->from_ptr[1]; |
53 | copy->to_ptr[2]=copy->from_ptr[2]; |
54 | } |
55 | |
56 | static void do_field_4(Copy_field *copy) |
57 | { |
58 | copy->to_ptr[0]=copy->from_ptr[0]; |
59 | copy->to_ptr[1]=copy->from_ptr[1]; |
60 | copy->to_ptr[2]=copy->from_ptr[2]; |
61 | copy->to_ptr[3]=copy->from_ptr[3]; |
62 | } |
63 | |
64 | static void do_field_6(Copy_field *copy) |
65 | { // For blob field |
66 | copy->to_ptr[0]=copy->from_ptr[0]; |
67 | copy->to_ptr[1]=copy->from_ptr[1]; |
68 | copy->to_ptr[2]=copy->from_ptr[2]; |
69 | copy->to_ptr[3]=copy->from_ptr[3]; |
70 | copy->to_ptr[4]=copy->from_ptr[4]; |
71 | copy->to_ptr[5]=copy->from_ptr[5]; |
72 | } |
73 | |
74 | static void do_field_8(Copy_field *copy) |
75 | { |
76 | copy->to_ptr[0]=copy->from_ptr[0]; |
77 | copy->to_ptr[1]=copy->from_ptr[1]; |
78 | copy->to_ptr[2]=copy->from_ptr[2]; |
79 | copy->to_ptr[3]=copy->from_ptr[3]; |
80 | copy->to_ptr[4]=copy->from_ptr[4]; |
81 | copy->to_ptr[5]=copy->from_ptr[5]; |
82 | copy->to_ptr[6]=copy->from_ptr[6]; |
83 | copy->to_ptr[7]=copy->from_ptr[7]; |
84 | } |
85 | |
86 | |
87 | static void do_field_to_null_str(Copy_field *copy) |
88 | { |
89 | if (*copy->from_null_ptr & copy->from_bit) |
90 | { |
91 | bzero(copy->to_ptr,copy->from_length); |
92 | copy->to_null_ptr[0]=1; // Always bit 1 |
93 | } |
94 | else |
95 | { |
96 | copy->to_null_ptr[0]=0; |
97 | memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); |
98 | } |
99 | } |
100 | |
101 | |
102 | static void do_outer_field_to_null_str(Copy_field *copy) |
103 | { |
104 | if (*copy->null_row || |
105 | (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))) |
106 | { |
107 | bzero(copy->to_ptr,copy->from_length); |
108 | copy->to_null_ptr[0]=1; // Always bit 1 |
109 | } |
110 | else |
111 | { |
112 | copy->to_null_ptr[0]=0; |
113 | memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); |
114 | } |
115 | } |
116 | |
117 | |
118 | static int set_bad_null_error(Field *field, int err) |
119 | { |
120 | switch (field->table->in_use->count_cuted_fields) { |
121 | case CHECK_FIELD_WARN: |
122 | field->set_warning(Sql_condition::WARN_LEVEL_WARN, err, 1); |
123 | /* fall through */ |
124 | case CHECK_FIELD_IGNORE: |
125 | case CHECK_FIELD_EXPRESSION: |
126 | return 0; |
127 | case CHECK_FIELD_ERROR_FOR_NULL: |
128 | if (!field->table->in_use->no_errors) |
129 | my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name.str); |
130 | return -1; |
131 | } |
132 | DBUG_ASSERT(0); // impossible |
133 | return -1; |
134 | } |
135 | |
136 | |
137 | int set_field_to_null(Field *field) |
138 | { |
139 | if (field->table->null_catch_flags & CHECK_ROW_FOR_NULLS_TO_REJECT) |
140 | { |
141 | field->table->null_catch_flags|= REJECT_ROW_DUE_TO_NULL_FIELDS; |
142 | return -1; |
143 | } |
144 | if (field->real_maybe_null()) |
145 | { |
146 | field->set_null(); |
147 | field->reset(); |
148 | return 0; |
149 | } |
150 | field->reset(); |
151 | return set_bad_null_error(field, WARN_DATA_TRUNCATED); |
152 | } |
153 | |
154 | |
155 | /** |
156 | Set TIMESTAMP to NOW(), AUTO_INCREMENT to the next number, or report an error |
157 | |
158 | @param field Field to update |
159 | |
160 | @retval |
161 | 0 Field could take 0 or an automatic conversion was used |
162 | @retval |
163 | -1 Field could not take NULL and no conversion was used. |
164 | If no_conversion was not set, an error message is printed |
165 | */ |
166 | |
167 | int convert_null_to_field_value_or_error(Field *field) |
168 | { |
169 | if (field->type() == MYSQL_TYPE_TIMESTAMP) |
170 | { |
171 | ((Field_timestamp*) field)->set_time(); |
172 | return 0; |
173 | } |
174 | |
175 | field->reset(); // Note: we ignore any potential failure of reset() here. |
176 | |
177 | if (field == field->table->next_number_field) |
178 | { |
179 | field->table->auto_increment_field_not_null= FALSE; |
180 | return 0; // field is set in fill_record() |
181 | } |
182 | return set_bad_null_error(field, ER_BAD_NULL_ERROR); |
183 | } |
184 | |
185 | /** |
186 | Set field to NULL or TIMESTAMP or to next auto_increment number. |
187 | |
188 | @param field Field to update |
189 | @param no_conversions Set to 1 if we should return 1 if field can't |
190 | take null values. |
191 | If set to 0 we will do store the 'default value' |
192 | if the field is a special field. If not we will |
193 | give an error. |
194 | |
195 | @retval |
196 | 0 Field could take 0 or an automatic conversion was used |
197 | @retval |
198 | -1 Field could not take NULL and no conversion was used. |
199 | If no_conversion was not set, an error message is printed |
200 | */ |
201 | |
202 | int |
203 | set_field_to_null_with_conversions(Field *field, bool no_conversions) |
204 | { |
205 | if (field->table->null_catch_flags & CHECK_ROW_FOR_NULLS_TO_REJECT) |
206 | { |
207 | field->table->null_catch_flags|= REJECT_ROW_DUE_TO_NULL_FIELDS; |
208 | return -1; |
209 | } |
210 | if (field->real_maybe_null()) |
211 | { |
212 | field->set_null(); |
213 | field->reset(); |
214 | return 0; |
215 | } |
216 | if (no_conversions) |
217 | return -1; |
218 | |
219 | return convert_null_to_field_value_or_error(field); |
220 | } |
221 | |
222 | |
223 | static void do_skip(Copy_field *copy __attribute__((unused))) |
224 | { |
225 | } |
226 | |
227 | |
228 | /* |
229 | Copy: (NULLable field) -> (NULLable field) |
230 | |
231 | note: if the record we're copying from is NULL-complemetned (i.e. |
232 | from_field->table->null_row==1), it will also have all NULLable columns to be |
233 | set to NULLs, so we dont need to check table->null_row here. |
234 | */ |
235 | |
236 | static void do_copy_null(Copy_field *copy) |
237 | { |
238 | if (*copy->from_null_ptr & copy->from_bit) |
239 | { |
240 | *copy->to_null_ptr|=copy->to_bit; |
241 | copy->to_field->reset(); |
242 | } |
243 | else |
244 | { |
245 | *copy->to_null_ptr&= ~copy->to_bit; |
246 | (copy->do_copy2)(copy); |
247 | } |
248 | } |
249 | |
250 | /* |
251 | Copy: (not-NULL field in table that can be NULL-complemented) -> (NULLable |
252 | field) |
253 | */ |
254 | |
255 | static void do_outer_field_null(Copy_field *copy) |
256 | { |
257 | if (*copy->null_row || |
258 | (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))) |
259 | { |
260 | *copy->to_null_ptr|=copy->to_bit; |
261 | copy->to_field->reset(); |
262 | } |
263 | else |
264 | { |
265 | *copy->to_null_ptr&= ~copy->to_bit; |
266 | (copy->do_copy2)(copy); |
267 | } |
268 | } |
269 | |
270 | /* |
271 | Copy: (not-NULL field in table that can be NULL-complemented) -> (not-NULL |
272 | field) |
273 | */ |
274 | static void do_copy_nullable_row_to_notnull(Copy_field *copy) |
275 | { |
276 | if (*copy->null_row || |
277 | (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))) |
278 | { |
279 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
280 | WARN_DATA_TRUNCATED, 1); |
281 | copy->to_field->reset(); |
282 | } |
283 | else |
284 | { |
285 | (copy->do_copy2)(copy); |
286 | } |
287 | |
288 | } |
289 | |
290 | /* Copy: (NULL-able field) -> (not NULL-able field) */ |
291 | static void do_copy_not_null(Copy_field *copy) |
292 | { |
293 | if (*copy->from_null_ptr & copy->from_bit) |
294 | { |
295 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
296 | WARN_DATA_TRUNCATED, 1); |
297 | copy->to_field->reset(); |
298 | } |
299 | else |
300 | (copy->do_copy2)(copy); |
301 | } |
302 | |
303 | |
304 | /* Copy: (non-NULLable field) -> (NULLable field) */ |
305 | static void do_copy_maybe_null(Copy_field *copy) |
306 | { |
307 | *copy->to_null_ptr&= ~copy->to_bit; |
308 | (copy->do_copy2)(copy); |
309 | } |
310 | |
311 | /* timestamp and next_number has special handling in case of NULL values */ |
312 | |
313 | static void do_copy_timestamp(Copy_field *copy) |
314 | { |
315 | if (*copy->from_null_ptr & copy->from_bit) |
316 | { |
317 | /* Same as in set_field_to_null_with_conversions() */ |
318 | ((Field_timestamp*) copy->to_field)->set_time(); |
319 | } |
320 | else |
321 | (copy->do_copy2)(copy); |
322 | } |
323 | |
324 | |
325 | static void do_copy_next_number(Copy_field *copy) |
326 | { |
327 | if (*copy->from_null_ptr & copy->from_bit) |
328 | { |
329 | /* Same as in set_field_to_null_with_conversions() */ |
330 | copy->to_field->table->auto_increment_field_not_null= FALSE; |
331 | copy->to_field->reset(); |
332 | } |
333 | else |
334 | (copy->do_copy2)(copy); |
335 | } |
336 | |
337 | |
338 | void Field_blob::do_copy_blob(Copy_field *copy) |
339 | { |
340 | ((Field_blob*) copy->to_field)->copy_value(((Field_blob*) copy->from_field)); |
341 | } |
342 | |
343 | void Field_blob::do_conv_blob(Copy_field *copy) |
344 | { |
345 | copy->from_field->val_str(©->tmp); |
346 | ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), |
347 | copy->tmp.length(), |
348 | copy->tmp.charset()); |
349 | } |
350 | |
351 | /** Save blob in copy->tmp for GROUP BY. */ |
352 | |
353 | static void do_save_blob(Copy_field *copy) |
354 | { |
355 | char buff[MAX_FIELD_WIDTH]; |
356 | String res(buff,sizeof(buff),copy->tmp.charset()); |
357 | copy->from_field->val_str(&res); |
358 | copy->tmp.copy(res); |
359 | ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), |
360 | copy->tmp.length(), |
361 | copy->tmp.charset()); |
362 | } |
363 | |
364 | |
365 | void Field::do_field_string(Copy_field *copy) |
366 | { |
367 | char buff[MAX_FIELD_WIDTH]; |
368 | String res(buff, sizeof(buff), copy->from_field->charset()); |
369 | res.length(0U); |
370 | |
371 | copy->from_field->val_str(&res); |
372 | copy->to_field->store(res.c_ptr_quick(), res.length(), res.charset()); |
373 | } |
374 | |
375 | |
376 | void Field_enum::do_field_enum(Copy_field *copy) |
377 | { |
378 | if (copy->from_field->val_int() == 0) |
379 | ((Field_enum *) copy->to_field)->store_type((ulonglong) 0); |
380 | else |
381 | do_field_string(copy); |
382 | } |
383 | |
384 | |
385 | static void do_field_varbinary_pre50(Copy_field *copy) |
386 | { |
387 | char buff[MAX_FIELD_WIDTH]; |
388 | copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset()); |
389 | copy->from_field->val_str(©->tmp); |
390 | |
391 | /* Use the same function as in 4.1 to trim trailing spaces */ |
392 | size_t length= my_lengthsp_8bit(&my_charset_bin, copy->tmp.c_ptr_quick(), |
393 | copy->from_field->field_length); |
394 | |
395 | copy->to_field->store(copy->tmp.c_ptr_quick(), length, |
396 | copy->tmp.charset()); |
397 | } |
398 | |
399 | |
400 | void Field::do_field_int(Copy_field *copy) |
401 | { |
402 | longlong value= copy->from_field->val_int(); |
403 | copy->to_field->store(value, |
404 | MY_TEST(copy->from_field->flags & UNSIGNED_FLAG)); |
405 | } |
406 | |
407 | void Field::do_field_real(Copy_field *copy) |
408 | { |
409 | double value=copy->from_field->val_real(); |
410 | copy->to_field->store(value); |
411 | } |
412 | |
413 | |
414 | void Field::do_field_decimal(Copy_field *copy) |
415 | { |
416 | my_decimal value; |
417 | copy->to_field->store_decimal(copy->from_field->val_decimal(&value)); |
418 | } |
419 | |
420 | |
421 | void Field::do_field_timestamp(Copy_field *copy) |
422 | { |
423 | // XXX why couldn't we do it everywhere? |
424 | copy->from_field->save_in_field(copy->to_field); |
425 | } |
426 | |
427 | |
428 | void Field::do_field_temporal(Copy_field *copy) |
429 | { |
430 | MYSQL_TIME ltime; |
431 | // TODO: we now need to check result |
432 | if (copy->from_field->get_date(<ime, 0)) |
433 | copy->to_field->reset(); |
434 | else |
435 | copy->to_field->store_time_dec(<ime, copy->from_field->decimals()); |
436 | } |
437 | |
438 | |
439 | void Field_time::do_field_time(Copy_field *copy) |
440 | { |
441 | MYSQL_TIME ltime; |
442 | if (copy->from_field->get_date(<ime, TIME_TIME_ONLY)) |
443 | copy->to_field->reset(); |
444 | else |
445 | copy->to_field->store_time_dec(<ime, copy->from_field->decimals()); |
446 | } |
447 | |
448 | |
449 | /** |
450 | string copy for single byte characters set when to string is shorter than |
451 | from string. |
452 | */ |
453 | |
454 | static void do_cut_string(Copy_field *copy) |
455 | { |
456 | CHARSET_INFO *cs= copy->from_field->charset(); |
457 | memcpy(copy->to_ptr,copy->from_ptr,copy->to_length); |
458 | |
459 | /* Check if we loosed any important characters */ |
460 | if (cs->cset->scan(cs, |
461 | (char*) copy->from_ptr + copy->to_length, |
462 | (char*) copy->from_ptr + copy->from_length, |
463 | MY_SEQ_SPACES) < copy->from_length - copy->to_length) |
464 | { |
465 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
466 | WARN_DATA_TRUNCATED, 1); |
467 | } |
468 | } |
469 | |
470 | |
471 | /** |
472 | string copy for multi byte characters set when to string is shorter than |
473 | from string. |
474 | */ |
475 | |
476 | static void do_cut_string_complex(Copy_field *copy) |
477 | { // Shorter string field |
478 | CHARSET_INFO *cs= copy->from_field->charset(); |
479 | const uchar *from_end= copy->from_ptr + copy->from_length; |
480 | Well_formed_prefix prefix(cs, |
481 | (char*) copy->from_ptr, |
482 | (char*) from_end, |
483 | copy->to_length / cs->mbmaxlen); |
484 | size_t copy_length= prefix.length(); |
485 | if (copy->to_length < copy_length) |
486 | copy_length= copy->to_length; |
487 | memcpy(copy->to_ptr, copy->from_ptr, copy_length); |
488 | |
489 | /* Check if we lost any important characters */ |
490 | if (unlikely(prefix.well_formed_error_pos() || |
491 | cs->cset->scan(cs, (char*) copy->from_ptr + copy_length, |
492 | (char*) from_end, |
493 | MY_SEQ_SPACES) < |
494 | (copy->from_length - copy_length))) |
495 | { |
496 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
497 | WARN_DATA_TRUNCATED, 1); |
498 | } |
499 | |
500 | if (copy_length < copy->to_length) |
501 | cs->cset->fill(cs, (char*) copy->to_ptr + copy_length, |
502 | copy->to_length - copy_length, ' '); |
503 | } |
504 | |
505 | |
506 | |
507 | |
508 | static void do_expand_binary(Copy_field *copy) |
509 | { |
510 | CHARSET_INFO *cs= copy->from_field->charset(); |
511 | memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); |
512 | cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length, |
513 | copy->to_length-copy->from_length, '\0'); |
514 | } |
515 | |
516 | |
517 | |
518 | static void do_expand_string(Copy_field *copy) |
519 | { |
520 | CHARSET_INFO *cs= copy->from_field->charset(); |
521 | memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); |
522 | cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length, |
523 | copy->to_length-copy->from_length, ' '); |
524 | } |
525 | |
526 | |
527 | static void do_varstring1(Copy_field *copy) |
528 | { |
529 | uint length= (uint) *(uchar*) copy->from_ptr; |
530 | if (length > copy->to_length- 1) |
531 | { |
532 | length=copy->to_length - 1; |
533 | if (copy->from_field->table->in_use->count_cuted_fields > |
534 | CHECK_FIELD_EXPRESSION && |
535 | copy->to_field) |
536 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
537 | WARN_DATA_TRUNCATED, 1); |
538 | } |
539 | *(uchar*) copy->to_ptr= (uchar) length; |
540 | memcpy(copy->to_ptr+1, copy->from_ptr + 1, length); |
541 | } |
542 | |
543 | |
544 | static void do_varstring1_mb(Copy_field *copy) |
545 | { |
546 | CHARSET_INFO *cs= copy->from_field->charset(); |
547 | uint from_length= (uint) *(uchar*) copy->from_ptr; |
548 | const uchar *from_ptr= copy->from_ptr + 1; |
549 | uint to_char_length= (copy->to_length - 1) / cs->mbmaxlen; |
550 | Well_formed_prefix prefix(cs, (char*) from_ptr, from_length, to_char_length); |
551 | if (prefix.length() < from_length) |
552 | { |
553 | if (current_thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) |
554 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
555 | WARN_DATA_TRUNCATED, 1); |
556 | } |
557 | *copy->to_ptr= (uchar) prefix.length(); |
558 | memcpy(copy->to_ptr + 1, from_ptr, prefix.length()); |
559 | } |
560 | |
561 | |
562 | static void do_varstring2(Copy_field *copy) |
563 | { |
564 | uint length=uint2korr(copy->from_ptr); |
565 | if (length > copy->to_length- HA_KEY_BLOB_LENGTH) |
566 | { |
567 | length=copy->to_length-HA_KEY_BLOB_LENGTH; |
568 | if (copy->from_field->table->in_use->count_cuted_fields > |
569 | CHECK_FIELD_EXPRESSION && |
570 | copy->to_field) |
571 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
572 | WARN_DATA_TRUNCATED, 1); |
573 | } |
574 | int2store(copy->to_ptr,length); |
575 | memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, copy->from_ptr + HA_KEY_BLOB_LENGTH, |
576 | length); |
577 | } |
578 | |
579 | |
580 | static void do_varstring2_mb(Copy_field *copy) |
581 | { |
582 | CHARSET_INFO *cs= copy->from_field->charset(); |
583 | uint char_length= (copy->to_length - HA_KEY_BLOB_LENGTH) / cs->mbmaxlen; |
584 | uint from_length= uint2korr(copy->from_ptr); |
585 | const uchar *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH; |
586 | Well_formed_prefix prefix(cs, (char*) from_beg, from_length, char_length); |
587 | if (prefix.length() < from_length) |
588 | { |
589 | if (current_thd->count_cuted_fields > CHECK_FIELD_EXPRESSION) |
590 | copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN, |
591 | WARN_DATA_TRUNCATED, 1); |
592 | } |
593 | int2store(copy->to_ptr, prefix.length()); |
594 | memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, prefix.length()); |
595 | } |
596 | |
597 | |
598 | /*************************************************************************** |
599 | ** The different functions that fills in a Copy_field class |
600 | ***************************************************************************/ |
601 | |
602 | /** |
603 | copy of field to maybe null string. |
604 | If field is null then the all bytes are set to 0. |
605 | if field is not null then the first byte is set to 1 and the rest of the |
606 | string is the field value. |
607 | The 'to' buffer should have a size of field->pack_length()+1 |
608 | */ |
609 | |
610 | void Copy_field::set(uchar *to,Field *from) |
611 | { |
612 | from_ptr=from->ptr; |
613 | to_ptr=to; |
614 | from_length=from->pack_length_in_rec(); |
615 | if (from->maybe_null()) |
616 | { |
617 | from_null_ptr=from->null_ptr; |
618 | from_bit= from->null_bit; |
619 | to_ptr[0]= 1; // Null as default value |
620 | to_null_ptr= (uchar*) to_ptr++; |
621 | to_bit= 1; |
622 | if (from->table->maybe_null) |
623 | { |
624 | null_row= &from->table->null_row; |
625 | do_copy= do_outer_field_to_null_str; |
626 | } |
627 | else |
628 | do_copy= do_field_to_null_str; |
629 | } |
630 | else |
631 | { |
632 | to_null_ptr= 0; // For easy debugging |
633 | do_copy= do_field_eq; |
634 | } |
635 | } |
636 | |
637 | |
638 | /* |
639 | To do: |
640 | |
641 | If 'save' is set to true and the 'from' is a blob field, do_copy is set to |
642 | do_save_blob rather than do_conv_blob. The only differences between them |
643 | appears to be: |
644 | |
645 | - do_save_blob allocates and uses an intermediate buffer before calling |
646 | Field_blob::store. Is this in order to trigger the call to |
647 | well_formed_copy_nchars, by changing the pointer copy->tmp.ptr()? |
648 | That call will take place anyway in all known cases. |
649 | */ |
650 | void Copy_field::set(Field *to,Field *from,bool save) |
651 | { |
652 | if (to->type() == MYSQL_TYPE_NULL) |
653 | { |
654 | to_null_ptr=0; // For easy debugging |
655 | to_ptr=0; |
656 | do_copy=do_skip; |
657 | return; |
658 | } |
659 | from_field=from; |
660 | to_field=to; |
661 | from_ptr=from->ptr; |
662 | from_length=from->pack_length_in_rec(); |
663 | to_ptr= to->ptr; |
664 | to_length=to_field->pack_length_in_rec(); |
665 | |
666 | // set up null handling |
667 | from_null_ptr=to_null_ptr=0; |
668 | if (from->maybe_null()) |
669 | { |
670 | from_null_ptr= from->null_ptr; |
671 | from_bit= from->null_bit; |
672 | if (to_field->real_maybe_null()) |
673 | { |
674 | to_null_ptr= to->null_ptr; |
675 | to_bit= to->null_bit; |
676 | if (from_null_ptr) |
677 | do_copy= do_copy_null; |
678 | else |
679 | { |
680 | null_row= &from->table->null_row; |
681 | do_copy= do_outer_field_null; |
682 | } |
683 | } |
684 | else |
685 | { |
686 | if (to_field->type() == MYSQL_TYPE_TIMESTAMP) |
687 | do_copy= do_copy_timestamp; // Automatic timestamp |
688 | else if (to_field == to_field->table->next_number_field) |
689 | do_copy= do_copy_next_number; |
690 | else |
691 | { |
692 | if (!from_null_ptr) |
693 | { |
694 | null_row= &from->table->null_row; |
695 | do_copy= do_copy_nullable_row_to_notnull; |
696 | } |
697 | else |
698 | do_copy= do_copy_not_null; |
699 | } |
700 | } |
701 | } |
702 | else if (to_field->real_maybe_null()) |
703 | { |
704 | to_null_ptr= to->null_ptr; |
705 | to_bit= to->null_bit; |
706 | do_copy= do_copy_maybe_null; |
707 | } |
708 | else |
709 | do_copy=0; |
710 | |
711 | if ((to->flags & BLOB_FLAG) && save) |
712 | do_copy2= do_save_blob; |
713 | else |
714 | do_copy2= to->get_copy_func(from); |
715 | if (!do_copy) // Not null |
716 | do_copy=do_copy2; |
717 | } |
718 | |
719 | |
720 | Field::Copy_func *Field_timestamp::get_copy_func(const Field *from) const |
721 | { |
722 | Field::Copy_func *copy= Field_temporal::get_copy_func(from); |
723 | if (copy == do_field_temporal && from->type() == MYSQL_TYPE_TIMESTAMP) |
724 | return do_field_timestamp; |
725 | else |
726 | return copy; |
727 | } |
728 | |
729 | |
730 | Field::Copy_func *Field_temporal::get_copy_func(const Field *from) const |
731 | { |
732 | /* If types are not 100 % identical then convert trough get_date() */ |
733 | if (from->cmp_type() == REAL_RESULT) |
734 | return do_field_string; // TODO: MDEV-9344 |
735 | if (from->type() == MYSQL_TYPE_YEAR) |
736 | return do_field_string; // TODO: MDEV-9343 |
737 | if (from->type() == MYSQL_TYPE_BIT) |
738 | return do_field_int; |
739 | if (!eq_def(from) || |
740 | (table->in_use->variables.sql_mode & |
741 | (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))) |
742 | return do_field_temporal; |
743 | return get_identical_copy_func(); |
744 | } |
745 | |
746 | |
747 | Field::Copy_func *Field_varstring::get_copy_func(const Field *from) const |
748 | { |
749 | if (from->type() == MYSQL_TYPE_BIT) |
750 | return do_field_int; |
751 | /* |
752 | Detect copy from pre 5.0 varbinary to varbinary as of 5.0 and |
753 | use special copy function that removes trailing spaces and thus |
754 | repairs data. |
755 | */ |
756 | if (from->type() == MYSQL_TYPE_VAR_STRING && !from->has_charset() && |
757 | !Field_varstring::has_charset()) |
758 | return do_field_varbinary_pre50; |
759 | if (Field_varstring::real_type() != from->real_type() || |
760 | Field_varstring::charset() != from->charset() || |
761 | length_bytes != ((const Field_varstring*) from)->length_bytes || |
762 | !compression_method() != !from->compression_method()) |
763 | return do_field_string; |
764 | return length_bytes == 1 ? |
765 | (from->charset()->mbmaxlen == 1 ? do_varstring1 : do_varstring1_mb) : |
766 | (from->charset()->mbmaxlen == 1 ? do_varstring2 : do_varstring2_mb); |
767 | } |
768 | |
769 | |
770 | Field::Copy_func *Field_string::get_copy_func(const Field *from) const |
771 | { |
772 | if (from->type() == MYSQL_TYPE_BIT) |
773 | return do_field_int; |
774 | if (Field_string::real_type() != from->real_type() || |
775 | Field_string::charset() != from->charset()) |
776 | return do_field_string; |
777 | if (Field_string::pack_length() < from->pack_length()) |
778 | return (Field_string::charset()->mbmaxlen == 1 ? |
779 | do_cut_string : do_cut_string_complex); |
780 | if (Field_string::pack_length() > from->pack_length()) |
781 | return Field_string::charset() == &my_charset_bin ? do_expand_binary : |
782 | do_expand_string; |
783 | return get_identical_copy_func(); |
784 | } |
785 | |
786 | |
787 | Field::Copy_func *Field::get_identical_copy_func() const |
788 | { |
789 | /* Identical field types */ |
790 | switch (pack_length()) { |
791 | case 1: return do_field_1; |
792 | case 2: return do_field_2; |
793 | case 3: return do_field_3; |
794 | case 4: return do_field_4; |
795 | case 6: return do_field_6; |
796 | case 8: return do_field_8; |
797 | } |
798 | return do_field_eq; |
799 | } |
800 | |
801 | |
802 | bool Field_temporal::memcpy_field_possible(const Field *from) const |
803 | { |
804 | return real_type() == from->real_type() && |
805 | decimals() == from->decimals() && |
806 | !sql_mode_for_dates(table->in_use); |
807 | } |
808 | |
809 | |
810 | static int field_conv_memcpy(Field *to, Field *from) |
811 | { |
812 | /* |
813 | This may happen if one does 'UPDATE ... SET x=x' |
814 | The test is here mostly for valgrind, but can also be relevant |
815 | if memcpy() is implemented with prefetch-write |
816 | */ |
817 | if (to->ptr != from->ptr) |
818 | memcpy(to->ptr,from->ptr, to->pack_length()); |
819 | return 0; |
820 | } |
821 | |
822 | |
823 | /** |
824 | Copy value of the field with conversion. |
825 | |
826 | @note Impossibility of simple copy should be checked before this call. |
827 | |
828 | @param to The field to copy to |
829 | |
830 | @retval TRUE ERROR |
831 | @retval FALSE OK |
832 | |
833 | */ |
834 | static int field_conv_incompatible(Field *to, Field *from) |
835 | { |
836 | return to->store_field(from); |
837 | } |
838 | |
839 | |
840 | /** |
841 | Simple quick field converter that is called on insert, e.g.: |
842 | INSERT INTO t1 (field1) SELECT field2 FROM t2; |
843 | */ |
844 | |
845 | int field_conv(Field *to,Field *from) |
846 | { |
847 | return to->memcpy_field_possible(from) ? |
848 | field_conv_memcpy(to, from) : |
849 | field_conv_incompatible(to, from); |
850 | } |
851 | |
852 | |
853 | fast_field_copier Field::get_fast_field_copier(const Field *from) |
854 | { |
855 | DBUG_ENTER("Field::get_fast_field_copier" ); |
856 | DBUG_RETURN(memcpy_field_possible(from) ? |
857 | &field_conv_memcpy : |
858 | &field_conv_incompatible); |
859 | } |
860 | |