~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/set_user_var.cc

  • Committer: Lee
  • Date: 2008-10-30 21:40:56 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030214056-hdbeobj2dmaezdmz
more changes to move functions from item_func.cc/h to the functions directory

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 CSTDINT_H
 
22
#include <drizzled/functions/set_user_var.h>
 
23
 
 
24
/*
 
25
  When a user variable is updated (in a SET command or a query like
 
26
  SELECT @a:= ).
 
27
*/
 
28
 
 
29
bool Item_func_set_user_var::fix_fields(Session *session, Item **ref)
 
30
{
 
31
  assert(fixed == 0);
 
32
  /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
 
33
  if (Item_func::fix_fields(session, ref) ||
 
34
      !(entry= get_variable(&session->user_vars, name, 1)))
 
35
    return true;
 
36
  /*
 
37
     Remember the last query which updated it, this way a query can later know
 
38
     if this variable is a constant item in the query (it is if update_query_id
 
39
     is different from query_id).
 
40
  */
 
41
  entry->update_query_id= session->query_id;
 
42
  /*
 
43
    As it is wrong and confusing to associate any
 
44
    character set with NULL, @a should be latin2
 
45
    after this query sequence:
 
46
 
 
47
      SET @a=_latin2'string';
 
48
      SET @a=NULL;
 
49
 
 
50
    I.e. the second query should not change the charset
 
51
    to the current default value, but should keep the
 
52
    original value assigned during the first query.
 
53
    In order to do it, we don't copy charset
 
54
    from the argument if the argument is NULL
 
55
    and the variable has previously been initialized.
 
56
  */
 
57
  null_item= (args[0]->type() == NULL_ITEM);
 
58
  if (!entry->collation.collation || !null_item)
 
59
    entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
 
60
  collation.set(entry->collation.collation, DERIVATION_IMPLICIT);
 
61
  cached_result_type= args[0]->result_type();
 
62
  return false;
 
63
}
 
64
 
 
65
void
 
66
Item_func_set_user_var::fix_length_and_dec()
 
67
{
 
68
  maybe_null=args[0]->maybe_null;
 
69
  max_length=args[0]->max_length;
 
70
  decimals=args[0]->decimals;
 
71
  collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
 
72
}
 
73
 
 
74
/*
 
75
  Mark field in read_map
 
76
 
 
77
  NOTES
 
78
    This is used by filesort to register used fields in a a temporary
 
79
    column read set or to register used fields in a view
 
80
*/
 
81
 
 
82
bool Item_func_set_user_var::register_field_in_read_map(unsigned char *arg)
 
83
{
 
84
  if (result_field)
 
85
  {
 
86
    Table *table= (Table *) arg;
 
87
    if (result_field->table == table || !table)
 
88
      bitmap_set_bit(result_field->table->read_set, result_field->field_index);
 
89
    if (result_field->vcol_info && result_field->vcol_info->expr_item)
 
90
      return result_field->vcol_info->
 
91
               expr_item->walk(&Item::register_field_in_read_map, 1, arg);
 
92
  }
 
93
  return 0;
 
94
}
 
95
 
 
96
/*
 
97
  Mark field in bitmap supplied as *arg
 
98
 
 
99
*/
 
100
 
 
101
bool Item_func_set_user_var::register_field_in_bitmap(unsigned char *arg)
 
102
{
 
103
  MY_BITMAP *bitmap = (MY_BITMAP *) arg;
 
104
  assert(bitmap);
 
105
  if (result_field)
 
106
  {
 
107
    bitmap_set_bit(bitmap, result_field->field_index);
 
108
  }
 
109
  return 0;
 
110
}
 
111
 
 
112
bool
 
113
Item_func_set_user_var::update_hash(void *ptr, uint32_t length,
 
114
                                    Item_result res_type,
 
115
                                    const CHARSET_INFO * const cs, Derivation dv,
 
116
                                    bool unsigned_arg)
 
117
{
 
118
  /*
 
119
    If we set a variable explicitely to NULL then keep the old
 
120
    result type of the variable
 
121
  */
 
122
  if ((null_value= args[0]->null_value) && null_item)
 
123
    res_type= entry->type;                      // Don't change type of item
 
124
  if (::update_hash(entry, (null_value= args[0]->null_value),
 
125
                    ptr, length, res_type, cs, dv, unsigned_arg))
 
126
  {
 
127
    null_value= 1;
 
128
    return 1;
 
129
  }
 
130
  return 0;
 
131
}
 
132
 
 
133
/**
 
134
  This functions is invoked on SET \@variable or
 
135
  \@variable:= expression.
 
136
 
 
137
  Evaluate (and check expression), store results.
 
138
 
 
139
  @note
 
140
    For now it always return OK. All problem with value evaluating
 
141
    will be caught by session->is_error() check in sql_set_variables().
 
142
 
 
143
  @retval
 
144
    false OK.
 
145
*/
 
146
 
 
147
bool
 
148
Item_func_set_user_var::check(bool use_result_field)
 
149
{
 
150
  if (use_result_field && !result_field)
 
151
    use_result_field= false;
 
152
 
 
153
  switch (cached_result_type) {
 
154
  case REAL_RESULT:
 
155
  {
 
156
    save_result.vreal= use_result_field ? result_field->val_real() :
 
157
                        args[0]->val_real();
 
158
    break;
 
159
  }
 
160
  case INT_RESULT:
 
161
  {
 
162
    save_result.vint= use_result_field ? result_field->val_int() :
 
163
                       args[0]->val_int();
 
164
    unsigned_flag= use_result_field ? ((Field_num*)result_field)->unsigned_flag:
 
165
                    args[0]->unsigned_flag;
 
166
    break;
 
167
  }
 
168
  case STRING_RESULT:
 
169
  {
 
170
    save_result.vstr= use_result_field ? result_field->val_str(&value) :
 
171
                       args[0]->val_str(&value);
 
172
    break;
 
173
  }
 
174
  case DECIMAL_RESULT:
 
175
  {
 
176
    save_result.vdec= use_result_field ?
 
177
                       result_field->val_decimal(&decimal_buff) :
 
178
                       args[0]->val_decimal(&decimal_buff);
 
179
    break;
 
180
  }
 
181
  case ROW_RESULT:
 
182
  default:
 
183
    // This case should never be chosen
 
184
    assert(0);
 
185
    break;
 
186
  }
 
187
  return(false);
 
188
}
 
189
 
 
190
/**
 
191
  This functions is invoked on
 
192
  SET \@variable or \@variable:= expression.
 
193
 
 
194
  @note
 
195
    We have to store the expression as such in the variable, independent of
 
196
    the value method used by the user
 
197
 
 
198
  @retval
 
199
    0   OK
 
200
  @retval
 
201
    1   EOM Error
 
202
 
 
203
*/
 
204
 
 
205
bool
 
206
Item_func_set_user_var::update()
 
207
{
 
208
  bool res= false;
 
209
 
 
210
  switch (cached_result_type) {
 
211
  case REAL_RESULT:
 
212
  {
 
213
    res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal),
 
214
                     REAL_RESULT, &my_charset_bin, DERIVATION_IMPLICIT, 0);
 
215
    break;
 
216
  }
 
217
  case INT_RESULT:
 
218
  {
 
219
    res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
 
220
                     INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT,
 
221
                     unsigned_flag);
 
222
    break;
 
223
  }
 
224
  case STRING_RESULT:
 
225
  {
 
226
    if (!save_result.vstr)                                      // Null value
 
227
      res= update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin,
 
228
                       DERIVATION_IMPLICIT, 0);
 
229
    else
 
230
      res= update_hash((void*) save_result.vstr->ptr(),
 
231
                       save_result.vstr->length(), STRING_RESULT,
 
232
                       save_result.vstr->charset(),
 
233
                       DERIVATION_IMPLICIT, 0);
 
234
    break;
 
235
  }
 
236
  case DECIMAL_RESULT:
 
237
  {
 
238
    if (!save_result.vdec)                                      // Null value
 
239
      res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin,
 
240
                       DERIVATION_IMPLICIT, 0);
 
241
    else
 
242
      res= update_hash((void*) save_result.vdec,
 
243
                       sizeof(my_decimal), DECIMAL_RESULT,
 
244
                       &my_charset_bin, DERIVATION_IMPLICIT, 0);
 
245
    break;
 
246
  }
 
247
  case ROW_RESULT:
 
248
  default:
 
249
    // This case should never be chosen
 
250
    assert(0);
 
251
    break;
 
252
  }
 
253
  return(res);
 
254
}
 
255
 
 
256
double Item_func_set_user_var::val_real()
 
257
{
 
258
  assert(fixed == 1);
 
259
  check(0);
 
260
  update();                                     // Store expression
 
261
  return entry->val_real(&null_value);
 
262
}
 
263
 
 
264
int64_t Item_func_set_user_var::val_int()
 
265
{
 
266
  assert(fixed == 1);
 
267
  check(0);
 
268
  update();                                     // Store expression
 
269
  return entry->val_int(&null_value);
 
270
}
 
271
 
 
272
String *Item_func_set_user_var::val_str(String *str)
 
273
{
 
274
  assert(fixed == 1);
 
275
  check(0);
 
276
  update();                                     // Store expression
 
277
  return entry->val_str(&null_value, str, decimals);
 
278
}
 
279
 
 
280
 
 
281
my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
 
282
{
 
283
  assert(fixed == 1);
 
284
  check(0);
 
285
  update();                                     // Store expression
 
286
  return entry->val_decimal(&null_value, val);
 
287
}
 
288
 
 
289
double Item_func_set_user_var::val_result()
 
290
{
 
291
  assert(fixed == 1);
 
292
  check(true);
 
293
  update();                                     // Store expression
 
294
  return entry->val_real(&null_value);
 
295
}
 
296
 
 
297
int64_t Item_func_set_user_var::val_int_result()
 
298
{
 
299
  assert(fixed == 1);
 
300
  check(true);
 
301
  update();                                     // Store expression
 
302
  return entry->val_int(&null_value);
 
303
}
 
304
 
 
305
String *Item_func_set_user_var::str_result(String *str)
 
306
{
 
307
  assert(fixed == 1);
 
308
  check(true);
 
309
  update();                                     // Store expression
 
310
  return entry->val_str(&null_value, str, decimals);
 
311
}
 
312
 
 
313
 
 
314
my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val)
 
315
{
 
316
  assert(fixed == 1);
 
317
  check(true);
 
318
  update();                                     // Store expression
 
319
  return entry->val_decimal(&null_value, val);
 
320
}
 
321
 
 
322
void Item_func_set_user_var::print(String *str, enum_query_type query_type)
 
323
{
 
324
  str->append(STRING_WITH_LEN("(@"));
 
325
  str->append(name.str, name.length);
 
326
  str->append(STRING_WITH_LEN(":="));
 
327
  args[0]->print(str, query_type);
 
328
  str->append(')');
 
329
}
 
330
 
 
331
 
 
332
void Item_func_set_user_var::print_as_stmt(String *str,
 
333
                                           enum_query_type query_type)
 
334
{
 
335
  str->append(STRING_WITH_LEN("set @"));
 
336
  str->append(name.str, name.length);
 
337
  str->append(STRING_WITH_LEN(":="));
 
338
  args[0]->print(str, query_type);
 
339
  str->append(')');
 
340
}
 
341
 
 
342
bool Item_func_set_user_var::send(Protocol *protocol, String *str_arg)
 
343
{
 
344
  if (result_field)
 
345
  {
 
346
    check(1);
 
347
    update();
 
348
    return protocol->store(result_field);
 
349
  }
 
350
  return Item::send(protocol, str_arg);
 
351
}
 
352
 
 
353
void Item_func_set_user_var::make_field(Send_field *tmp_field)
 
354
{
 
355
  if (result_field)
 
356
  {
 
357
    result_field->make_field(tmp_field);
 
358
    assert(tmp_field->table_name != 0);
 
359
    if (Item::name)
 
360
      tmp_field->col_name=Item::name;               // Use user supplied name
 
361
  }
 
362
  else
 
363
    Item::make_field(tmp_field);
 
364
}
 
365
 
 
366
/*
 
367
  Save the value of a user variable into a field
 
368
 
 
369
  SYNOPSIS
 
370
    save_in_field()
 
371
      field           target field to save the value to
 
372
      no_conversion   flag indicating whether conversions are allowed
 
373
 
 
374
  DESCRIPTION
 
375
    Save the function value into a field and update the user variable
 
376
    accordingly. If a result field is defined and the target field doesn't
 
377
    coincide with it then the value from the result field will be used as
 
378
    the new value of the user variable.
 
379
 
 
380
    The reason to have this method rather than simply using the result
 
381
    field in the val_xxx() methods is that the value from the result field
 
382
    not always can be used when the result field is defined.
 
383
    Let's consider the following cases:
 
384
    1) when filling a tmp table the result field is defined but the value of it
 
385
    is undefined because it has to be produced yet. Thus we can't use it.
 
386
    2) on execution of an INSERT ... SELECT statement the save_in_field()
 
387
    function will be called to fill the data in the new record. If the SELECT
 
388
    part uses a tmp table then the result field is defined and should be
 
389
    used in order to get the correct result.
 
390
 
 
391
    The difference between the SET_USER_VAR function and regular functions
 
392
    like CONCAT is that the Item_func objects for the regular functions are
 
393
    replaced by Item_field objects after the values of these functions have
 
394
    been stored in a tmp table. Yet an object of the Item_field class cannot
 
395
    be used to update a user variable.
 
396
    Due to this we have to handle the result field in a special way here and
 
397
    in the Item_func_set_user_var::send() function.
 
398
 
 
399
  RETURN VALUES
 
400
    false       Ok
 
401
    true        Error
 
402
*/
 
403
 
 
404
int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions,
 
405
                                          bool can_use_result_field)
 
406
{
 
407
  bool use_result_field= (!can_use_result_field ? 0 :
 
408
                          (result_field && result_field != field));
 
409
  int error;
 
410
 
 
411
  /* Update the value of the user variable */
 
412
  check(use_result_field);
 
413
  update();
 
414
 
 
415
  if (result_type() == STRING_RESULT ||
 
416
      (result_type() == REAL_RESULT && field->result_type() == STRING_RESULT))
 
417
  {
 
418
    String *result;
 
419
    const CHARSET_INFO * const cs= collation.collation;
 
420
    char buff[MAX_FIELD_WIDTH];         // Alloc buffer for small columns
 
421
    str_value.set_quick(buff, sizeof(buff), cs);
 
422
    result= entry->val_str(&null_value, &str_value, decimals);
 
423
 
 
424
    if (null_value)
 
425
    {
 
426
      str_value.set_quick(0, 0, cs);
 
427
      return set_field_to_null_with_conversions(field, no_conversions);
 
428
    }
 
429
 
 
430
    /* NOTE: If null_value == false, "result" must be not NULL.  */
 
431
 
 
432
    field->set_notnull();
 
433
    error=field->store(result->ptr(),result->length(),cs);
 
434
    str_value.set_quick(0, 0, cs);
 
435
  }
 
436
  else if (result_type() == REAL_RESULT)
 
437
  {
 
438
    double nr= entry->val_real(&null_value);
 
439
    if (null_value)
 
440
      return set_field_to_null(field);
 
441
    field->set_notnull();
 
442
    error=field->store(nr);
 
443
  }
 
444
  else if (result_type() == DECIMAL_RESULT)
 
445
  {
 
446
    my_decimal decimal_value;
 
447
    my_decimal *val= entry->val_decimal(&null_value, &decimal_value);
 
448
    if (null_value)
 
449
      return set_field_to_null(field);
 
450
    field->set_notnull();
 
451
    error=field->store_decimal(val);
 
452
  }
 
453
  else
 
454
  {
 
455
    int64_t nr= entry->val_int(&null_value);
 
456
    if (null_value)
 
457
      return set_field_to_null_with_conversions(field, no_conversions);
 
458
    field->set_notnull();
 
459
    error=field->store(nr, unsigned_flag);
 
460
  }
 
461
  return error;
 
462
}
 
463
 
 
464