~ubuntu-branches/ubuntu/karmic/firebird2.1/karmic

« back to all changes in this revision

Viewing changes to src/jrd/intl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Damyan Ivanov
  • Date: 2008-05-26 23:59:25 UTC
  • Revision ID: james.westby@ubuntu.com-20080526235925-2pnqj6nxpppoeaer
Tags: upstream-2.1.0.17798-0.ds2
ImportĀ upstreamĀ versionĀ 2.1.0.17798-0.ds2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************  history ************
 
2
*
 
3
*       COMPONENT: JRD  MODULE: INTL.CPP
 
4
*       generated by Marion V2.5     2/6/90
 
5
*       from dev              db        on 4-JAN-1995
 
6
*****************************************************************
 
7
*
 
8
*       PR      2002-06-02 Added ugly c hack in
 
9
*       intl_back_compat_alloc_func_lookup.
 
10
*       When someone has time we need to change the references to
 
11
*       return (void*) function to something more C++ like
 
12
*
 
13
*       42 4711 3 11 17  tamlin   2001
 
14
*       Added silly numbers before my name, and converted it to C++.
 
15
*
 
16
*       18850   daves   4-JAN-1995
 
17
*       Fix gds__alloc usage
 
18
*
 
19
*       18837   deej    31-DEC-1994
 
20
*       fixing up HARBOR_MERGE
 
21
*
 
22
*       18821   deej    27-DEC-1994
 
23
*       HARBOR MERGE
 
24
*
 
25
*       18789   jdavid  19-DEC-1994
 
26
*       Cast some functions
 
27
*
 
28
*       17508   jdavid  15-JUL-1994
 
29
*       Bring it up to date
 
30
*
 
31
*       17500   daves   13-JUL-1994
 
32
*       Bug 6645: Different calculation of partial keys
 
33
*
 
34
*       17202   katz    24-MAY-1994
 
35
*       PC_PLATFORM requires the .dll extension
 
36
*
 
37
*       17191   katz    23-MAY-1994
 
38
*       OS/2 requires the .dll extension
 
39
*
 
40
*       17180   katz    23-MAY-1994
 
41
*       Define location of DLL on OS/2
 
42
*
 
43
*       17149   katz    20-MAY-1994
 
44
*       In JRD, isc_arg_number arguments are SLONG's not int's
 
45
*
 
46
*       16633   daves   19-APR-1994
 
47
*       Bug 6202: International licensing uses INTERNATIONAL product code
 
48
*
 
49
*       16555   katz    17-APR-1994
 
50
*       The last argument of calls to ERR_post should be 0
 
51
*
 
52
*       16521   katz    14-APR-1994
 
53
*       Borland C needs a decorated symbol to lookup
 
54
*
 
55
*       16403   daves   8-APR-1994
 
56
*       Bug 6441: Emit an error whenever transliteration from ttype_binary attempted
 
57
*
 
58
*       16141   katz    28-MAR-1994
 
59
*       Don't declare return value from ISC_lookup_entrypoint as API_ROUTINE
 
60
*
 
61
 * The contents of this file are subject to the Interbase Public
 
62
 * License Version 1.0 (the "License"); you may not use this file
 
63
 * except in compliance with the License. You may obtain a copy
 
64
 * of the License at http://www.Inprise.com/IPL.html
 
65
 *
 
66
 * Software distributed under the License is distributed on an
 
67
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 
68
 * or implied. See the License for the specific language governing
 
69
 * rights and limitations under the License.
 
70
 *
 
71
 * The Original Code was created by Inprise Corporation
 
72
 * and its predecessors. Portions created by Inprise Corporation are
 
73
 * Copyright (C) Inprise Corporation.
 
74
 *
 
75
 * All Rights Reserved.
 
76
 * Contributor(s): ______________________________________.
 
77
 *
 
78
 * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
 
79
 *
 
80
 * 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
 
81
 *
 
82
*/
 
83
 
 
84
 
 
85
/*
 
86
 *      PROGRAM:        JRD Intl
 
87
 *      MODULE:         intl.cpp
 
88
 *      DESCRIPTION:    International text support routines
 
89
 *
 
90
 * copyright (c) 1992, 1993 by Borland International
 
91
 */
 
92
 
 
93
#include "firebird.h"
 
94
#include <string.h>
 
95
#include "../jrd/common.h"
 
96
#include <stdio.h>
 
97
#include "../jrd/jrd.h"
 
98
#include "../jrd/req.h"
 
99
#include "../jrd/val.h"
 
100
#include "gen/iberror.h"
 
101
#include "../jrd/intl.h"
 
102
#include "../jrd/intl_classes.h"
 
103
#include "../jrd/ods.h"
 
104
#include "../jrd/btr.h"
 
105
#include "../intl/charsets.h"
 
106
#include "../intl/country_codes.h"
 
107
#include "../jrd/gdsassert.h"
 
108
//#include "../jrd/license.h"
 
109
#ifdef INTL_BUILTIN
 
110
#include "../intl/ld_proto.h"
 
111
#endif
 
112
#include "../jrd/cvt_proto.h"
 
113
#include "../jrd/err_proto.h"
 
114
#include "../jrd/fun_proto.h"
 
115
#include "../jrd/gds_proto.h"
 
116
#include "../jrd/iberr_proto.h"
 
117
#include "../jrd/intl_proto.h"
 
118
#include "../jrd/isc_proto.h"
 
119
#include "../jrd/lck_proto.h"
 
120
#include "../jrd/met_proto.h"
 
121
#include "../jrd/thd.h"
 
122
#include "../jrd/evl_string.h"
 
123
#include "../jrd/intlobj_new.h"
 
124
#include "../jrd/jrd.h"
 
125
#include "../jrd/mov_proto.h"
 
126
#include "../jrd/IntlManager.h"
 
127
#include "../common/classes/init.h"
 
128
 
 
129
using namespace Jrd;
 
130
 
 
131
#define IS_TEXT(x)      (((x)->dsc_dtype == dtype_text)   ||\
 
132
                         ((x)->dsc_dtype == dtype_varying)||\
 
133
                         ((x)->dsc_dtype == dtype_cstring))
 
134
 
 
135
 
 
136
static bool all_spaces(thread_db*, CHARSET_ID, const BYTE*, ULONG, ULONG);
 
137
static int blocking_ast_collation(void* ast_object);
 
138
static void pad_spaces(thread_db*, CHARSET_ID, BYTE *, ULONG);
 
139
static INTL_BOOL lookup_charset(charset* cs, const SubtypeInfo* info);
 
140
static INTL_BOOL lookup_texttype(texttype* tt, const SubtypeInfo* info);
 
141
 
 
142
 
 
143
// Classes and structures used internally to this file and intl implementation
 
144
class CharSetContainer
 
145
{
 
146
public:
 
147
        CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInfo* info);
 
148
 
 
149
        void destroy()
 
150
        {
 
151
                cs->destroy();
 
152
                for (size_t i = 0; i < charset_collations.getCount(); i++)
 
153
                        if (charset_collations[i])
 
154
                                charset_collations[i]->destroy();
 
155
        }
 
156
 
 
157
        CharSet* getCharSet() { return cs; }
 
158
 
 
159
        Collation* lookupCollation(thread_db* tdbb, USHORT tt_id);
 
160
        void unloadCollation(thread_db* tdbb, USHORT tt_id);
 
161
 
 
162
        CsConvert lookupConverter(thread_db* tdbb, CHARSET_ID to_cs);
 
163
 
 
164
        static CharSetContainer* lookupCharset(thread_db* tdbb, USHORT ttype);
 
165
        static Lock* createCollationLock(thread_db* tdbb, USHORT ttype);
 
166
 
 
167
private:
 
168
        Firebird::Array<Collation*> charset_collations;
 
169
        CharSet* cs;
 
170
};
 
171
 
 
172
 
 
173
CharSetContainer* CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
 
174
{
 
175
/**************************************
 
176
 *
 
177
 *      l o o k u p C h a r s e t
 
178
 *
 
179
 **************************************
 
180
 *
 
181
 * Functional description
 
182
 *
 
183
 *      Lookup a character set descriptor.
 
184
 *
 
185
 *      First, search the appropriate vector that hangs
 
186
 *      off the dbb.  If not found, then call the lower
 
187
 *      level lookup routine to allocate it, or punt
 
188
 *              if we don't know about the charset.
 
189
 *
 
190
 * Returns:
 
191
 *      *charset
 
192
 *      <never>         - if error
 
193
 *
 
194
 **************************************/
 
195
        CharSetContainer *cs = NULL;
 
196
 
 
197
        SET_TDBB(tdbb);
 
198
        Database* dbb = tdbb->getDatabase();
 
199
 
 
200
        USHORT id = TTYPE_TO_CHARSET(ttype);
 
201
        if (id == CS_dynamic)
 
202
                id = tdbb->getAttachment()->att_charset;
 
203
 
 
204
        if (id >= dbb->dbb_charsets.getCount())
 
205
                dbb->dbb_charsets.resize(id + 10);
 
206
        else
 
207
                cs = dbb->dbb_charsets[id];
 
208
 
 
209
        // allocate a new character set object if we couldn't find one.
 
210
        if (!cs) {
 
211
                SubtypeInfo info;
 
212
 
 
213
                if (id == CS_UTF16)
 
214
                        info.charsetName = "UTF16";
 
215
 
 
216
                if ((id == CS_UTF16) || MET_get_char_coll_subtype_info(tdbb, id, &info))
 
217
                {
 
218
                        dbb->dbb_charsets[id] = cs =
 
219
                                FB_NEW(*dbb->dbb_permanent) CharSetContainer(*dbb->dbb_permanent, id, &info);
 
220
                }
 
221
                else
 
222
                        ERR_post(isc_text_subtype, isc_arg_number, (ISC_STATUS) ttype, 0);
 
223
        }
 
224
 
 
225
        return cs;
 
226
}
 
227
 
 
228
Lock* CharSetContainer::createCollationLock(thread_db* tdbb, USHORT ttype)
 
229
{
 
230
/**************************************
 
231
 *
 
232
 *      c r e a t e C o l l a t i o n L o c k
 
233
 *
 
234
 **************************************
 
235
 *
 
236
 * Functional description
 
237
 *      Create a collation lock.
 
238
 *
 
239
 **************************************/
 
240
        Lock* lock = FB_NEW_RPT(*tdbb->getDatabase()->dbb_permanent, 0) Lock;
 
241
        lock->lck_parent = tdbb->getDatabase()->dbb_lock;
 
242
        lock->lck_dbb = tdbb->getDatabase();
 
243
        lock->lck_key.lck_long = ttype;
 
244
        lock->lck_length = sizeof(lock->lck_key.lck_long);
 
245
        lock->lck_type = LCK_tt_exist;
 
246
        lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
 
247
        lock->lck_object = NULL;
 
248
        lock->lck_ast = blocking_ast_collation;
 
249
 
 
250
        return lock;
 
251
}
 
252
 
 
253
CharSetContainer::CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInfo* info) :
 
254
        charset_collations(p),
 
255
        cs(NULL)
 
256
{
 
257
        charset* csL = FB_NEW(p) charset;
 
258
        memset(csL, 0, sizeof(charset));
 
259
 
 
260
        if (lookup_charset(csL, info) && (csL->charset_flags & CHARSET_ASCII_BASED))
 
261
                this->cs = CharSet::createInstance(p, cs_id, csL);
 
262
        else
 
263
        {
 
264
                delete csL;
 
265
                ERR_post(isc_charset_not_installed, isc_arg_string, ERR_cstring(info->charsetName.c_str()), 0);
 
266
        }
 
267
}
 
268
 
 
269
CsConvert CharSetContainer::lookupConverter(thread_db* tdbb, CHARSET_ID toCsId)
 
270
{
 
271
        if (toCsId == CS_UTF16)
 
272
                return CsConvert(cs->getStruct(), NULL);
 
273
        else
 
274
        {
 
275
                CharSet* toCs = INTL_charset_lookup(tdbb, toCsId);
 
276
 
 
277
                if (cs->getId() == CS_UTF16)
 
278
                        return CsConvert(NULL, toCs->getStruct());
 
279
                else
 
280
                        return CsConvert(cs->getStruct(), toCs->getStruct());
 
281
        }
 
282
}
 
283
 
 
284
Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
 
285
{
 
286
        const USHORT id = TTYPE_TO_COLLATION(tt_id);
 
287
 
 
288
        if (id < charset_collations.getCount() && charset_collations[id] != NULL)
 
289
        {
 
290
                if (charset_collations[id]->obsolete)
 
291
                {
 
292
                        if (charset_collations[id]->existenceLock)
 
293
                                LCK_release(tdbb, charset_collations[id]->existenceLock);
 
294
 
 
295
                        charset_collations[id]->destroy();
 
296
                        delete charset_collations[id];
 
297
                        charset_collations[id] = NULL;
 
298
                }
 
299
                else
 
300
                        return charset_collations[id];
 
301
        }
 
302
 
 
303
        SubtypeInfo info;
 
304
        if (MET_get_char_coll_subtype_info(tdbb, tt_id, &info))
 
305
        {
 
306
                CharSet* charset = INTL_charset_lookup(tdbb, TTYPE_TO_CHARSET(tt_id));
 
307
 
 
308
                if (TTYPE_TO_CHARSET(tt_id) != CS_METADATA)
 
309
                {
 
310
                        Firebird::UCharBuffer specificAttributes;
 
311
                        ULONG size = info.specificAttributes.getCount() * charset->maxBytesPerChar();
 
312
 
 
313
                        size = INTL_convert_bytes(tdbb, TTYPE_TO_CHARSET(tt_id),
 
314
                                                                          specificAttributes.getBuffer(size), size,
 
315
                                                                          CS_METADATA, info.specificAttributes.begin(),
 
316
                                                                          info.specificAttributes.getCount(), ERR_post);
 
317
                        specificAttributes.shrink(size);
 
318
                        info.specificAttributes = specificAttributes;
 
319
                }
 
320
 
 
321
                texttype* tt = FB_NEW(*tdbb->getDatabase()->dbb_permanent) texttype;
 
322
                memset(tt, 0, sizeof(texttype));
 
323
 
 
324
                if (!lookup_texttype(tt, &info))
 
325
                {
 
326
                        delete tt;
 
327
                        ERR_post(isc_collation_not_installed,
 
328
                                isc_arg_string, ERR_cstring(info.collationName.c_str()),
 
329
                                isc_arg_string, ERR_cstring(info.charsetName.c_str()), 0);
 
330
                }
 
331
 
 
332
                if (charset_collations.getCount() <= id)
 
333
                        charset_collations.grow(id + 1);
 
334
 
 
335
                fb_assert((tt->texttype_canonical_width == 0 && tt->texttype_fn_canonical == NULL) ||
 
336
                                  (tt->texttype_canonical_width != 0 && tt->texttype_fn_canonical != NULL));
 
337
 
 
338
                if (tt->texttype_canonical_width == 0)
 
339
                {
 
340
                        if (charset->isMultiByte())
 
341
                                tt->texttype_canonical_width = sizeof(ULONG);   // UTF-32
 
342
                        else
 
343
                        {
 
344
                                tt->texttype_canonical_width = charset->minBytesPerChar();
 
345
                                // canonical is equal to string, then TEXTTYPE_DIRECT_MATCH can be turned on
 
346
                                tt->texttype_flags |= TEXTTYPE_DIRECT_MATCH;
 
347
                        }
 
348
                }
 
349
 
 
350
                charset_collations[id] = Collation::createInstance(*tdbb->getDatabase()->dbb_permanent, tt_id, tt, charset);
 
351
                charset_collations[id]->name = info.collationName;
 
352
 
 
353
                // we don't need a lock in the charset
 
354
                if (id != 0)
 
355
                {
 
356
                        Lock* lock = charset_collations[id]->existenceLock =
 
357
                                CharSetContainer::createCollationLock(tdbb, tt_id);
 
358
                        lock->lck_object = (blk*)charset_collations[id];
 
359
 
 
360
                        LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT);
 
361
                }
 
362
        }
 
363
        else
 
364
                ERR_post(isc_text_subtype, isc_arg_number, (ISC_STATUS) tt_id, 0);
 
365
 
 
366
        return charset_collations[id];
 
367
}
 
368
 
 
369
 
 
370
void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id)
 
371
{
 
372
        const USHORT id = TTYPE_TO_COLLATION(tt_id);
 
373
 
 
374
        if (id < charset_collations.getCount() && charset_collations[id] != NULL)
 
375
        {
 
376
                if (charset_collations[id]->useCount != 0)
 
377
                {
 
378
                        ERR_post(isc_no_meta_update,
 
379
                                         isc_arg_gds, isc_obj_in_use,
 
380
                                         isc_arg_string, charset_collations[id]->name.c_str(),
 
381
                                         0);
 
382
                }
 
383
 
 
384
                if (charset_collations[id]->existenceLock)
 
385
                        LCK_convert_non_blocking(tdbb, charset_collations[id]->existenceLock, LCK_EX, LCK_WAIT);
 
386
 
 
387
                charset_collations[id]->obsolete = true;
 
388
 
 
389
                if (charset_collations[id]->existenceLock)
 
390
                {
 
391
                        LCK_release(tdbb, charset_collations[id]->existenceLock);
 
392
                        charset_collations[id]->existenceLock = NULL;
 
393
                }
 
394
        }
 
395
        else
 
396
        {
 
397
                Lock* lock = CharSetContainer::createCollationLock(tdbb, tt_id);
 
398
 
 
399
                LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);
 
400
                LCK_release(tdbb, lock);
 
401
 
 
402
                delete lock;
 
403
        }
 
404
}
 
405
 
 
406
 
 
407
static INTL_BOOL lookup_charset(charset* cs, const SubtypeInfo* info)
 
408
{
 
409
        return IntlManager::lookupCharSet(info->charsetName.c_str(), cs);
 
410
}
 
411
 
 
412
 
 
413
static INTL_BOOL lookup_texttype(texttype* tt, const SubtypeInfo* info)
 
414
{
 
415
        return IntlManager::lookupCollation(info->baseCollationName.c_str(), info->charsetName.c_str(),
 
416
                info->attributes, info->specificAttributes.begin(),
 
417
                info->specificAttributes.getCount(), info->ignoreAttributes, tt);
 
418
}
 
419
 
 
420
 
 
421
void Database::destroyIntlObjects()
 
422
{
 
423
        for (size_t i = 0; i < dbb_charsets.getCount(); i++)
 
424
        {
 
425
                if (dbb_charsets[i])
 
426
                {
 
427
                        dbb_charsets[i]->destroy();
 
428
                        dbb_charsets[i] = 0;
 
429
                }
 
430
        }
 
431
}
 
432
 
 
433
 
 
434
CHARSET_ID INTL_charset(thread_db* tdbb, USHORT ttype)
 
435
{
 
436
/**************************************
 
437
 *
 
438
 *      I N T L _ c h a r s e t
 
439
 *
 
440
 **************************************
 
441
 *
 
442
 * Functional description
 
443
 *      Return the character set ID for a piece of text.
 
444
 *
 
445
 **************************************/
 
446
 
 
447
        switch (ttype)
 
448
        {
 
449
        case ttype_none:
 
450
                return (CS_NONE);
 
451
        case ttype_ascii:
 
452
                return (CS_ASCII);
 
453
        case ttype_unicode_fss:
 
454
                return (CS_UNICODE_FSS);
 
455
        case ttype_binary:
 
456
                return (CS_BINARY);
 
457
        case ttype_dynamic:
 
458
                SET_TDBB(tdbb);
 
459
                return (tdbb->getAttachment()->att_charset);
 
460
        default:
 
461
                return (TTYPE_TO_CHARSET(ttype));
 
462
        }
 
463
}
 
464
 
 
465
 
 
466
int INTL_compare(thread_db* tdbb,
 
467
                                const dsc* pText1,
 
468
                                const dsc* pText2,
 
469
                                FPTR_ERROR err)
 
470
{
 
471
/**************************************
 
472
 *
 
473
 *      I N T L _ c o m p a r e
 
474
 *
 
475
 **************************************
 
476
 *
 
477
 * Functional description
 
478
 *      Compare two pieces of international text.
 
479
 *
 
480
 **************************************/
 
481
        SET_TDBB(tdbb);
 
482
 
 
483
        fb_assert(pText1 != NULL);
 
484
        fb_assert(pText2 != NULL);
 
485
        fb_assert(IS_TEXT(pText1) && IS_TEXT(pText2));
 
486
        fb_assert(INTL_data_or_binary(pText1) || INTL_data_or_binary(pText2));
 
487
        fb_assert(err);
 
488
 
 
489
/* normal compare routine from CVT_compare */
 
490
/* trailing spaces in strings are ignored for comparision */
 
491
 
 
492
        UCHAR* p1;
 
493
        USHORT t1;
 
494
        USHORT length1 = CVT_get_string_ptr(pText1, &t1, &p1, NULL, 0, err);
 
495
 
 
496
        UCHAR* p2;
 
497
        USHORT t2;
 
498
        USHORT length2 = CVT_get_string_ptr(pText2, &t2, &p2, NULL, 0, err);
 
499
 
 
500
/* YYY - by SQL II compare_type must be explicit in the
 
501
   SQL statement if there is any doubt */
 
502
 
 
503
        USHORT compare_type = MAX(t1, t2);      /* YYY */
 
504
        UCHAR buffer[MAX_KEY];
 
505
 
 
506
        if (t1 != t2) {
 
507
                CHARSET_ID cs1 = INTL_charset(tdbb, t1);
 
508
                CHARSET_ID cs2 = INTL_charset(tdbb, t2);
 
509
                if (cs1 != cs2) {
 
510
                        if (compare_type != t2) {
 
511
                                /* convert pText2 to pText1's type, if possible */
 
512
                                /* YYY - should failure to convert really return
 
513
                                   an error here?
 
514
                                   Support joining a 437 & Latin1 Column, and we
 
515
                                   pick the compare_type as 437, still only want the
 
516
                                   equal values....
 
517
                                   But then, what about < operations, which make no
 
518
                                   sense if the string cannot be expressed...
 
519
                                 */
 
520
 
 
521
                                length2 = INTL_convert_bytes(tdbb, cs1,
 
522
                                                                                         buffer, sizeof(buffer),
 
523
                                                                                         cs2, p2, length2, err);
 
524
                                p2 = buffer;
 
525
                        }
 
526
                        else {
 
527
                                /* convert pText1 to pText2's type, if possible */
 
528
 
 
529
                                length1 = INTL_convert_bytes(tdbb, cs2,
 
530
                                                                                         buffer, sizeof(buffer),
 
531
                                                                                         cs1, p1, length1, err);
 
532
                                p1 = buffer;
 
533
                        }
 
534
                }
 
535
        }
 
536
 
 
537
        TextType* obj = INTL_texttype_lookup(tdbb, compare_type);
 
538
 
 
539
        return obj->compare(length1, p1, length2, p2);
 
540
}
 
541
 
 
542
 
 
543
ULONG INTL_convert_bytes(thread_db* tdbb,
 
544
                                                 CHARSET_ID dest_type,
 
545
                                                 BYTE* dest_ptr,
 
546
                                                 ULONG dest_len,
 
547
                                                 CHARSET_ID src_type,
 
548
                                                 const BYTE* src_ptr,
 
549
                                                 ULONG src_len,
 
550
                                                 FPTR_ERROR err)
 
551
{
 
552
/**************************************
 
553
 *
 
554
 *      I N T L _ c o n v e r t _ b y t e s
 
555
 *
 
556
 **************************************
 
557
 *
 
558
 * Functional description
 
559
 *      Given a string of bytes in one character set, convert it to another
 
560
 *      character set.
 
561
 *
 
562
 *      If (dest_ptr) is NULL, return the count of bytes needed to convert
 
563
 *      the string.  This does not guarantee the string can be converted,
 
564
 *      the purpose of this is to allocate a large enough buffer.
 
565
 *
 
566
 * RETURNS:
 
567
 *      Length of resulting string, in bytes.
 
568
 *      calls (err) if conversion error occurs.
 
569
 *
 
570
 **************************************/
 
571
        ULONG len;
 
572
 
 
573
 
 
574
        SET_TDBB(tdbb);
 
575
 
 
576
        fb_assert(src_ptr != NULL);
 
577
        fb_assert(src_type != dest_type);
 
578
        fb_assert(err != NULL);
 
579
 
 
580
        dest_type = INTL_charset(tdbb, dest_type);
 
581
        src_type = INTL_charset(tdbb, src_type);
 
582
 
 
583
        const UCHAR* const start_dest_ptr = dest_ptr;
 
584
 
 
585
        if ((dest_type == CS_BINARY) ||
 
586
                (dest_type == CS_NONE) ||
 
587
                (src_type == CS_BINARY) ||
 
588
                (src_type == CS_NONE))
 
589
        {
 
590
                /* See if we just need a length estimate */
 
591
                if (dest_ptr == NULL)
 
592
                        return (src_len);
 
593
 
 
594
                if (dest_type != CS_BINARY && dest_type != CS_NONE)
 
595
                {
 
596
                        CharSet* toCharSet = INTL_charset_lookup(tdbb, dest_type);
 
597
 
 
598
                        if (!toCharSet->wellFormed(src_len, src_ptr))
 
599
                                (*err)(isc_malformed_string, 0);
 
600
                }
 
601
 
 
602
                len = MIN(dest_len, src_len);
 
603
                if (len)
 
604
                        do {
 
605
                                *dest_ptr++ = *src_ptr++;
 
606
                        } while (--len);
 
607
 
 
608
                /* See if only space characters are remaining */
 
609
                len = src_len - MIN(dest_len, src_len);
 
610
                if (!len || all_spaces(tdbb, src_type, src_ptr, len, 0))
 
611
                        return (dest_ptr - start_dest_ptr);
 
612
                else
 
613
                        (*err) (isc_arith_except, 0);
 
614
        }
 
615
        else if (src_len == 0)
 
616
                return (0);
 
617
        else
 
618
                /* character sets are known to be different */
 
619
        {
 
620
                /* Do we know an object from cs1 to cs2? */
 
621
 
 
622
                CsConvert cs_obj = INTL_convert_lookup(tdbb, dest_type, src_type);
 
623
                return cs_obj.convert(src_len, src_ptr, dest_len, dest_ptr, NULL, true);
 
624
        }
 
625
 
 
626
        return (0);                                     /* to remove compiler errors.  This should never be executed */
 
627
}
 
628
 
 
629
 
 
630
CsConvert INTL_convert_lookup(thread_db* tdbb,
 
631
                                                                CHARSET_ID to_cs,
 
632
                                                                CHARSET_ID from_cs)
 
633
{
 
634
/**************************************
 
635
 *
 
636
 *      I N T L _ c o n v e r t _ l o o k u p
 
637
 *
 
638
 **************************************
 
639
 *
 
640
 * Functional description
 
641
 *
 
642
 **************************************/
 
643
 
 
644
        SET_TDBB(tdbb);
 
645
        Database* dbb = tdbb->getDatabase();
 
646
        CHECK_DBB(dbb);
 
647
 
 
648
        if (from_cs == CS_dynamic)
 
649
                from_cs = tdbb->getAttachment()->att_charset;
 
650
 
 
651
        if (to_cs == CS_dynamic)
 
652
                to_cs = tdbb->getAttachment()->att_charset;
 
653
 
 
654
/* Should from_cs == to_cs? be handled better? YYY */
 
655
 
 
656
        fb_assert(from_cs != CS_dynamic);
 
657
        fb_assert(to_cs != CS_dynamic);
 
658
 
 
659
        CharSetContainer* charset = CharSetContainer::lookupCharset(tdbb, from_cs);
 
660
 
 
661
        return charset->lookupConverter(tdbb, to_cs);
 
662
}
 
663
 
 
664
 
 
665
int INTL_convert_string(dsc* to, const dsc* from, FPTR_ERROR err)
 
666
{
 
667
/**************************************
 
668
 *
 
669
 *      I N T L _ c o n v e r t _ s t r i n g
 
670
 *
 
671
 **************************************
 
672
 *
 
673
 * Functional description
 
674
 *      Convert a string from one type to another
 
675
 *
 
676
 * RETURNS:
 
677
 *      0 if no error in conversion
 
678
 *      non-zero otherwise.
 
679
 *      CVC: Unfortunately, this function puts the source in the 2nd param,
 
680
 *      as opposed to the CVT routines, so const help mitigating coding mistakes.
 
681
 *
 
682
 **************************************/
 
683
 
 
684
/* Note: This function is called from outside the engine as
 
685
   well as inside - we likely can't get rid of JRD_get_thread_data here */
 
686
        thread_db* tdbb = JRD_get_thread_data();
 
687
        if (tdbb == NULL)                       /* are we in the Engine? */
 
688
                return (1);                             /* no, then can't access intl gah */
 
689
 
 
690
        fb_assert(to != NULL);
 
691
        fb_assert(from != NULL);
 
692
        fb_assert(IS_TEXT(to) && IS_TEXT(from));
 
693
 
 
694
        CHARSET_ID from_cs = INTL_charset(tdbb, INTL_TTYPE(from));
 
695
        CHARSET_ID to_cs = INTL_charset(tdbb, INTL_TTYPE(to));
 
696
 
 
697
        UCHAR* start = to->dsc_address;
 
698
        UCHAR* p = start;
 
699
 
 
700
/* Must convert dtype(cstring,text,vary) and ttype(ascii,binary,..intl..) */
 
701
 
 
702
        UCHAR* from_ptr;
 
703
        USHORT from_type;
 
704
        const USHORT from_len =
 
705
                CVT_get_string_ptr(from, &from_type, &from_ptr, NULL, 0, err);
 
706
 
 
707
        ULONG to_size, to_len, to_fill;
 
708
        to_size = to_len = TEXT_LEN(to);
 
709
        ULONG from_fill;
 
710
 
 
711
        const UCHAR* q = from_ptr;
 
712
        CharSet* toCharSet = INTL_charset_lookup(tdbb, to_cs);
 
713
        ULONG toLength;
 
714
 
 
715
        switch (to->dsc_dtype) {
 
716
        case dtype_text:
 
717
                if ((from_cs != to_cs) && (to_cs != CS_BINARY) && (to_cs != CS_NONE) && (from_cs != CS_NONE)) {
 
718
 
 
719
                        to_len = INTL_convert_bytes(tdbb, to_cs, to->dsc_address, to_size,
 
720
                                                                                from_cs, from_ptr, from_len, err);
 
721
                        toLength = to_len;
 
722
                        to_fill = to_size - to_len;
 
723
                        from_fill = 0;          /* Convert_bytes handles source truncation */
 
724
                        p += to_len;
 
725
                }
 
726
                else {
 
727
                        /* binary string can always be converted TO by byte-copy */
 
728
 
 
729
                        to_len = MIN(from_len, to_size);
 
730
                        if (!toCharSet->wellFormed(to_len, q))
 
731
                                (*err)(isc_malformed_string, 0);
 
732
                        toLength = to_len;
 
733
                        from_fill = from_len - to_len;
 
734
                        to_fill = to_size - to_len;
 
735
                        if (to_len)
 
736
                                do
 
737
                                        *p++ = *q++;
 
738
                                while (--to_len);
 
739
                }
 
740
 
 
741
                if (to_fill > 0)
 
742
                        pad_spaces(tdbb, to_cs, p, to_fill);
 
743
                break;
 
744
 
 
745
        case dtype_cstring:
 
746
                if ((from_cs != to_cs) && (to_cs != CS_BINARY) && (to_cs != CS_NONE) && (from_cs != CS_NONE)) {
 
747
                        to_len = INTL_convert_bytes(tdbb, to_cs, to->dsc_address, to_size,
 
748
                                                                                from_cs, from_ptr, from_len, err);
 
749
                        toLength = to_len;
 
750
                        to->dsc_address[to_len] = 0;
 
751
                        from_fill = 0;          /* Convert_bytes handles source truncation */
 
752
                }
 
753
                else {
 
754
                        /* binary string can always be converted TO by byte-copy */
 
755
 
 
756
                        to_len = MIN(from_len, to_size);
 
757
                        if (!toCharSet->wellFormed(to_len, q))
 
758
                                (*err)(isc_malformed_string, 0);
 
759
                        toLength = to_len;
 
760
                        from_fill = from_len - to_len;
 
761
                        if (to_len)
 
762
                                do
 
763
                                        *p++ = *q++;
 
764
                                while (--to_len);
 
765
                        *p = 0;
 
766
                }
 
767
                break;
 
768
 
 
769
        case dtype_varying:
 
770
                if ((from_cs != to_cs) && (to_cs != CS_BINARY) && (to_cs != CS_NONE) && (from_cs != CS_NONE)) {
 
771
 
 
772
                        to_len =
 
773
                                INTL_convert_bytes(tdbb, to_cs,
 
774
                                                                   (start = reinterpret_cast<UCHAR*>(((vary*) to->dsc_address)->vary_string)),
 
775
                                                                   to_size, from_cs, from_ptr, from_len, err);
 
776
                        toLength = to_len;
 
777
                        ((vary*) to->dsc_address)->vary_length = to_len;
 
778
                        from_fill = 0;          /* Convert_bytes handles source truncation */
 
779
                }
 
780
                else {
 
781
                        /* binary string can always be converted TO by byte-copy */
 
782
                        to_len = MIN(from_len, to_size);
 
783
                        if (!toCharSet->wellFormed(to_len, q))
 
784
                                (*err)(isc_malformed_string, 0);
 
785
                        toLength = to_len;
 
786
                        from_fill = from_len - to_len;
 
787
                        ((vary*) p)->vary_length = to_len;
 
788
                        start = p = reinterpret_cast<UCHAR*>(((vary*) p)->vary_string);
 
789
                        if (to_len)
 
790
                                do
 
791
                                        *p++ = *q++;
 
792
                                while (--to_len);
 
793
                }
 
794
                break;
 
795
        }
 
796
 
 
797
        if (toCharSet->isMultiByte() &&
 
798
                !(toCharSet->getFlags() & CHARSET_LEGACY_SEMANTICS) &&
 
799
                toLength != 31 &&       /* allow non CHARSET_LEGACY_SEMANTICS to be used as connection charset */
 
800
                toCharSet->length(toLength, start, false) > to_size / toCharSet->maxBytesPerChar())
 
801
        {
 
802
                (*err)(isc_arith_except, 0);
 
803
        }
 
804
 
 
805
        if (from_fill)
 
806
                /* Make sure remaining characters on From string are spaces */
 
807
                if (!all_spaces(tdbb, from_cs, q, from_fill, 0))
 
808
                        (*err) (isc_arith_except, 0);
 
809
 
 
810
        return 0;
 
811
}
 
812
 
 
813
 
 
814
int INTL_data(const dsc* pText)
 
815
{
 
816
/**************************************
 
817
 *
 
818
 *      I N T L _ d a t a
 
819
 *
 
820
 **************************************
 
821
 *
 
822
 * Functional description
 
823
 *      Given an input text descriptor,
 
824
 *      return TRUE if the data pointed to represents
 
825
 *      international text (subject to user defined or non-binary
 
826
 *      collation or comparison).
 
827
 *
 
828
 **************************************/
 
829
 
 
830
        fb_assert(pText != NULL);
 
831
 
 
832
        if (!IS_TEXT(pText))
 
833
                return FALSE;
 
834
 
 
835
        if (!INTERNAL_TTYPE(pText))
 
836
                return TRUE;
 
837
 
 
838
        return FALSE;
 
839
}
 
840
 
 
841
int INTL_data_or_binary(const dsc* pText)
 
842
{
 
843
/**************************************
 
844
 *
 
845
 *      I N T L _ d a t a _ o r _ b i n a r y
 
846
 *
 
847
 **************************************
 
848
 *
 
849
 * Functional description
 
850
 *
 
851
 **************************************/
 
852
 
 
853
        return (INTL_data(pText) || (pText->dsc_ttype() == ttype_binary));
 
854
}
 
855
 
 
856
 
 
857
bool INTL_defined_type(thread_db* tdbb, USHORT t_type)
 
858
{
 
859
/**************************************
 
860
 *
 
861
 *      I N T L _ d e f i n e d _ t y p e
 
862
 *
 
863
 **************************************
 
864
 *
 
865
 * Functional description
 
866
 *      Is (t_type) a known text type?
 
867
 * Return:
 
868
 *      false   type is not defined.
 
869
 *      true    type is defined
 
870
 *
 
871
 * Note:
 
872
 *      Due to cleanup that must happen in DFW, this routine
 
873
 *      must return, and not call ERR directly.
 
874
 *
 
875
 **************************************/
 
876
        SET_TDBB(tdbb);
 
877
 
 
878
        ISC_STATUS* const original_status = tdbb->tdbb_status_vector;
 
879
        bool defined = true;
 
880
 
 
881
        try
 
882
        {
 
883
                ISC_STATUS_ARRAY local_status;
 
884
                tdbb->tdbb_status_vector = local_status;
 
885
 
 
886
                INTL_texttype_lookup(tdbb, t_type);
 
887
        }
 
888
        catch (...)
 
889
        {
 
890
                defined = false;
 
891
        }
 
892
 
 
893
        tdbb->tdbb_status_vector = original_status;
 
894
 
 
895
        return defined;
 
896
}
 
897
 
 
898
 
 
899
void INTL_init(thread_db* tdbb)
 
900
{
 
901
/**************************************
 
902
 *
 
903
 *      I N T L _ i n i t
 
904
 *
 
905
 **************************************
 
906
 *
 
907
 * Functional description
 
908
 *
 
909
 **************************************/
 
910
}
 
911
 
 
912
 
 
913
USHORT INTL_key_length(thread_db* tdbb, USHORT idxType, USHORT iLength)
 
914
{
 
915
/**************************************
 
916
 *
 
917
 *      I N T L _ k e y _ l e n g t h
 
918
 *
 
919
 **************************************
 
920
 *
 
921
 * Functional description
 
922
 *      Given an index type, and a maximum length (iLength)
 
923
 *      return the length of the byte string key descriptor to
 
924
 *      use when collating text of this type.
 
925
 *
 
926
 **************************************/
 
927
        SET_TDBB(tdbb);
 
928
 
 
929
        fb_assert(idxType >= idx_first_intl_string);
 
930
 
 
931
        const USHORT ttype = INTL_INDEX_TO_TEXT(idxType);
 
932
 
 
933
        USHORT key_length;
 
934
        if (ttype <= ttype_last_internal)
 
935
                key_length = iLength;
 
936
        else {
 
937
                TextType* obj = INTL_texttype_lookup(tdbb, ttype);
 
938
                key_length = obj->key_length(iLength);
 
939
        }
 
940
 
 
941
/* Validity checks on the computed key_length */
 
942
 
 
943
        if (key_length > MAX_KEY)
 
944
                key_length = MAX_KEY;
 
945
 
 
946
        if (key_length < iLength)
 
947
                key_length = iLength;
 
948
 
 
949
        return (key_length);
 
950
}
 
951
 
 
952
 
 
953
CharSet* INTL_charset_lookup(thread_db* tdbb, USHORT parm1)
 
954
{
 
955
/**************************************
 
956
 *
 
957
 *      I N T L _ c h a r s e t _ l o o k u p
 
958
 *
 
959
 **************************************
 
960
 *
 
961
 * Functional description
 
962
 *
 
963
 *      Lookup a character set descriptor.
 
964
 *
 
965
 *      First, search the appropriate vector that hangs
 
966
 *      off the dbb.  If not found, then call the lower
 
967
 *      level lookup routine to allocate it, or punt
 
968
 *              if we don't know about the charset.
 
969
 *
 
970
 * Returns:
 
971
 *      *charset        - if no errors;
 
972
 *      <never>         - if error
 
973
 *
 
974
 **************************************/
 
975
        CharSetContainer *cs = CharSetContainer::lookupCharset(tdbb, parm1);
 
976
        return cs->getCharSet();
 
977
}
 
978
 
 
979
 
 
980
Collation* INTL_texttype_lookup(thread_db* tdbb,
 
981
                                                                USHORT parm1)
 
982
{
 
983
/**************************************
 
984
 *
 
985
 *      I N T L _ t e x t t y p e _ l o o k u p
 
986
 *
 
987
 **************************************
 
988
 *
 
989
 * Functional description
 
990
 *
 
991
 *      Lookup either a character set descriptor or
 
992
 *      texttype descriptor object.
 
993
 *
 
994
 *      First, search the appropriate vector that hangs
 
995
 *      off the dbb.  If not found, then call the lower
 
996
 *      level lookup routine to find it in the libraries.
 
997
 *
 
998
 * Returns:
 
999
 *      *object         - if no errors;
 
1000
 *      <never>         - if error
 
1001
 *
 
1002
 **************************************/
 
1003
        SET_TDBB(tdbb);
 
1004
        Database* dbb = tdbb->getDatabase();
 
1005
 
 
1006
        if (parm1 == ttype_dynamic)
 
1007
                parm1 = MAP_CHARSET_TO_TTYPE(tdbb->getAttachment()->att_charset);
 
1008
 
 
1009
        CharSetContainer* csc = CharSetContainer::lookupCharset(tdbb, parm1);
 
1010
 
 
1011
        return csc->lookupCollation(tdbb, parm1);
 
1012
}
 
1013
 
 
1014
 
 
1015
void INTL_texttype_unload(thread_db* tdbb,
 
1016
                                                  USHORT ttype)
 
1017
{
 
1018
/**************************************
 
1019
 *
 
1020
 *      I N T L _ t e x t t y p e _ u n l o a d
 
1021
 *
 
1022
 **************************************
 
1023
 *
 
1024
 * Functional description
 
1025
 *  Unload a collation from memory.
 
1026
 *
 
1027
 **************************************/
 
1028
        SET_TDBB(tdbb);
 
1029
 
 
1030
        CharSetContainer* csc = CharSetContainer::lookupCharset(tdbb, ttype);
 
1031
        if (csc)
 
1032
                csc->unloadCollation(tdbb, ttype);
 
1033
}
 
1034
 
 
1035
 
 
1036
bool INTL_texttype_validate(Jrd::thread_db* tdbb, const SubtypeInfo* info)
 
1037
{
 
1038
/**************************************
 
1039
 *
 
1040
 *      I N T L _ t e x t t y p e _ v a l i d a t e
 
1041
 *
 
1042
 **************************************
 
1043
 *
 
1044
 * Functional description
 
1045
 *  Check if collation attributes are valid.
 
1046
 *
 
1047
 **************************************/
 
1048
        SET_TDBB(tdbb);
 
1049
 
 
1050
        texttype tt;
 
1051
        memset(&tt, 0, sizeof(tt));
 
1052
 
 
1053
        bool ret = lookup_texttype(&tt, info);
 
1054
 
 
1055
        if (ret && tt.texttype_fn_destroy)
 
1056
                tt.texttype_fn_destroy(&tt);
 
1057
 
 
1058
        return ret;
 
1059
}
 
1060
 
 
1061
 
 
1062
void INTL_pad_spaces(thread_db* tdbb, DSC * type, UCHAR * string, ULONG length)
 
1063
{
 
1064
/**************************************
 
1065
 *
 
1066
 *      I N T L _ p a d _ s p a c e s
 
1067
 *
 
1068
 **************************************
 
1069
 *
 
1070
 * Functional description
 
1071
 *      Pad a buffer with spaces, using the character
 
1072
 *      set's defined space character.
 
1073
 *
 
1074
 **************************************/
 
1075
        SET_TDBB(tdbb);
 
1076
 
 
1077
        fb_assert(type != NULL);
 
1078
        fb_assert(IS_TEXT(type));
 
1079
        fb_assert(string != NULL);
 
1080
 
 
1081
        const USHORT charset = INTL_charset(tdbb, type->dsc_ttype());
 
1082
        pad_spaces(tdbb, charset, string, length);
 
1083
}
 
1084
 
 
1085
 
 
1086
USHORT INTL_string_to_key(thread_db* tdbb,
 
1087
                                                USHORT idxType,
 
1088
                                                const dsc* pString,
 
1089
                                                DSC* pByte,
 
1090
                                                USHORT key_type)
 
1091
{
 
1092
/**************************************
 
1093
 *
 
1094
 *      I N T L _ s t r i n g _ t o _ k e y
 
1095
 *
 
1096
 **************************************
 
1097
 *
 
1098
 * Functional description
 
1099
 *      Given an input string, convert it to a byte string
 
1100
 *      that will collate naturally (byte order).
 
1101
 *
 
1102
 *      Return the length of the resulting byte string.
 
1103
 *
 
1104
 **************************************/
 
1105
        UCHAR pad_char;
 
1106
        USHORT ttype;
 
1107
 
 
1108
        SET_TDBB(tdbb);
 
1109
 
 
1110
        fb_assert(idxType >= idx_first_intl_string || idxType == idx_string
 
1111
                   || idxType == idx_byte_array || idxType == idx_metadata);
 
1112
        fb_assert(pString != NULL);
 
1113
        fb_assert(pByte != NULL);
 
1114
        fb_assert(pString->dsc_address != NULL);
 
1115
        fb_assert(pByte->dsc_address != NULL);
 
1116
        fb_assert(pByte->dsc_dtype == dtype_text);
 
1117
 
 
1118
        switch (idxType) {
 
1119
        case idx_string:
 
1120
                pad_char = ' ';
 
1121
                ttype = ttype_none;
 
1122
                break;
 
1123
        case idx_byte_array:
 
1124
                pad_char = 0;
 
1125
                ttype = ttype_binary;
 
1126
                break;
 
1127
        case idx_metadata:
 
1128
                pad_char = ' ';
 
1129
                ttype = ttype_metadata;
 
1130
                break;
 
1131
        default:
 
1132
                pad_char = 0;
 
1133
                ttype = INTL_INDEX_TO_TEXT(idxType);
 
1134
                break;
 
1135
        }
 
1136
 
 
1137
/* Make a string into the proper type of text */
 
1138
 
 
1139
        MoveBuffer temp;
 
1140
        UCHAR* src;
 
1141
        USHORT len = MOV_make_string2(tdbb, pString, ttype, &src, temp);
 
1142
 
 
1143
        USHORT outlen;
 
1144
        char* dest = reinterpret_cast<char*>(pByte->dsc_address);
 
1145
        USHORT destLen = pByte->dsc_length;
 
1146
 
 
1147
        switch (ttype) {
 
1148
        case ttype_metadata:
 
1149
        case ttype_binary:
 
1150
        case ttype_ascii:
 
1151
        case ttype_none:
 
1152
                while (len-- && destLen-- > 0)
 
1153
                        *dest++ = *src++;
 
1154
                /* strip off ending pad characters */
 
1155
                while (dest > (const char*)pByte->dsc_address) {
 
1156
                        if (*(dest - 1) == pad_char)
 
1157
                                dest--;
 
1158
                        else
 
1159
                                break;
 
1160
                }
 
1161
                outlen = (dest - (const char*)pByte->dsc_address);
 
1162
                break;
 
1163
        default:
 
1164
                TextType* obj = INTL_texttype_lookup(tdbb, ttype);
 
1165
                outlen = obj->string_to_key(len,
 
1166
                                                                        reinterpret_cast<const unsigned char*>(src),
 
1167
                                                                        pByte->dsc_length,
 
1168
                                                                        reinterpret_cast<unsigned char*>(dest),
 
1169
                                                                        key_type);
 
1170
                break;
 
1171
        }
 
1172
 
 
1173
        return (outlen);
 
1174
}
 
1175
 
 
1176
 
 
1177
int INTL_str_to_upper(thread_db* tdbb, DSC * pString)
 
1178
{
 
1179
/**************************************
 
1180
 *
 
1181
 *      I N T L _ s t r _ t o _ u p p e r
 
1182
 *
 
1183
 **************************************
 
1184
 *
 
1185
 * Functional description
 
1186
 *      Given an input string, convert it to uppercase
 
1187
 *
 
1188
 **************************************/
 
1189
        SET_TDBB(tdbb);
 
1190
 
 
1191
        fb_assert(pString != NULL);
 
1192
        fb_assert(pString->dsc_address != NULL);
 
1193
 
 
1194
        UCHAR* src;
 
1195
        UCHAR buffer[MAX_KEY];
 
1196
        USHORT ttype;
 
1197
        USHORT len =
 
1198
                CVT_get_string_ptr(pString, &ttype, &src,
 
1199
                                                   reinterpret_cast<vary*>(buffer),
 
1200
                                                   sizeof(buffer), ERR_post);
 
1201
 
 
1202
        UCHAR* dest;
 
1203
        switch (ttype) {
 
1204
        case ttype_binary:
 
1205
                /* cannot uppercase binary strings */
 
1206
                break;
 
1207
 
 
1208
        case ttype_none:
 
1209
        case ttype_ascii:
 
1210
                dest = src;
 
1211
                while (len--) {
 
1212
                        *dest++ = UPPER7(*src);
 
1213
                        src++;
 
1214
                }
 
1215
                break;
 
1216
 
 
1217
        default:
 
1218
                TextType* obj = INTL_texttype_lookup(tdbb, ttype);
 
1219
                obj->str_to_upper(len, src, len, src);  // ASF: this works for all cases? (src and dst buffers are the same)
 
1220
                break;
 
1221
        }
 
1222
/*
 
1223
 * Added to remove compiler errors. Callers are not checking
 
1224
 * the return code from this function 4/5/95.
 
1225
*/
 
1226
        return (0);
 
1227
}
 
1228
 
 
1229
 
 
1230
int INTL_str_to_lower(thread_db* tdbb, DSC * pString)
 
1231
{
 
1232
/**************************************
 
1233
 *
 
1234
 *      I N T L _ s t r _ t o _ l o w e r
 
1235
 *
 
1236
 **************************************
 
1237
 *
 
1238
 * Functional description
 
1239
 *      Given an input string, convert it to lowercase
 
1240
 *
 
1241
 **************************************/
 
1242
        SET_TDBB(tdbb);
 
1243
 
 
1244
        fb_assert(pString != NULL);
 
1245
        fb_assert(pString->dsc_address != NULL);
 
1246
 
 
1247
        UCHAR* src;
 
1248
        UCHAR buffer[MAX_KEY];
 
1249
        USHORT ttype;
 
1250
        USHORT len =
 
1251
                CVT_get_string_ptr(pString, &ttype, &src,
 
1252
                                                   reinterpret_cast<vary*>(buffer),
 
1253
                                                   sizeof(buffer), ERR_post);
 
1254
 
 
1255
        UCHAR* dest;
 
1256
        switch (ttype) {
 
1257
        case ttype_binary:
 
1258
                /* cannot lowercase binary strings */
 
1259
                break;
 
1260
 
 
1261
        case ttype_none:
 
1262
        case ttype_ascii:
 
1263
                dest = src;
 
1264
                while (len--) {
 
1265
                        *dest++ = LOWWER7(*src);
 
1266
                        src++;
 
1267
                }
 
1268
                break;
 
1269
 
 
1270
        default:
 
1271
                TextType* obj = INTL_texttype_lookup(tdbb, ttype);
 
1272
                obj->str_to_lower(len, src, len, src);  // ASF: this works for all cases? (src and dst buffers are the same)
 
1273
                break;
 
1274
        }
 
1275
/*
 
1276
 * Added to remove compiler errors. Callers are not checking
 
1277
 * the return code from this function 4/5/95.
 
1278
*/
 
1279
        return (0);
 
1280
}
 
1281
 
 
1282
 
 
1283
static bool all_spaces(
 
1284
                                                  thread_db* tdbb,
 
1285
                                                  CHARSET_ID charset,
 
1286
                                                  const BYTE* ptr, ULONG len, ULONG offset)
 
1287
{
 
1288
/**************************************
 
1289
 *
 
1290
 *      a l l _ s p a c e s
 
1291
 *
 
1292
 **************************************
 
1293
 *
 
1294
 * Functional description
 
1295
 *      determine if the string at ptr[offset] ... ptr[len] is entirely
 
1296
 *      spaces, as per the space definition of (charset).
 
1297
 *      The binary representation of a Space is character-set dependent.
 
1298
 *      (0x20 for Ascii, 0x0020 for Unicode, 0x20 for SJIS, but must watch for
 
1299
 *      0x??20, which is NOT a space.
 
1300
 **************************************/
 
1301
        SET_TDBB(tdbb);
 
1302
 
 
1303
        fb_assert(ptr != NULL);
 
1304
 
 
1305
        CharSet* obj = INTL_charset_lookup(tdbb, charset);
 
1306
 
 
1307
/*
 
1308
 * We are assuming offset points to the first byte which was not
 
1309
 * consumed in a conversion.  And that offset is pointing
 
1310
 * to a character boundary
 
1311
 */
 
1312
 
 
1313
// Single-octet character sets are optimized here
 
1314
 
 
1315
        if (obj->getSpaceLength() == 1) {
 
1316
                const BYTE* p = &ptr[offset];
 
1317
                const BYTE* const end = &ptr[len];
 
1318
                while (p < end) {
 
1319
                        if (*p++ != *obj->getSpace())
 
1320
                                return false;
 
1321
                }
 
1322
                return true;
 
1323
        }
 
1324
        else {
 
1325
                const BYTE* p = &ptr[offset];
 
1326
                const BYTE* const end = &ptr[len];
 
1327
                const unsigned char* space = obj->getSpace();
 
1328
                const unsigned char* const end_space = &space[obj->getSpaceLength()];
 
1329
                while (p < end) {
 
1330
                        space = obj->getSpace();
 
1331
                        while (p < end && space < end_space) {
 
1332
                                if (*p++ != *space++)
 
1333
                                        return false;
 
1334
                        }
 
1335
                }
 
1336
                return true;
 
1337
        }
 
1338
}
 
1339
 
 
1340
 
 
1341
static int blocking_ast_collation(void* ast_object)
 
1342
{
 
1343
/**************************************
 
1344
 *
 
1345
 *      b l o c k i n g _ a s t _ c o l l a t i o n
 
1346
 *
 
1347
 **************************************
 
1348
 *
 
1349
 * Functional description
 
1350
 *      Someone is trying to drop a collation. If there
 
1351
 *      are outstanding interests in the existence of
 
1352
 *      the collation then just mark as blocking and return.
 
1353
 *      Otherwise, mark the collation as obsolete
 
1354
 *      and release the collation existence lock.
 
1355
 *
 
1356
 **************************************/
 
1357
        Collation* tt = static_cast<Collation*>(ast_object);
 
1358
 
 
1359
        if (tt && tt->useCount == 0)
 
1360
        {
 
1361
                tt->obsolete = true;
 
1362
 
 
1363
                if (tt->existenceLock)
 
1364
                {
 
1365
                        thread_db thd_context, *tdbb;
 
1366
 
 
1367
                        // Since this routine will be called asynchronously, we must establish
 
1368
                        // a thread context.
 
1369
                        JRD_set_thread_data(tdbb, thd_context);
 
1370
 
 
1371
                        tdbb->setDatabase(tt->existenceLock->lck_dbb);
 
1372
                        tdbb->setAttachment(tt->existenceLock->lck_attachment);
 
1373
                        tdbb->tdbb_quantum = QUANTUM;
 
1374
                        tdbb->setRequest(NULL);
 
1375
                        tdbb->setTransaction(NULL);
 
1376
                        Jrd::ContextPoolHolder context(tdbb, 0);
 
1377
 
 
1378
                        LCK_release(tdbb, tt->existenceLock);
 
1379
                        tt->existenceLock = NULL;
 
1380
 
 
1381
                        // Restore the prior thread context
 
1382
                        JRD_restore_thread_data();
 
1383
                }
 
1384
        }
 
1385
 
 
1386
        return 0;
 
1387
}
 
1388
 
 
1389
 
 
1390
static void pad_spaces(thread_db* tdbb, CHARSET_ID charset, BYTE* ptr, ULONG len)
 
1391
{                                                               /* byte count */
 
1392
/**************************************
 
1393
 *
 
1394
 *      p a d  _ s p a c e s
 
1395
 *
 
1396
 **************************************
 
1397
 *
 
1398
 * Functional description
 
1399
 *      Pad a buffer with the character set defined space character.
 
1400
 *
 
1401
 **************************************/
 
1402
        SET_TDBB(tdbb);
 
1403
 
 
1404
        fb_assert(ptr != NULL);
 
1405
 
 
1406
        CharSet* obj = INTL_charset_lookup(tdbb, charset);
 
1407
 
 
1408
/* Single-octet character sets are optimized here */
 
1409
        if (obj->getSpaceLength() == 1) {
 
1410
                const BYTE* const end = &ptr[len];
 
1411
                while (ptr < end)
 
1412
                        *ptr++ = *obj->getSpace();
 
1413
        }
 
1414
        else {
 
1415
                const BYTE* const end = &ptr[len];
 
1416
                const UCHAR* space = obj->getSpace();
 
1417
                const UCHAR* const end_space = &space[obj->getSpaceLength()];
 
1418
                while (ptr < end) {
 
1419
                        space = obj->getSpace();
 
1420
                        while (ptr < end && space < end_space) {
 
1421
                                *ptr++ = *space++;
 
1422
                        }
 
1423
                        /* This fb_assert is checking that we didn't have a buffer-end
 
1424
                         * in the middle of a space character
 
1425
                         */
 
1426
                        fb_assert(!(ptr == end) || (space == end_space));
 
1427
                }
 
1428
        }
 
1429
}