~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 "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->table == table || !table)
94
 
      result_field->table->setReadSet(result_field->field_index);
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(&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
 
  default:
171
 
    // This case should never be chosen
172
 
    assert(0);
173
 
    break;
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
 
  case INT_RESULT:
206
 
  {
207
 
    res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
208
 
                     INT_RESULT, &my_charset_bin, DERIVATION_IMPLICIT,
209
 
                     unsigned_flag);
210
 
    break;
211
 
  }
212
 
  case STRING_RESULT:
213
 
  {
214
 
    if (!save_result.vstr)                                      // Null value
215
 
      res= update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin,
216
 
                       DERIVATION_IMPLICIT, 0);
217
 
    else
218
 
      res= update_hash((void*) save_result.vstr->ptr(),
219
 
                       save_result.vstr->length(), STRING_RESULT,
220
 
                       save_result.vstr->charset(),
221
 
                       DERIVATION_IMPLICIT, 0);
222
 
    break;
223
 
  }
224
 
  case DECIMAL_RESULT:
225
 
  {
226
 
    if (!save_result.vdec)                                      // Null value
227
 
      res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin,
228
 
                       DERIVATION_IMPLICIT, 0);
229
 
    else
230
 
      res= update_hash((void*) save_result.vdec,
231
 
                       sizeof(my_decimal), DECIMAL_RESULT,
232
 
                       &my_charset_bin, DERIVATION_IMPLICIT, 0);
233
 
    break;
234
 
  }
235
 
  case ROW_RESULT:
236
 
  default:
237
 
    // This case should never be chosen
238
 
    assert(0);
239
 
    break;
240
 
  }
241
 
  return(res);
242
 
}
243
 
 
244
 
double Item_func_set_user_var::val_real()
245
 
{
246
 
  assert(fixed == 1);
247
 
  check(0);
248
 
  update();                                     // Store expression
249
 
  return entry->val_real(&null_value);
250
 
}
251
 
 
252
 
int64_t Item_func_set_user_var::val_int()
253
 
{
254
 
  assert(fixed == 1);
255
 
  check(0);
256
 
  update();                                     // Store expression
257
 
  return entry->val_int(&null_value);
258
 
}
259
 
 
260
 
String *Item_func_set_user_var::val_str(String *str)
261
 
{
262
 
  assert(fixed == 1);
263
 
  check(0);
264
 
  update();                                     // Store expression
265
 
  return entry->val_str(&null_value, str, decimals);
266
 
}
267
 
 
268
 
 
269
 
my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
270
 
{
271
 
  assert(fixed == 1);
272
 
  check(0);
273
 
  update();                                     // Store expression
274
 
  return entry->val_decimal(&null_value, val);
275
 
}
276
 
 
277
 
double Item_func_set_user_var::val_result()
278
 
{
279
 
  assert(fixed == 1);
280
 
  check(true);
281
 
  update();                                     // Store expression
282
 
  return entry->val_real(&null_value);
283
 
}
284
 
 
285
 
int64_t Item_func_set_user_var::val_int_result()
286
 
{
287
 
  assert(fixed == 1);
288
 
  check(true);
289
 
  update();                                     // Store expression
290
 
  return entry->val_int(&null_value);
291
 
}
292
 
 
293
 
String *Item_func_set_user_var::str_result(String *str)
294
 
{
295
 
  assert(fixed == 1);
296
 
  check(true);
297
 
  update();                                     // Store expression
298
 
  return entry->val_str(&null_value, str, decimals);
299
 
}
300
 
 
301
 
 
302
 
my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val)
303
 
{
304
 
  assert(fixed == 1);
305
 
  check(true);
306
 
  update();                                     // Store expression
307
 
  return entry->val_decimal(&null_value, val);
308
 
}
309
 
 
310
 
void Item_func_set_user_var::print(String *str, enum_query_type query_type)
311
 
{
312
 
  str->append(STRING_WITH_LEN("(@"));
313
 
  str->append(name.str, name.length);
314
 
  str->append(STRING_WITH_LEN(":="));
315
 
  args[0]->print(str, query_type);
316
 
  str->append(')');
317
 
}
318
 
 
319
 
bool Item_func_set_user_var::send(plugin::Client *client, String *str_arg)
320
 
{
321
 
  if (result_field)
322
 
  {
323
 
    check(1);
324
 
    update();
325
 
    return client->store(result_field);
326
 
  }
327
 
  return Item::send(client, str_arg);
328
 
}
329
 
 
330
 
void Item_func_set_user_var::make_field(SendField *tmp_field)
331
 
{
332
 
  if (result_field)
333
 
  {
334
 
    result_field->make_field(tmp_field);
335
 
    assert(tmp_field->table_name != 0);
336
 
    if (Item::name)
337
 
      tmp_field->col_name=Item::name;               // Use user supplied name
338
 
  }
339
 
  else
340
 
    Item::make_field(tmp_field);
341
 
}
342
 
 
343
 
/*
344
 
  Save the value of a user variable into a field
345
 
 
346
 
  SYNOPSIS
347
 
    save_in_field()
348
 
      field           target field to save the value to
349
 
      no_conversion   flag indicating whether conversions are allowed
350
 
 
351
 
  DESCRIPTION
352
 
    Save the function value into a field and update the user variable
353
 
    accordingly. If a result field is defined and the target field doesn't
354
 
    coincide with it then the value from the result field will be used as
355
 
    the new value of the user variable.
356
 
 
357
 
    The reason to have this method rather than simply using the result
358
 
    field in the val_xxx() methods is that the value from the result field
359
 
    not always can be used when the result field is defined.
360
 
    Let's consider the following cases:
361
 
    1) when filling a tmp table the result field is defined but the value of it
362
 
    is undefined because it has to be produced yet. Thus we can't use it.
363
 
    2) on execution of an INSERT ... SELECT statement the save_in_field()
364
 
    function will be called to fill the data in the new record. If the SELECT
365
 
    part uses a tmp table then the result field is defined and should be
366
 
    used in order to get the correct result.
367
 
 
368
 
    The difference between the SET_USER_VAR function and regular functions
369
 
    like CONCAT is that the Item_func objects for the regular functions are
370
 
    replaced by Item_field objects after the values of these functions have
371
 
    been stored in a tmp table. Yet an object of the Item_field class cannot
372
 
    be used to update a user variable.
373
 
    Due to this we have to handle the result field in a special way here and
374
 
    in the Item_func_set_user_var::send() function.
375
 
 
376
 
  RETURN VALUES
377
 
    false       Ok
378
 
    true        Error
379
 
*/
380
 
 
381
 
int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions,
382
 
                                          bool can_use_result_field)
383
 
{
384
 
  bool use_result_field= (!can_use_result_field ? 0 :
385
 
                          (result_field && result_field != field));
386
 
  int error;
387
 
 
388
 
  /* Update the value of the user variable */
389
 
  check(use_result_field);
390
 
  update();
391
 
 
392
 
  if (result_type() == STRING_RESULT ||
393
 
      (result_type() == REAL_RESULT && field->result_type() == STRING_RESULT))
394
 
  {
395
 
    String *result;
396
 
    const CHARSET_INFO * const cs= collation.collation;
397
 
    char buff[MAX_FIELD_WIDTH];         // Alloc buffer for small columns
398
 
    str_value.set_quick(buff, sizeof(buff), cs);
399
 
    result= entry->val_str(&null_value, &str_value, decimals);
400
 
 
401
 
    if (null_value)
402
 
    {
403
 
      str_value.set_quick(0, 0, cs);
404
 
      return set_field_to_null_with_conversions(field, no_conversions);
405
 
    }
406
 
 
407
 
    /* NOTE: If null_value == false, "result" must be not NULL.  */
408
 
 
409
 
    field->set_notnull();
410
 
    error=field->store(result->ptr(),result->length(),cs);
411
 
    str_value.set_quick(0, 0, cs);
412
 
  }
413
 
  else if (result_type() == REAL_RESULT)
414
 
  {
415
 
    double nr= entry->val_real(&null_value);
416
 
    if (null_value)
417
 
      return set_field_to_null(field);
418
 
    field->set_notnull();
419
 
    error=field->store(nr);
420
 
  }
421
 
  else if (result_type() == DECIMAL_RESULT)
422
 
  {
423
 
    my_decimal decimal_value;
424
 
    my_decimal *val= entry->val_decimal(&null_value, &decimal_value);
425
 
    if (null_value)
426
 
      return set_field_to_null(field);
427
 
    field->set_notnull();
428
 
    error=field->store_decimal(val);
429
 
  }
430
 
  else
431
 
  {
432
 
    int64_t nr= entry->val_int(&null_value);
433
 
    if (null_value)
434
 
      return set_field_to_null_with_conversions(field, no_conversions);
435
 
    field->set_notnull();
436
 
    error=field->store(nr, unsigned_flag);
437
 
  }
438
 
  return error;
439
 
}
440
 
 
441
 
 
442
 
} /* namespace drizzled */