~drizzle-trunk/drizzle/development

574.3.2 by Lee
initial changes to break out item_strfunc into functions/str
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
670.1.20 by Monty Taylor
Renamed functions to function... everything else is singular.
22
#include <drizzled/function/str/concat.h>
574.3.2 by Lee
initial changes to break out item_strfunc into functions/str
23
#include <drizzled/error.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.
24
#include <drizzled/session.h>
574.3.2 by Lee
initial changes to break out item_strfunc into functions/str
25
26
String *Item_func_concat::val_str(String *str)
27
{
28
  assert(fixed == 1);
29
  String *res,*res2,*use_as_buff;
30
  uint32_t i;
31
  bool is_const= 0;
32
33
  null_value=0;
34
  if (!(res=args[0]->val_str(str)))
35
    goto null;
36
  use_as_buff= &tmp_value;
37
  /* Item_subselect in --ps-protocol mode will state it as a non-const */
38
  is_const= args[0]->const_item() || !args[0]->used_tables();
39
  for (i=1 ; i < arg_count ; i++)
40
  {
41
    if (res->length() == 0)
42
    {
43
      if (!(res=args[i]->val_str(str)))
44
	goto null;
45
    }
46
    else
47
    {
48
      if (!(res2=args[i]->val_str(use_as_buff)))
49
	goto null;
50
      if (res2->length() == 0)
51
	continue;
52
      if (res->length()+res2->length() >
53
	  current_session->variables.max_allowed_packet)
54
      {
55
	push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
56
			    ER_WARN_ALLOWED_PACKET_OVERFLOWED,
57
			    ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
58
			    current_session->variables.max_allowed_packet);
59
	goto null;
60
      }
61
      if (!is_const && res->alloced_length() >= res->length()+res2->length())
62
      {						// Use old buffer
63
	res->append(*res2);
64
      }
65
      else if (str->alloced_length() >= res->length()+res2->length())
66
      {
67
	if (str == res2)
68
	  str->replace(0,0,*res);
69
	else
70
	{
71
	  str->copy(*res);
72
	  str->append(*res2);
73
	}
74
        res= str;
75
        use_as_buff= &tmp_value;
76
      }
77
      else if (res == &tmp_value)
78
      {
79
	if (res->append(*res2))			// Must be a blob
80
	  goto null;
81
      }
82
      else if (res2 == &tmp_value)
83
      {						// This can happend only 1 time
84
	if (tmp_value.replace(0,0,*res))
85
	  goto null;
86
	res= &tmp_value;
87
	use_as_buff=str;			// Put next arg here
88
      }
89
      else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
90
	       res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length())
91
      {
92
	/*
93
	  This happens really seldom:
94
	  In this case res2 is sub string of tmp_value.  We will
95
	  now work in place in tmp_value to set it to res | res2
96
	*/
97
	/* Chop the last characters in tmp_value that isn't in res2 */
98
	tmp_value.length((uint32_t) (res2->ptr() - tmp_value.ptr()) +
99
			 res2->length());
100
	/* Place res2 at start of tmp_value, remove chars before res2 */
101
	if (tmp_value.replace(0,(uint32_t) (res2->ptr() - tmp_value.ptr()),
102
			      *res))
103
	  goto null;
104
	res= &tmp_value;
105
	use_as_buff=str;			// Put next arg here
106
      }
107
      else
108
      {						// Two big const strings
109
        /*
110
          NOTE: We should be prudent in the initial allocation unit -- the
111
          size of the arguments is a function of data distribution, which
112
          can be any. Instead of overcommitting at the first row, we grow
113
          the allocated amount by the factor of 2. This ensures that no
114
          more than 25% of memory will be overcommitted on average.
115
        */
116
117
        uint32_t concat_len= res->length() + res2->length();
118
119
        if (tmp_value.alloced_length() < concat_len)
120
        {
121
          if (tmp_value.alloced_length() == 0)
122
          {
123
            if (tmp_value.alloc(concat_len))
124
              goto null;
125
          }
126
          else
127
          {
128
            uint32_t new_len = cmax(tmp_value.alloced_length() * 2, concat_len);
129
130
            if (tmp_value.realloc(new_len))
131
              goto null;
132
          }
133
        }
134
135
	if (tmp_value.copy(*res) || tmp_value.append(*res2))
136
	  goto null;
137
138
	res= &tmp_value;
139
	use_as_buff=str;
140
      }
141
      is_const= 0;
142
    }
143
  }
144
  res->set_charset(collation.collation);
145
  return res;
146
147
null:
148
  null_value=1;
149
  return 0;
150
}
151
152
153
void Item_func_concat::fix_length_and_dec()
154
{
155
  uint64_t max_result_length= 0;
156
157
  if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
158
    return;
159
160
  for (uint32_t i=0 ; i < arg_count ; i++)
161
  {
162
    if (args[i]->collation.collation->mbmaxlen != collation.collation->mbmaxlen)
163
      max_result_length+= (args[i]->max_length /
164
                           args[i]->collation.collation->mbmaxlen) *
165
                           collation.collation->mbmaxlen;
166
    else
167
      max_result_length+= args[i]->max_length;
168
  }
169
170
  if (max_result_length >= MAX_BLOB_WIDTH)
171
  {
172
    max_result_length= MAX_BLOB_WIDTH;
173
    maybe_null= 1;
174
  }
175
  max_length= (ulong) max_result_length;
176
}
177
178
179
/**
180
  concat with separator. First arg is the separator
181
  concat_ws takes at least two arguments.
182
*/
183
184
String *Item_func_concat_ws::val_str(String *str)
185
{
186
  assert(fixed == 1);
187
  char tmp_str_buff[10];
188
  String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info),
189
         *sep_str, *res, *res2,*use_as_buff;
190
  uint32_t i;
191
192
  null_value=0;
193
  if (!(sep_str= args[0]->val_str(&tmp_sep_str)))
194
    goto null;
195
196
  use_as_buff= &tmp_value;
197
  str->length(0);				// QQ; Should be removed
198
  res=str;
199
200
  // Skip until non-null argument is found.
201
  // If not, return the empty string
202
  for (i=1; i < arg_count; i++)
203
    if ((res= args[i]->val_str(str)))
204
      break;
205
  if (i ==  arg_count)
206
    return &my_empty_string;
207
208
  for (i++; i < arg_count ; i++)
209
  {
210
    if (!(res2= args[i]->val_str(use_as_buff)))
211
      continue;					// Skip NULL
212
213
    if (res->length() + sep_str->length() + res2->length() >
214
	current_session->variables.max_allowed_packet)
215
    {
216
      push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
217
			  ER_WARN_ALLOWED_PACKET_OVERFLOWED,
218
			  ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
219
			  current_session->variables.max_allowed_packet);
220
      goto null;
221
    }
222
    if (res->alloced_length() >=
223
	res->length() + sep_str->length() + res2->length())
224
    {						// Use old buffer
225
      res->append(*sep_str);			// res->length() > 0 always
226
      res->append(*res2);
227
    }
228
    else if (str->alloced_length() >=
229
	     res->length() + sep_str->length() + res2->length())
230
    {
231
      /* We have room in str;  We can't get any errors here */
232
      if (str == res2)
233
      {						// This is quote uncommon!
234
	str->replace(0,0,*sep_str);
235
	str->replace(0,0,*res);
236
      }
237
      else
238
      {
239
	str->copy(*res);
240
	str->append(*sep_str);
241
	str->append(*res2);
242
      }
243
      res=str;
244
      use_as_buff= &tmp_value;
245
    }
246
    else if (res == &tmp_value)
247
    {
248
      if (res->append(*sep_str) || res->append(*res2))
249
	goto null; // Must be a blob
250
    }
251
    else if (res2 == &tmp_value)
252
    {						// This can happend only 1 time
253
      if (tmp_value.replace(0,0,*sep_str) || tmp_value.replace(0,0,*res))
254
	goto null;
255
      res= &tmp_value;
256
      use_as_buff=str;				// Put next arg here
257
    }
258
    else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
259
	     res2->ptr() < tmp_value.ptr() + tmp_value.alloced_length())
260
    {
261
      /*
262
	This happens really seldom:
263
	In this case res2 is sub string of tmp_value.  We will
264
	now work in place in tmp_value to set it to res | sep_str | res2
265
      */
266
      /* Chop the last characters in tmp_value that isn't in res2 */
267
      tmp_value.length((uint32_t) (res2->ptr() - tmp_value.ptr()) +
268
		       res2->length());
269
      /* Place res2 at start of tmp_value, remove chars before res2 */
270
      if (tmp_value.replace(0,(uint32_t) (res2->ptr() - tmp_value.ptr()),
271
			    *res) ||
272
	  tmp_value.replace(res->length(),0, *sep_str))
273
	goto null;
274
      res= &tmp_value;
275
      use_as_buff=str;			// Put next arg here
276
    }
277
    else
278
    {						// Two big const strings
279
      /*
280
        NOTE: We should be prudent in the initial allocation unit -- the
281
        size of the arguments is a function of data distribution, which can
282
        be any. Instead of overcommitting at the first row, we grow the
283
        allocated amount by the factor of 2. This ensures that no more than
284
        25% of memory will be overcommitted on average.
285
      */
286
287
      uint32_t concat_len= res->length() + sep_str->length() + res2->length();
288
289
      if (tmp_value.alloced_length() < concat_len)
290
      {
291
        if (tmp_value.alloced_length() == 0)
292
        {
293
          if (tmp_value.alloc(concat_len))
294
            goto null;
295
        }
296
        else
297
        {
298
          uint32_t new_len = cmax(tmp_value.alloced_length() * 2, concat_len);
299
300
          if (tmp_value.realloc(new_len))
301
            goto null;
302
        }
303
      }
304
305
      if (tmp_value.copy(*res) ||
306
	  tmp_value.append(*sep_str) ||
307
	  tmp_value.append(*res2))
308
	goto null;
309
      res= &tmp_value;
310
      use_as_buff=str;
311
    }
312
  }
313
  res->set_charset(collation.collation);
314
  return res;
315
316
null:
317
  null_value=1;
318
  return 0;
319
}
320
321
322
void Item_func_concat_ws::fix_length_and_dec()
323
{
324
  uint64_t max_result_length;
325
326
  if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1))
327
    return;
328
329
  /*
330
     arg_count cannot be less than 2,
331
     it is done on parser level in sql_yacc.yy
332
     so, (arg_count - 2) is safe here.
333
  */
334
  max_result_length= (uint64_t) args[0]->max_length * (arg_count - 2);
335
  for (uint32_t i=1 ; i < arg_count ; i++)
336
    max_result_length+=args[i]->max_length;
337
338
  if (max_result_length >= MAX_BLOB_WIDTH)
339
  {
340
    max_result_length= MAX_BLOB_WIDTH;
341
    maybe_null= 1;
342
  }
343
  max_length= (ulong) max_result_length;
344
}
345