File indexing completed on 2025-01-19 05:21:02
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Adapter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Db 0026 */ 0027 // require_once 'Zend/Db.php'; 0028 0029 /** 0030 * @see Zend_Db_Select 0031 */ 0032 // require_once 'Zend/Db/Select.php'; 0033 0034 /** 0035 * Class for connecting to SQL databases and performing common operations. 0036 * 0037 * @category Zend 0038 * @package Zend_Db 0039 * @subpackage Adapter 0040 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0041 * @license http://framework.zend.com/license/new-bsd New BSD License 0042 */ 0043 abstract class Zend_Db_Adapter_Abstract 0044 { 0045 0046 /** 0047 * User-provided configuration 0048 * 0049 * @var array 0050 */ 0051 protected $_config = array(); 0052 0053 /** 0054 * Fetch mode 0055 * 0056 * @var integer 0057 */ 0058 protected $_fetchMode = Zend_Db::FETCH_ASSOC; 0059 0060 /** 0061 * Query profiler object, of type Zend_Db_Profiler 0062 * or a subclass of that. 0063 * 0064 * @var Zend_Db_Profiler 0065 */ 0066 protected $_profiler; 0067 0068 /** 0069 * Default class name for a DB statement. 0070 * 0071 * @var string 0072 */ 0073 protected $_defaultStmtClass = 'Zend_Db_Statement'; 0074 0075 /** 0076 * Default class name for the profiler object. 0077 * 0078 * @var string 0079 */ 0080 protected $_defaultProfilerClass = 'Zend_Db_Profiler'; 0081 0082 /** 0083 * Database connection 0084 * 0085 * @var object|resource|null 0086 */ 0087 protected $_connection = null; 0088 0089 /** 0090 * Specifies the case of column names retrieved in queries 0091 * Options 0092 * Zend_Db::CASE_NATURAL (default) 0093 * Zend_Db::CASE_LOWER 0094 * Zend_Db::CASE_UPPER 0095 * 0096 * @var integer 0097 */ 0098 protected $_caseFolding = Zend_Db::CASE_NATURAL; 0099 0100 /** 0101 * Specifies whether the adapter automatically quotes identifiers. 0102 * If true, most SQL generated by Zend_Db classes applies 0103 * identifier quoting automatically. 0104 * If false, developer must quote identifiers themselves 0105 * by calling quoteIdentifier(). 0106 * 0107 * @var bool 0108 */ 0109 protected $_autoQuoteIdentifiers = true; 0110 0111 /** 0112 * Keys are UPPERCASE SQL datatypes or the constants 0113 * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. 0114 * 0115 * Values are: 0116 * 0 = 32-bit integer 0117 * 1 = 64-bit integer 0118 * 2 = float or decimal 0119 * 0120 * @var array Associative array of datatypes to values 0, 1, or 2. 0121 */ 0122 protected $_numericDataTypes = array( 0123 Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, 0124 Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, 0125 Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE 0126 ); 0127 0128 /** Weither or not that object can get serialized 0129 * 0130 * @var bool 0131 */ 0132 protected $_allowSerialization = true; 0133 0134 /** 0135 * Weither or not the database should be reconnected 0136 * to that adapter when waking up 0137 * 0138 * @var bool 0139 */ 0140 protected $_autoReconnectOnUnserialize = false; 0141 0142 /** 0143 * Constructor. 0144 * 0145 * $config is an array of key/value pairs or an instance of Zend_Config 0146 * containing configuration options. These options are common to most adapters: 0147 * 0148 * dbname => (string) The name of the database to user 0149 * username => (string) Connect to the database as this username. 0150 * password => (string) Password associated with the username. 0151 * host => (string) What host to connect to, defaults to localhost 0152 * 0153 * Some options are used on a case-by-case basis by adapters: 0154 * 0155 * port => (string) The port of the database 0156 * persistent => (boolean) Whether to use a persistent connection or not, defaults to false 0157 * protocol => (string) The network protocol, defaults to TCPIP 0158 * caseFolding => (int) style of case-alteration used for identifiers 0159 * socket => (string) The socket or named pipe that should be used 0160 * 0161 * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data 0162 * @throws Zend_Db_Adapter_Exception 0163 */ 0164 public function __construct($config) 0165 { 0166 /* 0167 * Verify that adapter parameters are in an array. 0168 */ 0169 if (!is_array($config)) { 0170 /* 0171 * Convert Zend_Config argument to a plain array. 0172 */ 0173 if ($config instanceof Zend_Config) { 0174 $config = $config->toArray(); 0175 } else { 0176 /** 0177 * @see Zend_Db_Adapter_Exception 0178 */ 0179 // require_once 'Zend/Db/Adapter/Exception.php'; 0180 throw new Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object'); 0181 } 0182 } 0183 0184 $this->_checkRequiredOptions($config); 0185 0186 $options = array( 0187 Zend_Db::CASE_FOLDING => $this->_caseFolding, 0188 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers, 0189 Zend_Db::FETCH_MODE => $this->_fetchMode, 0190 ); 0191 $driverOptions = array(); 0192 0193 /* 0194 * normalize the config and merge it with the defaults 0195 */ 0196 if (array_key_exists('options', $config)) { 0197 // can't use array_merge() because keys might be integers 0198 foreach ((array) $config['options'] as $key => $value) { 0199 $options[$key] = $value; 0200 } 0201 } 0202 if (array_key_exists('driver_options', $config)) { 0203 if (!empty($config['driver_options'])) { 0204 // can't use array_merge() because keys might be integers 0205 foreach ((array) $config['driver_options'] as $key => $value) { 0206 $driverOptions[$key] = $value; 0207 } 0208 } 0209 } 0210 0211 if (!isset($config['charset'])) { 0212 $config['charset'] = null; 0213 } 0214 0215 if (!isset($config['persistent'])) { 0216 $config['persistent'] = false; 0217 } 0218 0219 $this->_config = array_merge($this->_config, $config); 0220 $this->_config['options'] = $options; 0221 $this->_config['driver_options'] = $driverOptions; 0222 0223 0224 // obtain the case setting, if there is one 0225 if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) { 0226 $case = (int) $options[Zend_Db::CASE_FOLDING]; 0227 switch ($case) { 0228 case Zend_Db::CASE_LOWER: 0229 case Zend_Db::CASE_UPPER: 0230 case Zend_Db::CASE_NATURAL: 0231 $this->_caseFolding = $case; 0232 break; 0233 default: 0234 /** @see Zend_Db_Adapter_Exception */ 0235 // require_once 'Zend/Db/Adapter/Exception.php'; 0236 throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: ' 0237 . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER'); 0238 } 0239 } 0240 0241 if (array_key_exists(Zend_Db::FETCH_MODE, $options)) { 0242 if (is_string($options[Zend_Db::FETCH_MODE])) { 0243 $constant = 'Zend_Db::FETCH_' . strtoupper($options[Zend_Db::FETCH_MODE]); 0244 if(defined($constant)) { 0245 $options[Zend_Db::FETCH_MODE] = constant($constant); 0246 } 0247 } 0248 $this->setFetchMode((int) $options[Zend_Db::FETCH_MODE]); 0249 } 0250 0251 // obtain quoting property if there is one 0252 if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) { 0253 $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS]; 0254 } 0255 0256 // obtain allow serialization property if there is one 0257 if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) { 0258 $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION]; 0259 } 0260 0261 // obtain auto reconnect on unserialize property if there is one 0262 if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) { 0263 $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE]; 0264 } 0265 0266 // create a profiler object 0267 $profiler = false; 0268 if (array_key_exists(Zend_Db::PROFILER, $this->_config)) { 0269 $profiler = $this->_config[Zend_Db::PROFILER]; 0270 unset($this->_config[Zend_Db::PROFILER]); 0271 } 0272 $this->setProfiler($profiler); 0273 } 0274 0275 /** 0276 * Check for config options that are mandatory. 0277 * Throw exceptions if any are missing. 0278 * 0279 * @param array $config 0280 * @throws Zend_Db_Adapter_Exception 0281 */ 0282 protected function _checkRequiredOptions(array $config) 0283 { 0284 // we need at least a dbname 0285 if (! array_key_exists('dbname', $config)) { 0286 /** @see Zend_Db_Adapter_Exception */ 0287 // require_once 'Zend/Db/Adapter/Exception.php'; 0288 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); 0289 } 0290 0291 if (! array_key_exists('password', $config)) { 0292 /** 0293 * @see Zend_Db_Adapter_Exception 0294 */ 0295 // require_once 'Zend/Db/Adapter/Exception.php'; 0296 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials"); 0297 } 0298 0299 if (! array_key_exists('username', $config)) { 0300 /** 0301 * @see Zend_Db_Adapter_Exception 0302 */ 0303 // require_once 'Zend/Db/Adapter/Exception.php'; 0304 throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials"); 0305 } 0306 } 0307 0308 /** 0309 * Returns the underlying database connection object or resource. 0310 * If not presently connected, this initiates the connection. 0311 * 0312 * @return object|resource|null 0313 */ 0314 public function getConnection() 0315 { 0316 $this->_connect(); 0317 return $this->_connection; 0318 } 0319 0320 /** 0321 * Returns the configuration variables in this adapter. 0322 * 0323 * @return array 0324 */ 0325 public function getConfig() 0326 { 0327 return $this->_config; 0328 } 0329 0330 /** 0331 * Set the adapter's profiler object. 0332 * 0333 * The argument may be a boolean, an associative array, an instance of 0334 * Zend_Db_Profiler, or an instance of Zend_Config. 0335 * 0336 * A boolean argument sets the profiler to enabled if true, or disabled if 0337 * false. The profiler class is the adapter's default profiler class, 0338 * Zend_Db_Profiler. 0339 * 0340 * An instance of Zend_Db_Profiler sets the adapter's instance to that 0341 * object. The profiler is enabled and disabled separately. 0342 * 0343 * An associative array argument may contain any of the keys 'enabled', 0344 * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the 0345 * boolean and object types documented above. The 'class' key is used to name a 0346 * class to use for a custom profiler. The class must be Zend_Db_Profiler or a 0347 * subclass. The class is instantiated with no constructor arguments. The 'class' 0348 * option is ignored when the 'instance' option is supplied. 0349 * 0350 * An object of type Zend_Config may contain the properties 'enabled', 'class', and 0351 * 'instance', just as if an associative array had been passed instead. 0352 * 0353 * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler 0354 * @return Zend_Db_Adapter_Abstract Provides a fluent interface 0355 * @throws Zend_Db_Profiler_Exception if the object instance or class specified 0356 * is not Zend_Db_Profiler or an extension of that class. 0357 */ 0358 public function setProfiler($profiler) 0359 { 0360 $enabled = null; 0361 $profilerClass = $this->_defaultProfilerClass; 0362 $profilerInstance = null; 0363 0364 if ($profilerIsObject = is_object($profiler)) { 0365 if ($profiler instanceof Zend_Db_Profiler) { 0366 $profilerInstance = $profiler; 0367 } else if ($profiler instanceof Zend_Config) { 0368 $profiler = $profiler->toArray(); 0369 } else { 0370 /** 0371 * @see Zend_Db_Profiler_Exception 0372 */ 0373 // require_once 'Zend/Db/Profiler/Exception.php'; 0374 throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler' 0375 . ' or Zend_Config when provided as an object'); 0376 } 0377 } 0378 0379 if (is_array($profiler)) { 0380 if (isset($profiler['enabled'])) { 0381 $enabled = (bool) $profiler['enabled']; 0382 } 0383 if (isset($profiler['class'])) { 0384 $profilerClass = $profiler['class']; 0385 } 0386 if (isset($profiler['instance'])) { 0387 $profilerInstance = $profiler['instance']; 0388 } 0389 } else if (!$profilerIsObject) { 0390 $enabled = (bool) $profiler; 0391 } 0392 0393 if ($profilerInstance === null) { 0394 if (!class_exists($profilerClass)) { 0395 // require_once 'Zend/Loader.php'; 0396 Zend_Loader::loadClass($profilerClass); 0397 } 0398 $profilerInstance = new $profilerClass(); 0399 } 0400 0401 if (!$profilerInstance instanceof Zend_Db_Profiler) { 0402 /** @see Zend_Db_Profiler_Exception */ 0403 // require_once 'Zend/Db/Profiler/Exception.php'; 0404 throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend ' 0405 . 'Zend_Db_Profiler'); 0406 } 0407 0408 if (null !== $enabled) { 0409 $profilerInstance->setEnabled($enabled); 0410 } 0411 0412 $this->_profiler = $profilerInstance; 0413 0414 return $this; 0415 } 0416 0417 0418 /** 0419 * Returns the profiler for this adapter. 0420 * 0421 * @return Zend_Db_Profiler 0422 */ 0423 public function getProfiler() 0424 { 0425 return $this->_profiler; 0426 } 0427 0428 /** 0429 * Get the default statement class. 0430 * 0431 * @return string 0432 */ 0433 public function getStatementClass() 0434 { 0435 return $this->_defaultStmtClass; 0436 } 0437 0438 /** 0439 * Set the default statement class. 0440 * 0441 * @return Zend_Db_Adapter_Abstract Fluent interface 0442 */ 0443 public function setStatementClass($class) 0444 { 0445 $this->_defaultStmtClass = $class; 0446 return $this; 0447 } 0448 0449 /** 0450 * Prepares and executes an SQL statement with bound data. 0451 * 0452 * @param mixed $sql The SQL statement with placeholders. 0453 * May be a string or Zend_Db_Select. 0454 * @param mixed $bind An array of data to bind to the placeholders. 0455 * @return Zend_Db_Statement_Interface 0456 */ 0457 public function query($sql, $bind = array()) 0458 { 0459 // connect to the database if needed 0460 $this->_connect(); 0461 0462 // is the $sql a Zend_Db_Select object? 0463 if ($sql instanceof Zend_Db_Select) { 0464 if (empty($bind)) { 0465 $bind = $sql->getBind(); 0466 } 0467 0468 $sql = $sql->assemble(); 0469 } 0470 0471 // make sure $bind to an array; 0472 // don't use (array) typecasting because 0473 // because $bind may be a Zend_Db_Expr object 0474 if (!is_array($bind)) { 0475 $bind = array($bind); 0476 } 0477 0478 // prepare and execute the statement with profiling 0479 $stmt = $this->prepare($sql); 0480 $stmt->execute($bind); 0481 0482 // return the results embedded in the prepared statement object 0483 $stmt->setFetchMode($this->_fetchMode); 0484 return $stmt; 0485 } 0486 0487 /** 0488 * Leave autocommit mode and begin a transaction. 0489 * 0490 * @return Zend_Db_Adapter_Abstract 0491 */ 0492 public function beginTransaction() 0493 { 0494 $this->_connect(); 0495 $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION); 0496 $this->_beginTransaction(); 0497 $this->_profiler->queryEnd($q); 0498 return $this; 0499 } 0500 0501 /** 0502 * Commit a transaction and return to autocommit mode. 0503 * 0504 * @return Zend_Db_Adapter_Abstract 0505 */ 0506 public function commit() 0507 { 0508 $this->_connect(); 0509 $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION); 0510 $this->_commit(); 0511 $this->_profiler->queryEnd($q); 0512 return $this; 0513 } 0514 0515 /** 0516 * Roll back a transaction and return to autocommit mode. 0517 * 0518 * @return Zend_Db_Adapter_Abstract 0519 */ 0520 public function rollBack() 0521 { 0522 $this->_connect(); 0523 $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION); 0524 $this->_rollBack(); 0525 $this->_profiler->queryEnd($q); 0526 return $this; 0527 } 0528 0529 /** 0530 * Inserts a table row with specified data. 0531 * 0532 * @param mixed $table The table to insert data into. 0533 * @param array $bind Column-value pairs. 0534 * @return int The number of affected rows. 0535 * @throws Zend_Db_Adapter_Exception 0536 */ 0537 public function insert($table, array $bind) 0538 { 0539 // extract and quote col names from the array keys 0540 $cols = array(); 0541 $vals = array(); 0542 $i = 0; 0543 foreach ($bind as $col => $val) { 0544 $cols[] = $this->quoteIdentifier($col, true); 0545 if ($val instanceof Zend_Db_Expr) { 0546 $vals[] = $val->__toString(); 0547 unset($bind[$col]); 0548 } else { 0549 if ($this->supportsParameters('positional')) { 0550 $vals[] = '?'; 0551 } else { 0552 if ($this->supportsParameters('named')) { 0553 unset($bind[$col]); 0554 $bind[':col'.$i] = $val; 0555 $vals[] = ':col'.$i; 0556 $i++; 0557 } else { 0558 /** @see Zend_Db_Adapter_Exception */ 0559 // require_once 'Zend/Db/Adapter/Exception.php'; 0560 throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); 0561 } 0562 } 0563 } 0564 } 0565 0566 // build the statement 0567 $sql = "INSERT INTO " 0568 . $this->quoteIdentifier($table, true) 0569 . ' (' . implode(', ', $cols) . ') ' 0570 . 'VALUES (' . implode(', ', $vals) . ')'; 0571 0572 // execute the statement and return the number of affected rows 0573 if ($this->supportsParameters('positional')) { 0574 $bind = array_values($bind); 0575 } 0576 $stmt = $this->query($sql, $bind); 0577 $result = $stmt->rowCount(); 0578 return $result; 0579 } 0580 0581 /** 0582 * Updates table rows with specified data based on a WHERE clause. 0583 * 0584 * @param mixed $table The table to update. 0585 * @param array $bind Column-value pairs. 0586 * @param mixed $where UPDATE WHERE clause(s). 0587 * @return int The number of affected rows. 0588 * @throws Zend_Db_Adapter_Exception 0589 */ 0590 public function update($table, array $bind, $where = '') 0591 { 0592 /** 0593 * Build "col = ?" pairs for the statement, 0594 * except for Zend_Db_Expr which is treated literally. 0595 */ 0596 $set = array(); 0597 $i = 0; 0598 foreach ($bind as $col => $val) { 0599 if ($val instanceof Zend_Db_Expr) { 0600 $val = $val->__toString(); 0601 unset($bind[$col]); 0602 } else { 0603 if ($this->supportsParameters('positional')) { 0604 $val = '?'; 0605 } else { 0606 if ($this->supportsParameters('named')) { 0607 unset($bind[$col]); 0608 $bind[':col'.$i] = $val; 0609 $val = ':col'.$i; 0610 $i++; 0611 } else { 0612 /** @see Zend_Db_Adapter_Exception */ 0613 // require_once 'Zend/Db/Adapter/Exception.php'; 0614 throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); 0615 } 0616 } 0617 } 0618 $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val; 0619 } 0620 0621 $where = $this->_whereExpr($where); 0622 0623 /** 0624 * Build the UPDATE statement 0625 */ 0626 $sql = "UPDATE " 0627 . $this->quoteIdentifier($table, true) 0628 . ' SET ' . implode(', ', $set) 0629 . (($where) ? " WHERE $where" : ''); 0630 0631 /** 0632 * Execute the statement and return the number of affected rows 0633 */ 0634 if ($this->supportsParameters('positional')) { 0635 $stmt = $this->query($sql, array_values($bind)); 0636 } else { 0637 $stmt = $this->query($sql, $bind); 0638 } 0639 $result = $stmt->rowCount(); 0640 return $result; 0641 } 0642 0643 /** 0644 * Deletes table rows based on a WHERE clause. 0645 * 0646 * @param mixed $table The table to update. 0647 * @param mixed $where DELETE WHERE clause(s). 0648 * @return int The number of affected rows. 0649 */ 0650 public function delete($table, $where = '') 0651 { 0652 $where = $this->_whereExpr($where); 0653 0654 /** 0655 * Build the DELETE statement 0656 */ 0657 $sql = "DELETE FROM " 0658 . $this->quoteIdentifier($table, true) 0659 . (($where) ? " WHERE $where" : ''); 0660 0661 /** 0662 * Execute the statement and return the number of affected rows 0663 */ 0664 $stmt = $this->query($sql); 0665 $result = $stmt->rowCount(); 0666 return $result; 0667 } 0668 0669 /** 0670 * Convert an array, string, or Zend_Db_Expr object 0671 * into a string to put in a WHERE clause. 0672 * 0673 * @param mixed $where 0674 * @return string 0675 */ 0676 protected function _whereExpr($where) 0677 { 0678 if (empty($where)) { 0679 return $where; 0680 } 0681 if (!is_array($where)) { 0682 $where = array($where); 0683 } 0684 foreach ($where as $cond => &$term) { 0685 // is $cond an int? (i.e. Not a condition) 0686 if (is_int($cond)) { 0687 // $term is the full condition 0688 if ($term instanceof Zend_Db_Expr) { 0689 $term = $term->__toString(); 0690 } 0691 } else { 0692 // $cond is the condition with placeholder, 0693 // and $term is quoted into the condition 0694 $term = $this->quoteInto($cond, $term); 0695 } 0696 $term = '(' . $term . ')'; 0697 } 0698 0699 $where = implode(' AND ', $where); 0700 return $where; 0701 } 0702 0703 /** 0704 * Creates and returns a new Zend_Db_Select object for this adapter. 0705 * 0706 * @return Zend_Db_Select 0707 */ 0708 public function select() 0709 { 0710 return new Zend_Db_Select($this); 0711 } 0712 0713 /** 0714 * Get the fetch mode. 0715 * 0716 * @return int 0717 */ 0718 public function getFetchMode() 0719 { 0720 return $this->_fetchMode; 0721 } 0722 0723 /** 0724 * Fetches all SQL result rows as a sequential array. 0725 * Uses the current fetchMode for the adapter. 0726 * 0727 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0728 * @param mixed $bind Data to bind into SELECT placeholders. 0729 * @param mixed $fetchMode Override current fetch mode. 0730 * @return array 0731 */ 0732 public function fetchAll($sql, $bind = array(), $fetchMode = null) 0733 { 0734 if ($fetchMode === null) { 0735 $fetchMode = $this->_fetchMode; 0736 } 0737 $stmt = $this->query($sql, $bind); 0738 $result = $stmt->fetchAll($fetchMode); 0739 return $result; 0740 } 0741 0742 /** 0743 * Fetches the first row of the SQL result. 0744 * Uses the current fetchMode for the adapter. 0745 * 0746 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0747 * @param mixed $bind Data to bind into SELECT placeholders. 0748 * @param mixed $fetchMode Override current fetch mode. 0749 * @return mixed Array, object, or scalar depending on fetch mode. 0750 */ 0751 public function fetchRow($sql, $bind = array(), $fetchMode = null) 0752 { 0753 if ($fetchMode === null) { 0754 $fetchMode = $this->_fetchMode; 0755 } 0756 $stmt = $this->query($sql, $bind); 0757 $result = $stmt->fetch($fetchMode); 0758 return $result; 0759 } 0760 0761 /** 0762 * Fetches all SQL result rows as an associative array. 0763 * 0764 * The first column is the key, the entire row array is the 0765 * value. You should construct the query to be sure that 0766 * the first column contains unique values, or else 0767 * rows with duplicate values in the first column will 0768 * overwrite previous data. 0769 * 0770 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0771 * @param mixed $bind Data to bind into SELECT placeholders. 0772 * @return array 0773 */ 0774 public function fetchAssoc($sql, $bind = array()) 0775 { 0776 $stmt = $this->query($sql, $bind); 0777 $data = array(); 0778 while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) { 0779 $tmp = array_values(array_slice($row, 0, 1)); 0780 $data[$tmp[0]] = $row; 0781 } 0782 return $data; 0783 } 0784 0785 /** 0786 * Fetches the first column of all SQL result rows as an array. 0787 * 0788 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0789 * @param mixed $bind Data to bind into SELECT placeholders. 0790 * @return array 0791 */ 0792 public function fetchCol($sql, $bind = array()) 0793 { 0794 $stmt = $this->query($sql, $bind); 0795 $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0); 0796 return $result; 0797 } 0798 0799 /** 0800 * Fetches all SQL result rows as an array of key-value pairs. 0801 * 0802 * The first column is the key, the second column is the 0803 * value. 0804 * 0805 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0806 * @param mixed $bind Data to bind into SELECT placeholders. 0807 * @return array 0808 */ 0809 public function fetchPairs($sql, $bind = array()) 0810 { 0811 $stmt = $this->query($sql, $bind); 0812 $data = array(); 0813 while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) { 0814 $data[$row[0]] = $row[1]; 0815 } 0816 return $data; 0817 } 0818 0819 /** 0820 * Fetches the first column of the first row of the SQL result. 0821 * 0822 * @param string|Zend_Db_Select $sql An SQL SELECT statement. 0823 * @param mixed $bind Data to bind into SELECT placeholders. 0824 * @return string 0825 */ 0826 public function fetchOne($sql, $bind = array()) 0827 { 0828 $stmt = $this->query($sql, $bind); 0829 $result = $stmt->fetchColumn(0); 0830 return $result; 0831 } 0832 0833 /** 0834 * Quote a raw string. 0835 * 0836 * @param string $value Raw string 0837 * @return string Quoted string 0838 */ 0839 protected function _quote($value) 0840 { 0841 if (is_int($value)) { 0842 return $value; 0843 } elseif (is_float($value)) { 0844 return sprintf('%F', $value); 0845 } 0846 return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'"; 0847 } 0848 0849 /** 0850 * Safely quotes a value for an SQL statement. 0851 * 0852 * If an array is passed as the value, the array values are quoted 0853 * and then returned as a comma-separated string. 0854 * 0855 * @param mixed $value The value to quote. 0856 * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null. 0857 * @return mixed An SQL-safe quoted value (or string of separated values). 0858 */ 0859 public function quote($value, $type = null) 0860 { 0861 $this->_connect(); 0862 0863 if ($value instanceof Zend_Db_Select) { 0864 return '(' . $value->assemble() . ')'; 0865 } 0866 0867 if ($value instanceof Zend_Db_Expr) { 0868 return $value->__toString(); 0869 } 0870 0871 if (is_array($value)) { 0872 foreach ($value as &$val) { 0873 $val = $this->quote($val, $type); 0874 } 0875 return implode(', ', $value); 0876 } 0877 0878 if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) { 0879 $quotedValue = '0'; 0880 switch ($this->_numericDataTypes[$type]) { 0881 case Zend_Db::INT_TYPE: // 32-bit integer 0882 $quotedValue = (string) intval($value); 0883 break; 0884 case Zend_Db::BIGINT_TYPE: // 64-bit integer 0885 // ANSI SQL-style hex literals (e.g. x'[\dA-F]+') 0886 // are not supported here, because these are string 0887 // literals, not numeric literals. 0888 if (preg_match('/^( 0889 [+-]? # optional sign 0890 (?: 0891 0[Xx][\da-fA-F]+ # ODBC-style hexadecimal 0892 |\d+ # decimal or octal, or MySQL ZEROFILL decimal 0893 (?:[eE][+-]?\d+)? # optional exponent on decimals or octals 0894 ) 0895 )/x', 0896 (string) $value, $matches)) { 0897 $quotedValue = $matches[1]; 0898 } 0899 break; 0900 case Zend_Db::FLOAT_TYPE: // float or decimal 0901 $quotedValue = sprintf('%F', $value); 0902 } 0903 return $quotedValue; 0904 } 0905 0906 return $this->_quote($value); 0907 } 0908 0909 /** 0910 * Quotes a value and places into a piece of text at a placeholder. 0911 * 0912 * The placeholder is a question-mark; all placeholders will be replaced 0913 * with the quoted value. For example: 0914 * 0915 * <code> 0916 * $text = "WHERE date < ?"; 0917 * $date = "2005-01-02"; 0918 * $safe = $sql->quoteInto($text, $date); 0919 * // $safe = "WHERE date < '2005-01-02'" 0920 * </code> 0921 * 0922 * @param string $text The text with a placeholder. 0923 * @param mixed $value The value to quote. 0924 * @param string $type OPTIONAL SQL datatype 0925 * @param integer $count OPTIONAL count of placeholders to replace 0926 * @return string An SQL-safe quoted value placed into the original text. 0927 */ 0928 public function quoteInto($text, $value, $type = null, $count = null) 0929 { 0930 if ($count === null) { 0931 return str_replace('?', $this->quote($value, $type), $text); 0932 } else { 0933 return implode($this->quote($value, $type), explode('?', $text, $count + 1)); 0934 } 0935 } 0936 0937 /** 0938 * Quotes an identifier. 0939 * 0940 * Accepts a string representing a qualified indentifier. For Example: 0941 * <code> 0942 * $adapter->quoteIdentifier('myschema.mytable') 0943 * </code> 0944 * Returns: "myschema"."mytable" 0945 * 0946 * Or, an array of one or more identifiers that may form a qualified identifier: 0947 * <code> 0948 * $adapter->quoteIdentifier(array('myschema','my.table')) 0949 * </code> 0950 * Returns: "myschema"."my.table" 0951 * 0952 * The actual quote character surrounding the identifiers may vary depending on 0953 * the adapter. 0954 * 0955 * @param string|array|Zend_Db_Expr $ident The identifier. 0956 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. 0957 * @return string The quoted identifier. 0958 */ 0959 public function quoteIdentifier($ident, $auto=false) 0960 { 0961 return $this->_quoteIdentifierAs($ident, null, $auto); 0962 } 0963 0964 /** 0965 * Quote a column identifier and alias. 0966 * 0967 * @param string|array|Zend_Db_Expr $ident The identifier or expression. 0968 * @param string $alias An alias for the column. 0969 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. 0970 * @return string The quoted identifier and alias. 0971 */ 0972 public function quoteColumnAs($ident, $alias, $auto=false) 0973 { 0974 return $this->_quoteIdentifierAs($ident, $alias, $auto); 0975 } 0976 0977 /** 0978 * Quote a table identifier and alias. 0979 * 0980 * @param string|array|Zend_Db_Expr $ident The identifier or expression. 0981 * @param string $alias An alias for the table. 0982 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. 0983 * @return string The quoted identifier and alias. 0984 */ 0985 public function quoteTableAs($ident, $alias = null, $auto = false) 0986 { 0987 return $this->_quoteIdentifierAs($ident, $alias, $auto); 0988 } 0989 0990 /** 0991 * Quote an identifier and an optional alias. 0992 * 0993 * @param string|array|Zend_Db_Expr $ident The identifier or expression. 0994 * @param string $alias An optional alias. 0995 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. 0996 * @param string $as The string to add between the identifier/expression and the alias. 0997 * @return string The quoted identifier and alias. 0998 */ 0999 protected function _quoteIdentifierAs($ident, $alias = null, $auto = false, $as = ' AS ') 1000 { 1001 if ($ident instanceof Zend_Db_Expr) { 1002 $quoted = $ident->__toString(); 1003 } elseif ($ident instanceof Zend_Db_Select) { 1004 $quoted = '(' . $ident->assemble() . ')'; 1005 } else { 1006 if (is_string($ident)) { 1007 $ident = explode('.', $ident); 1008 } 1009 if (is_array($ident)) { 1010 $segments = array(); 1011 foreach ($ident as $segment) { 1012 if ($segment instanceof Zend_Db_Expr) { 1013 $segments[] = $segment->__toString(); 1014 } else { 1015 $segments[] = $this->_quoteIdentifier($segment, $auto); 1016 } 1017 } 1018 if ($alias !== null && end($ident) == $alias) { 1019 $alias = null; 1020 } 1021 $quoted = implode('.', $segments); 1022 } else { 1023 $quoted = $this->_quoteIdentifier($ident, $auto); 1024 } 1025 } 1026 if ($alias !== null) { 1027 $quoted .= $as . $this->_quoteIdentifier($alias, $auto); 1028 } 1029 return $quoted; 1030 } 1031 1032 /** 1033 * Quote an identifier. 1034 * 1035 * @param string $value The identifier or expression. 1036 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. 1037 * @return string The quoted identifier and alias. 1038 */ 1039 protected function _quoteIdentifier($value, $auto=false) 1040 { 1041 if ($auto === false || $this->_autoQuoteIdentifiers === true) { 1042 $q = $this->getQuoteIdentifierSymbol(); 1043 return ($q . str_replace("$q", "$q$q", $value) . $q); 1044 } 1045 return $value; 1046 } 1047 1048 /** 1049 * Returns the symbol the adapter uses for delimited identifiers. 1050 * 1051 * @return string 1052 */ 1053 public function getQuoteIdentifierSymbol() 1054 { 1055 return '"'; 1056 } 1057 1058 /** 1059 * Return the most recent value from the specified sequence in the database. 1060 * This is supported only on RDBMS brands that support sequences 1061 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. 1062 * 1063 * @param string $sequenceName 1064 * @return string 1065 */ 1066 public function lastSequenceId($sequenceName) 1067 { 1068 return null; 1069 } 1070 1071 /** 1072 * Generate a new value from the specified sequence in the database, and return it. 1073 * This is supported only on RDBMS brands that support sequences 1074 * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. 1075 * 1076 * @param string $sequenceName 1077 * @return string 1078 */ 1079 public function nextSequenceId($sequenceName) 1080 { 1081 return null; 1082 } 1083 1084 /** 1085 * Helper method to change the case of the strings used 1086 * when returning result sets in FETCH_ASSOC and FETCH_BOTH 1087 * modes. 1088 * 1089 * This is not intended to be used by application code, 1090 * but the method must be public so the Statement class 1091 * can invoke it. 1092 * 1093 * @param string $key 1094 * @return string 1095 */ 1096 public function foldCase($key) 1097 { 1098 switch ($this->_caseFolding) { 1099 case Zend_Db::CASE_LOWER: 1100 $value = strtolower((string) $key); 1101 break; 1102 case Zend_Db::CASE_UPPER: 1103 $value = strtoupper((string) $key); 1104 break; 1105 case Zend_Db::CASE_NATURAL: 1106 default: 1107 $value = (string) $key; 1108 } 1109 return $value; 1110 } 1111 1112 /** 1113 * called when object is getting serialized 1114 * This disconnects the DB object that cant be serialized 1115 * 1116 * @throws Zend_Db_Adapter_Exception 1117 * @return array 1118 */ 1119 public function __sleep() 1120 { 1121 if ($this->_allowSerialization == false) { 1122 /** @see Zend_Db_Adapter_Exception */ 1123 // require_once 'Zend/Db/Adapter/Exception.php'; 1124 throw new Zend_Db_Adapter_Exception( 1125 get_class($this) . ' is not allowed to be serialized' 1126 ); 1127 } 1128 $this->_connection = null; 1129 1130 return array_keys( 1131 array_diff_key(get_object_vars($this), array('_connection' => null)) 1132 ); 1133 } 1134 1135 /** 1136 * called when object is getting unserialized 1137 * 1138 * @return void 1139 */ 1140 public function __wakeup() 1141 { 1142 if ($this->_autoReconnectOnUnserialize == true) { 1143 $this->getConnection(); 1144 } 1145 } 1146 1147 /** 1148 * Abstract Methods 1149 */ 1150 1151 /** 1152 * Returns a list of the tables in the database. 1153 * 1154 * @return array 1155 */ 1156 abstract public function listTables(); 1157 1158 /** 1159 * Returns the column descriptions for a table. 1160 * 1161 * The return value is an associative array keyed by the column name, 1162 * as returned by the RDBMS. 1163 * 1164 * The value of each array element is an associative array 1165 * with the following keys: 1166 * 1167 * SCHEMA_NAME => string; name of database or schema 1168 * TABLE_NAME => string; 1169 * COLUMN_NAME => string; column name 1170 * COLUMN_POSITION => number; ordinal position of column in table 1171 * DATA_TYPE => string; SQL datatype name of column 1172 * DEFAULT => string; default expression of column, null if none 1173 * NULLABLE => boolean; true if column can have nulls 1174 * LENGTH => number; length of CHAR/VARCHAR 1175 * SCALE => number; scale of NUMERIC/DECIMAL 1176 * PRECISION => number; precision of NUMERIC/DECIMAL 1177 * UNSIGNED => boolean; unsigned property of an integer type 1178 * PRIMARY => boolean; true if column is part of the primary key 1179 * PRIMARY_POSITION => integer; position of column in primary key 1180 * 1181 * @param string $tableName 1182 * @param string $schemaName OPTIONAL 1183 * @return array 1184 */ 1185 abstract public function describeTable($tableName, $schemaName = null); 1186 1187 /** 1188 * Creates a connection to the database. 1189 * 1190 * @return void 1191 */ 1192 abstract protected function _connect(); 1193 1194 /** 1195 * Test if a connection is active 1196 * 1197 * @return boolean 1198 */ 1199 abstract public function isConnected(); 1200 1201 /** 1202 * Force the connection to close. 1203 * 1204 * @return void 1205 */ 1206 abstract public function closeConnection(); 1207 1208 /** 1209 * Prepare a statement and return a PDOStatement-like object. 1210 * 1211 * @param string|Zend_Db_Select $sql SQL query 1212 * @return Zend_Db_Statement|PDOStatement 1213 */ 1214 abstract public function prepare($sql); 1215 1216 /** 1217 * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. 1218 * 1219 * As a convention, on RDBMS brands that support sequences 1220 * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence 1221 * from the arguments and returns the last id generated by that sequence. 1222 * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method 1223 * returns the last value generated for such a column, and the table name 1224 * argument is disregarded. 1225 * 1226 * @param string $tableName OPTIONAL Name of table. 1227 * @param string $primaryKey OPTIONAL Name of primary key column. 1228 * @return string 1229 */ 1230 abstract public function lastInsertId($tableName = null, $primaryKey = null); 1231 1232 /** 1233 * Begin a transaction. 1234 */ 1235 abstract protected function _beginTransaction(); 1236 1237 /** 1238 * Commit a transaction. 1239 */ 1240 abstract protected function _commit(); 1241 1242 /** 1243 * Roll-back a transaction. 1244 */ 1245 abstract protected function _rollBack(); 1246 1247 /** 1248 * Set the fetch mode. 1249 * 1250 * @param integer $mode 1251 * @return void 1252 * @throws Zend_Db_Adapter_Exception 1253 */ 1254 abstract public function setFetchMode($mode); 1255 1256 /** 1257 * Adds an adapter-specific LIMIT clause to the SELECT statement. 1258 * 1259 * @param mixed $sql 1260 * @param integer $count 1261 * @param integer $offset 1262 * @return string 1263 */ 1264 abstract public function limit($sql, $count, $offset = 0); 1265 1266 /** 1267 * Check if the adapter supports real SQL parameters. 1268 * 1269 * @param string $type 'positional' or 'named' 1270 * @return bool 1271 */ 1272 abstract public function supportsParameters($type); 1273 1274 /** 1275 * Retrieve server version in PHP style 1276 * 1277 * @return string 1278 */ 1279 abstract public function getServerVersion(); 1280 }