~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-08-04 19:37:18 UTC
  • mto: (261.2.2 codestyle)
  • mto: This revision was merged to the branch mainline in revision 262.
  • Revision ID: monty@inaugust.com-20080804193718-f0rz13uli4429ozb
Changed gettext_noop() to N_()

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
 
#include <drizzled/session.h>
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