00001 <?php
00027 require_once 'Zend/Db/Adapter/Abstract.php';
00028
00032 require_once 'Zend/Db/Profiler.php';
00033
00037 require_once 'Zend/Db/Select.php';
00038
00042 require_once 'Zend/Db/Statement/Mysqli.php';
00043
00044
00052 class Zend_Db_Adapter_Mysqli extends Zend_Db_Adapter_Abstract
00053 {
00054
00066 protected $_numericDataTypes = array(
00067 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
00068 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
00069 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
00070 'INT' => Zend_Db::INT_TYPE,
00071 'INTEGER' => Zend_Db::INT_TYPE,
00072 'MEDIUMINT' => Zend_Db::INT_TYPE,
00073 'SMALLINT' => Zend_Db::INT_TYPE,
00074 'TINYINT' => Zend_Db::INT_TYPE,
00075 'BIGINT' => Zend_Db::BIGINT_TYPE,
00076 'SERIAL' => Zend_Db::BIGINT_TYPE,
00077 'DEC' => Zend_Db::FLOAT_TYPE,
00078 'DECIMAL' => Zend_Db::FLOAT_TYPE,
00079 'DOUBLE' => Zend_Db::FLOAT_TYPE,
00080 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE,
00081 'FIXED' => Zend_Db::FLOAT_TYPE,
00082 'FLOAT' => Zend_Db::FLOAT_TYPE
00083 );
00084
00088 protected $_stmt = null;
00089
00095 protected $_defaultStmtClass = 'Zend_Db_Statement_Mysqli';
00096
00104 protected function _quote($value)
00105 {
00106 if (is_int($value) || is_float($value)) {
00107 return $value;
00108 }
00109 $this->_connect();
00110 return "'" . $this->_connection->real_escape_string($value) . "'";
00111 }
00112
00118 public function getQuoteIdentifierSymbol()
00119 {
00120 return "`";
00121 }
00122
00128 public function listTables()
00129 {
00130 $result = array();
00131
00132
00133 $sql = 'SHOW TABLES';
00134 if ($queryResult = $this->getConnection()->query($sql)) {
00135 while ($row = $queryResult->fetch_row()) {
00136 $result[] = $row[0];
00137 }
00138 $queryResult->close();
00139 } else {
00143 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00144 throw new Zend_Db_Adapter_Mysqli_Exception($this->getConnection()->error);
00145 }
00146 return $result;
00147 }
00148
00177 public function describeTable($tableName, $schemaName = null)
00178 {
00184 if ($schemaName) {
00185 $sql = 'DESCRIBE ' . $this->quoteIdentifier("$schemaName.$tableName", true);
00186 } else {
00187 $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true);
00188 }
00189
00194 if ($queryResult = $this->getConnection()->query($sql)) {
00195 while ($row = $queryResult->fetch_assoc()) {
00196 $result[] = $row;
00197 }
00198 $queryResult->close();
00199 } else {
00203 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00204 throw new Zend_Db_Adapter_Mysqli_Exception($this->getConnection()->error);
00205 }
00206
00207 $desc = array();
00208
00209 $row_defaults = array(
00210 'Length' => null,
00211 'Scale' => null,
00212 'Precision' => null,
00213 'Unsigned' => null,
00214 'Primary' => false,
00215 'PrimaryPosition' => null,
00216 'Identity' => false
00217 );
00218 $i = 1;
00219 $p = 1;
00220 foreach ($result as $key => $row) {
00221 $row = array_merge($row_defaults, $row);
00222 if (preg_match('/unsigned/', $row['Type'])) {
00223 $row['Unsigned'] = true;
00224 }
00225 if (preg_match('/^((?:var)?char)\((\d+)\)/', $row['Type'], $matches)) {
00226 $row['Type'] = $matches[1];
00227 $row['Length'] = $matches[2];
00228 } else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row['Type'], $matches)) {
00229 $row['Type'] = 'decimal';
00230 $row['Precision'] = $matches[1];
00231 $row['Scale'] = $matches[2];
00232 } else if (preg_match('/^float\((\d+),(\d+)\)/', $row['Type'], $matches)) {
00233 $row['Type'] = 'float';
00234 $row['Precision'] = $matches[1];
00235 $row['Scale'] = $matches[2];
00236 } else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row['Type'], $matches)) {
00237 $row['Type'] = $matches[1];
00242 }
00243 if (strtoupper($row['Key']) == 'PRI') {
00244 $row['Primary'] = true;
00245 $row['PrimaryPosition'] = $p;
00246 if ($row['Extra'] == 'auto_increment') {
00247 $row['Identity'] = true;
00248 } else {
00249 $row['Identity'] = false;
00250 }
00251 ++$p;
00252 }
00253 $desc[$this->foldCase($row['Field'])] = array(
00254 'SCHEMA_NAME' => null,
00255 'TABLE_NAME' => $this->foldCase($tableName),
00256 'COLUMN_NAME' => $this->foldCase($row['Field']),
00257 'COLUMN_POSITION' => $i,
00258 'DATA_TYPE' => $row['Type'],
00259 'DEFAULT' => $row['Default'],
00260 'NULLABLE' => (bool) ($row['Null'] == 'YES'),
00261 'LENGTH' => $row['Length'],
00262 'SCALE' => $row['Scale'],
00263 'PRECISION' => $row['Precision'],
00264 'UNSIGNED' => $row['Unsigned'],
00265 'PRIMARY' => $row['Primary'],
00266 'PRIMARY_POSITION' => $row['PrimaryPosition'],
00267 'IDENTITY' => $row['Identity']
00268 );
00269 ++$i;
00270 }
00271 return $desc;
00272 }
00273
00280 protected function _connect()
00281 {
00282 if ($this->_connection) {
00283 return;
00284 }
00285
00286 if (!extension_loaded('mysqli')) {
00290 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00291 throw new Zend_Db_Adapter_Mysqli_Exception('The Mysqli extension is required for this adapter but the extension is not loaded');
00292 }
00293
00294 if (isset($this->_config['port'])) {
00295 $port = (integer) $this->_config['port'];
00296 } else {
00297 $port = null;
00298 }
00299
00300 $this->_connection = mysqli_init();
00301
00302 if(!empty($this->_config['driver_options'])) {
00303 foreach($this->_config['driver_options'] as $option=>$value) {
00304 if(is_string($option)) {
00305
00306
00307 $option = @constant(strtoupper($option));
00308 if($option === null)
00309 continue;
00310 }
00311 mysqli_options($this->_connection, $option, $value);
00312 }
00313 }
00314
00315
00316
00317 $_isConnected = @mysqli_real_connect(
00318 $this->_connection,
00319 $this->_config['host'],
00320 $this->_config['username'],
00321 $this->_config['password'],
00322 $this->_config['dbname'],
00323 $port
00324 );
00325
00326 if ($_isConnected === false || mysqli_connect_errno()) {
00327
00328 $this->closeConnection();
00332 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00333 throw new Zend_Db_Adapter_Mysqli_Exception(mysqli_connect_error());
00334 }
00335
00336 if (!empty($this->_config['charset'])) {
00337 mysqli_set_charset($this->_connection, $this->_config['charset']);
00338 }
00339 }
00340
00346 public function isConnected()
00347 {
00348 return ((bool) ($this->_connection instanceof mysqli));
00349 }
00350
00356 public function closeConnection()
00357 {
00358 if ($this->isConnected()) {
00359 $this->_connection->close();
00360 }
00361 $this->_connection = null;
00362 }
00363
00370 public function prepare($sql)
00371 {
00372 $this->_connect();
00373 if ($this->_stmt) {
00374 $this->_stmt->close();
00375 }
00376 $stmtClass = $this->_defaultStmtClass;
00377 if (!class_exists($stmtClass)) {
00378 require_once 'Zend/Loader.php';
00379 Zend_Loader::loadClass($stmtClass);
00380 }
00381 $stmt = new $stmtClass($this, $sql);
00382 if ($stmt === false) {
00383 return false;
00384 }
00385 $stmt->setFetchMode($this->_fetchMode);
00386 $this->_stmt = $stmt;
00387 return $stmt;
00388 }
00389
00407 public function lastInsertId($tableName = null, $primaryKey = null)
00408 {
00409 $mysqli = $this->_connection;
00410 return (string) $mysqli->insert_id;
00411 }
00412
00418 protected function _beginTransaction()
00419 {
00420 $this->_connect();
00421 $this->_connection->autocommit(false);
00422 }
00423
00429 protected function _commit()
00430 {
00431 $this->_connect();
00432 $this->_connection->commit();
00433 $this->_connection->autocommit(true);
00434 }
00435
00441 protected function _rollBack()
00442 {
00443 $this->_connect();
00444 $this->_connection->rollback();
00445 $this->_connection->autocommit(true);
00446 }
00447
00455 public function setFetchMode($mode)
00456 {
00457 switch ($mode) {
00458 case Zend_Db::FETCH_LAZY:
00459 case Zend_Db::FETCH_ASSOC:
00460 case Zend_Db::FETCH_NUM:
00461 case Zend_Db::FETCH_BOTH:
00462 case Zend_Db::FETCH_NAMED:
00463 case Zend_Db::FETCH_OBJ:
00464 $this->_fetchMode = $mode;
00465 break;
00466 case Zend_Db::FETCH_BOUND:
00470 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00471 throw new Zend_Db_Adapter_Mysqli_Exception('FETCH_BOUND is not supported yet');
00472 break;
00473 default:
00477 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00478 throw new Zend_Db_Adapter_Mysqli_Exception("Invalid fetch mode '$mode' specified");
00479 }
00480 }
00481
00490 public function limit($sql, $count, $offset = 0)
00491 {
00492 $count = intval($count);
00493 if ($count <= 0) {
00497 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00498 throw new Zend_Db_Adapter_Mysqli_Exception("LIMIT argument count=$count is not valid");
00499 }
00500
00501 $offset = intval($offset);
00502 if ($offset < 0) {
00506 require_once 'Zend/Db/Adapter/Mysqli/Exception.php';
00507 throw new Zend_Db_Adapter_Mysqli_Exception("LIMIT argument offset=$offset is not valid");
00508 }
00509
00510 $sql .= " LIMIT $count";
00511 if ($offset > 0) {
00512 $sql .= " OFFSET $offset";
00513 }
00514
00515 return $sql;
00516 }
00517
00524 public function supportsParameters($type)
00525 {
00526 switch ($type) {
00527 case 'positional':
00528 return true;
00529 case 'named':
00530 default:
00531 return false;
00532 }
00533 }
00534
00540 public function getServerVersion()
00541 {
00542 $this->_connect();
00543 $version = $this->_connection->server_version;
00544 $major = (int) ($version / 10000);
00545 $minor = (int) ($version % 10000 / 100);
00546 $revision = (int) ($version % 100);
00547 return $major . '.' . $minor . '.' . $revision;
00548 }
00549 }