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