~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2003 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
17
/**
18
  @file
19
20
  @brief
21
  Functions to copy data to or from fields
22
23
    This could be done with a single short function but opencoding this
24
    gives much more speed.
25
*/
26
27
#include "mysql_priv.h"
28
#include <m_ctype.h>
29
30
static void do_field_eq(Copy_field *copy)
31
{
32
  memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
33
}
34
35
static void do_field_1(Copy_field *copy)
36
{
37
  copy->to_ptr[0]=copy->from_ptr[0];
38
}
39
40
static void do_field_2(Copy_field *copy)
41
{
42
  copy->to_ptr[0]=copy->from_ptr[0];
43
  copy->to_ptr[1]=copy->from_ptr[1];
44
}
45
46
static void do_field_3(Copy_field *copy)
47
{
48
  copy->to_ptr[0]=copy->from_ptr[0];
49
  copy->to_ptr[1]=copy->from_ptr[1];
50
  copy->to_ptr[2]=copy->from_ptr[2];
51
}
52
53
static void do_field_4(Copy_field *copy)
54
{
55
  copy->to_ptr[0]=copy->from_ptr[0];
56
  copy->to_ptr[1]=copy->from_ptr[1];
57
  copy->to_ptr[2]=copy->from_ptr[2];
58
  copy->to_ptr[3]=copy->from_ptr[3];
59
}
60
61
static void do_field_6(Copy_field *copy)
62
{						// For blob field
63
  copy->to_ptr[0]=copy->from_ptr[0];
64
  copy->to_ptr[1]=copy->from_ptr[1];
65
  copy->to_ptr[2]=copy->from_ptr[2];
66
  copy->to_ptr[3]=copy->from_ptr[3];
67
  copy->to_ptr[4]=copy->from_ptr[4];
68
  copy->to_ptr[5]=copy->from_ptr[5];
69
}
70
71
static void do_field_8(Copy_field *copy)
72
{
73
  copy->to_ptr[0]=copy->from_ptr[0];
74
  copy->to_ptr[1]=copy->from_ptr[1];
75
  copy->to_ptr[2]=copy->from_ptr[2];
76
  copy->to_ptr[3]=copy->from_ptr[3];
77
  copy->to_ptr[4]=copy->from_ptr[4];
78
  copy->to_ptr[5]=copy->from_ptr[5];
79
  copy->to_ptr[6]=copy->from_ptr[6];
80
  copy->to_ptr[7]=copy->from_ptr[7];
81
}
82
83
84
static void do_field_to_null_str(Copy_field *copy)
85
{
86
  if (*copy->from_null_ptr & copy->from_bit)
87
  {
88
    bzero(copy->to_ptr,copy->from_length);
89
    copy->to_null_ptr[0]=1;			// Always bit 1
90
  }
91
  else
92
  {
93
    copy->to_null_ptr[0]=0;
94
    memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
95
  }
96
}
97
98
99
static void do_outer_field_to_null_str(Copy_field *copy)
100
{
101
  if (*copy->null_row ||
102
      (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
103
  {
104
    bzero(copy->to_ptr,copy->from_length);
105
    copy->to_null_ptr[0]=1;			// Always bit 1
106
  }
107
  else
108
  {
109
    copy->to_null_ptr[0]=0;
110
    memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
111
  }
112
}
113
114
115
int
116
set_field_to_null(Field *field)
117
{
118
  if (field->real_maybe_null())
119
  {
120
    field->set_null();
121
    field->reset();
122
    return 0;
123
  }
124
  field->reset();
125
  if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN)
126
  {
127
    field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
128
    return 0;
129
  }
130
  if (!field->table->in_use->no_errors)
131
    my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
132
  return -1;
133
}
134
135
136
/**
137
  Set field to NULL or TIMESTAMP or to next auto_increment number.
138
139
  @param field           Field to update
140
  @param no_conversions  Set to 1 if we should return 1 if field can't
141
                         take null values.
142
                         If set to 0 we will do store the 'default value'
143
                         if the field is a special field. If not we will
144
                         give an error.
145
146
  @retval
147
    0    Field could take 0 or an automatic conversion was used
148
  @retval
149
    -1   Field could not take NULL and no conversion was used.
150
    If no_conversion was not set, an error message is printed
151
*/
152
153
int
154
set_field_to_null_with_conversions(Field *field, bool no_conversions)
155
{
156
  if (field->real_maybe_null())
157
  {
158
    field->set_null();
159
    field->reset();
160
    return 0;
161
  }
162
  if (no_conversions)
163
    return -1;
164
165
  /*
166
    Check if this is a special type, which will get a special walue
167
    when set to NULL (TIMESTAMP fields which allow setting to NULL
168
    are handled by first check).
169
  */
170
  if (field->type() == MYSQL_TYPE_TIMESTAMP)
171
  {
172
    ((Field_timestamp*) field)->set_time();
173
    return 0;					// Ok to set time to NULL
174
  }
175
  field->reset();
176
  if (field == field->table->next_number_field)
177
  {
178
    field->table->auto_increment_field_not_null= FALSE;
179
    return 0;				  // field is set in fill_record()
180
  }
181
  if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN)
182
  {
183
    field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1);
184
    return 0;
185
  }
186
  if (!field->table->in_use->no_errors)
187
    my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
188
  return -1;
189
}
190
191
192
static void do_skip(Copy_field *copy __attribute__((unused)))
193
{
194
}
195
196
197
static void do_copy_null(Copy_field *copy)
198
{
199
  if (*copy->from_null_ptr & copy->from_bit)
200
  {
201
    *copy->to_null_ptr|=copy->to_bit;
202
    copy->to_field->reset();
203
  }
204
  else
205
  {
206
    *copy->to_null_ptr&= ~copy->to_bit;
207
    (copy->do_copy2)(copy);
208
  }
209
}
210
211
212
static void do_outer_field_null(Copy_field *copy)
213
{
214
  if (*copy->null_row ||
215
      (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
216
  {
217
    *copy->to_null_ptr|=copy->to_bit;
218
    copy->to_field->reset();
219
  }
220
  else
221
  {
222
    *copy->to_null_ptr&= ~copy->to_bit;
223
    (copy->do_copy2)(copy);
224
  }
225
}
226
227
228
static void do_copy_not_null(Copy_field *copy)
229
{
230
  if (*copy->from_null_ptr & copy->from_bit)
231
  {
232
    copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
233
                                WARN_DATA_TRUNCATED, 1);
234
    copy->to_field->reset();
235
  }
236
  else
237
    (copy->do_copy2)(copy);
238
}
239
240
241
static void do_copy_maybe_null(Copy_field *copy)
242
{
243
  *copy->to_null_ptr&= ~copy->to_bit;
244
  (copy->do_copy2)(copy);
245
}
246
247
/* timestamp and next_number has special handling in case of NULL values */
248
249
static void do_copy_timestamp(Copy_field *copy)
250
{
251
  if (*copy->from_null_ptr & copy->from_bit)
252
  {
253
    /* Same as in set_field_to_null_with_conversions() */
254
    ((Field_timestamp*) copy->to_field)->set_time();
255
  }
256
  else
257
    (copy->do_copy2)(copy);
258
}
259
260
261
static void do_copy_next_number(Copy_field *copy)
262
{
263
  if (*copy->from_null_ptr & copy->from_bit)
264
  {
265
    /* Same as in set_field_to_null_with_conversions() */
266
    copy->to_field->table->auto_increment_field_not_null= FALSE;
267
    copy->to_field->reset();
268
  }
269
  else
270
    (copy->do_copy2)(copy);
271
}
272
273
274
static void do_copy_blob(Copy_field *copy)
275
{
276
  ulong length=((Field_blob*) copy->from_field)->get_length();
277
  ((Field_blob*) copy->to_field)->store_length(length);
278
  memcpy_fixed(copy->to_ptr,copy->from_ptr,sizeof(char*));
279
}
280
281
static void do_conv_blob(Copy_field *copy)
282
{
283
  copy->from_field->val_str(&copy->tmp);
284
  ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
285
					 copy->tmp.length(),
286
					 copy->tmp.charset());
287
}
288
289
/** Save blob in copy->tmp for GROUP BY. */
290
291
static void do_save_blob(Copy_field *copy)
292
{
293
  char buff[MAX_FIELD_WIDTH];
294
  String res(buff,sizeof(buff),copy->tmp.charset());
295
  copy->from_field->val_str(&res);
296
  copy->tmp.copy(res);
297
  ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
298
					 copy->tmp.length(),
299
					 copy->tmp.charset());
300
}
301
302
303
static void do_field_string(Copy_field *copy)
304
{
305
  char buff[MAX_FIELD_WIDTH];
306
  copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset());
307
  copy->from_field->val_str(&copy->tmp);
308
  copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),
309
                        copy->tmp.charset());
310
}
311
312
313
static void do_field_enum(Copy_field *copy)
314
{
315
  if (copy->from_field->val_int() == 0)
316
    ((Field_enum *) copy->to_field)->store_type((ulonglong) 0);
317
  else
318
    do_field_string(copy);
319
}
320
321
322
static void do_field_varbinary_pre50(Copy_field *copy)
323
{
324
  char buff[MAX_FIELD_WIDTH];
325
  copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset());
326
  copy->from_field->val_str(&copy->tmp);
327
328
  /* Use the same function as in 4.1 to trim trailing spaces */
329
  uint length= my_lengthsp_8bit(&my_charset_bin, copy->tmp.c_ptr_quick(),
330
                                copy->from_field->field_length);
331
332
  copy->to_field->store(copy->tmp.c_ptr_quick(), length,
333
                        copy->tmp.charset());
334
}
335
336
337
static void do_field_int(Copy_field *copy)
338
{
339
  longlong value= copy->from_field->val_int();
340
  copy->to_field->store(value,
341
                        test(copy->from_field->flags & UNSIGNED_FLAG));
342
}
343
344
static void do_field_real(Copy_field *copy)
345
{
346
  double value=copy->from_field->val_real();
347
  copy->to_field->store(value);
348
}
349
350
351
static void do_field_decimal(Copy_field *copy)
352
{
353
  my_decimal value;
354
  copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
355
}
356
357
358
/**
359
  string copy for single byte characters set when to string is shorter than
360
  from string.
361
*/
362
363
static void do_cut_string(Copy_field *copy)
364
{
365
  CHARSET_INFO *cs= copy->from_field->charset();
366
  memcpy(copy->to_ptr,copy->from_ptr,copy->to_length);
367
368
  /* Check if we loosed any important characters */
369
  if (cs->cset->scan(cs,
370
                     (char*) copy->from_ptr + copy->to_length,
371
                     (char*) copy->from_ptr + copy->from_length,
372
                     MY_SEQ_SPACES) < copy->from_length - copy->to_length)
373
  {
374
    copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
375
                                WARN_DATA_TRUNCATED, 1);
376
  }
377
}
378
379
380
/**
381
  string copy for multi byte characters set when to string is shorter than
382
  from string.
383
*/
384
385
static void do_cut_string_complex(Copy_field *copy)
386
{						// Shorter string field
387
  int well_formed_error;
388
  CHARSET_INFO *cs= copy->from_field->charset();
389
  const uchar *from_end= copy->from_ptr + copy->from_length;
390
  uint copy_length= cs->cset->well_formed_len(cs,
391
                                              (char*) copy->from_ptr,
392
                                              (char*) from_end, 
393
                                              copy->to_length / cs->mbmaxlen,
394
                                              &well_formed_error);
395
  if (copy->to_length < copy_length)
396
    copy_length= copy->to_length;
397
  memcpy(copy->to_ptr, copy->from_ptr, copy_length);
398
399
  /* Check if we lost any important characters */
400
  if (well_formed_error ||
401
      cs->cset->scan(cs, (char*) copy->from_ptr + copy_length,
402
                     (char*) from_end,
403
                     MY_SEQ_SPACES) < (copy->from_length - copy_length))
404
  {
405
    copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
406
                                WARN_DATA_TRUNCATED, 1);
407
  }
408
409
  if (copy_length < copy->to_length)
410
    cs->cset->fill(cs, (char*) copy->to_ptr + copy_length,
411
                   copy->to_length - copy_length, ' ');
412
}
413
414
415
416
417
static void do_expand_binary(Copy_field *copy)
418
{
419
  CHARSET_INFO *cs= copy->from_field->charset();
420
  memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
421
  cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
422
                     copy->to_length-copy->from_length, '\0');
423
}
424
425
426
427
static void do_expand_string(Copy_field *copy)
428
{
429
  CHARSET_INFO *cs= copy->from_field->charset();
430
  memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
431
  cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
432
                     copy->to_length-copy->from_length, ' ');
433
}
434
435
436
static void do_varstring1(Copy_field *copy)
437
{
438
  uint length= (uint) *(uchar*) copy->from_ptr;
439
  if (length > copy->to_length- 1)
440
  {
441
    length=copy->to_length - 1;
442
    if (copy->from_field->table->in_use->count_cuted_fields)
443
      copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
444
                                  WARN_DATA_TRUNCATED, 1);
445
  }
446
  *(uchar*) copy->to_ptr= (uchar) length;
447
  memcpy(copy->to_ptr+1, copy->from_ptr + 1, length);
448
}
449
450
451
static void do_varstring1_mb(Copy_field *copy)
452
{
453
  int well_formed_error;
454
  CHARSET_INFO *cs= copy->from_field->charset();
455
  uint from_length= (uint) *(uchar*) copy->from_ptr;
456
  const uchar *from_ptr= copy->from_ptr + 1;
457
  uint to_char_length= (copy->to_length - 1) / cs->mbmaxlen;
458
  uint length= cs->cset->well_formed_len(cs, (char*) from_ptr,
459
                                         (char*) from_ptr + from_length,
460
                                         to_char_length, &well_formed_error);
461
  if (length < from_length)
462
  {
463
    if (current_thd->count_cuted_fields)
464
      copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
465
                                  WARN_DATA_TRUNCATED, 1);
466
  }
467
  *copy->to_ptr= (uchar) length;
468
  memcpy(copy->to_ptr + 1, from_ptr, length);
469
}
470
471
472
static void do_varstring2(Copy_field *copy)
473
{
474
  uint length=uint2korr(copy->from_ptr);
475
  if (length > copy->to_length- HA_KEY_BLOB_LENGTH)
476
  {
477
    length=copy->to_length-HA_KEY_BLOB_LENGTH;
478
    if (copy->from_field->table->in_use->count_cuted_fields)
479
      copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
480
                                  WARN_DATA_TRUNCATED, 1);
481
  }
482
  int2store(copy->to_ptr,length);
483
  memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, copy->from_ptr + HA_KEY_BLOB_LENGTH,
484
         length);
485
}
486
487
488
static void do_varstring2_mb(Copy_field *copy)
489
{
490
  int well_formed_error;
491
  CHARSET_INFO *cs= copy->from_field->charset();
492
  uint char_length= (copy->to_length - HA_KEY_BLOB_LENGTH) / cs->mbmaxlen;
493
  uint from_length= uint2korr(copy->from_ptr);
494
  const uchar *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
495
  uint length= cs->cset->well_formed_len(cs, (char*) from_beg,
496
                                         (char*) from_beg + from_length,
497
                                         char_length, &well_formed_error);
498
  if (length < from_length)
499
  {
500
    if (current_thd->count_cuted_fields)
501
      copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
502
                                  WARN_DATA_TRUNCATED, 1);
503
  }  
504
  int2store(copy->to_ptr, length);
505
  memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, length);
506
}
507
 
508
509
/***************************************************************************
510
** The different functions that fills in a Copy_field class
511
***************************************************************************/
512
513
/**
514
  copy of field to maybe null string.
515
  If field is null then the all bytes are set to 0.
516
  if field is not null then the first byte is set to 1 and the rest of the
517
  string is the field value.
518
  The 'to' buffer should have a size of field->pack_length()+1
519
*/
520
521
void Copy_field::set(uchar *to,Field *from)
522
{
523
  from_ptr=from->ptr;
524
  to_ptr=to;
525
  from_length=from->pack_length();
526
  if (from->maybe_null())
527
  {
528
    from_null_ptr=from->null_ptr;
529
    from_bit=	  from->null_bit;
530
    to_ptr[0]=	  1;				// Null as default value
531
    to_null_ptr=  (uchar*) to_ptr++;
532
    to_bit=	  1;
533
    if (from->table->maybe_null)
534
    {
535
      null_row=   &from->table->null_row;
536
      do_copy=	  do_outer_field_to_null_str;
537
    }
538
    else
539
      do_copy=	  do_field_to_null_str;
540
  }
541
  else
542
  {
543
    to_null_ptr=  0;				// For easy debugging
544
    do_copy=	  do_field_eq;
545
  }
546
}
547
548
549
/*
550
  To do: 
551
552
  If 'save\ is set to true and the 'from' is a blob field, do_copy is set to
553
  do_save_blob rather than do_conv_blob.  The only differences between them
554
  appears to be:
555
556
  - do_save_blob allocates and uses an intermediate buffer before calling 
557
    Field_blob::store. Is this in order to trigger the call to 
558
    well_formed_copy_nchars, by changing the pointer copy->tmp.ptr()?
559
    That call will take place anyway in all known cases.
560
561
  - The above causes a truncation to MAX_FIELD_WIDTH. Is this the intended 
562
    effect? Truncation is handled by well_formed_copy_nchars anyway.
563
 */
564
void Copy_field::set(Field *to,Field *from,bool save)
565
{
566
  if (to->type() == MYSQL_TYPE_NULL)
567
  {
568
    to_null_ptr=0;				// For easy debugging
569
    to_ptr=0;
570
    do_copy=do_skip;
571
    return;
572
  }
573
  from_field=from;
574
  to_field=to;
575
  from_ptr=from->ptr;
576
  from_length=from->pack_length();
577
  to_ptr=  to->ptr;
578
  to_length=to_field->pack_length();
579
580
  // set up null handling
581
  from_null_ptr=to_null_ptr=0;
582
  if (from->maybe_null())
583
  {
584
    from_null_ptr=	from->null_ptr;
585
    from_bit=		from->null_bit;
586
    if (to_field->real_maybe_null())
587
    {
588
      to_null_ptr=	to->null_ptr;
589
      to_bit=		to->null_bit;
590
      if (from_null_ptr)
591
	do_copy=	do_copy_null;
592
      else
593
      {
594
	null_row=	&from->table->null_row;
595
	do_copy=	do_outer_field_null;
596
      }
597
    }
598
    else
599
    {
600
      if (to_field->type() == MYSQL_TYPE_TIMESTAMP)
601
        do_copy= do_copy_timestamp;               // Automatic timestamp
602
      else if (to_field == to_field->table->next_number_field)
603
        do_copy= do_copy_next_number;
604
      else
605
        do_copy= do_copy_not_null;
606
    }
607
  }
608
  else if (to_field->real_maybe_null())
609
  {
610
    to_null_ptr=	to->null_ptr;
611
    to_bit=		to->null_bit;
612
    do_copy= do_copy_maybe_null;
613
  }
614
  else
615
   do_copy=0;
616
617
  if ((to->flags & BLOB_FLAG) && save)
618
    do_copy2= do_save_blob;
619
  else
620
    do_copy2= get_copy_func(to,from);
621
  if (!do_copy)					// Not null
622
    do_copy=do_copy2;
623
}
624
625
626
Copy_field::Copy_func *
627
Copy_field::get_copy_func(Field *to,Field *from)
628
{
629
  bool compatible_db_low_byte_first= (to->table->s->db_low_byte_first ==
630
                                     from->table->s->db_low_byte_first);
631
  if (to->flags & BLOB_FLAG)
632
  {
633
    if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
634
      return do_conv_blob;
635
    if (from_length != to_length || !compatible_db_low_byte_first)
636
    {
637
      // Correct pointer to point at char pointer
638
      to_ptr+=   to_length - to->table->s->blob_ptr_size;
639
      from_ptr+= from_length- from->table->s->blob_ptr_size;
640
      return do_copy_blob;
641
    }
642
  }
643
  else
644
  {
645
    if (to->real_type() == MYSQL_TYPE_BIT ||
646
        from->real_type() == MYSQL_TYPE_BIT)
647
      return do_field_int;
648
    if (to->result_type() == DECIMAL_RESULT)
649
      return do_field_decimal;
650
    // Check if identical fields
651
    if (from->result_type() == STRING_RESULT)
652
    {
653
      /*
654
        Detect copy from pre 5.0 varbinary to varbinary as of 5.0 and
655
        use special copy function that removes trailing spaces and thus
656
        repairs data.
657
      */
658
      if (from->type() == MYSQL_TYPE_VAR_STRING && !from->has_charset() &&
659
          to->type() == MYSQL_TYPE_VARCHAR && !to->has_charset())
660
        return do_field_varbinary_pre50;
661
662
      /*
663
        If we are copying date or datetime's we have to check the dates
664
        if we don't allow 'all' dates.
665
      */
666
      if (to->real_type() != from->real_type() ||
667
          !compatible_db_low_byte_first ||
668
          (((to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) && to->type() == MYSQL_TYPE_DATE) || to->type() == MYSQL_TYPE_DATETIME))
669
      {
670
	if (from->real_type() == MYSQL_TYPE_ENUM ||
671
	    from->real_type() == MYSQL_TYPE_SET)
672
	  if (to->result_type() != STRING_RESULT)
673
	    return do_field_int;		// Convert SET to number
674
	return do_field_string;
675
      }
676
      if (to->real_type() == MYSQL_TYPE_ENUM ||
677
	  to->real_type() == MYSQL_TYPE_SET)
678
      {
679
	if (!to->eq_def(from))
680
        {
681
          if (from->real_type() == MYSQL_TYPE_ENUM &&
682
              to->real_type() == MYSQL_TYPE_ENUM)
683
            return do_field_enum;
684
          else
685
            return do_field_string;
686
        }
687
      }
688
      else if (to->charset() != from->charset())
689
	return do_field_string;
690
      else if (to->real_type() == MYSQL_TYPE_VARCHAR)
691
      {
692
        if (((Field_varstring*) to)->length_bytes !=
693
            ((Field_varstring*) from)->length_bytes)
694
          return do_field_string;
695
        if (to_length != from_length)
696
          return (((Field_varstring*) to)->length_bytes == 1 ?
697
                  (from->charset()->mbmaxlen == 1 ? do_varstring1 :
698
                                                    do_varstring1_mb) :
699
                  (from->charset()->mbmaxlen == 1 ? do_varstring2 :
700
                                                    do_varstring2_mb));
701
      }
702
      else if (to_length < from_length)
703
	return (from->charset()->mbmaxlen == 1 ?
704
                do_cut_string : do_cut_string_complex);
705
      else if (to_length > from_length)
706
      {
707
        if (to->charset() == &my_charset_bin)
708
          return do_expand_binary;
709
        else
710
          return do_expand_string;
711
      }
712
713
    }
714
    else if (to->real_type() != from->real_type() ||
715
	     to_length != from_length ||
716
             !compatible_db_low_byte_first)
717
    {
718
      if (to->real_type() == MYSQL_TYPE_DECIMAL ||
719
	  to->result_type() == STRING_RESULT)
720
	return do_field_string;
721
      if (to->result_type() == INT_RESULT)
722
	return do_field_int;
723
      return do_field_real;
724
    }
725
    else
726
    {
727
      if (!to->eq_def(from) || !compatible_db_low_byte_first)
728
      {
729
	if (to->real_type() == MYSQL_TYPE_DECIMAL)
730
	  return do_field_string;
731
	if (to->result_type() == INT_RESULT)
732
	  return do_field_int;
733
	else
734
	  return do_field_real;
735
      }
736
    }
737
  }
738
    /* Eq fields */
739
  switch (to_length) {
740
  case 1: return do_field_1;
741
  case 2: return do_field_2;
742
  case 3: return do_field_3;
743
  case 4: return do_field_4;
744
  case 6: return do_field_6;
745
  case 8: return do_field_8;
746
  }
747
  return do_field_eq;
748
}
749
750
751
/** Simple quick field convert that is called on insert. */
752
753
int field_conv(Field *to,Field *from)
754
{
755
  if (to->real_type() == from->real_type() &&
756
      !(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs))
757
  {
758
    /* Please god, will someone rewrite this to be readable :( */
759
    if (to->pack_length() == from->pack_length() && 
760
        !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && 
761
        to->real_type() != MYSQL_TYPE_ENUM && 
762
        to->real_type() != MYSQL_TYPE_SET && to->real_type() != MYSQL_TYPE_BIT &&
763
        (to->real_type() != MYSQL_TYPE_NEWDECIMAL || (to->field_length == from->field_length && (((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
764
        from->charset() == to->charset() &&
765
	to->table->s->db_low_byte_first == from->table->s->db_low_byte_first &&
766
        (!(to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || (to->type() != MYSQL_TYPE_DATE && to->type() != MYSQL_TYPE_DATETIME)) && 
767
        (from->real_type() != MYSQL_TYPE_VARCHAR || ((Field_varstring*)from)->length_bytes == ((Field_varstring*)to)->length_bytes))
768
    {						// Identical fields
769
#ifdef HAVE_purify
770
      /* This may happen if one does 'UPDATE ... SET x=x' */
771
      if (to->ptr != from->ptr)
772
#endif
773
        memcpy(to->ptr,from->ptr,to->pack_length());
774
      return 0;
775
    }
776
  }
777
  if (to->type() == MYSQL_TYPE_BLOB)
778
  {						// Be sure the value is stored
779
    Field_blob *blob=(Field_blob*) to;
780
    from->val_str(&blob->value);
781
    /*
782
      Copy value if copy_blobs is set, or source is not a string and
783
      we have a pointer to its internal string conversion buffer.
784
    */
785
    if (to->table->copy_blobs ||
786
        (!blob->value.is_alloced() &&
787
         from->real_type() != MYSQL_TYPE_STRING &&
788
         from->real_type() != MYSQL_TYPE_VARCHAR))
789
      blob->value.copy();
790
    return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
791
  }
792
  if (from->real_type() == MYSQL_TYPE_ENUM &&
793
      to->real_type() == MYSQL_TYPE_ENUM &&
794
      from->val_int() == 0)
795
  {
796
    ((Field_enum *)(to))->store_type(0);
797
    return 0;
798
  }
799
  else if ((from->result_type() == STRING_RESULT &&
800
            (to->result_type() == STRING_RESULT ||
801
             (from->real_type() != MYSQL_TYPE_ENUM &&
802
              from->real_type() != MYSQL_TYPE_SET))) ||
803
           to->type() == MYSQL_TYPE_DECIMAL)
804
  {
805
    char buff[MAX_FIELD_WIDTH];
806
    String result(buff,sizeof(buff),from->charset());
807
    from->val_str(&result);
808
    /*
809
      We use c_ptr_quick() here to make it easier if to is a float/double
810
      as the conversion routines will do a copy of the result doesn't
811
      end with \0. Can be replaced with .ptr() when we have our own
812
      string->double conversion.
813
    */
814
    return to->store(result.c_ptr_quick(),result.length(),from->charset());
815
  }
816
  else if (from->result_type() == REAL_RESULT)
817
    return to->store(from->val_real());
818
  else if (from->result_type() == DECIMAL_RESULT)
819
  {
820
    my_decimal buff;
821
    return to->store_decimal(from->val_decimal(&buff));
822
  }
823
  else
824
    return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
825
}