~ubuntu-branches/ubuntu/natty/mysql-5.1/natty-security

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/db2i_charsetSupport.cc

Tags: 5.1.54-1ubuntu1
* Synchronize from Debian Experimental:
* Merge from debian unstable:
  + debian/control:
     * Update maintainer according to spec.
     * Move section from "misc" to "database".
     * Added libmysqlclient16-dev an empty transitional package. 
     * Added mysql-client-core-5.1 package.
     * Suggest mailx for mysql-server-5.1
     * Add mysql-testsuite package so you can run the testsuite seperately.
  + debian/additions/my.cnf:
    * Remove language options. Error message files are located in a different directory in Mysql
      5.0. Setting the language option to use /usr/share/mysql/english breaks Mysql 5.0. Both 5.0
      and 5.1 use a different value that works. (LP: #316974)
  + Add apparmor profile:
    + debian/apparmor-profile: apparmor-profile
    + debian/rules, debian/mysql-server-5.1.files: install apparmor profile
    + debian/mysql-server-5.1.dirs: add etc/apparmor.d/fore-complain
    + debian/mysql-server-5.1.postrm: remove symlink in force-complain/ on purge.
    + debian/mysql-server-5.1.README.Debian: add apparmor documentation.
    + debian/additions/my.cnf: Add warning about apparmor. (LP: #201799)
    + debian/mysql-server-5.1.postinst: reload apparmor profiles
  * Convert the package from sysvinit to upstart:
    + debian/mysql-server-5.1.mysql.upstart: Add upstart script.
    + debian/mysql-server-5.1.mysql.init: Dropped, unused now with upstart.
    + debian/additions/mysqld_safe_syslog.cnf: Dropped, unused now with upstart.
    + debian/additons/my.cnf: Remove pid declaration and setup error logging to /var/log/mysql since
      we're not piping anything around logger anymore.
    + debian/rules, debian/mysql-server-5.1.logcheck.ignore.{paranoid,worstation},
      debian/mysql-server-5.1.logcheck.ignore.server: : Remove references to mysqld_safe
    + debian/patches/38_scripts_mysqld_safe.sh_signals.dpatch: Dropped
  * Added -fno-strict-aliasing to CFLAGS to get around mysql testsuite build failures.
  * Add Apport hook (LP: #354188):
    + debian/mysql-server-5.1.py: apport package hook
    + debian/rules: Make it installable
  * debian/mysql-server-5.1.mysql-server.logrotate: Check to see if mysql is running before
    running logrotate. (LP: #513135)
  * Make the testsuite installable. (LP: #530752)
    + debian/mysql-server-5.1.files, debian/rules: install apport package hook
  * debian/mysql-server-5.1.preinst: Set mysql user's home directory
    to /nonexistent to protect against having the /var/lib/mysql
    user-writeable. If an attacker can trick mysqld into creating
    dot files in the home directory, he could do .rhost-like attacks
    on the system. (LP: #293258)
  * debian/control: mysql-client-5.1 should depend on mysql-core-client-5.1.
    (LP: #590952)
  * debian/mysql-server.5.1.postinst: Specify the mysql user when installing 
    the mysql databases. (LP: #591875)
  * Installing mysql_config_pic in /usr/bin so users of libmysqld-pic
    can extract the appropriate compile flags. (LP: #605021) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Licensed Materials - Property of IBM
3
 
DB2 Storage Engine Enablement
4
 
Copyright IBM Corporation 2007,2008
5
 
All rights reserved
6
 
 
7
 
Redistribution and use in source and binary forms, with or without modification,
8
 
are permitted provided that the following conditions are met: 
9
 
 (a) Redistributions of source code must retain this list of conditions, the
10
 
     copyright notice in section {d} below, and the disclaimer following this
11
 
     list of conditions. 
12
 
 (b) Redistributions in binary form must reproduce this list of conditions, the
13
 
     copyright notice in section (d) below, and the disclaimer following this
14
 
     list of conditions, in the documentation and/or other materials provided
15
 
     with the distribution. 
16
 
 (c) The name of IBM may not be used to endorse or promote products derived from
17
 
     this software without specific prior written permission. 
18
 
 (d) The text of the required copyright notice is: 
19
 
       Licensed Materials - Property of IBM
20
 
       DB2 Storage Engine Enablement 
21
 
       Copyright IBM Corporation 2007,2008 
22
 
       All rights reserved
23
 
 
24
 
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
25
 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26
 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27
 
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29
 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
 
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33
 
OF SUCH DAMAGE.
34
 
*/
35
 
 
36
 
 
37
 
 
38
 
#include "db2i_charsetSupport.h"
39
 
#include "as400_types.h"
40
 
#include "as400_protos.h"
41
 
#include "db2i_ileBridge.h"
42
 
#include "qlgusr.h"
43
 
#include "db2i_errors.h"
44
 
 
45
 
 
46
 
/*
47
 
  The following arrays define a mapping between IANA-style text descriptors and
48
 
  IBM i CCSID text descriptors. The mapping is a 1-to-1 correlation between
49
 
  corresponding array slots.
50
 
*/
51
 
#define MAX_IANASTRING 23
52
 
static const char ianaStringType[MAX_IANASTRING][10] = 
53
 
{
54
 
    {"ascii"},
55
 
    {"Big5"},    //big5
56
 
    {"cp1250"},
57
 
    {"cp1251"},
58
 
    {"cp1256"},
59
 
    {"cp850"},
60
 
    {"cp852"},
61
 
    {"cp866"},
62
 
    {"IBM943"},   //cp932
63
 
    {"EUC-KR"},   //euckr
64
 
    {"IBM1381"},  //gb2312
65
 
    {"IBM1386"},  //gbk
66
 
    {"greek"},
67
 
    {"hebrew"},
68
 
    {"latin1"},
69
 
    {"latin2"},
70
 
    {"latin5"},
71
 
    {"macce"},
72
 
    {"tis620"},
73
 
    {"Shift_JIS"}, //sjis
74
 
    {"ucs2"},
75
 
    {"EUC-JP"},    //ujis
76
 
    {"utf8"}
77
 
};
78
 
static const char ccsidType[MAX_IANASTRING][6] = 
79
 
{
80
 
    {"367"},  //ascii
81
 
    {"950"},  //big5
82
 
    {"1250"}, //cp1250
83
 
    {"1251"}, //cp1251
84
 
    {"1256"}, //cp1256
85
 
    {"850"},  //cp850
86
 
    {"852"},  //cp852
87
 
    {"866"},  //cp866
88
 
    {"943"},  //cp932
89
 
    {"970"},  //euckr
90
 
    {"1381"}, //gb2312
91
 
    {"1386"}, //gbk
92
 
    {"813"},  //greek
93
 
    {"916"},  //hebrew
94
 
    {"923"},  //latin1
95
 
    {"912"},  //latin2
96
 
    {"920"},  //latin5
97
 
    {"1282"}, //macce
98
 
    {"874"},  //tis620
99
 
    {"943"},  //sjis
100
 
    {"13488"},//ucs2
101
 
    {"5050"}, //ujis
102
 
    {"1208"}  //utf8
103
 
};
104
 
 
105
 
static _ILEpointer *QlgCvtTextDescToDesc_sym;
106
 
 
107
 
/* We keep a cache of the mapping for text descriptions obtained via
108
 
   QlgTextDescToDesc. The following structures implement this cache. */
109
 
static HASH textDescMapHash;
110
 
static MEM_ROOT textDescMapMemroot;
111
 
static pthread_mutex_t textDescMapHashMutex;
112
 
struct TextDescMap
113
 
{
114
 
  struct HashKey
115
 
  {
116
 
    int32 inType;
117
 
    int32 outType;
118
 
    char inDesc[Qlg_MaxDescSize];
119
 
  } hashKey;  
120
 
  char outDesc[Qlg_MaxDescSize];
121
 
};
122
 
 
123
 
/* We keep a cache of the mapping for open iconv descriptors. The following 
124
 
   structures implement this cache. */
125
 
static HASH iconvMapHash;
126
 
static MEM_ROOT iconvMapMemroot;
127
 
static pthread_mutex_t iconvMapHashMutex;
128
 
struct IconvMap
129
 
{
130
 
  struct HashKey
131
 
  {
132
 
    uint32 direction; // These are uint32s to avoid garbage data in the key from compiler padding
133
 
    uint32 db2CCSID;
134
 
    const CHARSET_INFO* myCharset;
135
 
  } hashKey;
136
 
  iconv_t iconvDesc;
137
 
};
138
 
 
139
 
 
140
 
/**
141
 
  Initialize the static structures used by this module.
142
 
  
143
 
  This must only be called once per plugin instantiation.
144
 
  
145
 
  @return  0 if successful. Failure otherwise
146
 
*/
147
 
int32 initCharsetSupport()
148
 
{
149
 
  DBUG_ENTER("initCharsetSupport");
150
 
 
151
 
  int actmark = _ILELOAD("QSYS/QLGUSR", ILELOAD_LIBOBJ);
152
 
  if ( actmark == -1 )
153
 
  {
154
 
    DBUG_PRINT("initCharsetSupport", ("conversion srvpgm activation failed"));
155
 
    DBUG_RETURN(1);
156
 
  }
157
 
 
158
 
  QlgCvtTextDescToDesc_sym = (ILEpointer*)malloc_aligned(sizeof(ILEpointer));
159
 
  if (_ILESYM(QlgCvtTextDescToDesc_sym, actmark, "QlgCvtTextDescToDesc") == -1)
160
 
  {
161
 
    DBUG_PRINT("initCharsetSupport", 
162
 
        ("resolve of QlgCvtTextDescToDesc failed"));
163
 
    DBUG_RETURN(errno);
164
 
  }
165
 
 
166
 
  VOID(pthread_mutex_init(&textDescMapHashMutex,MY_MUTEX_INIT_FAST));
167
 
  hash_init(&textDescMapHash, &my_charset_bin, 10, offsetof(TextDescMap, hashKey), sizeof(TextDescMap::hashKey), 0, 0, HASH_UNIQUE);
168
 
 
169
 
  VOID(pthread_mutex_init(&iconvMapHashMutex,MY_MUTEX_INIT_FAST));
170
 
  hash_init(&iconvMapHash, &my_charset_bin, 10, offsetof(IconvMap, hashKey), sizeof(IconvMap::hashKey), 0, 0, HASH_UNIQUE);
171
 
 
172
 
  init_alloc_root(&textDescMapMemroot, 2048, 0);
173
 
  init_alloc_root(&iconvMapMemroot, 256, 0);
174
 
 
175
 
  initMyconv();
176
 
  
177
 
  DBUG_RETURN(0);
178
 
}
179
 
 
180
 
/**
181
 
  Cleanup the static structures used by this module.
182
 
  
183
 
  This must only be called once per plugin instantiation and only if 
184
 
  initCharsetSupport() was successful.
185
 
*/
186
 
void doneCharsetSupport()
187
 
{
188
 
  cleanupMyconv();
189
 
    
190
 
  free_root(&textDescMapMemroot, 0);
191
 
  free_root(&iconvMapMemroot, 0);
192
 
  
193
 
  pthread_mutex_destroy(&textDescMapHashMutex);
194
 
  hash_free(&textDescMapHash);
195
 
  pthread_mutex_destroy(&iconvMapHashMutex);
196
 
  hash_free(&iconvMapHash);
197
 
  free_aligned(QlgCvtTextDescToDesc_sym);
198
 
}
199
 
 
200
 
 
201
 
/**
202
 
  Convert a text description from one type to another.
203
 
  
204
 
  This function is just a wrapper for the IBM i QlgTextDescToDesc function plus
205
 
  some overrides for conversions that the API does not handle correctly and 
206
 
  support for caching the computed conversion.
207
 
    
208
 
  @param inType  The type of descriptor pointed to by "in".
209
 
  @param outType  The type of descriptor requested for "out".
210
 
  @param in  The descriptor to be convereted.
211
 
  @param[out] out  The equivalent descriptor
212
 
  @param hashKey  The hash key to be used for caching the conversion result.
213
 
    
214
 
  @return  0 if successful. Failure otherwise
215
 
*/
216
 
static int32 getNewTextDesc(const int32 inType, 
217
 
                            const int32 outType, 
218
 
                            const char* in, 
219
 
                            char* out,
220
 
                            const TextDescMap::HashKey* hashKey)
221
 
{
222
 
  DBUG_ENTER("db2i_charsetSupport::getNewTextDesc");
223
 
  const arg_type_t signature[] = { ARG_INT32, ARG_INT32, ARG_MEMPTR, ARG_INT32, ARG_MEMPTR, ARG_INT32, ARG_INT32, ARG_END };
224
 
  struct ArgList
225
 
  {
226
 
    ILEarglist_base base;
227
 
    int32 CRDIInType;
228
 
    int32 CRDIOutType;
229
 
    ILEpointer CRDIDesc;
230
 
    int32 CRDIDescSize;
231
 
    ILEpointer CRDODesc;
232
 
    int32 CRDODescSize;
233
 
    int32 CTDCCSID;
234
 
  } *arguments;
235
 
 
236
 
  if ((inType == Qlg_TypeIANA) && (outType == Qlg_TypeAix41))
237
 
  {
238
 
    // Override non-standard charsets
239
 
    if (unlikely(strcmp("IBM1381", in) == 0))
240
 
    {
241
 
      strcpy(out, "IBM-1381");
242
 
      DBUG_RETURN(0);
243
 
    }
244
 
  }
245
 
  else if ((inType == Qlg_TypeAS400CCSID) && (outType == Qlg_TypeAix41))
246
 
  {
247
 
    // Override non-standard charsets
248
 
    if (strcmp("1148", in) == 0)
249
 
    {
250
 
      strcpy(out, "IBM-1148");
251
 
      DBUG_RETURN(0);
252
 
    }
253
 
    else if (unlikely(strcmp("1153", in) == 0))
254
 
    {
255
 
      strcpy(out, "IBM-1153");
256
 
      DBUG_RETURN(0);
257
 
    }
258
 
  }
259
 
 
260
 
  char argBuf[sizeof(ArgList)+15];
261
 
  arguments = (ArgList*)roundToQuadWordBdy(argBuf);
262
 
 
263
 
  arguments->CRDIInType = inType;
264
 
  arguments->CRDIOutType = outType;
265
 
  arguments->CRDIDesc.s.addr = (address64_t) in;
266
 
  arguments->CRDIDescSize = Qlg_MaxDescSize;
267
 
  arguments->CRDODesc.s.addr = (address64_t) out;
268
 
  arguments->CRDODescSize = Qlg_MaxDescSize;
269
 
  arguments->CTDCCSID = 819;
270
 
  _ILECALL(QlgCvtTextDescToDesc_sym, 
271
 
      &arguments->base,
272
 
      signature, 
273
 
      RESULT_INT32);
274
 
  if (unlikely(arguments->base.result.s_int32.r_int32 < 0))
275
 
  {
276
 
    if (arguments->base.result.s_int32.r_int32 == Qlg_InDescriptorNotFound)
277
 
    {
278
 
      DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
279
 
    }
280
 
    else
281
 
    {
282
 
      getErrTxt(DB2I_ERR_ILECALL,"QlgCvtTextDescToDesc",arguments->base.result.s_int32.r_int32);
283
 
      DBUG_RETURN(DB2I_ERR_ILECALL);
284
 
    }
285
 
  }
286
 
  
287
 
  // Store the conversion information into a cache entry
288
 
  TextDescMap* mapping = (TextDescMap*)alloc_root(&textDescMapMemroot, sizeof(TextDescMap));
289
 
  if (unlikely(!mapping))
290
 
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
291
 
  memcpy(&(mapping->hashKey), hashKey, sizeof(hashKey));
292
 
  strcpy(mapping->outDesc, out);
293
 
  pthread_mutex_lock(&textDescMapHashMutex);
294
 
  my_hash_insert(&textDescMapHash, (const uchar*)mapping);
295
 
  pthread_mutex_unlock(&textDescMapHashMutex);
296
 
  
297
 
  DBUG_RETURN(0);
298
 
}
299
 
 
300
 
 
301
 
/**
302
 
  Convert a text description from one type to another.
303
 
  
304
 
  This function takes a text description in one representation and converts 
305
 
  it into another representation. Although the OS provides some facilities for
306
 
  doing this, the support is not complete, nor does MySQL always use standard
307
 
  identifiers. Therefore, there are a lot of hardcoded overrides required.
308
 
  There is probably some room for optimization here, but this should not be
309
 
  called frequently under most circumstances.
310
 
 
311
 
  @param inType  The type of descriptor pointed to by "in".
312
 
  @param outType  The type of descriptor requested for "out".
313
 
  @param in  The descriptor to be convereted.
314
 
  @param[out] out  The equivalent descriptor
315
 
    
316
 
  @return  0 if successful. Failure otherwise
317
 
*/
318
 
static int32 convertTextDesc(const int32 inType, const int32 outType, const char* inDesc, char* outDesc)
319
 
{
320
 
  DBUG_ENTER("db2i_charsetSupport::convertTextDesc");
321
 
  const char* inDescOverride;
322
 
  
323
 
  if (inType == Qlg_TypeIANA) 
324
 
  {
325
 
    // Override non-standard charsets
326
 
    if (strcmp("big5", inDesc) == 0)
327
 
      inDescOverride = "Big5";
328
 
    else if (strcmp("cp932", inDesc) == 0)
329
 
      inDescOverride = "IBM943";
330
 
    else if (strcmp("euckr", inDesc) == 0)
331
 
      inDescOverride = "EUC-KR";
332
 
    else if (strcmp("gb2312", inDesc) == 0)
333
 
      inDescOverride = "IBM1381";
334
 
    else if (strcmp("gbk", inDesc) == 0)
335
 
      inDescOverride = "IBM1386";
336
 
    else if (strcmp("sjis", inDesc) == 0)
337
 
      inDescOverride = "Shift_JIS";
338
 
    else if (strcmp("ujis", inDesc) == 0)
339
 
      inDescOverride = "EUC-JP";
340
 
    else
341
 
      inDescOverride = inDesc;
342
 
     
343
 
    // Hardcode non-standard charsets
344
 
    if (outType == Qlg_TypeAix41) 
345
 
    {
346
 
      if (strcmp("Big5", inDescOverride) == 0)
347
 
      {
348
 
        strcpy(outDesc,"big5");
349
 
        DBUG_RETURN(0);
350
 
      }
351
 
      else if (strcmp("IBM1386", inDescOverride) == 0)
352
 
      {
353
 
        strcpy(outDesc,"GBK");
354
 
        DBUG_RETURN(0);
355
 
      }
356
 
      else if (strcmp("Shift_JIS", inDescOverride) == 0 ||
357
 
               strcmp("IBM943", inDescOverride) == 0)
358
 
      {
359
 
        strcpy(outDesc,"IBM-943");
360
 
        DBUG_RETURN(0);
361
 
      }
362
 
      else if (strcmp("tis620", inDescOverride) == 0)
363
 
      {
364
 
        strcpy(outDesc,"TIS-620");
365
 
        DBUG_RETURN(0);
366
 
      }
367
 
      else if (strcmp("ucs2", inDescOverride) == 0)
368
 
      {
369
 
        strcpy(outDesc,"UCS-2");
370
 
        DBUG_RETURN(0);
371
 
      }
372
 
      else if (strcmp("cp1250", inDescOverride) == 0)
373
 
      {
374
 
        strcpy(outDesc,"IBM-1250");
375
 
        DBUG_RETURN(0);
376
 
      }
377
 
      else if (strcmp("cp1251", inDescOverride) == 0)
378
 
      {
379
 
        strcpy(outDesc,"IBM-1251");
380
 
        DBUG_RETURN(0);
381
 
      }
382
 
      else if (strcmp("cp1256", inDescOverride) == 0)
383
 
      {
384
 
        strcpy(outDesc,"IBM-1256");
385
 
        DBUG_RETURN(0);
386
 
      }
387
 
      else if (strcmp("macce", inDescOverride) == 0)
388
 
      {
389
 
        strcpy(outDesc,"IBM-1282");
390
 
        DBUG_RETURN(0);
391
 
      }
392
 
    }
393
 
    else if (outType == Qlg_TypeAS400CCSID)
394
 
    {
395
 
      // See if we can fast path the convert
396
 
      for (int loopCnt = 0; loopCnt < MAX_IANASTRING; ++loopCnt)
397
 
      {
398
 
        if (strcmp((char*)ianaStringType[loopCnt],inDescOverride) == 0)
399
 
        {
400
 
          strcpy(outDesc,ccsidType[loopCnt]);
401
 
          DBUG_RETURN(0);
402
 
        }
403
 
      }
404
 
    }
405
 
  }
406
 
  else 
407
 
    inDescOverride = inDesc;
408
 
 
409
 
  // We call getNewTextDesc for all other conversions and cache the result.  
410
 
  TextDescMap *mapping;
411
 
  TextDescMap::HashKey hashKey;
412
 
  hashKey.inType= inType;
413
 
  hashKey.outType= outType;
414
 
  uint32 len = strlen(inDescOverride);
415
 
  memcpy(hashKey.inDesc, inDescOverride, len);
416
 
  memset(hashKey.inDesc+len, 0, sizeof(hashKey.inDesc) - len);
417
 
  
418
 
  if (!(mapping=(TextDescMap *) hash_search(&textDescMapHash,
419
 
                                           (const uchar*)&hashKey,
420
 
                                           sizeof(hashKey))))
421
 
  {
422
 
    DBUG_RETURN(getNewTextDesc(inType, outType, inDescOverride, outDesc, &hashKey));
423
 
  }
424
 
  else
425
 
  {
426
 
    strcpy(outDesc, mapping->outDesc);
427
 
  }
428
 
  DBUG_RETURN(0);
429
 
}
430
 
 
431
 
 
432
 
/**
433
 
  Convert an IANA character set name into a DB2 for i CCSID value.
434
 
    
435
 
  @param parmIANADesc  An IANA character set name
436
 
  @param[out] db2Ccsid  The equivalent CCSID value
437
 
    
438
 
  @return  0 if successful. Failure otherwise
439
 
*/
440
 
int32 convertIANAToDb2Ccsid(const char* parmIANADesc, uint16* db2Ccsid)
441
 
{
442
 
  int32 rc; 
443
 
  uint16 aixCcsid;
444
 
  char aixCcsidString[Qlg_MaxDescSize];
445
 
  int aixEncodingScheme;
446
 
  int db2EncodingScheme;
447
 
  rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAS400CCSID, parmIANADesc, aixCcsidString);
448
 
  if (unlikely(rc))
449
 
  {
450
 
    if (rc == DB2I_ERR_UNSUPP_CHARSET)
451
 
      getErrTxt(DB2I_ERR_UNSUPP_CHARSET, parmIANADesc);
452
 
    
453
 
    return rc;
454
 
  }
455
 
  aixCcsid = atoi(aixCcsidString);
456
 
  rc = getEncodingScheme(aixCcsid, aixEncodingScheme);     
457
 
  if (rc != 0) 
458
 
    return rc;                   
459
 
  switch(aixEncodingScheme) { // Select on encoding scheme     
460
 
    case 0x1100: // EDCDIC SBCS                   
461
 
    case 0x2100: // ASCII SBCS                    
462
 
    case 0x4100: // AIX SBCS                      
463
 
    case 0x4105: // MS Windows                    
464
 
    case 0x5100: // ISO 7 bit ASCII               
465
 
      db2EncodingScheme = 0x1100;
466
 
      break;
467
 
    case 0x1200: // EDCDIC DBCS                   
468
 
    case 0x2200: // ASCII DBCS                    
469
 
      db2EncodingScheme = 0x1200;
470
 
      break;
471
 
    case 0x1301: // EDCDIC Mixed                  
472
 
    case 0x2300: // ASCII Mixed                   
473
 
    case 0x4403: // EUC (ISO 2022)                
474
 
      db2EncodingScheme = 0x1301;
475
 
      break;
476
 
    case 0x7200: // UCS2                          
477
 
      db2EncodingScheme = 0x7200;
478
 
      break;
479
 
    case 0x7807: // UTF-8                         
480
 
      db2EncodingScheme = 0x7807;
481
 
      break;
482
 
    case 0x7500: // UTF-32                        
483
 
      db2EncodingScheme = 0x7500;
484
 
      break;
485
 
    default: // Unknown                       
486
 
      {
487
 
         getErrTxt(DB2I_ERR_UNKNOWN_ENCODING,aixEncodingScheme);
488
 
         return DB2I_ERR_UNKNOWN_ENCODING;
489
 
      }
490
 
      break;
491
 
  }
492
 
  if (aixEncodingScheme == db2EncodingScheme) 
493
 
  {
494
 
    *db2Ccsid = aixCcsid;
495
 
  } 
496
 
  else 
497
 
  {
498
 
    rc = getAssociatedCCSID(aixCcsid, db2EncodingScheme, db2Ccsid); // EDCDIC SBCS
499
 
    if (rc != 0)
500
 
      return rc;
501
 
  }
502
 
  
503
 
  return 0;
504
 
}
505
 
 
506
 
 
507
 
/**
508
 
  Obtain the encoding scheme of a CCSID.
509
 
    
510
 
  @param inCcsid  An IBM i CCSID
511
 
  @param[out] outEncodingScheme  The associated encoding scheme
512
 
    
513
 
  @return  0 if successful. Failure otherwise
514
 
*/
515
 
int32 getEncodingScheme(const uint16 inCcsid, int32& outEncodingScheme)
516
 
{
517
 
  DBUG_ENTER("db2i_charsetSupport::getEncodingScheme");
518
 
  
519
 
  static bool ptrInited = FALSE;
520
 
  static char ptrSpace[sizeof(ILEpointer) + 15];
521
 
  static ILEpointer* ptrToPtr = (ILEpointer*)roundToQuadWordBdy(ptrSpace);
522
 
  int rc;
523
 
    
524
 
  if (!ptrInited)
525
 
  {  
526
 
    rc = _RSLOBJ2(ptrToPtr, RSLOBJ_TS_PGM, "QTQGESP", "QSYS");
527
 
 
528
 
    if (rc)
529
 
    {
530
 
      getErrTxt(DB2I_ERR_RESOLVE_OBJ,"QTQGESP","QSYS","*PGM",errno);
531
 
      DBUG_RETURN(DB2I_ERR_RESOLVE_OBJ);
532
 
    }
533
 
    ptrInited = TRUE;
534
 
  }
535
 
  
536
 
  DBUG_ASSERT(inCcsid != 0);
537
 
  
538
 
  int GESPCCSID = inCcsid;
539
 
  int GESPLen = 32;
540
 
  int GESPNbrVal = 0;
541
 
  int32 GESPES;
542
 
  int GESPCSCPL[32];
543
 
  int GESPFB[3];
544
 
  void* ILEArgv[7];
545
 
  ILEArgv[0] = &GESPCCSID;
546
 
  ILEArgv[1] = &GESPLen;
547
 
  ILEArgv[2] = &GESPNbrVal;
548
 
  ILEArgv[3] = &GESPES;
549
 
  ILEArgv[4] = &GESPCSCPL;
550
 
  ILEArgv[5] = &GESPFB;
551
 
  ILEArgv[6] = NULL;
552
 
  
553
 
  rc = _PGMCALL(ptrToPtr, (void**)&ILEArgv, 0);
554
 
  
555
 
  if (rc)
556
 
  {
557
 
     getErrTxt(DB2I_ERR_PGMCALL,"QTQGESP","QSYS",rc);
558
 
     DBUG_RETURN(DB2I_ERR_PGMCALL);
559
 
  }
560
 
  if (GESPFB[0] != 0 ||
561
 
      GESPFB[1] != 0 ||
562
 
      GESPFB[2] != 0) 
563
 
  {
564
 
    getErrTxt(DB2I_ERR_QTQGESP,GESPFB[0],GESPFB[1],GESPFB[2]);
565
 
    DBUG_RETURN(DB2I_ERR_QTQGESP);
566
 
  }
567
 
  outEncodingScheme = GESPES;
568
 
  
569
 
  DBUG_RETURN(0);
570
 
}
571
 
 
572
 
 
573
 
/**
574
 
  Get the best fit equivalent CCSID. (Wrapper for QTQGRDC API)
575
 
    
576
 
  @param inCcsid  An IBM i CCSID
577
 
  @param inEncodingScheme  The encoding scheme
578
 
  @param[out] outCcsid  The equivalent CCSID
579
 
    
580
 
  @return  0 if successful. Failure otherwise
581
 
*/
582
 
int32 getAssociatedCCSID(const uint16 inCcsid, const int inEncodingScheme, uint16* outCcsid)
583
 
{
584
 
  DBUG_ENTER("db2i_charsetSupport::getAssociatedCCSID");
585
 
  static bool ptrInited = FALSE;
586
 
  static char ptrSpace[sizeof(ILEpointer) + 15];
587
 
  static ILEpointer* ptrToPtr = (ILEpointer*)roundToQuadWordBdy(ptrSpace);
588
 
  int rc;
589
 
  
590
 
  // Override non-standard charsets
591
 
  if ((inCcsid == 923) && (inEncodingScheme == 0x1100))
592
 
  {
593
 
    *outCcsid = 1148;
594
 
    DBUG_RETURN(0);
595
 
  }
596
 
  else if ((inCcsid == 1250) && (inEncodingScheme == 0x1100))
597
 
  {
598
 
    *outCcsid = 1153;
599
 
    DBUG_RETURN(0);
600
 
  }
601
 
 
602
 
  if (!ptrInited)
603
 
  {  
604
 
    rc = _RSLOBJ2(ptrToPtr, RSLOBJ_TS_PGM, "QTQGRDC", "QSYS");
605
 
 
606
 
    if (rc)
607
 
    {
608
 
       getErrTxt(DB2I_ERR_RESOLVE_OBJ,"QTQGRDC","QSYS","*PGM",errno);
609
 
       DBUG_RETURN(DB2I_ERR_RESOLVE_OBJ);
610
 
    }
611
 
    ptrInited = TRUE;
612
 
  }
613
 
 
614
 
  int GRDCCCSID = inCcsid;
615
 
  int GRDCES = inEncodingScheme;
616
 
  int GRDCSel = 0;
617
 
  int GRDCAssCCSID;
618
 
  int GRDCFB[3];
619
 
  void* ILEArgv[7];
620
 
  ILEArgv[0] = &GRDCCCSID;
621
 
  ILEArgv[1] = &GRDCES;
622
 
  ILEArgv[2] = &GRDCSel;
623
 
  ILEArgv[3] = &GRDCAssCCSID;
624
 
  ILEArgv[4] = &GRDCFB;
625
 
  ILEArgv[5] = NULL;
626
 
  
627
 
  rc = _PGMCALL(ptrToPtr, (void**)&ILEArgv, 0);
628
 
 
629
 
  if (rc)  
630
 
  {
631
 
     getErrTxt(DB2I_ERR_PGMCALL,"QTQGRDC","QSYS",rc);
632
 
     DBUG_RETURN(DB2I_ERR_PGMCALL);
633
 
  }
634
 
  if (GRDCFB[0] != 0 ||
635
 
      GRDCFB[1] != 0 ||
636
 
      GRDCFB[2] != 0)
637
 
  {
638
 
    getErrTxt(DB2I_ERR_QTQGRDC,GRDCFB[0],GRDCFB[1],GRDCFB[2]);
639
 
    DBUG_RETURN(DB2I_ERR_QTQGRDC);
640
 
  }
641
 
 
642
 
  *outCcsid = GRDCAssCCSID;
643
 
 
644
 
  DBUG_RETURN(0);
645
 
}
646
 
 
647
 
/**
648
 
  Open an iconv conversion between a MySQL charset and the respective IBM i CCSID
649
 
    
650
 
  @param direction  The direction of the conversion
651
 
  @param mysqlCSName  Name of the MySQL character set
652
 
  @param db2CCSID  The IBM i CCSID
653
 
  @param hashKey  The key to use for inserting the opened conversion into the cache
654
 
  @param[out] newConversion  The iconv descriptor
655
 
    
656
 
  @return  0 if successful. Failure otherwise
657
 
*/
658
 
static int32 openNewConversion(enum_conversionDirection direction, 
659
 
                               const char* mysqlCSName, 
660
 
                               uint16 db2CCSID, 
661
 
                               IconvMap::HashKey* hashKey, 
662
 
                               iconv_t& newConversion)
663
 
{
664
 
  DBUG_ENTER("db2i_charsetSupport::openNewConversion");
665
 
  
666
 
  char mysqlAix41Desc[Qlg_MaxDescSize];
667
 
  char db2Aix41Desc[Qlg_MaxDescSize];
668
 
  char db2CcsidString[6] = "";
669
 
  int32 rc;
670
 
 
671
 
  /*
672
 
     First we have to convert the MySQL IANA-like name and the DB2 CCSID into
673
 
     there equivalent iconv descriptions.
674
 
  */
675
 
  rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAix41, mysqlCSName, mysqlAix41Desc);
676
 
  if (unlikely(rc))
677
 
  {
678
 
    if (rc == DB2I_ERR_UNSUPP_CHARSET)
679
 
      getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
680
 
    
681
 
    DBUG_RETURN(rc);
682
 
  }
683
 
  CHARSET_INFO *cs= &my_charset_bin;
684
 
  (uint)(cs->cset->long10_to_str)(cs,db2CcsidString,sizeof(db2CcsidString), 10, db2CCSID);  
685
 
  rc = convertTextDesc(Qlg_TypeAS400CCSID, Qlg_TypeAix41, db2CcsidString, db2Aix41Desc);
686
 
  if (unlikely(rc))
687
 
  {
688
 
    if (rc == DB2I_ERR_UNSUPP_CHARSET)
689
 
      getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
690
 
    
691
 
    DBUG_RETURN(rc);
692
 
  }
693
 
  
694
 
  /* Call iconv to open the conversion. */
695
 
  if (direction == toDB2)
696
 
  {
697
 
    newConversion = iconv_open(db2Aix41Desc, mysqlAix41Desc);
698
 
  }
699
 
  else
700
 
  {
701
 
    newConversion = iconv_open(mysqlAix41Desc, db2Aix41Desc);
702
 
  }
703
 
 
704
 
  if (unlikely(newConversion == (iconv_t) -1))
705
 
  {
706
 
    getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
707
 
    DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
708
 
  }
709
 
 
710
 
  /* Insert the new conversion into the cache. */
711
 
  IconvMap* mapping = (IconvMap*)alloc_root(&iconvMapMemroot, sizeof(IconvMap));
712
 
  if (!mapping)
713
 
  {
714
 
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(IconvMap));
715
 
    DBUG_RETURN( HA_ERR_OUT_OF_MEM);
716
 
  }
717
 
  memcpy(&(mapping->hashKey), hashKey, sizeof(mapping->hashKey));
718
 
  mapping->iconvDesc = newConversion;
719
 
  pthread_mutex_lock(&iconvMapHashMutex);
720
 
  my_hash_insert(&iconvMapHash, (const uchar*)mapping);
721
 
  pthread_mutex_unlock(&iconvMapHashMutex);
722
 
  
723
 
  DBUG_RETURN(0);
724
 
}
725
 
 
726
 
 
727
 
/**
728
 
  Open an iconv conversion between a MySQL charset and the respective IBM i CCSID
729
 
    
730
 
  @param direction  The direction of the conversion
731
 
  @param cs  The MySQL character set
732
 
  @param db2CCSID  The IBM i CCSID
733
 
  @param[out] newConversion  The iconv descriptor
734
 
    
735
 
  @return  0 if successful. Failure otherwise
736
 
*/
737
 
int32 getConversion(enum_conversionDirection direction, const CHARSET_INFO* cs, uint16 db2CCSID, iconv_t& conversion)
738
 
{
739
 
  DBUG_ENTER("db2i_charsetSupport::getConversion");
740
 
  
741
 
  int32 rc;
742
 
 
743
 
  /* Build the hash key */  
744
 
  IconvMap::HashKey hashKey;
745
 
  hashKey.direction= direction;
746
 
  hashKey.myCharset= cs;
747
 
  hashKey.db2CCSID= db2CCSID;
748
 
  
749
 
  /* Look for the conversion in the cache and add it if it is not there. */
750
 
  IconvMap *mapping;
751
 
  if (!(mapping= (IconvMap *) hash_search(&iconvMapHash,
752
 
                                         (const uchar*)&hashKey,
753
 
                                         sizeof(hashKey))))
754
 
  {
755
 
    DBUG_PRINT("getConversion", ("Hash miss for direction=%d, cs=%s, ccsid=%d", direction, cs->name, db2CCSID));
756
 
    rc= openNewConversion(direction, cs->csname, db2CCSID, &hashKey, conversion);
757
 
    if (rc)
758
 
      DBUG_RETURN(rc);
759
 
  }
760
 
  else
761
 
  {
762
 
    conversion= mapping->iconvDesc;
763
 
  }
764
 
 
765
 
  DBUG_RETURN(0);
766
 
}
767
 
 
768
 
/**
769
 
  Fast-path conversion from ASCII to EBCDIC for use in converting
770
 
  identifiers to be sent to the QMY APIs.
771
 
  
772
 
  @param input  ASCII data
773
 
  @param[out] ouput  EBCDIC data
774
 
  @param ilen  Size of input buffer and output buffer
775
 
*/
776
 
int convToEbcdic(const char* input, char* output, size_t ilen)
777
 
{
778
 
  static bool inited = FALSE;
779
 
  static iconv_t ic;
780
 
  
781
 
  if (ilen == 0)
782
 
    return 0;
783
 
  
784
 
  if (!inited)
785
 
  {
786
 
    ic = iconv_open( "IBM-037", "ISO8859-1" );
787
 
    inited = TRUE;
788
 
  }
789
 
  size_t substitutedChars;
790
 
  size_t olen = ilen;
791
 
  if (iconv( ic, (char**)&input, &ilen, &output, &olen, &substitutedChars ) == -1)
792
 
    return errno;
793
 
  
794
 
  return 0;
795
 
}
796
 
 
797
 
 
798
 
/**
799
 
  Fast-path conversion from EBCDIC to ASCII for use in converting
800
 
  data received from the QMY APIs.
801
 
  
802
 
  @param input  EBCDIC data
803
 
  @param[out] ouput  ASCII data
804
 
  @param ilen  Size of input buffer and output buffer
805
 
*/
806
 
int convFromEbcdic(const char* input, char* output, size_t ilen)
807
 
{
808
 
  static bool inited = FALSE;
809
 
  static iconv_t ic;
810
 
  
811
 
  if (ilen == 0)
812
 
    return 0;
813
 
 
814
 
  if (!inited)
815
 
  {
816
 
    ic = iconv_open("ISO8859-1", "IBM-037");
817
 
    inited = TRUE;
818
 
  }
819
 
  
820
 
  size_t substitutedChars;
821
 
  size_t olen = ilen;
822
 
  if (iconv( ic, (char**)&input, &ilen, &output, &olen, &substitutedChars) == -1)
823
 
    return errno;
824
 
  
825
 
  return 0;
826
 
}