~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/set_user_var.cc

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