~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/set_user_var.cc

  • Committer: Monty Taylor
  • Date: 2008-10-09 22:38:27 UTC
  • mto: This revision was merged to the branch mainline in revision 497.
  • Revision ID: monty@inaugust.com-20081009223827-bc9gvpiplsmvpwyq
Moved test() to its own file.
Made a new function to possibly replace int10_to_str.

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