~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Lee
  • Date: 2008-10-30 22:02:01 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030220201-elb6qprbzpn7c5a4
add my name to the AUTHORS file

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, Inc.
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
 
          session.variables.max_allowed_packet)
61
 
      {
62
 
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
63
 
                            ER_WARN_ALLOWED_PACKET_OVERFLOWED,
64
 
                            ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
65
 
                            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
 
        size_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
 
        session.variables.max_allowed_packet)
222
 
    {
223
 
      push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
224
 
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
225
 
                          ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
226
 
                          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
 
      size_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 */