~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-02-23 22:14:30 UTC
  • mfrom: (1273.13.96 build)
  • Revision ID: brian@gaz-20100223221430-7v7mwb3r3moku9zj
Merge of stewart.

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 "config.h"
21
 
 
22
 
#include <drizzled/function/str/substr.h>
23
 
 
24
 
#include <algorithm>
25
 
 
26
 
using namespace std;
27
 
 
28
 
namespace drizzled
29
 
{
30
 
 
31
 
String *Item_func_substr::val_str(String *str)
32
 
{
33
 
  assert(fixed == 1);
34
 
  String *res  = args[0]->val_str(str);
35
 
  /* must be int64_t to avoid truncation */
36
 
  int64_t start= args[1]->val_int();
37
 
  /* Assumes that the maximum length of a String is < INT32_MAX. */
38
 
  /* Limit so that code sees out-of-bound value properly. */
39
 
  int64_t length= arg_count == 3 ? args[2]->val_int() : INT32_MAX;
40
 
  int64_t tmp_length;
41
 
 
42
 
  if ((null_value=(args[0]->null_value || args[1]->null_value ||
43
 
                   (arg_count == 3 && args[2]->null_value))))
44
 
    return 0;
45
 
 
46
 
  /* Negative or zero length, will return empty string. */
47
 
  if ((arg_count == 3) && (length <= 0) &&
48
 
      (length == 0 || !args[2]->unsigned_flag))
49
 
    return &my_empty_string;
50
 
 
51
 
  /* Assumes that the maximum length of a String is < INT32_MAX. */
52
 
  /* Set here so that rest of code sees out-of-bound value as such. */
53
 
  if ((length <= 0) || (length > INT32_MAX))
54
 
    length= INT32_MAX;
55
 
 
56
 
  /* if "unsigned_flag" is set, we have a *huge* positive number. */
57
 
  /* Assumes that the maximum length of a String is < INT32_MAX. */
58
 
  if ((!args[1]->unsigned_flag && (start < INT32_MIN || start > INT32_MAX)) ||
59
 
      (args[1]->unsigned_flag && ((uint64_t) start > INT32_MAX)))
60
 
    return &my_empty_string;
61
 
 
62
 
  start= ((start < 0) ? res->numchars() + start : start - 1);
63
 
  start= res->charpos((int) start);
64
 
  if ((start < 0) || ((uint) start + 1 > res->length()))
65
 
    return &my_empty_string;
66
 
 
67
 
  length= res->charpos((int) length, (uint32_t) start);
68
 
  tmp_length= res->length() - start;
69
 
  length= min(length, tmp_length);
70
 
 
71
 
  if (!start && (int64_t) res->length() == length)
72
 
    return res;
73
 
  tmp_value.set(*res, (uint32_t) start, (uint32_t) length);
74
 
  return &tmp_value;
75
 
}
76
 
 
77
 
void Item_func_substr::fix_length_and_dec()
78
 
{
79
 
  max_length=args[0]->max_length;
80
 
 
81
 
  collation.set(args[0]->collation);
82
 
  if (args[1]->const_item())
83
 
  {
84
 
    int32_t start= (int32_t) args[1]->val_int();
85
 
    if (start < 0)
86
 
      max_length= ((uint)(-start) > max_length) ? 0 : (uint)(-start);
87
 
    else
88
 
      max_length-= min((uint)(start - 1), max_length);
89
 
  }
90
 
  if (arg_count == 3 && args[2]->const_item())
91
 
  {
92
 
    int32_t length= (int32_t) args[2]->val_int();
93
 
    if (length <= 0)
94
 
      max_length=0;
95
 
    else
96
 
      set_if_smaller(max_length,(uint) length);
97
 
  }
98
 
  max_length*= collation.collation->mbmaxlen;
99
 
}
100
 
 
101
 
 
102
 
void Item_func_substr_index::fix_length_and_dec()
103
 
{
104
 
  max_length= args[0]->max_length;
105
 
 
106
 
  if (agg_arg_charsets(collation, args, 2, MY_COLL_CMP_CONV, 1))
107
 
    return;
108
 
}
109
 
 
110
 
 
111
 
String *Item_func_substr_index::val_str(String *str)
112
 
{
113
 
  assert(fixed == 1);
114
 
  String *res= args[0]->val_str(str);
115
 
  String *delimiter= args[1]->val_str(&tmp_value);
116
 
  int32_t count= (int32_t) args[2]->val_int();
117
 
  uint32_t offset;
118
 
 
119
 
  if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
120
 
  {                                     // string and/or delim are null
121
 
    null_value=1;
122
 
    return 0;
123
 
  }
124
 
  null_value=0;
125
 
  uint32_t delimiter_length= delimiter->length();
126
 
  if (!res->length() || !delimiter_length || !count)
127
 
    return &my_empty_string;            // Wrong parameters
128
 
 
129
 
  res->set_charset(collation.collation);
130
 
 
131
 
  if (use_mb(res->charset()))
132
 
  {
133
 
    const char *ptr= res->ptr();
134
 
    const char *strend= ptr+res->length();
135
 
    const char *end= strend-delimiter_length+1;
136
 
    const char *search= delimiter->ptr();
137
 
    const char *search_end= search+delimiter_length;
138
 
    int32_t n=0,c=count,pass;
139
 
    register uint32_t l;
140
 
    for (pass=(count>0);pass<2;++pass)
141
 
    {
142
 
      while (ptr < end)
143
 
      {
144
 
        if (*ptr == *search)
145
 
        {
146
 
          register char *i,*j;
147
 
          i=(char*) ptr+1; j=(char*) search+1;
148
 
          while (j != search_end)
149
 
            if (*i++ != *j++) goto skip;
150
 
          if (pass==0) ++n;
151
 
          else if (!--c) break;
152
 
          ptr+= delimiter_length;
153
 
          continue;
154
 
        }
155
 
    skip:
156
 
        if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
157
 
        else ++ptr;
158
 
      } /* either not found or got total number when count<0 */
159
 
      if (pass == 0) /* count<0 */
160
 
      {
161
 
        c+=n+1;
162
 
        if (c<=0) return res; /* not found, return original string */
163
 
        ptr=res->ptr();
164
 
      }
165
 
      else
166
 
      {
167
 
        if (c) return res; /* Not found, return original string */
168
 
        if (count>0) /* return left part */
169
 
        {
170
 
          tmp_value.set(*res,0,(ulong) (ptr-res->ptr()));
171
 
        }
172
 
        else /* return right part */
173
 
        {
174
 
          ptr+= delimiter_length;
175
 
          tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr));
176
 
        }
177
 
      }
178
 
    }
179
 
  }
180
 
  else
181
 
  {
182
 
    if (count > 0)
183
 
    {                                   // start counting from the beginning
184
 
      for (offset=0; ; offset+= delimiter_length)
185
 
      {
186
 
        if ((int) (offset= res->strstr(*delimiter, offset)) < 0)
187
 
          return res;                   // Didn't find, return org string
188
 
        if (!--count)
189
 
        {
190
 
          tmp_value.set(*res,0,offset);
191
 
          break;
192
 
        }
193
 
      }
194
 
    }
195
 
    else
196
 
    {
197
 
      /*
198
 
        Negative index, start counting at the end
199
 
      */
200
 
      for (offset=res->length(); offset ;)
201
 
      {
202
 
        /*
203
 
          this call will result in finding the position pointing to one
204
 
          address space less than where the found substring is located
205
 
          in res
206
 
        */
207
 
        if ((int) (offset= res->strrstr(*delimiter, offset)) < 0)
208
 
          return res;                   // Didn't find, return org string
209
 
        /*
210
 
          At this point, we've searched for the substring
211
 
          the number of times as supplied by the index value
212
 
        */
213
 
        if (!++count)
214
 
        {
215
 
          offset+= delimiter_length;
216
 
          tmp_value.set(*res,offset,res->length()- offset);
217
 
          break;
218
 
        }
219
 
      }
220
 
    }
221
 
  }
222
 
  /*
223
 
    We always mark tmp_value as const so that if val_str() is called again
224
 
    on this object, we don't disrupt the contents of tmp_value when it was
225
 
    derived from another String.
226
 
  */
227
 
  tmp_value.mark_as_const();
228
 
  return (&tmp_value);
229
 
}
230
 
 
231
 
} /* namespace drizzled */