1 /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 #include "sql_priv.h"
24 /*
25 It is necessary to include set_var.h instead of item.h because there
26 are dependencies on include order for set_var.h and item.h. This
27 will be resolved later.
28 */
29 #include "sql_class.h" // THD, set_var.h: THD
30 #include "set_var.h"
31
32 /**
33 Row items used for comparing rows and IN operations on rows:
34
35 @verbatim
36 (a, b, c) > (10, 10, 30)
37 (a, b, c) = (select c, d, e, from t1 where x=12)
38 (a, b, c) IN ((1,2,2), (3,4,5), (6,7,8)
39 (a, b, c) IN (select c, d, e, from t1)
40 @endverbatim
41
42 @todo
43 think placing 2-3 component items in item (as it done for function
44 */
45
Item_row(List<Item> & arg)46 Item_row::Item_row(List<Item> &arg):
47 Item(), used_tables_cache(0), not_null_tables_cache(0),
48 const_item_cache(1), with_null(0)
49 {
50
51 //TODO: think placing 2-3 component items in item (as it done for function)
52 if ((arg_count= arg.elements))
53 items= (Item**) sql_alloc(sizeof(Item*)*arg_count);
54 else
55 items= 0;
56 List_iterator<Item> li(arg);
57 uint i= 0;
58 Item *item;
59 while ((item= li++))
60 {
61 items[i]= item;
62 i++;
63 }
64 }
65
Item_row(Item * head,List<Item> & tail)66 Item_row::Item_row(Item *head, List<Item> &tail):
67 used_tables_cache(0), not_null_tables_cache(0),
68 const_item_cache(1), with_null(0)
69 {
70
71 //TODO: think placing 2-3 component items in item (as it done for function)
72 arg_count= 1 + tail.elements;
73 items= (Item**) sql_alloc(sizeof(Item*)*arg_count);
74 if (items == NULL)
75 {
76 arg_count= 0;
77 return; // OOM
78 }
79 items[0]= head;
80 List_iterator<Item> li(tail);
81 uint i= 1;
82 Item *item;
83 while ((item= li++))
84 {
85 items[i]= item;
86 i++;
87 }
88 }
89
illegal_method_call(const char * method)90 void Item_row::illegal_method_call(const char *method)
91 {
92 DBUG_ENTER("Item_row::illegal_method_call");
93 DBUG_PRINT("error", ("!!! %s method was called for row item", method));
94 DBUG_ASSERT(0);
95 my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
96 DBUG_VOID_RETURN;
97 }
98
fix_fields(THD * thd,Item ** ref)99 bool Item_row::fix_fields(THD *thd, Item **ref)
100 {
101 DBUG_ASSERT(fixed == 0);
102 null_value= 0;
103 maybe_null= 0;
104 Item **arg, **arg_end;
105 for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
106 {
107 if (!(*arg)->fixed && (*arg)->fix_fields(thd, arg))
108 return TRUE;
109 // we can't assign 'item' before, because fix_fields() can change arg
110 Item *item= *arg;
111 used_tables_cache |= item->used_tables();
112 const_item_cache&= item->const_item() && !with_null;
113 not_null_tables_cache|= item->not_null_tables();
114
115 if (const_item_cache)
116 {
117 if (item->cols() > 1)
118 with_null|= item->null_inside();
119 else
120 {
121 if (item->is_null())
122 with_null|= 1;
123 }
124 }
125 maybe_null|= item->maybe_null;
126 with_sum_func|= item->with_sum_func;
127 with_subselect|= item->has_subquery();
128 }
129 fixed= 1;
130 return FALSE;
131 }
132
133
cleanup()134 void Item_row::cleanup()
135 {
136 DBUG_ENTER("Item_row::cleanup");
137
138 Item::cleanup();
139 /* Reset to the original values */
140 used_tables_cache= 0;
141 const_item_cache= 1;
142 with_null= 0;
143
144 DBUG_VOID_RETURN;
145 }
146
147
split_sum_func(THD * thd,Ref_ptr_array ref_pointer_array,List<Item> & fields)148 void Item_row::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
149 List<Item> &fields)
150 {
151 Item **arg, **arg_end;
152 for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
153 (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg, TRUE);
154 }
155
156
update_used_tables()157 void Item_row::update_used_tables()
158 {
159 used_tables_cache= 0;
160 const_item_cache= true;
161 with_subselect= false;
162 with_stored_program= false;
163 for (uint i= 0; i < arg_count; i++)
164 {
165 items[i]->update_used_tables();
166 used_tables_cache|= items[i]->used_tables();
167 const_item_cache&= items[i]->const_item();
168 with_subselect|= items[i]->has_subquery();
169 with_stored_program|= items[i]->has_stored_program();
170 }
171 }
172
fix_after_pullout(st_select_lex * parent_select,st_select_lex * removed_select)173 void Item_row::fix_after_pullout(st_select_lex *parent_select,
174 st_select_lex *removed_select)
175 {
176 used_tables_cache= 0;
177 not_null_tables_cache= 0;
178 const_item_cache= true;
179 for (uint i= 0; i < arg_count; i++)
180 {
181 items[i]->fix_after_pullout(parent_select, removed_select);
182 used_tables_cache|= items[i]->used_tables();
183 not_null_tables_cache|= items[i]->not_null_tables();
184 const_item_cache&= items[i]->const_item();
185 }
186 }
187
check_cols(uint c)188 bool Item_row::check_cols(uint c)
189 {
190 if (c != arg_count)
191 {
192 my_error(ER_OPERAND_COLUMNS, MYF(0), c);
193 return 1;
194 }
195 return 0;
196 }
197
print(String * str,enum_query_type query_type)198 void Item_row::print(String *str, enum_query_type query_type)
199 {
200 str->append('(');
201 for (uint i= 0; i < arg_count; i++)
202 {
203 if (i)
204 str->append(',');
205 items[i]->print(str, query_type);
206 }
207 str->append(')');
208 }
209
210
walk(Item_processor processor,bool walk_subquery,uchar * arg)211 bool Item_row::walk(Item_processor processor, bool walk_subquery, uchar *arg)
212 {
213 for (uint i= 0; i < arg_count; i++)
214 {
215 if (items[i]->walk(processor, walk_subquery, arg))
216 return 1;
217 }
218 return (this->*processor)(arg);
219 }
220
221
transform(Item_transformer transformer,uchar * arg)222 Item *Item_row::transform(Item_transformer transformer, uchar *arg)
223 {
224 DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
225
226 for (uint i= 0; i < arg_count; i++)
227 {
228 Item *new_item= items[i]->transform(transformer, arg);
229 if (!new_item)
230 return 0;
231
232 /*
233 THD::change_item_tree() should be called only if the tree was
234 really transformed, i.e. when a new item has been created.
235 Otherwise we'll be allocating a lot of unnecessary memory for
236 change records at each execution.
237 */
238 if (items[i] != new_item)
239 current_thd->change_item_tree(&items[i], new_item);
240 }
241 return (this->*transformer)(arg);
242 }
243
bring_value()244 void Item_row::bring_value()
245 {
246 for (uint i= 0; i < arg_count; i++)
247 items[i]->bring_value();
248 }
249