~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/param.cc

  • Committer: Brian Aker
  • Date: 2009-07-11 19:23:04 UTC
  • mfrom: (1089.1.14 merge)
  • Revision ID: brian@gaz-20090711192304-ootijyl5yf9jq9kd
Merge Brian

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program 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
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include <drizzled/server_includes.h>
 
21
#include <drizzled/session.h>
 
22
#include <drizzled/item/uint.h>
 
23
#include <drizzled/item/null.h>
 
24
#include <drizzled/item/float.h>
 
25
#include <drizzled/item/param.h>
 
26
#include <drizzled/sql_string.h>
 
27
#include <drizzled/util/convert.h>
 
28
#include <mystrings/utf8.h>
 
29
 
 
30
Item *Item_param::safe_charset_converter(const CHARSET_INFO * const tocs)
 
31
{
 
32
  if (const_item())
 
33
  {
 
34
    uint32_t cnv_errors;
 
35
    String *ostr= val_str(&cnvstr);
 
36
    cnvitem->str_value.copy(ostr->ptr(), ostr->length(),
 
37
                            ostr->charset(), tocs, &cnv_errors);
 
38
    if (cnv_errors)
 
39
       return NULL;
 
40
    cnvitem->str_value.mark_as_const();
 
41
    cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen;
 
42
    return cnvitem;
 
43
  }
 
44
  return NULL;
 
45
}
 
46
 
 
47
/**
 
48
  Default function of Item_param::set_param_func, so in case
 
49
  of malformed packet the server won't SIGSEGV.
 
50
*/
 
51
 
 
52
static void
 
53
default_set_param_func(Item_param *param, unsigned char **, ulong)
 
54
{
 
55
  param->set_null();
 
56
}
 
57
 
 
58
Item_param::Item_param(uint32_t pos_in_query_arg) :
 
59
  state(NO_VALUE),
 
60
  item_result_type(STRING_RESULT),
 
61
  /* Don't pretend to be a literal unless value for this item is set. */
 
62
  item_type(PARAM_ITEM),
 
63
  param_type(DRIZZLE_TYPE_VARCHAR),
 
64
  pos_in_query(pos_in_query_arg),
 
65
  set_param_func(default_set_param_func),
 
66
  limit_clause_param(false)
 
67
{
 
68
  name= (char*) "?";
 
69
  /*
 
70
    Since we can't say whenever this item can be NULL or cannot be NULL
 
71
    before mysql_stmt_execute(), so we assuming that it can be NULL until
 
72
    value is set.
 
73
  */
 
74
  maybe_null= 1;
 
75
  cnvitem= new Item_string("", 0, &my_charset_bin, DERIVATION_COERCIBLE);
 
76
  cnvstr.set(cnvbuf, sizeof(cnvbuf), &my_charset_bin);
 
77
}
 
78
 
 
79
void Item_param::set_null()
 
80
{
 
81
  /* These are cleared after each execution by reset() method */
 
82
  null_value= 1;
 
83
  /*
 
84
    Because of NULL and string values we need to set max_length for each new
 
85
    placeholder value: user can submit NULL for any placeholder type, and
 
86
    string length can be different in each execution.
 
87
  */
 
88
  max_length= 0;
 
89
  decimals= 0;
 
90
  state= NULL_VALUE;
 
91
  item_type= Item::NULL_ITEM;
 
92
  return;
 
93
}
 
94
 
 
95
void Item_param::set_int(int64_t i, uint32_t max_length_arg)
 
96
{
 
97
  value.integer= (int64_t) i;
 
98
  state= INT_VALUE;
 
99
  max_length= max_length_arg;
 
100
  decimals= 0;
 
101
  maybe_null= 0;
 
102
  return;
 
103
}
 
104
 
 
105
void Item_param::set_double(double d)
 
106
{
 
107
  value.real= d;
 
108
  state= REAL_VALUE;
 
109
  max_length= DBL_DIG + 8;
 
110
  decimals= NOT_FIXED_DEC;
 
111
  maybe_null= 0;
 
112
  return;
 
113
}
 
114
 
 
115
/**
 
116
  Set decimal parameter value from string.
 
117
 
 
118
  @param str      character string
 
119
  @param length   string length
 
120
 
 
121
  @note
 
122
    As we use character strings to send decimal values in
 
123
    binary protocol, we use str2my_decimal to convert it to
 
124
    internal decimal value.
 
125
*/
 
126
 
 
127
void Item_param::set_decimal(char *str, ulong length)
 
128
{
 
129
  char *end;
 
130
 
 
131
  end= str+length;
 
132
  str2my_decimal((uint32_t)E_DEC_FATAL_ERROR, str, &decimal_value, &end);
 
133
  state= DECIMAL_VALUE;
 
134
  decimals= decimal_value.frac;
 
135
  max_length= my_decimal_precision_to_length(decimal_value.precision(),
 
136
                                             decimals, unsigned_flag);
 
137
  maybe_null= 0;
 
138
  return;
 
139
}
 
140
 
 
141
/**
 
142
  Set parameter value from DRIZZLE_TIME value.
 
143
 
 
144
  @param tm              datetime value to set (time_type is ignored)
 
145
  @param type            type of datetime value
 
146
  @param max_length_arg  max length of datetime value as string
 
147
 
 
148
  @note
 
149
    If we value to be stored is not normalized, zero value will be stored
 
150
    instead and proper warning will be produced. This function relies on
 
151
    the fact that even wrong value sent over binary protocol fits into
 
152
    MAX_DATE_STRING_REP_LENGTH buffer.
 
153
*/
 
154
void Item_param::set_time(DRIZZLE_TIME *tm,
 
155
                          enum enum_drizzle_timestamp_type time_type,
 
156
                          uint32_t max_length_arg)
 
157
{
 
158
  value.time= *tm;
 
159
  value.time.time_type= time_type;
 
160
 
 
161
  if (value.time.year > 9999 || value.time.month > 12 ||
 
162
      value.time.day > 31 ||
 
163
      ((time_type != DRIZZLE_TIMESTAMP_TIME) && value.time.hour > 23) ||
 
164
      value.time.minute > 59 || value.time.second > 59)
 
165
  {
 
166
    char buff[MAX_DATE_STRING_REP_LENGTH];
 
167
    uint32_t length= my_TIME_to_str(&value.time, buff);
 
168
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
169
                                 buff, length, time_type, 0);
 
170
    set_zero_time(&value.time, DRIZZLE_TIMESTAMP_ERROR);
 
171
  }
 
172
 
 
173
  state= TIME_VALUE;
 
174
  maybe_null= 0;
 
175
  max_length= max_length_arg;
 
176
  decimals= 0;
 
177
  return;
 
178
}
 
179
 
 
180
 
 
181
bool Item_param::set_str(const char *str, ulong length)
 
182
{
 
183
  /*
 
184
    Assign string with no conversion: data is converted only after it's
 
185
    been written to the binary log.
 
186
  */
 
187
  uint32_t dummy_errors;
 
188
  if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin,
 
189
                     &dummy_errors))
 
190
    return(true);
 
191
  state= STRING_VALUE;
 
192
  max_length= length;
 
193
  maybe_null= 0;
 
194
  /* max_length and decimals are set after charset conversion */
 
195
  /* sic: str may be not null-terminated */
 
196
  return(false);
 
197
}
 
198
 
 
199
bool Item_param::set_longdata(const char *str, ulong length)
 
200
{
 
201
  /*
 
202
    If client character set is multibyte, end of long data packet
 
203
    may hit at the middle of a multibyte character.  Additionally,
 
204
    if binary log is open we must write long data value to the
 
205
    binary log in character set of client. This is why we can't
 
206
    convert long data to connection character set as it comes
 
207
    (here), and first have to concatenate all pieces together,
 
208
    write query to the binary log and only then perform conversion.
 
209
  */
 
210
  if (str_value.append(str, length, &my_charset_bin))
 
211
    return(true);
 
212
  state= LONG_DATA_VALUE;
 
213
  maybe_null= 0;
 
214
 
 
215
  return(false);
 
216
}
 
217
 
 
218
 
 
219
/**
 
220
  Set parameter value from user variable value.
 
221
 
 
222
  @param session   Current thread
 
223
  @param entry User variable structure (NULL means use NULL value)
 
224
 
 
225
  @retval
 
226
    0 OK
 
227
  @retval
 
228
    1 Out of memory
 
229
*/
 
230
 
 
231
bool Item_param::set_from_user_var(Session *session, const user_var_entry *entry)
 
232
{
 
233
  if (entry && entry->value)
 
234
  {
 
235
    item_result_type= entry->type;
 
236
    unsigned_flag= entry->unsigned_flag;
 
237
    if (limit_clause_param)
 
238
    {
 
239
      bool unused;
 
240
      set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS); item_type= Item::INT_ITEM;
 
241
      return(!unsigned_flag && value.integer < 0 ? 1 : 0);
 
242
    }
 
243
    switch (item_result_type) {
 
244
    case REAL_RESULT:
 
245
      set_double(*(double*)entry->value);
 
246
      item_type= Item::REAL_ITEM;
 
247
      break;
 
248
    case INT_RESULT:
 
249
      set_int(*(int64_t*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
 
250
      item_type= Item::INT_ITEM;
 
251
      break;
 
252
    case STRING_RESULT:
 
253
    {
 
254
      const CHARSET_INFO * const fromcs= entry->collation.collation;
 
255
      const CHARSET_INFO * const tocs= session->variables.getCollation();
 
256
      uint32_t dummy_offset;
 
257
 
 
258
      value.cs_info.character_set_of_placeholder=
 
259
        value.cs_info.character_set_client= fromcs;
 
260
      /*
 
261
        Setup source and destination character sets so that they
 
262
        are different only if conversion is necessary: this will
 
263
        make later checks easier.
 
264
      */
 
265
      value.cs_info.final_character_set_of_str_value=
 
266
        String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
 
267
        tocs : fromcs;
 
268
      /*
 
269
        Exact value of max_length is not known unless data is converted to
 
270
        charset of connection, so we have to set it later.
 
271
      */
 
272
      item_type= Item::STRING_ITEM;
 
273
 
 
274
      if (set_str((const char *)entry->value, entry->length))
 
275
        return(1);
 
276
      break;
 
277
    }
 
278
    case DECIMAL_RESULT:
 
279
    {
 
280
      const my_decimal *ent_value= (const my_decimal *)entry->value;
 
281
      my_decimal2decimal(ent_value, &decimal_value);
 
282
      state= DECIMAL_VALUE;
 
283
      decimals= ent_value->frac;
 
284
      max_length= my_decimal_precision_to_length(ent_value->precision(),
 
285
                                                 decimals, unsigned_flag);
 
286
      item_type= Item::DECIMAL_ITEM;
 
287
      break;
 
288
    }
 
289
    default:
 
290
      assert(0);
 
291
      set_null();
 
292
    }
 
293
  }
 
294
  else
 
295
    set_null();
 
296
 
 
297
  return(0);
 
298
}
 
299
 
 
300
/**
 
301
  Resets parameter after execution.
 
302
 
 
303
  @note
 
304
    We clear null_value here instead of setting it in set_* methods,
 
305
    because we want more easily handle case for long data.
 
306
*/
 
307
 
 
308
void Item_param::reset()
 
309
{
 
310
  /* Shrink string buffer if it's bigger than max possible CHAR column */
 
311
  if (str_value.alloced_length() > MAX_CHAR_WIDTH)
 
312
    str_value.free();
 
313
  else
 
314
    str_value.length(0);
 
315
  str_value_ptr.length(0);
 
316
  /*
 
317
    We must prevent all charset conversions until data has been written
 
318
    to the binary log.
 
319
  */
 
320
  str_value.set_charset(&my_charset_bin);
 
321
  collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
 
322
  state= NO_VALUE;
 
323
  maybe_null= 1;
 
324
  null_value= 0;
 
325
  /*
 
326
    Don't reset item_type to PARAM_ITEM: it's only needed to guard
 
327
    us from item optimizations at prepare stage, when item doesn't yet
 
328
    contain a literal of some kind.
 
329
    In all other cases when this object is accessed its value is
 
330
    set (this assumption is guarded by 'state' and
 
331
    assertS(state != NO_VALUE) in all Item_param::get_*
 
332
    methods).
 
333
  */
 
334
  return;
 
335
}
 
336
 
 
337
int Item_param::save_in_field(Field *field, bool no_conversions)
 
338
{
 
339
  field->set_notnull();
 
340
 
 
341
  switch (state) {
 
342
  case INT_VALUE:
 
343
    return field->store(value.integer, unsigned_flag);
 
344
  case REAL_VALUE:
 
345
    return field->store(value.real);
 
346
  case DECIMAL_VALUE:
 
347
    return field->store_decimal(&decimal_value);
 
348
  case TIME_VALUE:
 
349
    field->store_time(&value.time, value.time.time_type);
 
350
    return 0;
 
351
  case STRING_VALUE:
 
352
  case LONG_DATA_VALUE:
 
353
    return field->store(str_value.ptr(), str_value.length(),
 
354
                        str_value.charset());
 
355
  case NULL_VALUE:
 
356
    return set_field_to_null_with_conversions(field, no_conversions);
 
357
  case NO_VALUE:
 
358
  default:
 
359
    assert(0);
 
360
  }
 
361
  return 1;
 
362
}
 
363
 
 
364
bool Item_param::get_time(DRIZZLE_TIME *res)
 
365
{
 
366
  if (state == TIME_VALUE)
 
367
  {
 
368
    *res= value.time;
 
369
    return 0;
 
370
  }
 
371
  /*
 
372
    If parameter value isn't supplied assertion will fire in val_str()
 
373
    which is called from Item::get_time().
 
374
  */
 
375
  return Item::get_time(res);
 
376
}
 
377
 
 
378
 
 
379
bool Item_param::get_date(DRIZZLE_TIME *res, uint32_t fuzzydate)
 
380
{
 
381
  if (state == TIME_VALUE)
 
382
  {
 
383
    *res= value.time;
 
384
    return 0;
 
385
  }
 
386
  return Item::get_date(res, fuzzydate);
 
387
}
 
388
 
 
389
 
 
390
double Item_param::val_real()
 
391
{
 
392
  switch (state) {
 
393
  case REAL_VALUE:
 
394
    return value.real;
 
395
  case INT_VALUE:
 
396
    return (double) value.integer;
 
397
  case DECIMAL_VALUE:
 
398
  {
 
399
    double result;
 
400
    my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
 
401
    return result;
 
402
  }
 
403
  case STRING_VALUE:
 
404
  case LONG_DATA_VALUE:
 
405
  {
 
406
    int dummy_err;
 
407
    char *end_not_used;
 
408
    return my_strntod(str_value.charset(), (char*) str_value.ptr(),
 
409
                      str_value.length(), &end_not_used, &dummy_err);
 
410
  }
 
411
  case TIME_VALUE:
 
412
    /*
 
413
      This works for example when user says SELECT ?+0.0 and supplies
 
414
      time value for the placeholder.
 
415
    */
 
416
    return uint64_t2double(TIME_to_uint64_t(&value.time));
 
417
  case NULL_VALUE:
 
418
    return 0.0;
 
419
  default:
 
420
    assert(0);
 
421
  }
 
422
  return 0.0;
 
423
}
 
424
 
 
425
 
 
426
int64_t Item_param::val_int()
 
427
{
 
428
  switch (state) {
 
429
  case REAL_VALUE:
 
430
    return (int64_t) rint(value.real);
 
431
  case INT_VALUE:
 
432
    return value.integer;
 
433
  case DECIMAL_VALUE:
 
434
  {
 
435
    int64_t i;
 
436
    my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
 
437
    return i;
 
438
  }
 
439
  case STRING_VALUE:
 
440
  case LONG_DATA_VALUE:
 
441
    {
 
442
      int dummy_err;
 
443
      return my_strntoll(str_value.charset(), str_value.ptr(),
 
444
                         str_value.length(), 10, (char**) 0, &dummy_err);
 
445
    }
 
446
  case TIME_VALUE:
 
447
    return (int64_t) TIME_to_uint64_t(&value.time);
 
448
  case NULL_VALUE:
 
449
    return 0;
 
450
  default:
 
451
    assert(0);
 
452
  }
 
453
  return 0;
 
454
}
 
455
 
 
456
 
 
457
my_decimal *Item_param::val_decimal(my_decimal *dec)
 
458
{
 
459
  switch (state) {
 
460
  case DECIMAL_VALUE:
 
461
    return &decimal_value;
 
462
  case REAL_VALUE:
 
463
    double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
 
464
    return dec;
 
465
  case INT_VALUE:
 
466
    int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
 
467
    return dec;
 
468
  case STRING_VALUE:
 
469
  case LONG_DATA_VALUE:
 
470
    string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec);
 
471
    return dec;
 
472
  case TIME_VALUE:
 
473
  {
 
474
    int64_t i= (int64_t) TIME_to_uint64_t(&value.time);
 
475
    int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec);
 
476
    return dec;
 
477
  }
 
478
  case NULL_VALUE:
 
479
    return 0;
 
480
  default:
 
481
    assert(0);
 
482
  }
 
483
  return 0;
 
484
}
 
485
 
 
486
 
 
487
String *Item_param::val_str(String* str)
 
488
{
 
489
  switch (state) {
 
490
  case STRING_VALUE:
 
491
  case LONG_DATA_VALUE:
 
492
    return &str_value_ptr;
 
493
  case REAL_VALUE:
 
494
    str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
 
495
    return str;
 
496
  case INT_VALUE:
 
497
    str->set(value.integer, &my_charset_bin);
 
498
    return str;
 
499
  case DECIMAL_VALUE:
 
500
    if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
 
501
                          0, 0, 0, str) <= 1)
 
502
      return str;
 
503
    return NULL;
 
504
  case TIME_VALUE:
 
505
  {
 
506
    if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
 
507
      break;
 
508
    str->length((uint32_t) my_TIME_to_str(&value.time, (char*) str->ptr()));
 
509
    str->set_charset(&my_charset_bin);
 
510
    return str;
 
511
  }
 
512
  case NULL_VALUE:
 
513
    return NULL;
 
514
  default:
 
515
    assert(0);
 
516
  }
 
517
  return str;
 
518
}
 
519
 
 
520
/* TODO: fact next two functions out */
 
521
/**
 
522
    Transforms a string into "" or its expression in 0x... form.
 
523
*/
 
524
 
 
525
static char *str_to_hex(char *to, const char *from, uint32_t len)
 
526
{
 
527
  if (len)
 
528
  {
 
529
    *to++= '0';
 
530
    *to++= 'x';
 
531
    to+= (size_t) drizzled_string_to_hex(to, from, len);
 
532
  }
 
533
  else
 
534
    to= strcpy(to, "\"\"")+2;
 
535
  return to;                               // pointer to end 0 of 'to'
 
536
}
 
537
 
 
538
 
 
539
 
 
540
/*
 
541
  Add escape characters to a string (blob?) to make it suitable for a insert
 
542
  to should at least have place for length*2+1 chars
 
543
  Returns the length of the to string
 
544
*/
 
545
 
 
546
static uint32_t
 
547
_escape_string(char *to,const char *from, uint32_t length)
 
548
{
 
549
  const char *to_start= to;
 
550
  const char *end, *to_end=to_start + 2*length;
 
551
  bool overflow= false;
 
552
  for (end= from + length; from < end; from++)
 
553
  {
 
554
    uint32_t tmp_length;
 
555
    char escape= 0;
 
556
    if (!U8_IS_SINGLE(*from))
 
557
    {
 
558
      tmp_length= U8_LENGTH(*(uint32_t*)from);
 
559
      if (to + tmp_length > to_end)
 
560
      {
 
561
        overflow= true;
 
562
        break;
 
563
      }
 
564
      while (tmp_length--)
 
565
        *to++= *from++;
 
566
      from--;
 
567
      continue;
 
568
    }
 
569
    switch (*from) {
 
570
    case 0:                             /* Must be escaped for 'mysql' */
 
571
      escape= '0';
 
572
      break;
 
573
    case '\n':                          /* Must be escaped for logs */
 
574
      escape= 'n';
 
575
      break;
 
576
    case '\r':
 
577
      escape= 'r';
 
578
      break;
 
579
    case '\\':
 
580
      escape= '\\';
 
581
      break;
 
582
    case '\'':
 
583
      escape= '\'';
 
584
      break;
 
585
    case '"':                           /* Better safe than sorry */
 
586
      escape= '"';
 
587
      break;
 
588
    case '\032':                        /* This gives problems on Win32 */
 
589
      escape= 'Z';
 
590
      break;
 
591
    }
 
592
    if (escape)
 
593
    {
 
594
      if (to + 2 > to_end)
 
595
      {
 
596
        overflow= true;
 
597
        break;
 
598
      }
 
599
      *to++= '\\';
 
600
      *to++= escape;
 
601
    }
 
602
    else
 
603
    {
 
604
      if (to + 1 > to_end)
 
605
      {
 
606
        overflow= true;
 
607
        break;
 
608
      }
 
609
      *to++= *from;
 
610
    }
 
611
  }
 
612
  *to= 0;
 
613
  return overflow ? (size_t) -1 : (size_t) (to - to_start);
 
614
}
 
615
 
 
616
/**
 
617
  Append a version of the 'from' string suitable for use in a query to
 
618
  the 'to' string.  To generate a correct escaping, the character set
 
619
  information in 'csinfo' is used.
 
620
*/
 
621
 
 
622
static int
 
623
append_query_string(const CHARSET_INFO * const csinfo,
 
624
                    String const *from, String *to)
 
625
{
 
626
  char *beg, *ptr;
 
627
  uint32_t const orig_len= to->length();
 
628
  if (to->reserve(orig_len + from->length()*2+3))
 
629
    return 1;
 
630
 
 
631
  beg= to->c_ptr_quick() + to->length();
 
632
  ptr= beg;
 
633
  if (csinfo->escape_with_backslash_is_dangerous)
 
634
    ptr= str_to_hex(ptr, from->ptr(), from->length());
 
635
  else
 
636
  {
 
637
    *ptr++= '\'';
 
638
    ptr+= _escape_string(ptr, from->ptr(), from->length());
 
639
    *ptr++='\'';
 
640
  }
 
641
  to->length(orig_len + ptr - beg);
 
642
  return 0;
 
643
}
 
644
 
 
645
 
 
646
/**
 
647
  Return Param item values in string format, for generating the dynamic
 
648
  query used in update/binary logs.
 
649
 
 
650
  @todo
 
651
    - Change interface and implementation to fill log data in place
 
652
    and avoid one more memcpy/alloc between str and log string.
 
653
    - In case of error we need to notify replication
 
654
    that binary log contains wrong statement
 
655
*/
 
656
 
 
657
const String *Item_param::query_val_str(String* str) const
 
658
{
 
659
  switch (state) {
 
660
  case INT_VALUE:
 
661
    str->set_int(value.integer, unsigned_flag, &my_charset_bin);
 
662
    break;
 
663
  case REAL_VALUE:
 
664
    str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
 
665
    break;
 
666
  case DECIMAL_VALUE:
 
667
    if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
 
668
                          0, 0, 0, str) > 1)
 
669
      return &my_null_string;
 
670
    break;
 
671
  case TIME_VALUE:
 
672
    {
 
673
      char *buf, *ptr;
 
674
      str->length(0);
 
675
      /*
 
676
        TODO: in case of error we need to notify replication
 
677
        that binary log contains wrong statement
 
678
      */
 
679
      if (str->reserve(MAX_DATE_STRING_REP_LENGTH+3))
 
680
        break;
 
681
 
 
682
      /* Create date string inplace */
 
683
      buf= str->c_ptr_quick();
 
684
      ptr= buf;
 
685
      *ptr++= '\'';
 
686
      ptr+= (uint32_t) my_TIME_to_str(&value.time, ptr);
 
687
      *ptr++= '\'';
 
688
      str->length((uint32_t) (ptr - buf));
 
689
      break;
 
690
    }
 
691
  case STRING_VALUE:
 
692
  case LONG_DATA_VALUE:
 
693
    {
 
694
      str->length(0);
 
695
      append_query_string(value.cs_info.character_set_client, &str_value, str);
 
696
      break;
 
697
    }
 
698
  case NULL_VALUE:
 
699
    return &my_null_string;
 
700
  default:
 
701
    assert(0);
 
702
  }
 
703
  return str;
 
704
}
 
705
 
 
706
 
 
707
bool Item_param::basic_const_item() const
 
708
{
 
709
  if (state == NO_VALUE || state == TIME_VALUE)
 
710
    return false;
 
711
  return true;
 
712
}
 
713
 
 
714
 
 
715
Item *
 
716
Item_param::clone_item()
 
717
{
 
718
  /* see comments in the header file */
 
719
  switch (state) {
 
720
  case NULL_VALUE:
 
721
    return new Item_null(name);
 
722
  case INT_VALUE:
 
723
    return (unsigned_flag ?
 
724
            new Item_uint(name, value.integer, max_length) :
 
725
            new Item_int(name, value.integer, max_length));
 
726
  case REAL_VALUE:
 
727
    return new Item_float(name, value.real, decimals, max_length);
 
728
  case STRING_VALUE:
 
729
  case LONG_DATA_VALUE:
 
730
    return new Item_string(name, str_value.c_ptr_quick(), str_value.length(),
 
731
                           str_value.charset());
 
732
  case TIME_VALUE:
 
733
    break;
 
734
  case NO_VALUE:
 
735
  default:
 
736
    assert(0);
 
737
  };
 
738
  return 0;
 
739
}
 
740
 
 
741
 
 
742
bool
 
743
Item_param::eq(const Item *arg, bool binary_cmp) const
 
744
{
 
745
  Item *item;
 
746
  if (!basic_const_item() || !arg->basic_const_item() || arg->type() != type())
 
747
    return false;
 
748
  /*
 
749
    We need to cast off const to call val_int(). This should be OK for
 
750
    a basic constant.
 
751
  */
 
752
  item= (Item*) arg;
 
753
 
 
754
  switch (state) {
 
755
  case NULL_VALUE:
 
756
    return true;
 
757
  case INT_VALUE:
 
758
    return value.integer == item->val_int() &&
 
759
           unsigned_flag == item->unsigned_flag;
 
760
  case REAL_VALUE:
 
761
    return value.real == item->val_real();
 
762
  case STRING_VALUE:
 
763
  case LONG_DATA_VALUE:
 
764
    if (binary_cmp)
 
765
      return !stringcmp(&str_value, &item->str_value);
 
766
    return !sortcmp(&str_value, &item->str_value, collation.collation);
 
767
  default:
 
768
    break;
 
769
  }
 
770
  return false;
 
771
}
 
772
 
 
773
/* End of Item_param related */
 
774
 
 
775
void Item_param::print(String *str, enum_query_type)
 
776
{
 
777
  if (state == NO_VALUE)
 
778
  {
 
779
    str->append('?');
 
780
  }
 
781
  else
 
782
  {
 
783
    char buffer[STRING_BUFFER_USUAL_SIZE];
 
784
    String tmp(buffer, sizeof(buffer), &my_charset_bin);
 
785
    const String *res;
 
786
    res= query_val_str(&tmp);
 
787
    str->append(*res);
 
788
  }
 
789
}