Beispiel #1
0
 /**
  * Standard modular run function.
  *
  * @return tempcode	Results
  */
 function run()
 {
     $out = new ocp_tempcode();
     $tables = $GLOBALS['SITE_DB']->query_select('db_meta', array('DISTINCT m_table'));
     if (count($GLOBALS['SITE_DB']->connection_write) > 4) {
         $GLOBALS['SITE_DB']->connection_write = call_user_func_array(array($GLOBALS['SITE_DB']->static_ob, 'db_get_connection'), $GLOBALS['SITE_DB']->connection_write);
         _general_db_init();
     }
     list($db, $db_name) = $GLOBALS['SITE_DB']->connection_write;
     mysql_select_db($db_name, $db);
     foreach ($tables as $table) {
         if ($table['m_table'] == 'sessions') {
             continue;
         }
         // HEAP, so can't be repaired
         $table = get_table_prefix() . $table['m_table'];
         // Check/Repair
         $result = mysql_query('CHECK TABLE ' . $table . ' FAST', $db);
         echo mysql_error($db);
         mysql_data_seek($result, mysql_num_rows($result) - 1);
         $status_row = mysql_fetch_assoc($result);
         if ($status_row['Msg_type'] != 'status') {
             $out->attach(paragraph(do_lang_tempcode('TABLE_ERROR', escape_html($table), escape_html($status_row['Msg_type']), array(escape_html($status_row['Msg_text']))), 'dfsdgdsgfgd'));
             $result2 = mysql_query('REPAIR TABLE ' . $table, $db);
             mysql_data_seek($result2, mysql_num_rows($result2) - 1);
             $status_row_2 = mysql_fetch_assoc($result2);
             $out->attach(paragraph(do_lang_tempcode('TABLE_FIXED', escape_html($table), escape_html($status_row_2['Msg_type']), array(escape_html($status_row_2['Msg_text']))), 'dfsdfgdst4'));
         }
         // Optimise
         mysql_unbuffered_query('OPTIMIZE TABLE ' . $table, $db);
     }
     return $out;
 }
Beispiel #2
0
/**
 * Change the primary key of a table.
 *
 * @param  object			Link to the real database object
 * @param  ID_TEXT		The name of the table to create the index on
 * @param  array			A list of fields to put in the new key
 */
function _helper_change_primary_key($this_ref, $table_name, $new_key)
{
    if (count($this_ref->connection_write) > 4) {
        $this_ref->connection_write = call_user_func_array(array($this_ref->static_ob, 'db_get_connection'), $this_ref->connection_write);
        _general_db_init();
    }
    $this_ref->static_ob->db_change_primary_key($this_ref->table_prefix . $table_name, $new_key, $this_ref->connection_write);
}
Beispiel #3
0
/**
 * Upgrade shared installs.
 */
function upgrade_sharedinstall_sites()
{
    global $CURRENT_SHARE_USER, $SITE_INFO, $TABLE_LANG_FIELDS;
    // Find sites
    $sites = array();
    foreach (array_keys($SITE_INFO) as $key) {
        $matches = array();
        if (preg_match('#^custom_user_(.*)#', $key, $matches) != 0) {
            $sites[] = $matches[1];
        }
    }
    disable_php_memory_limit();
    foreach ($sites as $i => $site) {
        if (function_exists('set_time_limit')) {
            @set_time_limit(0);
        }
        // Change active site
        $CURRENT_SHARE_USER = $site;
        $TABLE_LANG_FIELDS = array();
        _general_db_init();
        // Reset DB
        $GLOBALS['SITE_DB'] = new database_driver(get_db_site(), get_db_site_host(), get_db_site_user(), get_db_site_password(), get_table_prefix());
        $GLOBALS['FORUM_DB'] = $GLOBALS['SITE_DB'];
        // NB: File path will be ok
        // NB: Other internal caching could need changing in the future, but works at time of writing
        // Go!
        automate_upgrade();
        echo 'Upgraded ' . htmlentities($site) . '<br />';
        flush();
    }
}
Beispiel #4
0
 /**
  * This function is a very basic query executor. It shouldn't usually be used by you, as there are specialised abstracted versions available.
  *
  * @param  string			The complete SQL query
  * @param  ?integer		The maximum number of rows to affect (NULL: no limit)
  * @param  ?integer		The start row to affect (NULL: no specification)
  * @param  boolean		Whether to output an error on failure
  * @param  boolean		Whether to get an insert ID
  * @param  ?array			Extra language fields to join in for cache-prefilling. You only need to send this if you are doing a JOIN and carefully craft your query so table field names won't conflict (NULL: none)
  * @param  string			All the core fields have a prefix of this on them, so when we fiddle with language lookup we need to use this (only consider this if you're setting $lang_fields)
  * @param  boolean		Whether we are saving as a 'volatile' file extension (used in the XML DB driver, to mark things as being non-syndicated to subversion)
  * @return ?mixed			The results (NULL: no results)
  */
 function _query($query, $max = NULL, $start = NULL, $fail_ok = false, $get_insert_id = false, $lang_fields = NULL, $field_prefix = '', $save_as_volatile = false)
 {
     global $QUERY_COUNT, $NO_QUERY_LIMIT, $QUERY_LOG, $QUERY_LIST, $DEBUG_MODE, $IN_MINIKERNEL_VERSION, $QUERY_FILE_LOG, $UPON_QUERY_HOOKS;
     if ($QUERY_FILE_LOG !== NULL) {
         fwrite($QUERY_FILE_LOG, $query . ';' . chr(10) . chr(10));
     }
     if ($DEBUG_MODE) {
         if (get_forum_type() != 'none' && strpos($query, get_table_prefix() . 'f_') !== false && strpos($query, get_table_prefix() . 'f_') < 100 && strpos($query, 'f_welcome_emails') === false && $this->connection_write === $GLOBALS['SITE_DB']->connection_write && isset($GLOBALS['FORUM_DB']) && $GLOBALS['SITE_DB']->connection_write !== $GLOBALS['FORUM_DB']->connection_write && !$GLOBALS['NO_DB_SCOPE_CHECK']) {
             /*file_put_contents(get_file_base().'/uploads/downloads/test.txt',var_export(debug_backtrace(),true));
             		@exit($query);
             		@debug_print_backtrace();*/
             fatal_exit('Using OCF queries on the wrong driver');
         }
     }
     if (!$NO_QUERY_LIMIT) {
         $QUERY_COUNT++;
         //@exit('!');
         //if ($QUERY_COUNT>10) @ob_end_clean();@print('Query: '.$query.chr(10));
     }
     static $fb = NULL;
     if ($fb === NULL) {
         $fb = function_exists('fb');
     }
     if ($fb && !headers_sent() && get_param_integer('keep_firephp_queries', 0) == 1 && function_exists('fb')) {
         fb('Query: ' . $query);
     }
     if ($QUERY_COUNT == 68 && get_param_integer('keep_no_query_limit', 0) == 0 && count($_POST) == 0 && get_page_name() != 'admin_importer' && $IN_MINIKERNEL_VERSION == 0 && get_param('special_page_type', '') != 'query') {
         $NO_QUERY_LIMIT = true;
         $log_path = get_custom_file_base() . '/data_custom/big_query_screens.log';
         if (is_writable_wrap($log_path)) {
             $myfile = fopen($log_path, 'at');
             fwrite($myfile, get_self_url_easy() . chr(10));
             fclose($myfile);
         }
         if ($DEBUG_MODE) {
             $QUERY_COUNT = 0;
             fatal_exit(do_lang_tempcode('TOO_MANY_QUERIES'));
         }
     }
     $lang_strings_expecting = array();
     if (isset($lang_fields[0]) && function_exists('user_lang')) {
         $lang = user_lang();
         // We can we assume this, as we will cache against it -- if subsequently code wants something else it'd be a cache miss which is fine
         foreach ($lang_fields as $i => $field) {
             $_i = strval($i);
             $join = ' LEFT JOIN ' . $this->table_prefix . 'translate t' . $_i . ' ON t' . $_i . '.id=' . $field_prefix . $field . ' AND ' . db_string_equal_to('t' . $_i . '.language', $lang);
             $_query = strtoupper($query);
             $from_pos = strpos($_query, ' FROM ');
             $where_pos = strpos($_query, ' WHERE ');
             if ($where_pos === false) {
                 $_where_pos = 0;
                 do {
                     $_where_pos = strpos($_query, ' GROUP BY ', $_where_pos + 1);
                     if ($_where_pos !== false) {
                         $where_pos = $_where_pos;
                     }
                 } while ($_where_pos !== false);
             }
             if ($where_pos === false) {
                 $_where_pos = 0;
                 do {
                     $_where_pos = strpos($_query, ' ORDER BY ', $_where_pos + 1);
                     if ($_where_pos !== false) {
                         $where_pos = $_where_pos;
                     }
                 } while ($_where_pos !== false);
             }
             if ($where_pos !== false) {
                 $query = substr($query, 0, $where_pos) . $join . substr($query, $where_pos);
             } else {
                 $query .= $join;
             }
             $original = 't' . $_i . '.text_original AS t' . $_i . '__text_original';
             $parsed = 't' . $_i . '.text_parsed AS t' . $_i . '__text_parsed';
             $query = substr($query, 0, $from_pos) . ',' . $original . ',' . $parsed . substr($query, $from_pos);
             $lang_strings_expecting[] = array($field, 't' . $_i . '__text_original', 't' . $_i . '__text_parsed');
         }
     }
     if ($start < 0) {
         $start = 0;
     }
     if ($max < 0) {
         $max = 1;
     }
     if ($QUERY_LOG) {
         $before = microtime(false);
     }
     if (substr(strtoupper($query), 0, 7) == 'SELECT ') {
         $connection =& $this->connection_read;
     } else {
         $connection =& $this->connection_write;
     }
     if (isset($connection[4])) {
         $connection = call_user_func_array(array($this->static_ob, 'db_get_connection'), $connection);
         _general_db_init();
     }
     $ret = $this->static_ob->db_query($query, $connection, $max, $start, $fail_ok, $get_insert_id, false, $save_as_volatile);
     if ($QUERY_LOG) {
         $after = microtime(false);
         $text = !is_null($max) ? $query . ' (' . strval((int) $start) . '-' . strval((int) $start + $max) . ')' : $query;
         $out = array('time' => microtime_diff($after, $before), 'text' => $text);
         $QUERY_LIST[] = $out;
     }
     // Run hooks, if any exist
     if ($UPON_QUERY_HOOKS === NULL) {
         if (!function_exists('find_all_hooks')) {
             return $ret;
         }
         $UPON_QUERY_HOOKS = array();
         $hooks = find_all_hooks('systems', 'upon_query');
         foreach (array_keys($hooks) as $hook) {
             require_code('hooks/systems/upon_query/' . filter_naughty($hook));
             $UPON_QUERY_HOOKS[$hook] = object_factory('upon_query_' . filter_naughty($hook), true);
         }
     }
     foreach ($UPON_QUERY_HOOKS as $ob) {
         if ($ob !== NULL) {
             $ob->run($this, $query, $max, $start, $fail_ok, $get_insert_id, $ret);
         }
     }
     // Copy results to lang cache, but only if not null AND unset to avoid any confusion
     if ($ret !== NULL) {
         foreach ($lang_strings_expecting as $bits) {
             list($field, $original, $parsed) = $bits;
             foreach ($ret as $row) {
                 $entry = $row[$field];
                 if ($row[$original] !== NULL && count($this->text_lookup_original_cache) <= 1000) {
                     $this->text_lookup_original_cache[$entry] = $row[$original];
                 }
                 if ($row[$parsed] !== NULL && count($this->text_lookup_cache) <= 1000) {
                     $this->text_lookup_cache[$entry] = $row[$parsed];
                 }
                 unset($row[$original]);
                 unset($row[$parsed]);
             }
         }
     }
     return $ret;
 }
Beispiel #5
0
/**
 * Script to handle XML DB/MySQL chain synching.
 */
function xml_dump_script()
{
    // Run checks and set up chain DB
    if (get_db_type() != 'xml') {
        warn_exit('It makes no sense to run this script if you are not running the XML database driver.');
    }
    global $SITE_INFO;
    if (array_key_exists('db_chain_type', $SITE_INFO)) {
        require_code('database/' . $SITE_INFO['db_chain_type']);
        $chain_db = new database_driver($SITE_INFO['db_chain'], $SITE_INFO['db_chain_host'], $SITE_INFO['db_chain_user'], $SITE_INFO['db_chain_password'], get_table_prefix(), false, object_factory('Database_Static_' . $SITE_INFO['db_chain_type']));
    } else {
        warn_exit('It makes no sense to run this script if you have not set up the following config options in info.php: db_chain_type, db_chain_host, db_chain_user, db_chain_password, db_chain');
    }
    $chain_connection =& $chain_db->connection_write;
    if (count($chain_connection) > 4) {
        $chain_connection = call_user_func_array(array($chain_db->static_ob, 'db_get_connection'), $chain_connection);
        _general_db_init();
    }
    if (function_exists('set_time_limit')) {
        @set_time_limit(0);
    }
    $GLOBALS['DEBUG_MODE'] = false;
    $GLOBALS['SEMI_DEBUG_MODE'] = false;
    @ini_set('ocproducts.xss_detect', '0');
    if (strtolower(ocp_srv('REQUEST_METHOD')) == 'get') {
        $from = get_param('from', NULL);
        $skip = get_param('skip', NULL);
        $only = get_param('only', NULL);
        echo '
		<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
		<html xmlns="http://www.w3.org/1999/xhtml">
		<head>
		<title>XML/MySQL DB syncher</title>
		</head>
		<body>
		';
        echo '<p>Select the tables to sync below. Tables have been auto-ticked based on what seems to need re-synching.</p>';
        $keep = symbol_tempcode('KEEP', array('1'));
        echo '<form title="Choose tables" method="post" action="' . escape_html(find_script('xml_db_import') . $keep->evaluate()) . '">';
        $tables = array_keys(find_all_tables($GLOBALS['SITE_DB']));
        $mysql_status = list_to_map('Name', $chain_db->query('SHOW TABLE STATUS'));
        $mysql_tables = array_keys($mysql_status);
        foreach ($tables as $table_name) {
            $default_selected = (!is_null($from) && $table_name >= $from || !is_null($only) && in_array($table_name, explode(',', $only))) && (!is_null($skip) || !in_array($table_name, explode(',', $skip)));
            $missing = !in_array(get_table_prefix() . $table_name, $mysql_tables);
            $count_mismatch = !$missing && $chain_db->query_value($table_name, 'COUNT(*)') != $GLOBALS['SITE_DB']->query_value($table_name, 'COUNT(*)');
            $date_mismatch = false;
            if (!$missing && !$count_mismatch) {
                $last_m_time = NULL;
                $path = get_custom_file_base() . '/uploads/website_specific/' . get_db_site() . '/' . get_table_prefix() . $table_name;
                $dh = @opendir($path);
                if ($dh !== false) {
                    while (($f = readdir($dh)) !== false) {
                        if (substr($f, -4) == '.dat' || substr($f, -4) == '.xml') {
                            $last_m_time = @max($last_m_time, filemtime($path . '/' . $f));
                        }
                        // @ because of the 255 read filepath limit on Windows
                    }
                    closedir($dh);
                }
                if (!is_null($last_m_time)) {
                    $mysql_time = strtotime($mysql_status[get_table_prefix() . $table_name]['Update_time']);
                    $date_mismatch = $mysql_time < $last_m_time;
                    // We can't do "!=" as last m-time for MySQL could well by the last sync time
                }
            }
            $needs_doing = $count_mismatch || $date_mismatch || $missing || $default_selected;
            echo '
				<div style="width: 500px">
					<span style="float: right; font-style: italic">
					' . ($missing ? '[table is missing]' : '') . '
					' . ($count_mismatch ? '[different record-counts]' : '') . '
					' . ($date_mismatch ? '[different last-modified-time]' : '') . '
					</span>

					<input ' . ($needs_doing ? 'checked="checked" ' : '') . 'type="checkbox" name="table_' . htmlentities($table_name) . '" id="table_' . htmlentities($table_name) . '" value="1" />
					<label for="table_' . htmlentities($table_name) . '">' . htmlentities($table_name) . '</label>
				</div>
			';
        }
        echo '<p><input type="submit" value="Sync" /> &nbsp;&nbsp;&nbsp;&nbsp; [<a href="#" onclick="var form=document.getElementsByTagName(\'form\')[0]; for (var i=0;i&lt;form.elements.length;i++) if (form.elements[i].checked) form.elements[i].checked=false; return false;">un-tick all</a>]</p>';
        echo '</form>';
        echo '
		</body>
		</html>
		';
        exit;
    }
    // Actualiser
    $from = NULL;
    $skip = NULL;
    $only = '';
    foreach (array_keys($_POST) as $key) {
        if (substr($key, 0, 6) == 'table_') {
            if ($only != '') {
                $only .= ',';
            }
            $only .= substr($key, 6);
        }
    }
    if ($only == '') {
        $only = NULL;
    }
    @header('Content-type: text/plain');
    @ob_end_clean();
    $sql = get_sql_dump(true, true, $from, is_null($skip) ? array() : explode(',', $skip), is_null($only) ? NULL : explode(',', $only));
    $cnt = count($sql);
    foreach ($sql as $i => $s) {
        print 'Executing query ' . strval($i + 1) . '/' . strval($cnt) . ' ... ' . $s . "\n\n";
        flush();
        $fail_ok = substr($s, 0, 5) == 'ALTER';
        $chain_db->static_ob->db_query($s, $chain_connection, NULL, NULL, $fail_ok, false);
    }
    print '!!Done!!';
}
Beispiel #6
0
 /**
  * This function is a very basic query executor. It shouldn't usually be used by you, as there are abstracted versions available.
  *
  * @param  string			The complete SQL query
  * @param  array			A DB connection
  * @param  ?integer		The maximum number of rows to affect (NULL: no limit)
  * @param  ?integer		The start row to affect (NULL: no specification)
  * @param  boolean		Whether to not output an error on some kind of run-time failure (parse errors and clear programming errors are always fatal)
  * @param  boolean		Whether to get the autoincrement ID created for an insert query
  * @param  boolean		Whether to force the query to execute on the XML database driver (won't optimise by using MySQL). Useful for calls happening for multi-part queries from within this DB driver
  * @param  boolean		Whether we are saving as a 'volatile' file extension
  * @return ?mixed			The results (NULL: no results), or the insert ID
  */
 function db_query($query, $db, $max = NULL, $start = NULL, $fail_ok = false, $get_insert_id = false, $no_syndicate = false, $save_as_volatile = false)
 {
     global $DELIMITERS_FLIPPED, $DELIMITERS, $SYMBOL_DELIMINITER;
     // LEXING STAGE
     // ------------
     $i = 0;
     $query .= ' ';
     // Cheat so that we do not have to handle the end state differently
     $len = strlen($query);
     $tokens = array();
     $current_token = '';
     $doing_symbol_delimiter = true;
     while ($i < $len) {
         $next = $query[$i];
         if ($next == "'" || $next == '"') {
             if (trim($current_token) != '') {
                 if (isset($DELIMITERS_FLIPPED[strtoupper($current_token)])) {
                     $tokens[] = strtoupper($current_token);
                 } else {
                     $tokens[] = $current_token;
                 }
             }
             $current_token = '';
             $i++;
             while ($i < $len) {
                 $next = $query[$i];
                 if ($next == '\\') {
                     $i++;
                     $next = $query[$i];
                     $current_token .= $next;
                 } else {
                     if ($next == "'" || $next == '"') {
                         $tokens[] = "'";
                         $tokens[] = $current_token;
                         $tokens[] = "'";
                         break;
                     } else {
                         $current_token .= $next;
                     }
                 }
                 $i++;
             }
             $current_token = '';
             $doing_symbol_delimiter = true;
         } else {
             $symbol_delimiter_coming = isset($SYMBOL_DELIMINITER[$next]) && (isset($DELIMITERS_FLIPPED[$next]) || $i + 1 < $len && isset($DELIMITERS_FLIPPED[$next . $query[$i + 1]]));
             //  (NB: symbol delimiters are a maximum of two in length)
             if (($symbol_delimiter_coming || $doing_symbol_delimiter) && !$this->is_start_of_delimiter($current_token . $next)) {
                 if (trim($current_token) != '') {
                     if (isset($DELIMITERS_FLIPPED[strtoupper($current_token)])) {
                         $tokens[] = strtoupper($current_token);
                     } else {
                         $tokens[] = $current_token;
                     }
                 }
                 $current_token = $next;
                 $doing_symbol_delimiter = isset($SYMBOL_DELIMINITER[$next]);
             } else {
                 $current_token .= $next;
                 if ($doing_symbol_delimiter) {
                     $doing_symbol_delimiter = isset($SYMBOL_DELIMINITER[$next]);
                 }
             }
         }
         $i++;
     }
     $query = substr($query, 0, $len - 1);
     // PARSING/EXECUTION STAGE
     // -----------------------
     $random_key = mt_rand(0, min(2147483647, mt_getrandmax()));
     // Generated later, passed by reference. We will assume we only need one; multi inserts will need to each specify the key in full
     if (!is_null($GLOBALS['XML_CHAIN_DB']) && !$no_syndicate) {
         if (substr(strtoupper($query), 0, 7) == 'SELECT ') {
             $chain_connection =& $GLOBALS['XML_CHAIN_DB']->connection_read;
         } else {
             $chain_connection =& $GLOBALS['XML_CHAIN_DB']->connection_write;
         }
         if (count($chain_connection) > 4) {
             $chain_connection = call_user_func_array(array($GLOBALS['XML_CHAIN_DB']->static_ob, 'db_get_connection'), $chain_connection);
             _general_db_init();
         }
         switch ($tokens[0]) {
             case 'INSERT':
                 // DB chaining: It's a write query, so needs doing on chained DB too
                 //  But because it's an insert we may need to put in an auto-increment also
                 $_inserts = $this->_do_query_insert__parse($tokens, $query, $db, $fail_ok);
                 if (is_null($_inserts)) {
                     return NULL;
                 }
                 list($table_name, $inserts) = $_inserts;
                 $insert_keys = array_keys($inserts[0]);
                 $query_new = 'INSERT INTO ' . $table_name . ' (';
                 $schema = $this->_read_schema($db, $table_name, $fail_ok);
                 global $TABLE_BASES;
                 foreach ($schema as $key => $val) {
                     if (preg_replace('#[^\\w]#', '', $val) == 'AUTO' && !in_array($key, $insert_keys)) {
                         $insert_keys[] = $key;
                         foreach (array_keys($inserts) as $i) {
                             if ($i != 0) {
                                 $random_key = mt_rand(0, min(2147483647, mt_getrandmax()));
                             }
                             $inserts[$i][$key] = isset($TABLE_BASES[$table_name]) ? $TABLE_BASES[$table_name] : $this->db_get_first_id();
                             // We always want first record as '1', because we often reference it in a hard-coded way
                             while (file_exists($db[0] . '/' . $table_name . '/' . strval($inserts[$i][$key]) . '.xml') || file_exists($db[0] . '/' . $table_name . '/' . $this->_guid($schema, $inserts[$i]) . '.xml') || file_exists($db[0] . '/' . $table_name . '/' . strval($inserts[$i][$key]) . '.xml-volatile') || file_exists($db[0] . '/' . $table_name . '/' . $this->_guid($schema, $inserts[$i]) . '.xml-volatile')) {
                                 if ($GLOBALS['IN_MINIKERNEL_VERSION'] == 1) {
                                     $inserts[$i][$key]++;
                                     $TABLE_BASES[$table_name] = $inserts[$i][$key] + 1;
                                 } else {
                                     if ($i != 0) {
                                         $random_key = mt_rand(0, min(2147483647, mt_getrandmax()));
                                     }
                                     $inserts[$i][$key] = $random_key;
                                     // We don't use auto-increment, we use randomisation. As otherwise when people sync over revision control there'd be conflicts
                                 }
                             }
                         }
                     }
                 }
                 foreach ($insert_keys as $i => $key) {
                     if ($i != 0) {
                         $query_new .= ',';
                     }
                     $query_new .= $key;
                 }
                 $query_new .= ')';
                 foreach ($inserts as $ii => $insert) {
                     if ($ii != 0) {
                         $query_new .= ', (';
                     } else {
                         $query_new .= ' VALUES (';
                     }
                     $i = 0;
                     foreach ($insert as $value) {
                         if ($i != 0) {
                             $query_new .= ',';
                         }
                         if (is_integer($value)) {
                             $query_new .= strval($value);
                         } elseif (is_float($value)) {
                             $query_new .= float_to_raw_string($value);
                         } elseif (is_null($value)) {
                             $query_new .= 'NULL';
                         } else {
                             $query_new .= '\'' . db_escape_string($value) . '\'';
                         }
                         $i++;
                     }
                     $query_new .= ')';
                 }
                 $GLOBALS['XML_CHAIN_DB']->static_ob->db_query($query_new, $chain_connection, $max, $start, $fail_ok, $get_insert_id);
                 break;
             case 'UPDATE':
             case 'DELETE':
                 // DB chaining: It's a write query, so needs doing on chained DB too
                 $GLOBALS['XML_CHAIN_DB']->static_ob->db_query($query, $chain_connection, $max, $start, $fail_ok, $get_insert_id);
                 break;
             case 'SELECT':
                 return $GLOBALS['XML_CHAIN_DB']->static_ob->db_query($query, $chain_connection, $max, $start, $fail_ok, $get_insert_id);
         }
     }
     switch ($tokens[0]) {
         case 'ALTER':
             return $this->_do_query_alter($tokens, $query, $db, $fail_ok);
         case 'CREATE':
             return $this->_do_query_create($tokens, $query, $db, $fail_ok);
         case 'INSERT':
             return $this->_do_query_insert($tokens, $query, $db, $fail_ok, $get_insert_id, $random_key, $save_as_volatile);
         case 'UPDATE':
             return $this->_do_query_update($tokens, $query, $db, $max, $start, $fail_ok);
         case 'DELETE':
             return $this->_do_query_delete($tokens, $query, $db, $max, $start, $fail_ok);
         case 'SELECT':
             $at = 0;
             $results = $this->_do_query_select($tokens, $query, $db, $max, $start, $fail_ok, $at);
             return $results;
         case 'DROP':
             return $this->_do_query_drop($tokens, $query, $db, $fail_ok);
     }
     return $this->_bad_query($query, $fail_ok, 'Unrecognised query type, ' . $tokens[0]);
 }