~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/set_user_var.cc

  • Committer: Monty Taylor
  • Date: 2009-01-30 21:02:37 UTC
  • mto: (779.7.3 devel)
  • mto: This revision was merged to the branch mainline in revision 823.
  • Revision ID: mordred@inaugust.com-20090130210237-3n6ld8a9jc084jko
Commented out a test in subselect_sj - I think it might be a regression. Jay?

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