~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Moved the last of the libdrizzleclient calls into Protocol.

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
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