1 /* Copyright (c) 2000, 2011, 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 
24 /**
25   @file
26 
27   @brief
28   Buffers to save and compare item values
29 */
30 
31 #include "sql_priv.h"
32 /*
33   It is necessary to include set_var.h instead of item.h because there
34   are dependencies on include order for set_var.h and item.h. This
35   will be resolved later.
36 */
37 #include "sql_class.h"          // THD
38 #include "set_var.h"            // Cached_item, Cached_item_field, ...
39 
40 using std::min;
41 using std::max;
42 
43 /**
44   Create right type of Cached_item for an item.
45 */
46 
new_Cached_item(THD * thd,Item * item,bool use_result_field)47 Cached_item *new_Cached_item(THD *thd, Item *item, bool use_result_field)
48 {
49   if (item->real_item()->type() == Item::FIELD_ITEM &&
50       !(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG))
51   {
52     Item_field *real_item= (Item_field *) item->real_item();
53     Field *cached_field= use_result_field ? real_item->result_field :
54                                             real_item->field;
55     return new Cached_item_field(cached_field);
56   }
57   switch (item->result_type()) {
58   case STRING_RESULT:
59     if (item->is_temporal())
60       return new Cached_item_temporal((Item_field *) item);
61     return new Cached_item_str(thd, (Item_field *) item);
62   case INT_RESULT:
63     return new Cached_item_int((Item_field *) item);
64   case REAL_RESULT:
65     return new Cached_item_real(item);
66   case DECIMAL_RESULT:
67     return new Cached_item_decimal(item);
68   case ROW_RESULT:
69   default:
70     DBUG_ASSERT(0);
71     return 0;
72   }
73 }
74 
~Cached_item()75 Cached_item::~Cached_item() {}
76 
77 /**
78   Compare with old value and replace value with new value.
79 
80   @return
81     Return true if values have changed
82 */
83 
Cached_item_str(THD * thd,Item * arg)84 Cached_item_str::Cached_item_str(THD *thd, Item *arg)
85   :item(arg),
86    value_max_length(min<uint32>(arg->max_length, thd->variables.max_sort_length)),
87    value(value_max_length)
88 {}
89 
cmp(void)90 bool Cached_item_str::cmp(void)
91 {
92   String *res;
93   bool tmp;
94 
95   DBUG_ENTER("Cached_item_str::cmp");
96   DBUG_ASSERT(!item->is_temporal());
97   if ((res=item->val_str(&tmp_value)))
98     res->length(min(res->length(), value_max_length));
99   DBUG_PRINT("info", ("old: %s, new: %s",
100                       value.c_ptr_safe(), res ? res->c_ptr_safe() : ""));
101   if (null_value != item->null_value)
102   {
103     if ((null_value= item->null_value))
104       DBUG_RETURN(TRUE);			// New value was null
105     tmp=TRUE;
106   }
107   else if (null_value)
108     DBUG_RETURN(0);				// new and old value was null
109   else
110     tmp= sortcmp(&value,res,item->collation.collation) != 0;
111   if (tmp)
112     value.copy(*res);				// Remember for next cmp
113   DBUG_RETURN(tmp);
114 }
115 
~Cached_item_str()116 Cached_item_str::~Cached_item_str()
117 {
118   item=0;					// Safety
119 }
120 
cmp(void)121 bool Cached_item_real::cmp(void)
122 {
123   DBUG_ENTER("Cached_item_real::cmp");
124   double nr= item->val_real();
125   DBUG_PRINT("info", ("old: %f, new: %f", value, nr));
126   if (null_value != item->null_value || nr != value)
127   {
128     null_value= item->null_value;
129     value=nr;
130     DBUG_RETURN(TRUE);
131   }
132   DBUG_RETURN(FALSE);
133 }
134 
cmp(void)135 bool Cached_item_int::cmp(void)
136 {
137   DBUG_ENTER("Cached_item_int::cmp");
138   longlong nr=item->val_int();
139   DBUG_PRINT("info", ("old: %lld, new: %lld", value, nr));
140   if (null_value != item->null_value || nr != value)
141   {
142     null_value= item->null_value;
143     value=nr;
144     DBUG_RETURN(TRUE);
145   }
146   DBUG_RETURN(FALSE);
147 }
148 
149 
cmp(void)150 bool Cached_item_temporal::cmp(void)
151 {
152   DBUG_ENTER("Cached_item_temporal::cmp");
153   longlong nr= item->val_temporal_by_field_type();
154   DBUG_PRINT("info", ("old: %lld, new: %lld", value, nr));
155   if (null_value != item->null_value || nr != value)
156   {
157     null_value= item->null_value;
158     value= nr;
159     DBUG_RETURN(TRUE);
160   }
161   DBUG_RETURN(FALSE);
162 }
163 
164 
cmp(void)165 bool Cached_item_field::cmp(void)
166 {
167   DBUG_ENTER("Cached_item_field::cmp");
168   DBUG_EXECUTE("info", dbug_print(););
169 
170   bool different= false;
171 
172   if (field->is_null())
173   {
174     if (!null_value)
175     {
176       different= true;
177       null_value= true;
178     }
179   }
180   else
181   {
182     if (null_value)
183     {
184       different= true;
185       null_value= false;
186       field->get_image(buff, length, field->charset());
187     }
188     else if (field->cmp(buff))                  // Not a blob: cmp() is OK
189     {
190       different= true;
191       field->get_image(buff, length, field->charset());
192     }
193   }
194 
195   DBUG_RETURN(different);
196 }
197 
198 
Cached_item_decimal(Item * it)199 Cached_item_decimal::Cached_item_decimal(Item *it)
200   :item(it)
201 {
202   my_decimal_set_zero(&value);
203 }
204 
205 
cmp()206 bool Cached_item_decimal::cmp()
207 {
208   my_decimal tmp;
209   my_decimal *ptmp= item->val_decimal(&tmp);
210   if (null_value != item->null_value ||
211       (!item->null_value && my_decimal_cmp(&value, ptmp)))
212   {
213     null_value= item->null_value;
214     /* Save only not null values */
215     if (!null_value)
216     {
217       my_decimal2decimal(ptmp, &value);
218       return TRUE;
219     }
220     return FALSE;
221   }
222   return FALSE;
223 }
224