~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/set_user_var.cc

  • Committer: Andy Lester
  • Date: 2008-08-10 02:15:48 UTC
  • mto: (266.1.31 use-replace-funcs)
  • mto: This revision was merged to the branch mainline in revision 295.
  • Revision ID: andy@petdance.com-20080810021548-0zx8nhzva6al10k3
Added a proper const qualifer.

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