~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/set_user_var.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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