2 * Description: New Multibyte related additional function.
4 * Create 2001-03-03 Eiji Tokuya
5 * New Create 2001-09-16 Eiji Tokuya
10 #include "connection.h"
11 #include "pgapifunc.h"
20 static pg_CS CS_Table
[] = {
21 {"SQL_ASCII", SQL_ASCII
},
26 {"JOHAB", JOHAB
}, /* since 7.3 */
27 {"UTF8", UTF8
}, /* since 7.2 */
28 {"MULE_INTERNAL", MULE_INTERNAL
},
39 {"WIN1256", WIN1256
}, /* Arabic since 7.3 */
40 {"WIN1258", WIN1258
}, /* Vietnamese since 8.1 */
41 {"WIN866", WIN866
}, /* since 8.1 */
42 {"WIN874", WIN874
}, /* Thai since 7.3 */
44 {"WIN1251", WIN1251
}, /* Cyrillic */
45 {"WIN1252", WIN1252
}, /* Western Europe since 8.1 */
46 {"ISO_8859_5", ISO_8859_5
},
47 {"ISO_8859_6", ISO_8859_6
},
48 {"ISO_8859_7", ISO_8859_7
},
49 {"ISO_8859_8", ISO_8859_8
},
50 {"WIN1250", WIN1250
}, /* Central Europe */
51 {"WIN1253", WIN1253
}, /* Greek since 8.2 */
52 {"WIN1254", WIN1254
}, /* Turkish since 8.2 */
53 {"WIN1255", WIN1255
}, /* Hebrew since 8.2 */
54 {"WIN1257", WIN1257
}, /* Baltic(North Europe) since 8.2 */
58 {"GBK", GBK
}, /* since 7.3 */
59 {"UHC", UHC
}, /* since 7.3 */
60 {"GB18030", GB18030
}, /* since 7.3 */
64 static pg_CS CS_Alias
[] = {
72 CSTR OTHER_STRING
= "OTHER";
74 int pg_CS_code(const UCHAR
* characterset_string
)
78 for (i
= 0; CS_Table
[i
].code
!= OTHER
; i
++)
80 if (0 == stricmp((const char *)characterset_string
, CS_Table
[i
].name
))
88 for (i
= 0; CS_Alias
[i
].code
!= OTHER
; i
++)
90 if (0 == stricmp((const char *)characterset_string
, CS_Alias
[i
].name
))
102 UCHAR
*check_client_encoding(const UCHAR
* conn_settings
)
104 const UCHAR
*cptr
, *sptr
= NULL
;
106 BOOL allowed_cmd
= TRUE
, in_quote
= FALSE
;
110 for (cptr
= conn_settings
; *cptr
; cptr
++)
113 if (LITERAL_QUOTE
== *cptr
)
131 if (0 != strnicmp((const char *)cptr
, "set", 3))
140 if (0 != strnicmp((const char *)cptr
, "client_encoding", 15))
149 if (0 != strnicmp((const char *)cptr
, "to", 2))
158 if (LITERAL_QUOTE
== *cptr
)
161 for (sptr
= cptr
; *cptr
&& *cptr
!= LITERAL_QUOTE
;
165 for (sptr
= cptr
; *cptr
&& !isspace(*cptr
); cptr
++);
174 rptr
= (UCHAR
*)malloc(len
+ 1);
175 memcpy(rptr
, sptr
, len
);
177 mylog("extracted a client_encoding '%s' from conn_settings\n",
182 const UCHAR
*pg_CS_name(int characterset_code
)
185 for (i
= 0; CS_Table
[i
].code
!= OTHER
; i
++)
187 if (CS_Table
[i
].code
== characterset_code
)
188 return (const UCHAR
*)CS_Table
[i
].name
;
190 return (const UCHAR
*)(OTHER_STRING
);
193 static int pg_mb_maxlen(int characterset_code
)
195 switch (characterset_code
)
217 int pg_CS_stat(int stat
, unsigned int character
, int characterset_code
)
221 switch (characterset_code
)
225 if (stat
< 2 && character
>= 0x80)
227 if (character
>= 0xfc)
229 else if (character
>= 0xf8)
231 else if (character
>= 0xf0)
233 else if (character
>= 0xe0)
235 else if (character
>= 0xc0)
237 } else if (stat
> 2 && character
> 0x7f)
243 /* Shift-JIS Support. */
248 !(character
> 0x9f && character
< 0xe0))
256 /* Chinese Big5 Support. */
259 if (stat
< 2 && character
> 0xA0)
267 /* Chinese GBK Support. */
270 if (stat
< 2 && character
> 0x7F)
279 /* Korian UHC Support. */
282 if (stat
< 2 && character
> 0x7F)
294 if (stat
< 3 && character
== 0x8f) /* JIS X 0212 */
296 else if (stat
!= 2 && (character
== 0x8e || character
> 0xa0)) /* Half Katakana HighByte & Kanji HighByte */
305 /* EUC_CN, EUC_KR, JOHAB Support */
310 if (stat
< 2 && character
> 0xa0)
320 if (stat
< 4 && character
== 0x8e)
322 else if (stat
== 4 && character
> 0xa0)
324 else if ((stat
== 3 || stat
< 2) && character
> 0xa0)
332 /*Chinese GB18030 support.Added by Bill Huang <bhuang@redhat.com> <bill_huanghb@ybb.ne.jp> */
335 if (stat
< 2 && character
> 0x80)
339 if (character
>= 0x30 && character
<= 0x39)
343 } else if (stat
== 3)
345 if (character
>= 0x30 && character
<= 0x39)
363 UCHAR
*pg_mbschr(int csc
, const UCHAR
* string
, unsigned int character
)
366 const UCHAR
*s
, *rs
= NULL
;
368 for (s
= string
; *s
; s
++)
370 mb_st
= pg_CS_stat(mb_st
, (UCHAR
) * s
, csc
);
371 if (mb_st
== 0 && (*s
== character
))
377 return ((UCHAR
*) rs
);
380 size_t pg_mbslen(int csc
, const UCHAR
* string
)
385 for (len
= 0, cs_stat
= 0, s
= (UCHAR
*) string
; *s
!= 0; s
++)
387 cs_stat
= pg_CS_stat(cs_stat
, (unsigned int) *s
, csc
);
394 UCHAR
*pg_mbsinc(int csc
, const UCHAR
* current
)
399 mb_stat
= (int) pg_CS_stat(mb_stat
, *current
, csc
);
402 return ((UCHAR
*) current
+ mb_stat
);
407 static char *CC_lookup_cs_new(ConnectionClass
* self
)
413 CC_send_query(self
, "select pg_client_encoding()", NULL
,
414 IGNORE_ABORT_ON_CONN
| ROLLBACK_ON_ERROR
, NULL
);
415 if (QR_command_maybe_successful(res
))
417 const char *enc
= QR_get_value_backend_text(res
, 0, 0);
420 encstr
= strdup(enc
);
425 static char *CC_lookup_cs_old(ConnectionClass
* self
)
431 result
= PGAPI_AllocStmt(self
, &hstmt
);
432 if (!SQL_SUCCEEDED(result
))
436 PGAPI_ExecDirect(hstmt
, (const UCHAR
*)"Show Client_Encoding",
438 if (result
== SQL_SUCCESS_WITH_INFO
)
440 char sqlState
[8], errormsg
[128], enc
[32];
442 if (PGAPI_Error(NULL
, NULL
, hstmt
, (UCHAR
*)sqlState
,
443 NULL
, (UCHAR
*)errormsg
, sizeof(errormsg
), NULL
)
445 sscanf(errormsg
, "%*s %*s %*s %*s %*s %s", enc
) > 0)
446 encstr
= strdup(enc
);
448 PGAPI_FreeStmt(hstmt
, SQL_DROP
);
453 * This function works under Windows or Unicode case only.
454 * Simply returns NULL under other OSs.
456 const char *get_environment_encoding(const ConnectionClass
* conn
,
458 const char *currenc
, BOOL bStartup
)
460 const char *wenc
= NULL
;
463 #ifdef UNICODE_SUPPORT
464 if (CC_is_in_unicode_driver(conn
))
466 #endif /* UNICODE_SUPPORT */
467 if (setenc
&& stricmp(setenc
, OTHER_STRING
))
471 if (acp
>= 1251 && acp
<= 1258)
473 if (bStartup
|| stricmp(currenc
, "SQL_ASCII") == 0)
482 if (!bStartup
&& PG_VERSION_GT(conn
, 7.2))
486 if (!bStartup
&& PG_VERSION_GT(conn
, 7.2))
499 if (PG_VERSION_GE(conn
, 7.3))
503 if (strnicmp(currenc
, "LATIN", 5) == 0)
505 if (PG_VERSION_GE(conn
, 8.1))
511 if (PG_VERSION_GE(conn
, 8.1))
515 if (PG_VERSION_GE(conn
, 8.2))
519 if (PG_VERSION_GE(conn
, 8.2))
523 if (PG_VERSION_GE(conn
, 8.2))
527 if (PG_VERSION_GE(conn
, 8.2))
535 void CC_lookup_characterset(ConnectionClass
* self
)
537 char *encspec
= NULL
, *currenc
= NULL
, *tencstr
;
538 CSTR func
= "CC_lookup_characterset";
540 mylog("%s: entering...\n", func
);
541 if (self
->original_client_encoding
)
542 encspec
= strdup(self
->original_client_encoding
);
543 if (self
->current_client_encoding
)
544 currenc
= strdup(self
->current_client_encoding
);
545 else if (PG_VERSION_LT(self
, 7.2))
546 currenc
= CC_lookup_cs_old(self
);
548 currenc
= CC_lookup_cs_new(self
);
549 tencstr
= encspec
? encspec
: currenc
;
550 if (self
->original_client_encoding
)
552 if (stricmp(self
->original_client_encoding
, tencstr
))
556 snprintf(msg
, sizeof(msg
),
557 "The client_encoding '%s' was changed to '%s'",
558 self
->original_client_encoding
, tencstr
);
559 CC_set_error(self
, CONN_OPTION_VALUE_CHANGED
, msg
, func
);
561 free(self
->original_client_encoding
);
563 #ifndef UNICODE_SUPPORT
567 get_environment_encoding(self
, encspec
, currenc
, FALSE
);
568 if (wenc
&& (!tencstr
|| stricmp(tencstr
, wenc
)))
572 int errnum
= CC_get_errornumber(self
);
575 sprintf(query
, "set client_encoding to '%s'", wenc
);
577 CC_send_query(self
, query
, NULL
,
578 IGNORE_ABORT_ON_CONN
| ROLLBACK_ON_ERROR
,
580 cmd_success
= QR_command_maybe_successful(res
);
582 CC_set_errornumber(self
, errnum
);
585 self
->original_client_encoding
= strdup(wenc
);
586 self
->ccsc
= pg_CS_code(self
->original_client_encoding
);
595 #endif /* UNICODE_SUPPORT */
598 self
->original_client_encoding
= tencstr
;
599 if (encspec
&& currenc
)
601 self
->ccsc
= pg_CS_code((const UCHAR
*)tencstr
);
602 qlog(" [ Client encoding = '%s' (code = %d) ]\n",
603 self
->original_client_encoding
, self
->ccsc
);
608 snprintf(msg
, sizeof(msg
),
609 "would handle the encoding '%s' like ASCII",
611 CC_set_error(self
, CONN_OPTION_VALUE_CHANGED
, msg
, func
);
615 self
->ccsc
= SQL_ASCII
;
616 self
->original_client_encoding
= NULL
;
618 self
->mb_maxbyte_per_char
= pg_mb_maxlen(self
->ccsc
);
621 void encoded_str_constr(encoded_str
* encstr
, int ccsc
, const char *str
)
624 encstr
->encstr
= (const UCHAR
*)str
;
629 int encoded_nextchar(encoded_str
* encstr
)
633 chr
= encstr
->encstr
[++encstr
->pos
];
635 pg_CS_stat(encstr
->ccst
, (unsigned int) chr
, encstr
->ccsc
);
639 ssize_t
encoded_position_shift(encoded_str
* encstr
, size_t shift
)
641 encstr
->pos
+= shift
;
645 int encoded_byte_check(encoded_str
* encstr
, size_t abspos
)
649 chr
= encstr
->encstr
[encstr
->pos
= abspos
];
651 pg_CS_stat(encstr
->ccst
, (unsigned int) chr
, encstr
->ccsc
);