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 MySQL
15 *
16 * @copyright   Silicon Mechanics
17 * @license     GPL
18 *
19 * @package     MythWeb
20 * @subpackage  Database
21 *
22 * @uses        Database.php
23 * @uses        Database_mysql.php
24 * @uses        Database_Query.php
25 *
26 **/
27
28/**
29 * The basic MySQL database query type.
30 **/
31class Database_Query_mysql extends Database_Query {
32
33/**
34 * Executes the query that was previously passed to the constructor.
35 *
36 * @param mixed  $arg      Query arguments to escape and insert at ? placeholders in $query
37 * @param mixed  ...       Additional arguments
38 **/
39    function execute() {
40    // Load the function arguments, minus the query itself, which we already extracted
41        $args = func_get_args();
42    // Split out sub-arrays, etc..
43        $args = Database::smart_args($args);
44    // Were enough arguments passed in?
45        if (count($args) != $this->num_args_needed)
46            trigger_error('Database_Query called with '.count($args)." arguments, but requires $this->num_args_needed.", E_USER_ERROR);
47    // Finish any previous statements
48        $this->finish();
49    // Replace in the arguments
50        $this->last_query = '';
51        foreach ($this->query as $part) {
52            $this->last_query .= $part;
53            if (count($args)) {
54                $arg = array_shift($args);
55                $this->last_query .= is_null($arg)
56                                        ? 'NULL'
57                                        : "'".mysqli_real_escape_string($arg)."'";
58            }
59        }
60    // Perform the query
61    // If we don't have a valid connection, fataly error out.
62        if ($this->dbh === false) {
63            $this->db->error();
64            trigger_error($this->db->error, E_USER_ERROR);
65        }
66        $this->sh = mysqli_query($this->last_query, $this->dbh);
67
68    // Cache these
69        if (is_bool($this->sh)) {
70            $this->insert_id     = mysqli_insert_id($this->dbh);
71            $this->affected_rows = mysqli_affected_rows($this->dbh);
72        }
73        else {
74            $this->num_rows      = mysqli_num_rows($this->sh);
75        }
76
77        if ($this->sh === false) {
78            if ($this->db->fatal_errors)
79                trigger_error('SQL Error: '.mysqli_error($this->dbh).' [#'.mysqli_errno($this->dbh).']', E_USER_ERROR);
80            else
81                $this->db->error();
82        }
83    }
84
85/**
86 * The following routines basically replicate the mysql functions built into
87 * php.  The only difference is that the resource handle gets passed-in
88 * automatically.  eg.
89 *
90 *      mysqli_fetch_row($result);   ->  $sh->fetch_row();
91 *      mysqli_affected_rows($dbh);  ->  $sh->affected_rows();
92 **/
93
94/**
95 * Fetch a single column
96 * @return mixed
97 **/
98    function fetch_col() {
99        list($return) = mysqli_fetch_row($this->sh);
100        return $return;
101    }
102
103    function fetch_cols() {
104        $return = array();
105        while ($col = $this->fetch_col())
106            $return[] = $col;
107        return $return;
108    }
109
110/**
111 * Fetch a single row
112 *
113 * @link http://www.php.net/manual/en/function.mysql-fetch-row.php
114 * @return array
115 **/
116    function fetch_row() {
117        return mysqli_fetch_row($this->sh);
118    }
119
120/**
121 * Fetch a single assoc row
122 *
123 * @link http://www.php.net/manual/en/function.mysql-fetch-assoc.php
124 * @return assoc
125 **/
126    function fetch_assoc() {
127        return mysqli_fetch_assoc($this->sh);
128    }
129
130/**
131 * Fetch a single row as an array containing both numeric and assoc fields
132 *
133 * @link http://www.php.net/manual/en/function.mysql-fetch-array.php
134 * @return assoc
135 **/
136    function fetch_array($result_type=MYSQL_BOTH) {
137        return mysqli_fetch_array($this->sh, $result_type);
138    }
139
140/**
141 * Fetch a single row as an object
142 *
143 * @link http://www.php.net/manual/en/function.mysql-fetch-object.php
144 * @return object
145 **/
146    function fetch_object() {
147        return mysqli_fetch_object($this->sh);
148    }
149
150/**
151 * @link http://www.php.net/manual/en/function.mysql-data-seek.php
152 * @return bool
153 **/
154    function data_seek($row_number) {
155        return mysqli_data_seek($this->sh, $row_number);
156    }
157
158/**
159 * @link http://www.php.net/manual/en/function.mysql-num-rows.php
160 * @return int
161 **/
162    function num_rows() {
163        return $this->num_rows;
164    }
165
166/**
167 * @link http://www.php.net/manual/en/function.mysql-data-seek.php
168 * @return int
169 **/
170    function affected_rows() {
171        return $this->affected_rows;
172    }
173
174/**
175 * @link http://www.php.net/manual/en/function.mysql-insert-id.php
176 * @return int
177 **/
178    function insert_id() {
179        return $this->insert_id;
180    }
181
182/**
183 * For anal people like me who like to free up memory manually
184 **/
185    function finish() {
186        if ($this->sh && is_resource($this->sh))
187            mysqli_free_result($this->sh);
188        unset($this->sh);
189    }
190
191}
192