~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

initial changes to break out item_strfunc into functions/str

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