1<?php 2/** 3 * This file was originally written by Chris Petersen for several different open 4 * source projects. It is distrubuted under the GNU General Public License. 5 * I (Chris Petersen) have also granted a special LGPL license for this code to 6 * several companies I do work for on the condition that these companies will 7 * release any changes to this back to me and the open source community as GPL, 8 * thus continuing to improve the open source version of the library. If you 9 * would like to inquire about the status of this arrangement, please contact 10 * me personally. 11 * 12 * --- 13 * 14 * Query handler for the "compatible" version of the improved MySQL engine. 15 * This is also the parent class for the full/expanded mysqli query object, 16 * since many of the routines are shared between them. 17 * 18 * @copyright Silicon Mechanics 19 * @license GPL 20 * 21 * @package MythWeb 22 * @subpackage Database 23 * 24 * @uses Database.php 25 * @uses Database_mysqlicompat.php 26 * @uses Database_Query.php 27 * 28 **/ 29 30/** 31 * The basic mysqli database query type. 32 **/ 33class Database_Query_mysqlicompat extends Database_Query { 34 35/** 36 * Executes the query that was previously passed to the constructor. 37 * 38 * @param mixed $arg Query arguments to escape and insert at ? placeholders in $query 39 * @param mixed ... Additional arguments 40 **/ 41 function execute() { 42 // Load the function arguments, minus the query itself, which we already extracted 43 $args = func_get_args(); 44 // Split out sub-arrays, etc.. 45 $args = Database::smart_args($args); 46 // Were enough arguments passed in? 47 if (count($args) != $this->num_args_needed) 48 trigger_error('Database_Query_mysqlicompat called with '.count($args)." arguments, but requires $this->num_args_needed.", E_USER_ERROR); 49 // Finish any previous statements 50 $this->finish(); 51 // Replace in the arguments 52 $this->last_query = ''; 53 foreach ($this->query as $part) { 54 $this->last_query .= $part; 55 if (count($args)) { 56 $arg = array_shift($args); 57 $this->last_query .= is_null($arg) 58 ? 'NULL' 59 : "'".mysqli_real_escape_string($this->dbh, $arg)."'"; 60 } 61 } 62 // Perform the query 63 // If we don't have a valid connection, fataly error out. 64 if ($this->dbh === false) { 65 $this->db->error(); 66 trigger_error($this->db->error, E_USER_ERROR); 67 } 68 $this->sh = mysqli_query($this->dbh, $this->last_query); 69 70 // Cache these so the warning count below doesn't interfere 71 if (is_bool($this->sh)) { 72 $this->insert_id = mysqli_insert_id($this->dbh); 73 $this->affected_rows = mysqli_affected_rows($this->dbh); 74 } 75 else { 76 $this->num_rows = mysqli_num_rows($this->sh); 77 } 78 79 // On each execute, we clear the warnings of the statement handle, so it doesn't 80 // store them up 81 $this->warnings = array(); 82 // Check the warnings and store them 83 if (mysqli_warning_count($this->dbh)) { 84 if ($sh = mysqli_query($this->dbh, 'SHOW WARNINGS')) { 85 while ($row = mysqli_fetch_row($sh)) 86 $this->warnings[] = array( '#' => $row[1], 87 'MSG' => $row[2] ); 88 mysqli_free_result($sh); 89 // This is used in errors.php to output in the backtrace 90 global $_DEBUG; 91 $_DEBUG['Database Warnings'][] = array( 'Query' => $this->last_query, 92 'Warnings' => $this->warnings ); 93 } 94 } 95 96 if ($this->sh === false) { 97 if ($this->db->fatal_errors) 98 trigger_error('SQL Error: '.mysqli_error($this->dbh).' [#'.mysqli_errno($this->dbh).']', E_USER_ERROR); 99 else 100 $this->db->error(); 101 } 102 } 103 104/** 105 * The following routines basically replicate the mysqli functions built into 106 * php. The only difference is that the resource handle gets passed-in 107 * automatically. eg. 108 * 109 * mysqli_fetch_row($result); -> $sh->fetch_row(); 110 * mysqli_affected_rows($dbh); -> $sh->affected_rows(); 111 **/ 112 113/** 114 * Fetch a single column 115 * @return mixed 116 **/ 117 function fetch_col() { 118 list($return) = mysqli_fetch_row($this->sh); 119 return $return; 120 } 121 122 function fetch_cols() { 123 $return = array(); 124 while ($col = $this->fetch_col()) 125 $return[] = $col; 126 return $return; 127 } 128 129/** 130 * Fetch a single row 131 * 132 * @link http://www.php.net/manual/en/function.mysqli-fetch-row.php 133 * @return array 134 **/ 135 function fetch_row() { 136 return mysqli_fetch_row($this->sh); 137 } 138 139/** 140 * Fetch a single assoc row 141 * 142 * @link http://www.php.net/manual/en/function.mysqli-fetch-assoc.php 143 * @return assoc 144 **/ 145 function fetch_assoc() { 146 return mysqli_fetch_assoc($this->sh); 147 } 148 149/** 150 * Fetch a single row as an array containing both numeric and assoc fields 151 * 152 * @link http://www.php.net/manual/en/function.mysqli-fetch-array.php 153 * @return assoc 154 **/ 155 function fetch_array($result_type=MYSQLI_BOTH) { 156 return mysqli_fetch_array($this->sh, $result_type); 157 } 158 159/** 160 * Fetch a single row as an object 161 * 162 * @link http://www.php.net/manual/en/function.mysqli-fetch-object.php 163 * @return object 164 **/ 165 function fetch_object() { 166 return mysqli_fetch_object($this->sh); 167 } 168 169/** 170 * @link http://www.php.net/manual/en/function.mysqli-data-seek.php 171 * @return bool 172 **/ 173 function data_seek($row_number) { 174 return mysqli_data_seek($this->sh, $row_number); 175 } 176 177/** 178 * @link http://www.php.net/manual/en/function.mysqli-num-rows.php 179 * @return int 180 **/ 181 function num_rows() { 182 return $this->num_rows; 183 } 184 185/** 186 * @link http://www.php.net/manual/en/function.mysqli-data-seek.php 187 * @return int 188 **/ 189 function affected_rows() { 190 return $this->affected_rows; 191 } 192 193/** 194 * @link http://www.php.net/manual/en/function.mysqli-insert-id.php 195 * @return int 196 **/ 197 function insert_id() { 198 return $this->insert_id; 199 } 200 201/** 202 * For anal people like me who like to free up memory manually 203 **/ 204 function finish() { 205 if ($this->sh && is_resource($this->sh)) 206 mysqli_free_result($this->sh); 207 unset($this->sh); 208 } 209 210} 211