00001 <?php
00027 require_once 'Zend/Db.php';
00028
00032 require_once 'Zend/Db/Select.php';
00033
00043 abstract class Zend_Db_Adapter_Abstract
00044 {
00045
00051 protected $_config = array();
00052
00058 protected $_fetchMode = Zend_Db::FETCH_ASSOC;
00059
00066 protected $_profiler;
00067
00073 protected $_defaultStmtClass = 'Zend_Db_Statement';
00074
00080 protected $_defaultProfilerClass = 'Zend_Db_Profiler';
00081
00087 protected $_connection = null;
00088
00098 protected $_caseFolding = Zend_Db::CASE_NATURAL;
00099
00109 protected $_autoQuoteIdentifiers = true;
00110
00122 protected $_numericDataTypes = array(
00123 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
00124 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
00125 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE
00126 );
00127
00132 protected $_allowSerialization = true;
00133
00140 protected $_autoReconnectOnUnserialize = false;
00141
00163 public function __construct($config)
00164 {
00165
00166
00167
00168 if (!is_array($config)) {
00169
00170
00171
00172 if ($config instanceof Zend_Config) {
00173 $config = $config->toArray();
00174 } else {
00178 require_once 'Zend/Db/Adapter/Exception.php';
00179 throw new Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object');
00180 }
00181 }
00182
00183 $this->_checkRequiredOptions($config);
00184
00185 $options = array(
00186 Zend_Db::CASE_FOLDING => $this->_caseFolding,
00187 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
00188 );
00189 $driverOptions = array();
00190
00191
00192
00193
00194 if (array_key_exists('options', $config)) {
00195
00196 foreach ((array) $config['options'] as $key => $value) {
00197 $options[$key] = $value;
00198 }
00199 }
00200 if (array_key_exists('driver_options', $config)) {
00201 if (!empty($config['driver_options'])) {
00202
00203 foreach ((array) $config['driver_options'] as $key => $value) {
00204 $driverOptions[$key] = $value;
00205 }
00206 }
00207 }
00208
00209 if (!isset($config['charset'])) {
00210 $config['charset'] = null;
00211 }
00212
00213 if (!isset($config['persistent'])) {
00214 $config['persistent'] = false;
00215 }
00216
00217 $this->_config = array_merge($this->_config, $config);
00218 $this->_config['options'] = $options;
00219 $this->_config['driver_options'] = $driverOptions;
00220
00221
00222
00223 if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) {
00224 $case = (int) $options[Zend_Db::CASE_FOLDING];
00225 switch ($case) {
00226 case Zend_Db::CASE_LOWER:
00227 case Zend_Db::CASE_UPPER:
00228 case Zend_Db::CASE_NATURAL:
00229 $this->_caseFolding = $case;
00230 break;
00231 default:
00233 require_once 'Zend/Db/Adapter/Exception.php';
00234 throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: '
00235 . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER');
00236 }
00237 }
00238
00239
00240 if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
00241 $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];
00242 }
00243
00244
00245 if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) {
00246 $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION];
00247 }
00248
00249
00250 if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) {
00251 $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE];
00252 }
00253
00254
00255 $profiler = false;
00256 if (array_key_exists(Zend_Db::PROFILER, $this->_config)) {
00257 $profiler = $this->_config[Zend_Db::PROFILER];
00258 unset($this->_config[Zend_Db::PROFILER]);
00259 }
00260 $this->setProfiler($profiler);
00261 }
00262
00270 protected function _checkRequiredOptions(array $config)
00271 {
00272
00273 if (! array_key_exists('dbname', $config)) {
00275 require_once 'Zend/Db/Adapter/Exception.php';
00276 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance");
00277 }
00278
00279 if (! array_key_exists('password', $config)) {
00283 require_once 'Zend/Db/Adapter/Exception.php';
00284 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials");
00285 }
00286
00287 if (! array_key_exists('username', $config)) {
00291 require_once 'Zend/Db/Adapter/Exception.php';
00292 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials");
00293 }
00294 }
00295
00302 public function getConnection()
00303 {
00304 $this->_connect();
00305 return $this->_connection;
00306 }
00307
00313 public function getConfig()
00314 {
00315 return $this->_config;
00316 }
00317
00346 public function setProfiler($profiler)
00347 {
00348 $enabled = null;
00349 $profilerClass = $this->_defaultProfilerClass;
00350 $profilerInstance = null;
00351
00352 if ($profilerIsObject = is_object($profiler)) {
00353 if ($profiler instanceof Zend_Db_Profiler) {
00354 $profilerInstance = $profiler;
00355 } else if ($profiler instanceof Zend_Config) {
00356 $profiler = $profiler->toArray();
00357 } else {
00361 require_once 'Zend/Db/Profiler/Exception.php';
00362 throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler'
00363 . ' or Zend_Config when provided as an object');
00364 }
00365 }
00366
00367 if (is_array($profiler)) {
00368 if (isset($profiler['enabled'])) {
00369 $enabled = (bool) $profiler['enabled'];
00370 }
00371 if (isset($profiler['class'])) {
00372 $profilerClass = $profiler['class'];
00373 }
00374 if (isset($profiler['instance'])) {
00375 $profilerInstance = $profiler['instance'];
00376 }
00377 } else if (!$profilerIsObject) {
00378 $enabled = (bool) $profiler;
00379 }
00380
00381 if ($profilerInstance === null) {
00382 if (!class_exists($profilerClass)) {
00383 require_once 'Zend/Loader.php';
00384 Zend_Loader::loadClass($profilerClass);
00385 }
00386 $profilerInstance = new $profilerClass();
00387 }
00388
00389 if (!$profilerInstance instanceof Zend_Db_Profiler) {
00391 require_once 'Zend/Db/Profiler/Exception.php';
00392 throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend '
00393 . 'Zend_Db_Profiler');
00394 }
00395
00396 if (null !== $enabled) {
00397 $profilerInstance->setEnabled($enabled);
00398 }
00399
00400 $this->_profiler = $profilerInstance;
00401
00402 return $this;
00403 }
00404
00405
00411 public function getProfiler()
00412 {
00413 return $this->_profiler;
00414 }
00415
00421 public function getStatementClass()
00422 {
00423 return $this->_defaultStmtClass;
00424 }
00425
00431 public function setStatementClass($class)
00432 {
00433 $this->_defaultStmtClass = $class;
00434 return $this;
00435 }
00436
00445 public function query($sql, $bind = array())
00446 {
00447
00448 $this->_connect();
00449
00450
00451 if ($sql instanceof Zend_Db_Select) {
00452 if (empty($bind)) {
00453 $bind = $sql->getBind();
00454 }
00455
00456 $sql = $sql->assemble();
00457 }
00458
00459
00460
00461
00462 if (!is_array($bind)) {
00463 $bind = array($bind);
00464 }
00465
00466
00467 $stmt = $this->prepare($sql);
00468 $stmt->execute($bind);
00469
00470
00471 $stmt->setFetchMode($this->_fetchMode);
00472 return $stmt;
00473 }
00474
00480 public function beginTransaction()
00481 {
00482 $this->_connect();
00483 $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION);
00484 $this->_beginTransaction();
00485 $this->_profiler->queryEnd($q);
00486 return $this;
00487 }
00488
00494 public function commit()
00495 {
00496 $this->_connect();
00497 $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION);
00498 $this->_commit();
00499 $this->_profiler->queryEnd($q);
00500 return $this;
00501 }
00502
00508 public function rollBack()
00509 {
00510 $this->_connect();
00511 $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION);
00512 $this->_rollBack();
00513 $this->_profiler->queryEnd($q);
00514 return $this;
00515 }
00516
00524 public function insert($table, array $bind)
00525 {
00526
00527 $cols = array();
00528 $vals = array();
00529 foreach ($bind as $col => $val) {
00530 $cols[] = $this->quoteIdentifier($col, true);
00531 if ($val instanceof Zend_Db_Expr) {
00532 $vals[] = $val->__toString();
00533 unset($bind[$col]);
00534 } else {
00535 $vals[] = '?';
00536 }
00537 }
00538
00539
00540 $sql = "INSERT INTO "
00541 . $this->quoteIdentifier($table, true)
00542 . ' (' . implode(', ', $cols) . ') '
00543 . 'VALUES (' . implode(', ', $vals) . ')';
00544
00545
00546 $stmt = $this->query($sql, array_values($bind));
00547 $result = $stmt->rowCount();
00548 return $result;
00549 }
00550
00559 public function update($table, array $bind, $where = '')
00560 {
00565 $set = array();
00566 $i = 0;
00567 foreach ($bind as $col => $val) {
00568 if ($val instanceof Zend_Db_Expr) {
00569 $val = $val->__toString();
00570 unset($bind[$col]);
00571 } else {
00572 if ($this->supportsParameters('positional')) {
00573 $val = '?';
00574 } else {
00575 if ($this->supportsParameters('named')) {
00576 unset($bind[$col]);
00577 $bind[':'.$col.$i] = $val;
00578 $val = ':'.$col.$i;
00579 $i++;
00580 } else {
00582 require_once 'Zend/Db/Adapter/Exception.php';
00583 throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding");
00584 }
00585 }
00586 }
00587 $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val;
00588 }
00589
00590 $where = $this->_whereExpr($where);
00591
00595 $sql = "UPDATE "
00596 . $this->quoteIdentifier($table, true)
00597 . ' SET ' . implode(', ', $set)
00598 . (($where) ? " WHERE $where" : '');
00599
00603 if ($this->supportsParameters('positional')) {
00604 $stmt = $this->query($sql, array_values($bind));
00605 } else {
00606 $stmt = $this->query($sql, $bind);
00607 }
00608 $result = $stmt->rowCount();
00609 return $result;
00610 }
00611
00619 public function delete($table, $where = '')
00620 {
00621 $where = $this->_whereExpr($where);
00622
00626 $sql = "DELETE FROM "
00627 . $this->quoteIdentifier($table, true)
00628 . (($where) ? " WHERE $where" : '');
00629
00633 $stmt = $this->query($sql);
00634 $result = $stmt->rowCount();
00635 return $result;
00636 }
00637
00645 protected function _whereExpr($where)
00646 {
00647 if (empty($where)) {
00648 return $where;
00649 }
00650 if (!is_array($where)) {
00651 $where = array($where);
00652 }
00653 foreach ($where as $cond => &$term) {
00654
00655 if (is_int($cond)) {
00656
00657 if ($term instanceof Zend_Db_Expr) {
00658 $term = $term->__toString();
00659 }
00660 } else {
00661
00662
00663 $term = $this->quoteInto($cond, $term);
00664 }
00665 $term = '(' . $term . ')';
00666 }
00667
00668 $where = implode(' AND ', $where);
00669 return $where;
00670 }
00671
00677 public function select()
00678 {
00679 return new Zend_Db_Select($this);
00680 }
00681
00687 public function getFetchMode()
00688 {
00689 return $this->_fetchMode;
00690 }
00691
00701 public function fetchAll($sql, $bind = array(), $fetchMode = null)
00702 {
00703 if ($fetchMode === null) {
00704 $fetchMode = $this->_fetchMode;
00705 }
00706 $stmt = $this->query($sql, $bind);
00707 $result = $stmt->fetchAll($fetchMode);
00708 return $result;
00709 }
00710
00720 public function fetchRow($sql, $bind = array(), $fetchMode = null)
00721 {
00722 if ($fetchMode === null) {
00723 $fetchMode = $this->_fetchMode;
00724 }
00725 $stmt = $this->query($sql, $bind);
00726 $result = $stmt->fetch($fetchMode);
00727 return $result;
00728 }
00729
00743 public function fetchAssoc($sql, $bind = array())
00744 {
00745 $stmt = $this->query($sql, $bind);
00746 $data = array();
00747 while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) {
00748 $tmp = array_values(array_slice($row, 0, 1));
00749 $data[$tmp[0]] = $row;
00750 }
00751 return $data;
00752 }
00753
00763 public function fetchCol($sql, $bind = array())
00764 {
00765 $stmt = $this->query($sql, $bind);
00766 $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0);
00767 return $result;
00768 }
00769
00780 public function fetchPairs($sql, $bind = array())
00781 {
00782 $stmt = $this->query($sql, $bind);
00783 $data = array();
00784 while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) {
00785 $data[$row[0]] = $row[1];
00786 }
00787 return $data;
00788 }
00789
00797 public function fetchOne($sql, $bind = array())
00798 {
00799 $stmt = $this->query($sql, $bind);
00800 $result = $stmt->fetchColumn(0);
00801 return $result;
00802 }
00803
00810 protected function _quote($value)
00811 {
00812 if (is_int($value)) {
00813 return $value;
00814 } elseif (is_float($value)) {
00815 return sprintf('%F', $value);
00816 }
00817 return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
00818 }
00819
00830 public function quote($value, $type = null)
00831 {
00832 $this->_connect();
00833
00834 if ($value instanceof Zend_Db_Select) {
00835 return '(' . $value->assemble() . ')';
00836 }
00837
00838 if ($value instanceof Zend_Db_Expr) {
00839 return $value->__toString();
00840 }
00841
00842 if (is_array($value)) {
00843 foreach ($value as &$val) {
00844 $val = $this->quote($val, $type);
00845 }
00846 return implode(', ', $value);
00847 }
00848
00849 if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) {
00850 $quotedValue = '0';
00851 switch ($this->_numericDataTypes[$type]) {
00852 case Zend_Db::INT_TYPE:
00853 $quotedValue = (string) intval($value);
00854 break;
00855 case Zend_Db::BIGINT_TYPE:
00856
00857
00858
00859 if (preg_match('/^(
00860 [+-]? # optional sign
00861 (?:
00862 0[Xx][\da-fA-F]+ # ODBC-style hexadecimal
00863 |\d+ # decimal or octal, or MySQL ZEROFILL decimal
00864 (?:[eE][+-]?\d+)? # optional exponent on decimals or octals
00865 )
00866 )/x',
00867 (string) $value, $matches)) {
00868 $quotedValue = $matches[1];
00869 }
00870 break;
00871 case Zend_Db::FLOAT_TYPE:
00872 $quotedValue = sprintf('%F', $value);
00873 }
00874 return $quotedValue;
00875 }
00876
00877 return $this->_quote($value);
00878 }
00879
00899 public function quoteInto($text, $value, $type = null, $count = null)
00900 {
00901 if ($count === null) {
00902 return str_replace('?', $this->quote($value, $type), $text);
00903 } else {
00904 while ($count > 0) {
00905 if (strpos($text, '?') !== false) {
00906 $text = substr_replace($text, $this->quote($value, $type), strpos($text, '?'), 1);
00907 }
00908 --$count;
00909 }
00910 return $text;
00911 }
00912 }
00913
00936 public function quoteIdentifier($ident, $auto=false)
00937 {
00938 return $this->_quoteIdentifierAs($ident, null, $auto);
00939 }
00940
00949 public function quoteColumnAs($ident, $alias, $auto=false)
00950 {
00951 return $this->_quoteIdentifierAs($ident, $alias, $auto);
00952 }
00953
00962 public function quoteTableAs($ident, $alias = null, $auto = false)
00963 {
00964 return $this->_quoteIdentifierAs($ident, $alias, $auto);
00965 }
00966
00976 protected function _quoteIdentifierAs($ident, $alias = null, $auto = false, $as = ' AS ')
00977 {
00978 if ($ident instanceof Zend_Db_Expr) {
00979 $quoted = $ident->__toString();
00980 } elseif ($ident instanceof Zend_Db_Select) {
00981 $quoted = '(' . $ident->assemble() . ')';
00982 } else {
00983 if (is_string($ident)) {
00984 $ident = explode('.', $ident);
00985 }
00986 if (is_array($ident)) {
00987 $segments = array();
00988 foreach ($ident as $segment) {
00989 if ($segment instanceof Zend_Db_Expr) {
00990 $segments[] = $segment->__toString();
00991 } else {
00992 $segments[] = $this->_quoteIdentifier($segment, $auto);
00993 }
00994 }
00995 if ($alias !== null && end($ident) == $alias) {
00996 $alias = null;
00997 }
00998 $quoted = implode('.', $segments);
00999 } else {
01000 $quoted = $this->_quoteIdentifier($ident, $auto);
01001 }
01002 }
01003 if ($alias !== null) {
01004 $quoted .= $as . $this->_quoteIdentifier($alias, $auto);
01005 }
01006 return $quoted;
01007 }
01008
01016 protected function _quoteIdentifier($value, $auto=false)
01017 {
01018 if ($auto === false || $this->_autoQuoteIdentifiers === true) {
01019 $q = $this->getQuoteIdentifierSymbol();
01020 return ($q . str_replace("$q", "$q$q", $value) . $q);
01021 }
01022 return $value;
01023 }
01024
01030 public function getQuoteIdentifierSymbol()
01031 {
01032 return '"';
01033 }
01034
01043 public function lastSequenceId($sequenceName)
01044 {
01045 return null;
01046 }
01047
01056 public function nextSequenceId($sequenceName)
01057 {
01058 return null;
01059 }
01060
01073 public function foldCase($key)
01074 {
01075 switch ($this->_caseFolding) {
01076 case Zend_Db::CASE_LOWER:
01077 $value = strtolower((string) $key);
01078 break;
01079 case Zend_Db::CASE_UPPER:
01080 $value = strtoupper((string) $key);
01081 break;
01082 case Zend_Db::CASE_NATURAL:
01083 default:
01084 $value = (string) $key;
01085 }
01086 return $value;
01087 }
01088
01096 public function __sleep()
01097 {
01098 if ($this->_allowSerialization == false) {
01100 require_once 'Zend/Db/Adapter/Exception.php';
01101 throw new Zend_Db_Adapter_Exception(get_class($this) ." is not allowed to be serialized");
01102 }
01103 $this->_connection = false;
01104 return array_keys(array_diff_key(get_object_vars($this), array('_connection'=>false)));
01105 }
01106
01112 public function __wakeup()
01113 {
01114 if ($this->_autoReconnectOnUnserialize == true) {
01115 $this->getConnection();
01116 }
01117 }
01118
01128 abstract public function listTables();
01129
01157 abstract public function describeTable($tableName, $schemaName = null);
01158
01164 abstract protected function _connect();
01165
01171 abstract public function isConnected();
01172
01178 abstract public function closeConnection();
01179
01186 abstract public function prepare($sql);
01187
01202 abstract public function lastInsertId($tableName = null, $primaryKey = null);
01203
01207 abstract protected function _beginTransaction();
01208
01212 abstract protected function _commit();
01213
01217 abstract protected function _rollBack();
01218
01226 abstract public function setFetchMode($mode);
01227
01236 abstract public function limit($sql, $count, $offset = 0);
01237
01244 abstract public function supportsParameters($type);
01245
01251 abstract public function getServerVersion();
01252 }