~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

This patch completes the first step in the splitting of
the XA resource manager API from the storage engine API,
as outlined in the specification here:

http://drizzle.org/wiki/XaStorageEngine

* Splits plugin::StorageEngine into a base StorageEngine
  class and two derived classes, TransactionalStorageEngine
  and XaStorageEngine.  XaStorageEngine derives from
  TransactionalStorageEngine and creates the XA Resource
  Manager API for storage engines.

  - The methods moved from StorageEngine to TransactionalStorageEngine
    include releaseTemporaryLatches(), startConsistentSnapshot(), 
    commit(), rollback(), setSavepoint(), releaseSavepoint(),
    rollbackToSavepoint() and hasTwoPhaseCommit()
  - The methods moved from StorageEngine to XaStorageEngine
    include recover(), commitXid(), rollbackXid(), and prepare()

* Places all static "EngineVector"s into their proper
  namespaces (typedefs belong in header files, not implementation files)
  and places all static methods corresponding
  to either only transactional engines or only XA engines
  into their respective files in /drizzled/plugin/

* Modifies the InnoDB "handler" files to extend plugin::XaStorageEngine
  and not plugin::StorageEngine

The next step, as outlined in the wiki spec page above, is to isolate
the XA Resource Manager API into its own plugin class and modify
plugin::XaStorageEngine to implement plugin::XaResourceManager via
composition.  This is necessary to enable building plugins which can
participate in an XA transaction *without having to have that plugin
implement the entire storage engine API*

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