~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/dtcollation.cc

  • Committer: Monty Taylor
  • Date: 2008-07-09 16:42:25 UTC
  • mto: (77.6.1 glibclient-merge)
  • mto: This revision was merged to the branch mainline in revision 112.
  • Revision ID: monty@inaugust.com-20080709164225-2r6n4j98nhxh031l
Moved test to tests... 

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 <drizzled/dtcollation.h>
22
 
 
23
 
#include <drizzled/definitions.h>
24
 
#include <mysys/my_sys.h>
25
 
#include <mystrings/m_ctype.h>
26
 
#include <drizzled/error.h>
27
 
#include <drizzled/functions/str/conv_charset.h>
28
 
#include <drizzled/session.h>
29
 
 
30
 
 
31
 
static bool
32
 
left_is_superset(const DTCollation &left, const DTCollation &right)
33
 
{
34
 
  /* Allow convert to Unicode */
35
 
  if (left.collation->state & MY_CS_UNICODE &&
36
 
      (left.derivation < right.derivation ||
37
 
       (left.derivation == right.derivation &&
38
 
        !(right.collation->state & MY_CS_UNICODE))))
39
 
    return true;
40
 
  /* Allow convert from ASCII */
41
 
  if (right.repertoire == MY_REPERTOIRE_ASCII &&
42
 
      (left.derivation < right.derivation ||
43
 
       (left.derivation == right.derivation &&
44
 
        !(left.repertoire == MY_REPERTOIRE_ASCII))))
45
 
    return true;
46
 
  /* Disallow conversion otherwise */
47
 
  return false;
48
 
}
49
 
 
50
 
 
51
 
DTCollation::DTCollation()
52
 
{
53
 
  collation= &my_charset_bin;
54
 
  derivation= DERIVATION_NONE;
55
 
  repertoire= MY_REPERTOIRE_UNICODE30;
56
 
}
57
 
 
58
 
 
59
 
DTCollation::DTCollation(const CHARSET_INFO * const collation_arg,
60
 
                         Derivation derivation_arg)
61
 
{
62
 
  collation= collation_arg;
63
 
  derivation= derivation_arg;
64
 
  set_repertoire_from_charset(collation_arg);
65
 
}
66
 
void DTCollation::set_repertoire_from_charset(const CHARSET_INFO * const cs)
67
 
{
68
 
  repertoire= cs->state & MY_CS_PUREASCII ?
69
 
    MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30;
70
 
}
71
 
 
72
 
 
73
 
void DTCollation::set(DTCollation &dt)
74
 
{
75
 
  collation= dt.collation;
76
 
  derivation= dt.derivation;
77
 
  repertoire= dt.repertoire;
78
 
}
79
 
 
80
 
 
81
 
void DTCollation::set(const CHARSET_INFO * const collation_arg,
82
 
                      Derivation derivation_arg)
83
 
{
84
 
  collation= collation_arg;
85
 
  derivation= derivation_arg;
86
 
  set_repertoire_from_charset(collation_arg);
87
 
}
88
 
 
89
 
 
90
 
void DTCollation::set(const CHARSET_INFO * const collation_arg,
91
 
                      Derivation derivation_arg,
92
 
                      uint32_t repertoire_arg)
93
 
{
94
 
  collation= collation_arg;
95
 
  derivation= derivation_arg;
96
 
  repertoire= repertoire_arg;
97
 
}
98
 
 
99
 
 
100
 
void DTCollation::set(const CHARSET_INFO * const collation_arg)
101
 
{
102
 
  collation= collation_arg;
103
 
  set_repertoire_from_charset(collation_arg);
104
 
}
105
 
 
106
 
 
107
 
void DTCollation::set(Derivation derivation_arg)
108
 
{
109
 
  derivation= derivation_arg;
110
 
}
111
 
 
112
 
 
113
 
bool DTCollation::aggregate(DTCollation &dt, uint32_t flags)
114
 
{
115
 
  if (!my_charset_same(collation, dt.collation))
116
 
  {
117
 
    /*
118
 
      We do allow to use binary strings (like BLOBS)
119
 
      together with character strings.
120
 
      Binaries have more precedence than a character
121
 
      string of the same derivation.
122
 
    */
123
 
    if (collation == &my_charset_bin)
124
 
    {
125
 
      if (derivation <= dt.derivation)
126
 
        ; // Do nothing
127
 
      else
128
 
      {
129
 
        set(dt);
130
 
      }
131
 
    }
132
 
    else if (dt.collation == &my_charset_bin)
133
 
    {
134
 
      if (dt.derivation <= derivation)
135
 
      {
136
 
        set(dt);
137
 
      }
138
 
      else
139
 
      {
140
 
        // Do nothing
141
 
      }
142
 
    }
143
 
    else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
144
 
             left_is_superset(*this, dt))
145
 
    {
146
 
      // Do nothing
147
 
    }
148
 
    else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
149
 
             left_is_superset(dt, *this))
150
 
    {
151
 
      set(dt);
152
 
    }
153
 
    else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
154
 
             derivation < dt.derivation &&
155
 
             dt.derivation >= DERIVATION_SYSCONST)
156
 
    {
157
 
      // Do nothing;
158
 
    }
159
 
    else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
160
 
             dt.derivation < derivation &&
161
 
             derivation >= DERIVATION_SYSCONST)
162
 
    {
163
 
      set(dt);
164
 
    }
165
 
    else
166
 
    {
167
 
      // Cannot apply conversion
168
 
      set(0, DERIVATION_NONE, 0);
169
 
      return 1;
170
 
    }
171
 
  }
172
 
  else if (derivation < dt.derivation)
173
 
  {
174
 
    // Do nothing
175
 
  }
176
 
  else if (dt.derivation < derivation)
177
 
  {
178
 
    set(dt);
179
 
  }
180
 
  else
181
 
  {
182
 
    if (collation == dt.collation)
183
 
    {
184
 
      // Do nothing
185
 
    }
186
 
    else
187
 
    {
188
 
      if (derivation == DERIVATION_EXPLICIT)
189
 
      {
190
 
        set(0, DERIVATION_NONE, 0);
191
 
        return 1;
192
 
      }
193
 
      if (collation->state & MY_CS_BINSORT)
194
 
        return 0;
195
 
      if (dt.collation->state & MY_CS_BINSORT)
196
 
      {
197
 
        set(dt);
198
 
        return 0;
199
 
      }
200
 
      const CHARSET_INFO * const bin= get_charset_by_csname(collation->csname,
201
 
                                                            MY_CS_BINSORT,
202
 
                                                            MYF(0));
203
 
      set(bin, DERIVATION_NONE);
204
 
    }
205
 
  }
206
 
  repertoire|= dt.repertoire;
207
 
  return 0;
208
 
}
209
 
 
210
 
 
211
 
bool DTCollation::set(DTCollation &dt1, DTCollation &dt2, uint32_t flags)
212
 
{ set(dt1); return aggregate(dt2, flags); }
213
 
 
214
 
 
215
 
const char *DTCollation::derivation_name() const
216
 
{
217
 
  switch(derivation)
218
 
  {
219
 
  case DERIVATION_IGNORABLE: return "IGNORABLE";
220
 
  case DERIVATION_COERCIBLE: return "COERCIBLE";
221
 
  case DERIVATION_IMPLICIT:  return "IMPLICIT";
222
 
  case DERIVATION_SYSCONST:  return "SYSCONST";
223
 
  case DERIVATION_EXPLICIT:  return "EXPLICIT";
224
 
  case DERIVATION_NONE:      return "NONE";
225
 
  default: return "UNKNOWN";
226
 
  }
227
 
}
228
 
 
229
 
 
230
 
bool agg_item_collations(DTCollation &c, const char *fname,
231
 
                         Item **av, uint32_t count,
232
 
                         uint32_t flags, int item_sep)
233
 
{
234
 
  uint32_t i;
235
 
  Item **arg;
236
 
  c.set(av[0]->collation);
237
 
  for (i= 1, arg= &av[item_sep]; i < count; i++, arg++)
238
 
  {
239
 
    if (c.aggregate((*arg)->collation, flags))
240
 
    {
241
 
      my_coll_agg_error(av, count, fname, item_sep);
242
 
      return true;
243
 
    }
244
 
  }
245
 
  if ((flags & MY_COLL_DISALLOW_NONE) &&
246
 
      c.derivation == DERIVATION_NONE)
247
 
  {
248
 
    my_coll_agg_error(av, count, fname, item_sep);
249
 
    return true;
250
 
  }
251
 
  return false;
252
 
}
253
 
 
254
 
 
255
 
bool agg_item_collations_for_comparison(DTCollation &c, const char *fname,
256
 
                                        Item **av, uint32_t count,
257
 
                                        uint32_t flags)
258
 
{
259
 
  return (agg_item_collations(c, fname, av, count,
260
 
                              flags | MY_COLL_DISALLOW_NONE, 1));
261
 
}
262
 
 
263
 
 
264
 
bool agg_item_charsets(DTCollation &coll, const char *fname,
265
 
                       Item **args, uint32_t nargs, uint32_t flags,
266
 
                       int item_sep)
267
 
{
268
 
  Item **arg, *safe_args[2];
269
 
 
270
 
  memset(safe_args, 0, sizeof(safe_args));
271
 
 
272
 
  if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
273
 
    return true;
274
 
 
275
 
  /*
276
 
    For better error reporting: save the first and the second argument.
277
 
    We need this only if the the number of args is 3 or 2:
278
 
    - for a longer argument list, "Illegal mix of collations"
279
 
      doesn't display each argument's characteristics.
280
 
    - if nargs is 1, then this error cannot happen.
281
 
  */
282
 
  if (nargs >=2 && nargs <= 3)
283
 
  {
284
 
    safe_args[0]= args[0];
285
 
    safe_args[1]= args[item_sep];
286
 
  }
287
 
 
288
 
  Session *session= current_session;
289
 
  bool res= false;
290
 
  uint32_t i;
291
 
 
292
 
  for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
293
 
  {
294
 
    Item* conv;
295
 
    uint32_t dummy_offset;
296
 
    if (!String::needs_conversion(0, (*arg)->collation.collation,
297
 
                                  coll.collation,
298
 
                                  &dummy_offset))
299
 
      continue;
300
 
 
301
 
    if (!(conv= (*arg)->safe_charset_converter(coll.collation)) &&
302
 
        ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII))
303
 
      conv= new Item_func_conv_charset(*arg, coll.collation, 1);
304
 
 
305
 
    if (!conv)
306
 
    {
307
 
      if (nargs >=2 && nargs <= 3)
308
 
      {
309
 
        /* restore the original arguments for better error message */
310
 
        args[0]= safe_args[0];
311
 
        args[item_sep]= safe_args[1];
312
 
      }
313
 
      my_coll_agg_error(args, nargs, fname, item_sep);
314
 
      res= true;
315
 
      break; // we cannot return here, we need to restore "arena".
316
 
    }
317
 
    if ((*arg)->type() == Item::FIELD_ITEM)
318
 
      ((Item_field *)(*arg))->no_const_subst= 1;
319
 
    /*
320
 
      If in statement prepare, then we create a converter for two
321
 
      constant items, do it once and then reuse it.
322
 
      If we're in execution of a prepared statement, arena is NULL,
323
 
      and the conv was created in runtime memory. This can be
324
 
      the case only if the argument is a parameter marker ('?'),
325
 
      because for all true constants the charset converter has already
326
 
      been created in prepare. In this case register the change for
327
 
      rollback.
328
 
    */
329
 
    session->change_item_tree(arg, conv);
330
 
    /*
331
 
      We do not check conv->fixed, because Item_func_conv_charset which can
332
 
      be return by safe_charset_converter can't be fixed at creation
333
 
    */
334
 
    conv->fix_fields(session, arg);
335
 
  }
336
 
 
337
 
  return res;
338
 
}
339
 
 
340
 
 
341
 
void my_coll_agg_error(DTCollation &c1,
342
 
                       DTCollation &c2, const char *fname)
343
 
{
344
 
  my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
345
 
           c1.collation->name,c1.derivation_name(),
346
 
           c2.collation->name,c2.derivation_name(),
347
 
           fname);
348
 
}
349
 
 
350
 
 
351
 
void my_coll_agg_error(DTCollation &c1,
352
 
                       DTCollation &c2,
353
 
                       DTCollation &c3,
354
 
                       const char *fname)
355
 
{
356
 
  my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
357
 
           c1.collation->name,c1.derivation_name(),
358
 
           c2.collation->name,c2.derivation_name(),
359
 
           c3.collation->name,c3.derivation_name(),
360
 
           fname);
361
 
}
362
 
 
363
 
 
364
 
void my_coll_agg_error(Item** args, uint32_t count, const char *fname,
365
 
                       int item_sep)
366
 
{
367
 
  if (count == 2)
368
 
    my_coll_agg_error(args[0]->collation, args[item_sep]->collation, fname);
369
 
  else if (count == 3)
370
 
    my_coll_agg_error(args[0]->collation, args[item_sep]->collation,
371
 
                      args[2*item_sep]->collation, fname);
372
 
  else
373
 
    my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
374
 
}
375