Source for file _db.class.php
Documentation is available at _db.class.php
* This file implements the DB class.
* Based on ezSQL - Class to make it very easy to deal with MySQL database connections.
* - dynamic extension loading
* - Debug features (EXPLAIN...)
* This file is part of the Quam Plures project - {@link http://quamplures.net/}.
* See also {@link https://launchpad.net/quam-plures}.
* @copyright (c) 2009 - 2011 by the Quam Plures developers - {@link http://quamplures.net/}
* @copyright (c)2003-2009 by Francois PLANQUE - {@link http://fplanque.net/}.
* Parts of this file are copyright (c)2004 by Justin Vincent - {@link http://php.justinvincent.com}
* Parts of this file are copyright (c)2004-2005 by Daniel HAHLER - {@link http://thequod.de/contact}.
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* This file is based on the following package (excerpt from ezSQL's readme.txt):
* =======================================================================
* Author: Justin Vincent (justin@visunet.ie)
* Web: http://php.justinvincent.com
* Desc: Class to make it very easy to deal with database connections.
* License: FREE / Donation (LGPL - You may do what you like with ezSQL - no exceptions.)
* =======================================================================
* A $10 donation has been made to Justin VINCENT on behalf of the b2evolution team.
* The package has been relicensed as GPL based on
* "You may do what you like with ezSQL - no exceptions."
* 2004-10-14 (email): Justin VINCENT grants Francois PLANQUE the right to relicense
* this modified class under other licenses. "Just include a link to where you got it from."
* {@internal Open Source relicensing agreement:
* Daniel HAHLER grants Francois PLANQUE the right to license
* Daniel HAHLER's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author blueyed: Daniel HAHLER
* @author fplanque: Francois PLANQUE
* @todo transaction support
if( !defined('QP_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
define( 'EZSQL_VERSION', '1.25' );
define( 'OBJECT', 'OBJECT', true );
define( 'ARRAY_A', 'ARRAY_A', true);
define( 'ARRAY_N', 'ARRAY_N', true);
* Number of done queries.
* Number of rows in result set (after a select)
* Number of rows affected by insert, delete, update or replace
* Aliases that will be replaced in queries:
* Strings that will replace the aliases in queries:
* This gets appended to every "CREATE TABLE" query.
* Edit those if you have control over you MySQL server and want a more professional
* database than what is commonly offered by popular hosting providers.
* @todo dh> If the query itself uses already e.g. "CHARACTER SET latin1" it should not get overridden..
* Use transactions in DB?
* You need to use InnoDB in order to enable this. See the {@link $app_db_config "table_options" key}.
* How many transactions are currently nested?
* Rememeber if we have to rollback at the end of a nested transaction construct
* Database username's password
* Current connection charset
* @see DB::set_connection_charset()
* Do we want to log queries?
* If null, it gets set according to {@link $debug}.
* A subclass may set it by default (e.g. DbUnitTestCase_DB).
* Do we want to explain joins?
* This requires {@link DB::$log_queries} to be true.
* @todo fp> we'd probably want to group all the advanced debug vars under a single setting now. We might even auto enable it when $debug=2. (And we might actually want to include a $debug="cookie" mode for easy switching with bookmarks or a bookmarklet)
* Do we want to output a function backtrace for every query?
* Number of stack entries to show (from last to first) (Default: 0); true means 'all'.
* This requires {@link DB::$log_queries} to be true.
* Number of rows we want to dump in debug output (0 disables it)
* This requires {@link DB::$log_queries} to be true.
* Time in seconds that is considered a fast query (green).
* Time in seconds that is considered a slow query (red).
* Connects to the server and selects a database.
* @param array An array of parameters.
* - 'user': username to connect with
* - 'password': password to connect with
* - 'handle': a MySQL Database handle (from a previous {@link mysql_connect()})
* - 'name': the name of the default database, see {@link DB::select()}
* - 'host': host of the database; Default: 'localhost'
* - 'show_errors': Display SQL errors? (true/false); Default: don't change member default ({@link $show_errors})
* - 'halt_on_error': Halt on error? (true/false); Default: don't change member default ({@link $halt_on_error})
* - 'table_options': sets {@link $table_options}
* - 'use_transactions': sets {@link $use_transactions}
* - 'aliases': Aliases for tables (array( alias => table name )); Default: no aliases.
* - 'new_link': create a new link to the DB, even if there was a mysql_connect() with
* the same params before. (requires PHP 4.2)
* - 'client_flags': optional settings like compression or SSL encryption. See {@link http://www.php.net/manual/en/ref.mysql.php#mysql.client-flags}.
if( isset ( $params['handle'] ) )
$this->dbuser = $params['user'];
// Optional parameters (Allow overriding through $params):
if( isset ($params['name']) ) $this->dbname = $params['name'];
if( isset ($params['host']) ) $this->dbhost = $params['host'];
if( isset ($params['show_errors']) ) $this->show_errors = $params['show_errors'];
if( isset ($params['halt_on_error']) ) $this->halt_on_error = $params['halt_on_error'];
if( isset ($params['table_options']) ) $this->table_options = $params['table_options'];
if( isset ($params['use_transactions']) ) $this->use_transactions = $params['use_transactions'];
if( isset ($params['debug_dump_rows']) ) $this->debug_dump_rows = $params['debug_dump_rows']; // Nb of rows to dump
if( isset ($params['debug_explain_joins']) ) $this->debug_explain_joins = $params['debug_explain_joins'];
{ // $log_queries follows $debug and respects subclasses, which may define it:
{ // The mysql extension is not loaded, try to dynamically load it:
$mysql_ext_file = is_windows() ? 'php_mysql.dll' : 'mysql.so';
$old_track_errors = ini_set('track_errors', 1);
$old_html_errors = ini_set('html_errors', 0);
$error_msg = $php_errormsg;
if( $old_track_errors !== false ) ini_set('track_errors', $old_track_errors);
if( $old_html_errors !== false ) ini_set('html_errors', $old_html_errors);
$this->print_error( 'The PHP MySQL module could not be loaded.', '
<p><strong>Error:</strong> '. $error_msg. '</p>
<p>You probably have to edit your php configuration (php.ini) and enable this module ('. $mysql_ext_file. ').</p>
<p>Do not forget to restart your webserver (if necessary) after editing the PHP conf.</p>', false );
$new_link = isset ( $params['new_link'] ) ? $params['new_link'] : false;
$client_flags = isset ( $params['client_flags'] ) ? $params['client_flags'] : 0;
{ // Connect to the Database:
// mysql_error() is tied to an established connection
// if the connection fails we need a different method to get the error message
$old_track_errors = ini_set('track_errors', 1);
$old_html_errors = ini_set('html_errors', 0);
$mysql_error = $php_errormsg;
if( $old_track_errors !== false ) ini_set('track_errors', $old_track_errors);
if( $old_html_errors !== false ) ini_set('html_errors', $old_html_errors);
$this->print_error( 'Error establishing a database connection!', '
<p>('. $mysql_error. ')</p>
<li>Are you sure you have typed the correct user/password?</li>
<li>Are you sure that you have typed the correct hostname?</li>
<li>Are you sure that the database server is running?</li>
elseif( isset ($this->dbname) )
if( !empty($params['connection_charset']) )
{ // Specify which charset we are using on the client:
echo '<br />Server: '.$this->get_var( 'SELECT @@character_set_server' );
echo '<br />Database: '.$this->get_var( 'SELECT @@character_set_database' );
echo '<br />Connection: '.$this->get_var( 'SELECT @@character_set_connection' );
echo '<br />Client: '.$this->get_var( 'SELECT @@character_set_client' );
echo '<br />Results: '.$this->get_var( 'SELECT @@character_set_results' );
if( isset ($params['aliases']) )
{ // Prepare aliases for replacements:
foreach( $params['aliases'] as $dbalias => $dbreplace )
$this->dbaliases[] = '#\b'. $dbalias. '\b#'; // \b = word boundary
{ // Force MySQL strict mode
// TRADITIONAL mode is only available to mysql > 5.0.2
$mysql_version = $this->get_version( 'we do this in DEBUG mode only' );
$this->query( 'SET sql_mode = "TRADITIONAL"', 'we do this in DEBUG mode only' );
* Select a DB (if another one needs to be selected)
$this->print_error( 'Error selecting database ['. $db. ']!', '
<li>Are you sure the database exists?</li>
<li>Are you sure the DB user is allowed to use that database?</li>
<li>Are you sure there is a valid database connection?</li>
* Format a string correctly for safe insert under all PHP conditions
* Quote a value, either in single quotes (and escaped) or if it's NULL as 'NULL'.
* @param string|array|null
* @return string Quoted (and escaped) value or 'NULL'.
$r .= $this->quote($elt). ',';
* @return string Return the given value or 'NULL', if it's === NULL.
* Returns the correct WEEK() function to get the week number for the given date.
* @link http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
* @todo disable when MySQL < 4
* @param string will be used as is
* @param integer 0 for sunday, 1 for monday
function week( $date, $startofweek )
{ // Week starts on Monday, week 1 must have a monday in this year:
return ' WEEK( '. $date. ', 5 ) ';
// Week starts on Sunday, week 1 must have a sunday in this year:
return ' WEEK( '. $date. ', 0 ) ';
* TODO: fp> bloated: it probably doesn't make sense to display errors if we don't stop. Any use case?
* dh> Sure. Local testing (and test cases).
* @param string Short error (no HTML)
* @param string Extended description/help for the error (for HTML)
* @param string|falseQuery title; false if {@link DB::$last_query} should not get displayed
function print_error( $title = '', $html_str = '', $query_title = '' )
// All errors go to the global error array $EZSQL_ERROR..
global $EZSQL_ERROR, $is_cli;
// If no special error string then use mysql default..
$this->last_error = 'Unknown (and no $dbhandle available)';
// Log this error to the global array..
{ // no reason to generate a nice message:
{ // do not show errors, just die:
{ // Clean error message for command line interface:
if( ! empty($this->last_query) && $query_title !== false )
$err_msg .= "Your query: $query_title\n";
$err_msg = '<p class="error">MySQL error!</p>'."\n";
$err_msg .= "<div><p><strong>{ $this->last_error}</strong></p>\n ";
if( !empty($this->last_query) && $query_title !== false )
$err_msg .= '<p class="error">Your query: '.$query_title.'</p>';
if( function_exists('debug_die') )
{ // If there is an error then take note of it
echo '<div class="error">';
* Kill cached query results
function get_version( $query_title = NULL )
if( isset( $this->version ) )
// Blatantly ignore any error generated by potentially unknown function...
if( ($this->version_long = $this->get_var( 'SELECT VERSION()', 0, 0, $query_title ) ) === NULL )
{ // Very old version ( < 4.0 )
$this->version_long = '';
$this->version = preg_replace( '¤-.*¤', '', $this->version_long );
* Save the vars responsible for error handling.
* @see DB::restore_error_state()
function save_error_state()
$this->saved_error_states[] = array(
* Call this after {@link save_halt_on_error()} to
* restore the previous error state.
* @see DB::save_error_state()
function restore_error_state()
if( empty($this->saved_error_states)
|| ! is_array($this->saved_error_states) )
$state = array_pop($this->saved_error_states);
$this->error = $state['error'];
* @param string SQL query
* @param string title for debugging
* @return mixed # of rows affected or false if error
function query( $query, $title = '' )
// TODO: this should only replace the table name part(s), not the whole query!
// blueyed> I've changed it to replace in table name parts for UPDATE, INSERT and REPLACE, because
// it corrupted serialized data..
// IMHO, a cleaner solution would be to use {T_xxx} in the queries and replace it here. In object properties (e.g. DataObject::$dbtablename), only "T_xxx" would get used and surrounded by "{..}" in the queries it creates.
if( preg_match( '~^\s*(UPDATE\s+)(.*?)(\sSET\s.*)$~is', $query, $match ) )
{ // replace only between UPDATE and SET:
elseif( preg_match( '~^\s*(INSERT|REPLACE\s+)(.*?)(\s(VALUES|SET)\s.*)$~is', $query, $match ) )
{ // replace only between INSERT|REPLACE and VALUES|SET:
{ // replace in whole query:
if( ! empty($this->table_options) && preg_match( '#^ \s* create \s* table \s #ix', $query) )
{ // Query is a table creation, we add table options:
$query = preg_replace( '~;\s*$~', '', $query ); // remove any ";" at the end
{ // No aliases, but table_options:
if( preg_match( '#^ \s* create \s* table \s #ix', $query) )
{ // Query is a table creation, we add table options:
$query = preg_replace( '~;\s*$~', '', $query ); // remove any ";" at the end
// Keep track of the last query for debug..
// Perform the query via std mysql_query function..
{ // We want to log queries:
'results' => 'unknown' );
// Resume global query timer
$Timer->resume( 'sql_queries' );
// Start a timer for this particular query:
$Timer->start( 'sql_query', false );
{ // We want to log queries:
// Get duration for last query:
$this->queries[ $this->num_queries - 1 ]['time'] = $Timer->get_duration( 'sql_query', 10 );
// Pause global query timer:
$Timer->pause( 'sql_queries' );
// If there is an error then take note of it..
@mysql_free_result($this->result);
if( preg_match( '#^\s*(INSERT|DELETE|UPDATE|REPLACE)\s#i', $query, $match ) )
{ // Query was an insert, delete, update, replace:
{ // We want to log queries:
// Take note of the insert_id, for INSERT and REPLACE:
$match[1] = strtoupper($match[1]);
if( $match[1] == 'INSERT' || $match[1] == 'REPLACE' )
// Return number of rows affected
{ // Query was a select, alter, etc...:
if( is_resource($this->result) )
{ // It's not a resource for CREATE or DROP for example and can even trigger a fatal error (see http://forums.b2evolution.net//viewtopic.php?t=9529)
while( $row = mysql_fetch_object($this->result) )
// Store relults as an objects within main array
{ // We want to log queries:
// Return number of rows selected
{ // We want to log queries:
// Free original query's result:
@mysql_free_result($this->result);
{ // Query was a select, let's try to explain joins...
while( $row = @mysql_fetch_object($this->result) )
// Store results as an objects within main array
// Free "EXPLAIN" result resource:
@mysql_free_result($this->result);
* Get one variable from the DB - see docs for more detail
* Note: To be sure that you received NULL from the DB and not "no rows" check
* @return mixed NULL if not found, the value otherwise (which may also be NULL).
function get_var( $query = NULL, $x = 0, $y = 0, $title = '' )
// If there is a query then perform it if not then use cached results..
$this->query($query, $title);
// Extract var out of cached results based x,y vals
$values = array_values(get_object_vars($this->last_result[$y]));
* Get one row from the DB - see docs for more detail
function get_row( $query = NULL, $output = OBJECT, $y = 0, $title = '' )
// If there is a query then perform it if not then use cached results..
$this->query($query, $title);
// If the output is an object then return object using the row offset..
// If the output is an associative array then return row as such..
elseif( $output == ARRAY_A )
// If the output is an numerical array then return row as such..
elseif( $output == ARRAY_N )
? array_values( get_object_vars($this->last_result[$y]) )
// If invalid output type was specified..
$this->print_error('DB::get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N', '', false);
* Function to get 1 column from the cached result set based on X index
* see docs for usage and info
function get_col( $query = NULL, $x = 0, $title = '' )
// If there is a query then perform it if not then use cached results..
$this->query( $query, $title );
// Extract the column values
for( $i = 0, $count = count($this->last_result); $i < $count; $i++ )
$new_array[$i] = $this->get_var( NULL, $x, $i );
* Function to get the second column from the cached result indexed by the first column
* @return array [col_0] => col_1
function get_assoc( $query = NULL, $title = '' )
// If there is a query then perform it if not then use cached results..
$this->query( $query, $title );
// Extract the column values
for( $i = 0, $count = count($this->last_result); $i < $count; $i++ )
$key = $this->get_var( NULL, 0, $i );
$new_array[$key] = $this->get_var( NULL, 1, $i );
* Return the the query as a result set - see docs for more details
function get_results( $query = NULL, $output = OBJECT, $title = '' )
// If there is a query then perform it if not then use cached results..
$this->query($query, $title);
// Send back array of objects. Each row is an object
elseif( $output == ARRAY_A || $output == ARRAY_N )
$new_array[$i] = get_object_vars($row);
$new_array[$i] = array_values($new_array[$i]);
* Get a table (or "<p>No Results.</p>") for the SELECT query results.
* @return string HTML table or "No Results" if the
function debug_get_rows_table( $max_lines, $break_at_comma = false )
if( ! is_resource($this->result) )
return '<p>No Results.</p>';
$n = mysql_num_fields($this->result);
$col_info[$i] = mysql_fetch_field($this->result, $i);
// =====================================================
$r .= '<table cellspacing="0" summary="Results for query"><tr>';
for( $i = 0, $count = count($col_info); $i < $count; $i++ )
$r .= '<th><span class="type">'.$col_info[$i]->type. ' '. $col_info[$i]->max_length. '</span><br />'
. $col_info[$i]->name. '</th>';
// ======================================================
for( $i = 0, $n = min(count($this->last_result), $max_lines); $i < $n; $i++ )
$one_row = $this->get_row(NULL, ARRAY_N, $i);
foreach( $one_row as $item )
$r .= '<td class="odd">';
$item = str_replace( ',', '<br />', $item );
$item = str_replace( ';', '<br />', $item );
if( strlen( $item ) > 50 )
$item = substr( $item, 0, 50 ).'...';
$r .= htmlspecialchars($item);
$r .= '<tr><td colspan="'.(count($col_info)+1).'">No Results</td></tr>';
$r .= '<tr><td colspan="'.(count($col_info)+1).'">Max number of dumped rows has been reached.</td></tr>';
* @todo dh> Steal the code from phpMyAdmin :)
* @param boolean Format with/for HTML?
function format_query( $sql, $html = true )
$sql = trim( str_replace("\t", ' ', $sql ) );
$sql = htmlspecialchars( $sql );
$replace_prefix = "<br />\n";
// Split by FROM, WHERE, .. and AND, OR (if there's no comment sign before)
// TODO: dh> should not wrap in comments/string literals
'~(FROM|WHERE|GROUP BY|ORDER BY|LIMIT|VALUES)~',
$replace_prefix.( $html ? ' ' : ' ' ).' $1',
$sql = preg_replace( $search, $replace, $sql );
* Displays all queries that have been executed
* @param boolean Use HTML.
function dump_queries( $html = true )
if( is_object( $Timer ) )
$time_queries = $Timer->get_duration( 'sql_queries' );
echo '<strong>DB queries:</strong> '.$this->num_queries. "<br />\n";
{ // nothing more to do here..
// Javascript function to toggle DIVs (EXPLAIN, results, backtraces).
echo '<script type="text/javascript">
function debug_onclick_toggle_div( div_id, text_show, text_hide ) {
var div = document.getElementById(div_id);
var a = document.createElement("a");
a.style.display = "block";
var a_onclick = function() {
if( div.style.display == \'\' ) {
div.style.display = \'none\';
div.style.display = \'\';
div.parentNode.insertBefore(a, div);
foreach( $this->queries as $i => $query )
echo '<h4>Query #'.$count_queries.': '.$query['title']."</h4>\n";
echo '= Query #'.$count_queries.': '.$query['title']." =\n";
// Color-Format duration: long => red, fast => green, normal => black
$style_time_text = 'color:red;font-weight:bold;';
$style_time_graph = 'background-color:red;';
$plain_time_text = ' [slow]';
$style_time_text = 'color:green;';
$style_time_graph = 'background-color:green;';
$plain_time_text = ' [fast]';
$style_time_graph = 'background-color:black;';
// Number of rows with time (percentage and graph, if total time available)
echo '<div class="query_info">';
echo 'Rows: '.$query['rows'];
echo 'Rows: '.$query['rows'].' - Time: ';
if( $html && $style_time_text )
echo '<span style="'.$style_time_text.'">';
echo number_format( $query['time'], 4 ).'s';
{ // We have a total time we can use to calculate percentage:
echo ' ('.number_format( 100/$time_queries * $query['time'], 2 ).'%)';
if( $style_time_text || $plain_time_text )
echo $html ? '</span>' : $plain_time_text;
{ // We have a total time we can use to display a graph/bar:
$perc = round( 100/$time_queries * $query['time'] );
echo '<div style="margin:0; padding:0; height:12px; width:'.$perc.'%;'.$style_time_graph.'"></div>';
{ // display an ASCII bar
printf( "\n".'[%-50s]', str_repeat( '=', $perc / 2 ) );
echo $html ? '</div>' : "\n\n";
if( isset($query['explain']) )
$div_id = 'db_query_explain_'.$i.'_'.md5(serialize($query));
echo '<div id="'.$div_id.'">';
echo '<script type="text/javascript">debug_onclick_toggle_div("'.$div_id.'", "Show EXPLAIN", "Hide EXPLAIN");</script>';
{ // TODO: dh> contains html.
if( $query['results'] != 'unknown' )
$div_id = 'db_query_results_'.$i.'_'.md5(serialize($query));
echo '<div id="'.$div_id.'">';
echo '<script type="text/javascript">debug_onclick_toggle_div("'.$div_id.'", "Show results", "Hide results");</script>';
{ // TODO: dh> contains html.
if( isset($query['function_trace']) )
$div_id = 'db_query_backtrace_'.$i.'_'.md5(serialize($query));
echo '<div id="'.$div_id.'">';
echo $query['function_trace'];
echo '<script type="text/javascript">debug_onclick_toggle_div("'.$div_id.'", "Show function trace", "Hide function trace");</script>';
{ // TODO: dh> contains html.
echo $query['function_trace'];
echo "=============================================\n";
$count_rows += $query['rows'];
echo "\n<strong>Total rows:</strong> $count_rows<br />\n";
echo 'Total rows: '.$count_rows."\n";
* Note: By default, MySQL runs with autocommit mode enabled.
* This means that as soon as you execute a statement that updates (modifies)
* a table, MySQL stores the update on disk.
* Once you execute a BEGIN, the updates are "pending" until you execute a
* {@link DB::commit() COMMIT} or a {@link DB:rollback() ROLLBACK}
* Note 2: standard syntax would be START TRANSACTION but it's not supported by older
* MySQL versions whereas BEGIN is...
* Note 3: The default isolation level is REPEATABLE READ.
$this->query( 'BEGIN', 'BEGIN transaction' );
* Commit current transaction
{ // Only COMMIT if there are no remaining nested transactions:
$this->query( 'ROLLBACK', 'ROLLBACK transaction because there was a failure somewhere in the nesting of transactions' );
$this->query( 'COMMIT', 'COMMIT transaction' );
* Rollback current transaction
{ // Only ROLLBACK if there are no remaining nested transactions:
$this->query( 'ROLLBACK', 'ROLLBACK transaction' );
{ // Remember we'll have to roll back at the end!
* Convert a PHP charset to its MySQL equivalent.
* @param string PHP charset
* @return string MYSQL charset or unchanged
function php_to_mysql_charmap( $php_charset )
$php_charset = strtolower($php_charset);
* This is taken from phpMyAdmin (libraries/select_lang.lib.php).
static $mysql_charset_map = array(
'iso-8859-1' => 'latin1',
'iso-8859-2' => 'latin2',
'iso-8859-8' => 'hebrew',
'iso-8859-8-i' => 'hebrew',
'iso-8859-9' => 'latin5',
'iso-8859-13' => 'latin7',
'iso-8859-15' => 'latin1',
'windows-1250' => 'cp1250',
'windows-1251' => 'cp1251',
'windows-1252' => 'latin1',
'windows-1256' => 'cp1256',
'windows-1257' => 'cp1257',
if( isset($mysql_charset_map[$php_charset]) )
return $mysql_charset_map[$php_charset];
// for lack of a better answer:
* Set the charset of the connection.
* WARNING: this will fail on MySQL 3.23
* @staticvar array "regular charset => mysql charset map"
* @param boolean Use the "regular charset => mysql charset map"?
* @return boolean true on success, false on failure
function set_connection_charset( $charset, $use_map = true )
$charset = strtolower($charset);
{ // We want to use the map
// SET NAMES is not supported by MySQL 3.23 and for a non-supported charset even not in MySQL 5 probably..
if( $this->query( 'SET NAMES '. $charset ) === false )
$Debuglog->add( 'Could not "SET NAMES '. $charset. '"! (MySQL error: '. strip_tags($this->last_error). ')', 'locale' );
$Debuglog->add( 'Set DB connection charset: '. $charset, 'locale' );
// Blatantly ignore any error generated by SET NAMES...
|