diff --git a/lib/modules/Sql.pmod/mysql.pike b/lib/modules/Sql.pmod/mysql.pike index e47ae1748728025eac34af7d6a94f9b72502a509..def5731786fc60dacb025eb0805d381e01c67b32 100644 --- a/lib/modules/Sql.pmod/mysql.pike +++ b/lib/modules/Sql.pmod/mysql.pike @@ -1,5 +1,5 @@ /* - * $Id: mysql.pike,v 1.34 2006/11/17 18:43:17 mast Exp $ + * $Id: mysql.pike,v 1.35 2006/11/27 16:32:41 mast Exp $ * * Glue for the Mysql-module */ @@ -138,6 +138,9 @@ int get_unicode_encode_mode() #if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) void set_unicode_decode_mode (int enable) +#else +static void broken_set_unicode_decode_mode (int enable) +#endif //! Enable or disable unicode decode mode. //! //! In this mode, if the server supports UTF-8 then non-binary text @@ -175,6 +178,15 @@ void set_unicode_decode_mode (int enable) utf8_mode &= ~UNICODE_DECODE_MODE; } } + +#if !constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) +// See blurb at MySQLBrokenUnicodeWrapper in sql_util.pmod. The +// PIKE_BROKEN_MYSQL_UNICODE_MODE thingy ought to be a define, but +// it's an environment variable instead to avoid problems with +// overcaching in dumped files. +function(int:void) set_unicode_decode_mode = + getenv ("PIKE_BROKEN_MYSQL_UNICODE_MODE") && + broken_set_unicode_decode_mode; #endif int get_unicode_decode_mode() @@ -266,16 +278,17 @@ void set_charset (string charset) #if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) utf8_mode |= UNICODE_DECODE_MODE; #else - predef::error ("Unicode decode mode not supported - " - "compiled with MySQL client library < 4.1.0.\n"); + if (set_unicode_decode_mode) + utf8_mode |= UNICODE_DECODE_MODE; + else + predef::error ("Unicode decode mode not supported - " + "compiled with MySQL client library < 4.1.0.\n"); #endif } -#if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) else if (utf8_mode & UNICODE_DECODE_MODE && charset != "utf8") // This setting has been overridden by ::set_charset, so we need // to reinstate it. ::big_query ("SET character_set_results = utf8"); -#endif } string get_charset() @@ -564,9 +577,9 @@ int decode_datetime (string timestr) } #if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) -#define HAVE_MYSQL_FIELD_CHARSETNR_DO(X...) X +#define HAVE_MYSQL_FIELD_CHARSETNR_IFELSE(TRUE, FALSE) TRUE #else -#define HAVE_MYSQL_FIELD_CHARSETNR_DO(X...) +#define HAVE_MYSQL_FIELD_CHARSETNR_IFELSE(TRUE, FALSE) FALSE #endif #define QUERY_BODY(do_query) \ @@ -647,12 +660,13 @@ int decode_datetime (string timestr) \ if (!objectp(res)) return res; \ \ - HAVE_MYSQL_FIELD_CHARSETNR_DO ( \ - if (utf8_mode & UNICODE_DECODE_MODE) { \ - CH_DEBUG ("Using UnicodeWrapper for result.\n"); \ - return .sql_util.UnicodeWrapper(res); \ - } \ - ); \ + if (utf8_mode & UNICODE_DECODE_MODE) { \ + CH_DEBUG ("Using unicode wrapper for result.\n"); \ + return \ + HAVE_MYSQL_FIELD_CHARSETNR_IFELSE ( \ + .sql_util.MySQLUnicodeWrapper(res), \ + .sql_util.MySQLBrokenUnicodeWrapper (res)); \ + } \ return res; Mysql.mysql_result big_query (string query, @@ -764,15 +778,19 @@ static void create(string|void host, string|void database, update_unicode_encode_mode_from_charset (lower_case (charset)); -#if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) - if (charset == "unicode") - utf8_mode |= UNICODE_DECODE_MODE; - else if (options->unicode_decode_mode) - set_unicode_decode_mode (1); -#else - if (charset == "unicode" || options->unicode_decode_mode) - predef::error ("Unicode decode mode not supported - " - "compiled with MySQL client library < 4.1.0.\n"); +#if !constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) + if (set_unicode_encode_mode) { +#endif + if (charset == "unicode") + utf8_mode |= UNICODE_DECODE_MODE; + else if (options->unicode_decode_mode) + set_unicode_decode_mode (1); +#if !constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) + } + else + if (charset == "unicode" || options->unicode_decode_mode) + predef::error ("Unicode decode mode not supported - " + "compiled with MySQL client library < 4.1.0.\n"); #endif } else { diff --git a/lib/modules/Sql.pmod/sql_util.pmod b/lib/modules/Sql.pmod/sql_util.pmod index 6eb80ab9d808f7350aef1d707ce34d46da7e237f..206036a99142be64c131a1017d12f4ad4e3875ba 100644 --- a/lib/modules/Sql.pmod/sql_util.pmod +++ b/lib/modules/Sql.pmod/sql_util.pmod @@ -1,5 +1,5 @@ /* - * $Id: sql_util.pmod,v 1.16 2006/11/17 18:43:17 mast Exp $ + * $Id: sql_util.pmod,v 1.17 2006/11/27 16:32:43 mast Exp $ * * Some SQL utility functions. * They are kept here to avoid circular references. @@ -141,6 +141,7 @@ class UnicodeWrapper ( } #if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) + class MySQLUnicodeWrapper //! Result wrapper for MySQL that performs UTF-8 decoding of all //! nonbinary fields. Useful if the result charset of the connection @@ -165,4 +166,38 @@ class MySQLUnicodeWrapper return row; } } + +#else + +class MySQLBrokenUnicodeWrapper +// This one is used to get bug compatibility when compiled with an old +// MySQL client lib that doesn't have the charsetnr property in the +// field info. It looks at the binary flag instead, which is set for +// binary fields but might also be set for text fields (e.g. with a +// definition like "VARCHAR(255) BINARY"). +// +// I.e. the effect of using this one is that text fields with the +// binary flag won't be correctly decoded in unicode decode mode. This +// has to be enabled by defining the environment variable +// PIKE_BROKEN_MYSQL_UNICODE_MODE. With it the unicode decode mode +// will exist even when the client lib is too old to implement it +// correctly. +{ + inherit UnicodeWrapper; + + int|array(string) fetch_row() + { + int|array(string) row = master_result->fetch_row(); + if (!arrayp(row)) return row; + array(int|mapping(string:mixed)) field_info = fetch_fields(); + foreach(row; int i; string|int val) { + if (stringp(val) && field_info[i]->flags && + !field_info[i]->flags->binary) { + row[i] = utf8_to_string(val); + } + } + return row; + } +} + #endif