1 <?php
2 3 4 5 6 7 8 9 10
11
12
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
33 class NeevoDriverMySQLi extends NeevoParser implements INeevoDriver {
34
35
36
37 private $resource;
38
39
40 private $unbuffered;
41
42
43 private $affectedRows;
44
45
46 47 48 49 50
51 public function __construct(NeevoBaseStmt $statement = null){
52 if(!extension_loaded("mysqli"))
53 throw new NeevoDriverException("Cannot instantiate Neevo MySQLi driver - PHP extension 'mysqli' not loaded.");
54 if($statement instanceof NeevoBaseStmt)
55 parent::__construct($statement);
56 }
57
58
59 60 61 62 63 64
65 public function connect(array $config){
66
67
68 $defaults = array(
69 'resource' => null,
70 'charset' => 'utf8',
71 'username' => ini_get('mysqli.default_user'),
72 'password' => ini_get('mysqli.default_pw'),
73 'socket' => ini_get('mysqli.default_socket'),
74 'port' => ini_get('mysqli.default_port'),
75 'host' => ini_get('mysqli.default_host'),
76 'persistent' => false,
77 'unbuffered' => false
78 );
79
80 $config += $defaults;
81
82
83 if($config['resource'] instanceof mysqli)
84 $this->resource = $config['resource'];
85 else
86 $this->resource = new mysqli($config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket']);
87
88 if($this->resource->connect_errno)
89 throw new NeevoException($this->resource->connect_error, $this->resource->connect_errno);
90
91
92 if($this->resource instanceof mysqli){
93 $ok = @$this->resource->set_charset($config['charset']);
94 if(!$ok) $this->runQuery("SET NAMES ".$config['charset']);
95 }
96
97 $this->unbuffered = $config['unbuffered'];
98 }
99
100
101 102 103 104
105 public function closeConnection(){
106 @$this->resource->close();
107 }
108
109
110 111 112 113 114
115 public function freeResultSet($resultSet){
116 return true;
117 }
118
119
120 121 122 123 124 125
126 public function runQuery($queryString){
127
128 $this->affectedRows = false;
129 $result = $this->resource->query($queryString, $this->unbuffered ? MYSQLI_USE_RESULT : MYSQLI_STORE_RESULT);
130
131 $error = str_replace('You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use', 'Syntax error', $this->resource->error);
132 if($error && $result === false)
133 throw new NeevoException("Query failed. $error", $this->resource->errno, $queryString);
134
135 $this->affectedRows = $this->resource->affected_rows;
136 return $result;
137 }
138
139
140 141 142 143 144
145 public function beginTransaction($savepoint = null){
146 $this->runQuery($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
147 }
148
149
150 151 152 153 154
155 public function commit($savepoint = null){
156 $this->runQuery($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
157 }
158
159
160 161 162 163 164
165 public function rollback($savepoint = null){
166 $this->runQuery($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
167 }
168
169
170 171 172 173 174
175 public function fetch($resultSet){
176 return $resultSet->fetch_assoc();
177 }
178
179
180 181 182 183 184 185 186
187 public function seek($resultSet, $offset){
188 if($this->unbuffered)
189 throw new NeevoDriverException('Cannot seek on unbuffered result.');
190 return $resultSet->data_seek($offset);
191 }
192
193
194 195 196 197
198 public function getInsertId(){
199 return $this->resource->insert_id;
200 }
201
202
203 204 205 206 207
208 public function randomizeOrder(NeevoBaseStmt $statement){
209 $statement->order('RAND()');
210 }
211
212
213 214 215 216 217 218
219 public function getNumRows($resultSet){
220 if($this->unbuffered)
221 throw new NeevoDriverException('Cannot seek on unbuffered result.');
222 if($resultSet instanceof mysqli_result)
223 return $resultSet->num_rows;
224 return false;
225 }
226
227
228 229 230 231
232 public function getAffectedRows(){
233 return $this->affectedRows;
234 }
235
236
237 238 239 240 241 242 243
244 public function escape($value, $type){
245 switch($type){
246 case Neevo::BOOL:
247 return $value ? 1 :0;
248
249 case Neevo::TEXT:
250 return "'". $this->resource->real_escape_string($value) ."'";
251
252 case Neevo::IDENTIFIER:
253 return str_replace('`*`', '*', '`' . str_replace('.', '`.`', str_replace('`', '``', $value)) . '`');
254
255 case Neevo::BINARY:
256 return "_binary'" . mysqli_real_escape_string($this->resource, $value) . "'";
257
258 case Neevo::DATETIME:
259 return ($value instanceof DateTime) ? $value->format("'Y-m-d H:i:s'") : date("'Y-m-d H:i:s'", $value);
260
261 default:
262 throw new InvalidArgumentException('Unsupported data type.');
263 break;
264 }
265 }
266
267
268 269 270 271 272 273 274
275 public function unescape($value, $type){
276 if($type === Neevo::BINARY)
277 return $value;
278 throw new InvalidArgumentException('Unsupported data type.');
279 }
280
281
282 283 284 285 286
287 public function getPrimaryKey($table){
288 $key = '';
289 $q = $this->runQuery('SHOW FULL COLUMNS FROM '.$table);
290 while($col = $this->fetch($q)){
291 if(strtolower($col['Key']) === 'pri' && $key === '')
292 $key = $col['Field'];
293 }
294 return $key;
295 }
296
297
298 299 300 301 302 303
304 public function getColumnTypes($resultSet, $table){
305 static $colTypes;
306 if(empty($colTypes)){
307 $constants = get_defined_constants(true);
308 foreach($constants['mysqli'] as $type => $code){
309 if(strncmp($type, 'MYSQLI_TYPE_', 12) === 0)
310 $colTypes[$code] = strtolower(substr($type, 12));
311 }
312 $colTypes[MYSQLI_TYPE_LONG] = $colTypes[MYSQLI_TYPE_SHORT] = $colTypes[MYSQLI_TYPE_TINY] = 'int';
313 }
314
315 $cols = array();
316 while($field = $resultSet->fetch_field()){
317 $cols[$field->name] = $colTypes[$field->type];
318 }
319 return $cols;
320 }
321
322
323
324
325
326 327 328 329
330 protected function parseUpdateStmt(){
331 $sql = parent::parseUpdateStmt();
332 return $this->applyLimit($sql . $this->clauses[3]);
333 }
334
335
336 337 338 339
340 protected function parseDeleteStmt(){
341 $sql = parent::parseDeleteStmt();
342 return $this->applyLimit($sql . $this->clauses[3]);
343 }
344
345
346 }
347