~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/function/str/concat.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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