pike.git
/
lib
/
modules
/
Sql.pmod
/
mysql.pike
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Sql.pmod/mysql.pike:1:
/*
-
* $Id: mysql.pike,v 1.
23
2006/08/10
14
:
24
:
04
grubba
Exp $
+
* $Id: mysql.pike,v 1.
24
2006/08/10
19
:
35
:
26
mast
Exp $
* * Glue for the Mysql-module */ //! Implements the glue needed to access the Mysql-module from the generic //! SQL module. #pike __REAL_VERSION__ #if constant(Mysql.mysql) inherit Mysql.mysql; #define UTF8_DECODE_QUERY 1 #define UTF8_ENCODE_QUERY 2 //! Set to the above if the connection is in utf8-mode. static int utf8_mode;
-
+
//! The charset passed with the @expr{mysql_charset_name@} option.
+
static string initial_charset;
+
//! Enter unicode encode/decode mode. //! //! After this has been enabled, query-strings may be provided //! as wide (Unicode) strings, and any non-binary data will be //! decoded automatically according to UTF8. //!
-
+
//! The statement "@expr{SET NAMES 'utf8'@}" is sent to enable UTF8
+
//! mode for the connection.
+
//!
+
//! @param force
+
//! If this optional flag is nonzero then the statement to enable
+
//! UTF8 mode is sent even if this mode already is enabled according
+
//! to the internal flags.
+
//!
//! @returns
-
//! Returns @expr{1@} on success.
+
//! Returns @expr{1@} on success
or @expr{0@} if the server doesn't
+
//! support unicode (i
.
e. if the statement to enable UTF8 mode
+
//! fails).
//! //! @note
-
//!
All
strings
not
prefixed by the keyword @tt{BINARY@}
-
//!
will be
encoded
according
to
UTF8.
+
//!
Literal
strings prefixed by the keyword @tt{BINARY@}
will not be
+
//! encoded
using
UTF8.
//!
-
+
//! @note
+
//! Unicode support was added in MySQL 4.1.
+
//!
//! @seealso
-
//! @[enter_unicode_decode_mode()]
-
int(0..1) enter_unicode_mode()
+
//! @[enter_unicode_decode_mode()]
, @[leave_unicode_mode()]
+
int(0..1) enter_unicode_mode
(
void|int force
)
{
-
if (
!
utf8_mode) {
+
if (
force ||
utf8_mode
!= UTF8_DECODE_QUERY|UTF8_ENCODE_QUERY
) {
if (catch { big_query("SET NAMES 'utf8'"); }) { return 0; }
-
}
+
utf8_mode = UTF8_DECODE_QUERY|UTF8_ENCODE_QUERY;
-
+
}
return 1; } //! Enter unicode decode mode. //! //! After this has been enabled, non-binary data from the database //! will be decoded according to UTF8. //!
-
+
//! The statement "@expr{SET character_set_results = utf8@}" is sent
+
//! to enable UTF8 mode for the returned results.
+
//!
+
//! @param force
+
//! If this optional flag is nonzero then the statement to enable
+
//! UTF8 encoding of results is sent even though this mode already
+
//! is enabled according to the internal flags.
+
//!
//! @returns
-
//! Returns @expr{1@} on success.
+
//! Returns @expr{1@} on success
or @expr{0@} if the server doesn't
+
//! support unicode (i
.
e. if the statement to enable UTF8 mode
+
//! fails).
//! //! @note //! Any query encoding will need to be done by hand. //!
-
+
//! @note
+
//! If the connection previously was in full unicode mode as set by
+
//! @[enter_unicode_mode] then the server will still expect queries
+
//! to be UTF8 encoded. I.e. the server system variable
+
//! @expr{character_set_client@} retains the value @expr{'utf8'@}.
+
//!
+
//! @note
+
//! The server system variable @expr{character_set_results@} was
+
//! added in MySQL 4.1.1.
+
//!
//! @seealso
-
//! @[enter_unicode_mode()]
-
int(0..1) enter_unicode_decode_mode()
+
//! @[enter_unicode_mode()]
, @[leave_unicode_mode()]
+
int(0..1) enter_unicode_decode_mode
(
void|int force
)
{
-
if (
!
utf8_mode) {
+
if (
force ||
utf8_mode
!= UTF8_DECODE_QUERY
) {
if (catch {
-
big_query("SET
NAMES
'
utf8
'
");
+
big_query("SET
character_set_results
=
utf8");
}) { return 0; }
-
}
+
utf8_mode = UTF8_DECODE_QUERY;
-
+
}
return 1; }
-
//
FIXME:
Add
a
latin1 mode
?
+
//
!
Leave
unicode
mode.
+
//!
+
//!
After this no automatic UTF8 conversion is done of queries and
+
//! results.
+
//!
+
//! The statement "@expr{SET NAMES 'xxx'@}" is sent to the server,
+
//! where @expr{xxx@} is the charset that was passed with the
+
//! @expr{mysql_charset_name@} option when the connection was opened.
+
//! If that option wasn't specified then the charset @expr{latin1@} is
+
//! used, which is the default connection charset in MySQL.
+
//!
+
//! @param force
+
//! If this optional flag is nonzero then the statement to reset the
+
//! connection charset is sent even though unicode mode already is
+
//! disabled according to the internal flags.
+
//!
+
//! @returns
+
//! Returns @expr{1@} on success or @expr{0@} if the server doesn't
+
//! support unicode (i.e. if the statement to reset the connection
+
//! charset fails).
+
//!
+
//! @note
+
//! Unicode support was added in MySQL 4.1.
+
//!
+
//! @seealso
+
//! @[enter_unicode_mode()], @[enter_unicode_decode_mode()]
+
int(0..1) leave_unicode_mode (void|int force)
+
{
+
if (force || utf8_mode) {
+
if (catch {
+
big_query("SET NAMES '" + (initial_charset || "
latin1
")
+ "'");
+
}) {
+
return 0;
+
}
+
utf8_
mode
= 0;
+
}
+
return 1;
+
}
-
+
string query_unicode_mode()
+
//! Returns the current unicode mode status.
+
//!
+
//! @returns
+
//! @string
+
//! @value "full"
+
//! Full unicode mode as set by @[enter_unicode_mode] is
+
//! enabled.
+
//! @value "decode"
+
//! Decode unicode mode as set by @[enter_unicode_decode_mode]
+
//! is enabled.
+
//! @value 0
+
//! Unicode mode is not enabled. C.f. @[leave_unicode_mode].
+
//! @endstring
+
{
+
switch (utf8_mode) {
+
case UTF8_DECODE_QUERY|UTF8_ENCODE_QUERY: return "full";
+
case UTF8_DECODE_QUERY: return "decode";
+
default: return 0;
+
}
+
}
+
#if constant( Mysql.mysql.MYSQL_NO_ADD_DROP_DB ) // Documented in the C-file. void create_db( string db ) { ::big_query( "CREATE DATABASE "+db ); } void drop_db( string db ) { ::big_query( "DROP DATABASE "+db );
pike.git/lib/modules/Sql.pmod/mysql.pike:98:
({ "\\", "\"", "\0", "\'", "\n", "\r" }), ({ "\\\\", "\\\"", "\\0", "\\\'", "\\n", "\\r" })); } //! Encode the apropriate sections of the query according to UTF8. //! ie Those sections that are not strings prefixed by BINARY. string utf8_encode_query(string q) { string uq = upper_case(q); if (!has_value(uq, "BINARY")) return string_to_utf8(q);
-
if ((q & ("\x7f" * sizeof(q))) == q) return q;
+
// The following optimization is disabled since it causes more
+
// overhead in the case when q contains a large binary string (which
+
// is arguably the main reason for q getting really large).
+
//
if ((q & ("\x7f" * sizeof(q))) == q) return q;
// We need to find the segments that shouldn't be encoded. string e = ""; while(has_value(uq, "BINARY")) { string prefix = ""; string suffix; sscanf(q, "%[^\'\"]%s", prefix, suffix); e += string_to_utf8(prefix); if (!suffix || !sizeof(suffix)) { q = uq = ""; break; } string quote = suffix[..0]; int start = 1; int end; while ((end = search(suffix, quote, start)) >= 0) { if (suffix[end-1] == '\\') {
-
// Count the number of
preceeding
back-slashes.
+
// Count the number of
preceding
back-slashes.
// if odd, continue searching after the quote. int i; for (i = 2; i < end; i++) { if (suffix[end - i] != '\\') break; } if (!(i & 1)) { start = end+1; continue; } }
pike.git/lib/modules/Sql.pmod/mysql.pike:295:
if (utf8_mode & UTF8_DECODE_QUERY) { return .sql_util.UnicodeWrapper(res); } return ::big_query(q); } int(0..1) is_keyword( string name ) //! Return 1 if the argument @[name] is a mysql keyword. {
+
// FIXME: Document which version of MySQL this is up-to-date with.
return (< "action", "add", "aggregate", "all", "alter", "after", "and", "as", "asc", "avg", "avg_row_length", "auto_increment", "between", "bigint", "bit", "binary", "blob", "bool", "both", "by", "cascade", "case", "char", "character", "change", "check", "checksum", "column", "columns", "comment", "constraint", "create", "cross", "current_date", "current_time", "current_timestamp", "data", "database", "databases", "date", "datetime", "day", "day_hour", "day_minute", "day_second", "dayofmonth", "dayofweek", "dayofyear", "dec", "decimal", "default", "delayed", "delay_key_write", "delete", "desc", "describe", "distinct",
pike.git/lib/modules/Sql.pmod/mysql.pike:342:
"with", "write", "when", "where", "year", "year_month", "zerofill", >)[ lower_case(name) ]; } static void create(string|void host, string|void database, string|void user, string|void password, mapping(string:string|int)|void options) { if (options) { ::create(host||"", database||"", user||"", password||"", options);
+
initial_charset = options->mysql_charset_name;
+
switch (options->unicode_mode) {
+
case "full": enter_unicode_mode(); break;
+
case "decode": enter_unicode_decode_mode(); break;
+
}
} else { ::create(host||"", database||"", user||"", password||""); }
-
enter_unicode_mode();
+
} #else constant this_program_does_not_exist=1; #endif /* constant(Mysql.mysql) */