diff --git a/lib/modules/Sql.pmod/mysql.pike b/lib/modules/Sql.pmod/mysql.pike index eef7c16c8b2a705581b74dbc8dbe74f1161d0469..e47ae1748728025eac34af7d6a94f9b72502a509 100644 --- a/lib/modules/Sql.pmod/mysql.pike +++ b/lib/modules/Sql.pmod/mysql.pike @@ -1,5 +1,5 @@ /* - * $Id: mysql.pike,v 1.33 2006/11/04 19:06:49 nilsson Exp $ + * $Id: mysql.pike,v 1.34 2006/11/17 18:43:17 mast Exp $ * * Glue for the Mysql-module */ @@ -136,12 +136,13 @@ int get_unicode_encode_mode() return !!send_charset; } +#if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) void set_unicode_decode_mode (int enable) //! Enable or disable unicode decode mode. //! //! In this mode, if the server supports UTF-8 then non-binary text -//! strings in results are are automatically decoded to (possibly -//! wide) unicode strings. Not enabled by default. +//! strings in results are automatically decoded to (possibly wide) +//! unicode strings. Not enabled by default. //! //! The statement "@expr{SET character_set_results = utf8@}" is sent //! to the server to enable the mode. When the mode is disabled, @@ -157,9 +158,8 @@ void set_unicode_decode_mode (int enable) //! @expr{character_set_results@} was added in MySQL 4.1.1. //! //! @note -//! This mode is not compatible with earlier pike versions. You need -//! to run in compatibility mode <= 7.6 to have it disabled by -//! default. +//! This function is only available if Pike has been compiled with +//! MySQL client library 4.1.0 or later. //! //! @seealso //! @[set_unicode_encode_mode] @@ -175,6 +175,7 @@ void set_unicode_decode_mode (int enable) utf8_mode &= ~UNICODE_DECODE_MODE; } } +#endif int get_unicode_decode_mode() //! Returns nonzero if unicode decode mode is enabled, zero otherwise. @@ -261,12 +262,20 @@ void set_charset (string charset) utf8_mode & (LATIN1_UNICODE_ENCODE_MODE|UTF8_UNICODE_ENCODE_MODE)) update_unicode_encode_mode_from_charset (charset); - if (charset == "unicode") + if (charset == "unicode") { +#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"); +#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() @@ -554,6 +563,12 @@ int decode_datetime (string timestr) } } +#if constant (Mysql.mysql.HAVE_MYSQL_FIELD_CHARSETNR) +#define HAVE_MYSQL_FIELD_CHARSETNR_DO(X...) X +#else +#define HAVE_MYSQL_FIELD_CHARSETNR_DO(X...) +#endif + #define QUERY_BODY(do_query) \ if (bindings) \ query = .sql_util.emulate_bindings(query,bindings,this); \ @@ -632,10 +647,12 @@ int decode_datetime (string timestr) \ if (!objectp(res)) return res; \ \ - if (utf8_mode & UNICODE_DECODE_MODE) { \ - CH_DEBUG ("Using UnicodeWrapper for result.\n"); \ - return .sql_util.UnicodeWrapper(res); \ - } \ + HAVE_MYSQL_FIELD_CHARSETNR_DO ( \ + if (utf8_mode & UNICODE_DECODE_MODE) { \ + CH_DEBUG ("Using UnicodeWrapper for result.\n"); \ + return .sql_util.UnicodeWrapper(res); \ + } \ + ); \ return res; Mysql.mysql_result big_query (string query, @@ -747,10 +764,16 @@ 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"); +#endif } else { ::create(host||"", database||"", user||"", password||""); diff --git a/lib/modules/Sql.pmod/sql_util.pmod b/lib/modules/Sql.pmod/sql_util.pmod index 982594e466201c04c280d34d062b91a5c9af3cc1..6eb80ab9d808f7350aef1d707ce34d46da7e237f 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.15 2006/08/11 11:08:44 grubba Exp $ + * $Id: sql_util.pmod,v 1.16 2006/11/17 18:43:17 mast Exp $ * * Some SQL utility functions. * They are kept here to avoid circular references. @@ -61,9 +61,6 @@ string emulate_bindings(string query, mapping(string|int:mixed)|void bindings, } //! Result object wrapper performing utf8 decoding of all fields. -//! -//! Useful for eg Mysql connections which have been set to utf8-mode -//! using eg @expr{"SET NAMES 'utf8'"@}. class UnicodeWrapper ( //! The wrapped result object. static object master_result @@ -135,11 +132,37 @@ class UnicodeWrapper ( 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) { + if (stringp(val)) { + row[i] = utf8_to_string(val); + } + } + return row; + } +} + +#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 +//! has been set to UTF-8. +//! +//! @note +//! There's normally no need to use this class directly. It's used +//! automatically when @[Mysql.set_unicode_decode_mode] is activated. +{ + 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]->charsetnr != 63) { row[i] = utf8_to_string(val); } } return row; } } +#endif diff --git a/src/modules/Mysql/acconfig.h b/src/modules/Mysql/acconfig.h index 4dc03dbea78e3cb2f39ba7f6c617a1b6b1d56119..6e601a9ead3efec7434d891e80125ae8b864770f 100644 --- a/src/modules/Mysql/acconfig.h +++ b/src/modules/Mysql/acconfig.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: acconfig.h,v 1.17 2006/08/31 10:10:18 mast Exp $ +|| $Id: acconfig.h,v 1.18 2006/11/17 18:43:17 mast Exp $ */ /* @@ -83,4 +83,7 @@ /* Define if your mysql.h defines CLIENT_INTERACTIVE */ #undef HAVE_CLIENT_INTERACTIVE +/* Define if MYSQL_FIELD has a charsetnr member */ +#undef HAVE_MYSQL_FIELD_CHARSETNR + #endif /* PIKE_MYSQL_CONFIG_H */ diff --git a/src/modules/Mysql/configure.in b/src/modules/Mysql/configure.in index 47e061dfc07ae23264138929931a0cdd366ff40a..c4ac535b12e67dea18b123307fa535ffb6bb7ec8 100644 --- a/src/modules/Mysql/configure.in +++ b/src/modules/Mysql/configure.in @@ -1,5 +1,5 @@ # -# $Id: configure.in,v 1.53 2006/08/31 10:10:18 mast Exp $ +# $Id: configure.in,v 1.54 2006/11/17 18:43:17 mast Exp $ # # Configure script for the mysql-module # @@ -443,6 +443,34 @@ $ret_type * STDCALL mysql_fetch_lengths(MYSQL_RES *mysql) AC_CHECK_FUNCS(ldiv open sopen close read fileno puts fgets) + AC_MSG_CHECKING(for the charsetnr member in MYSQL_FIELD) + AC_CACHE_VAL(pike_cv_have_mysql_field_charsetnr, [ + AC_TRY_LINK([ +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#elif defined(HAVE_WINSOCK_H) +#include <winsock.h> +#endif + +#ifdef HAVE_MYSQL_H +#include <mysql.h> +#else +#ifdef HAVE_MYSQL_MYSQL_H +#include <mysql/mysql.h> +#else +#error Need mysql.h headerfile! +#endif +#endif + ], [ + void *foo__ = &(((MYSQL_FIELD *) 0)->charsetnr); + ], [pike_cv_have_mysql_field_charsetnr="yes"], + [pike_cv_have_mysql_field_charsetnr="no"]) + ]) + if test "$pike_cv_have_mysql_field_charsetnr" = yes; then + AC_DEFINE(HAVE_MYSQL_FIELD_CHARSETNR) + fi + AC_MSG_RESULT($pike_cv_have_mysql_field_charsetnr) + fi fi diff --git a/src/modules/Mysql/mysql.c b/src/modules/Mysql/mysql.c index 60fb401560df8cd3018ee9319ad6e28fe0b716fe..224b1939310e37024173a7ad1af440a2b4af97e6 100644 --- a/src/modules/Mysql/mysql.c +++ b/src/modules/Mysql/mysql.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: mysql.c,v 1.106 2006/09/16 18:19:21 mast Exp $ +|| $Id: mysql.c,v 1.107 2006/11/17 18:43:18 mast Exp $ */ /* @@ -1946,6 +1946,10 @@ PIKE_MODULE_INIT add_integer_constant( "CLIENT_SSL", CLIENT_SSL, 0); #endif +#ifdef HAVE_MYSQL_FIELD_CHARSETNR + add_integer_constant ("HAVE_MYSQL_FIELD_CHARSETNR", 1, 0); +#endif + set_init_callback(init_mysql_struct); set_exit_callback(exit_mysql_struct); diff --git a/src/modules/Mysql/result.c b/src/modules/Mysql/result.c index 20096f2e0770d5f9c30b1e8880e13112e01640aa..f3ddfe711e71559f4bbcf91889802cdc4a2f2b02 100644 --- a/src/modules/Mysql/result.c +++ b/src/modules/Mysql/result.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: result.c,v 1.36 2006/08/10 16:28:25 grubba Exp $ +|| $Id: result.c,v 1.37 2006/11/17 18:43:18 mast Exp $ */ /* @@ -134,6 +134,8 @@ void mysqlmod_parse_field(MYSQL_FIELD *field, int support_default) { if (field) { int nbits = 0; + struct svalue *save_sp = Pike_sp; + push_text("name"); push_text(field->name); push_text("table"); push_text(field->table); if (support_default) { @@ -251,12 +253,12 @@ void mysqlmod_parse_field(MYSQL_FIELD *field, int support_default) f_aggregate_multiset(nbits); push_text("decimals"); push_int(field->decimals); - - if (support_default) { - f_aggregate_mapping(8*2); - } else { - f_aggregate_mapping(7*2); - } + +#ifdef HAVE_MYSQL_FIELD_CHARSETNR + push_text ("charsetnr"); push_int (field->charsetnr); +#endif + + f_aggregate_mapping (Pike_sp - save_sp); } else { /* * Should this be an error?