~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

pandora-build v0.72 - Moved remaining hard-coded tests into pandora-build
macros.
Add PANDORA_DRIZZLE_BUILD to run the extra checks that drizzle needs that 
plugins would also need to run so we can just use that macro in generated
external plugin builds.
Added support to register_plugins for external plugin building.
Renamed register_plugins.py to pandora-plugin.

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