~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/set_user_var.cc

  • Committer: Stewart Smith
  • Date: 2009-06-16 03:02:59 UTC
  • mto: This revision was merged to the branch mainline in revision 1065.
  • Revision ID: stewart@flamingspork.com-20090616030259-tn2thqrajk6cappd
ER_NISAMCHK is unused, mark it as so. Thanks to Paul DuBois for researching this for MySQL.

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