~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-18 15:43:20 UTC
  • mto: (492.3.20 drizzle-clean-code)
  • mto: This revision was merged to the branch mainline in revision 530.
  • Revision ID: brian@tangent.org-20081018154320-jc9jyij3mdf08abp
Updating tests.

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