| /** | |
| * Zend Framework | |
| * | |
| * LICENSE | |
| * | |
| * This source file is subject to the new BSD license that is bundled | |
| * with this package in the file LICENSE.txt. | |
| * It is also available through the world-wide-web at this URL: | |
| * http://framework.zend.com/license/new-bsd | |
| * If you did not receive a copy of the license and are unable to | |
| * obtain it through the world-wide-web, please send an email | |
| * to license@zend.com so we can send you a copy immediately. | |
| * | |
| * @category Zend | |
| * @package Zend_Db | |
| * @subpackage Statement | |
| * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) | |
| * @license http://framework.zend.com/license/new-bsd New BSD License | |
| * @version $Id: Statement.php 23775 2011-03-01 17:25:24Z ralph $ | |
| */ | |
| /** | |
| * @see Zend_Db | |
| */ | |
| // require_once 'Zend/Db.php'; | |
| /** | |
| * @see Zend_Db_Statement_Interface | |
| */ | |
| // require_once 'Zend/Db/Statement/Interface.php'; | |
| /** | |
| * Abstract class to emulate a PDOStatement for native database adapters. | |
| * | |
| * @category Zend | |
| * @package Zend_Db | |
| * @subpackage Statement | |
| * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) | |
| * @license http://framework.zend.com/license/new-bsd New BSD License | |
| */ | |
| abstract class Zend_Db_Statement implements Zend_Db_Statement_Interface | |
| { | |
| /** | |
| * @var resource|object The driver level statement object/resource | |
| */ | |
| protected $_stmt = null; | |
| /** | |
| * @var Zend_Db_Adapter_Abstract | |
| */ | |
| protected $_adapter = null; | |
| /** | |
| * The current fetch mode. | |
| * | |
| * @var integer | |
| */ | |
| protected $_fetchMode = Zend_Db::FETCH_ASSOC; | |
| /** | |
| * Attributes. | |
| * | |
| * @var array | |
| */ | |
| protected $_attribute = array(); | |
| /** | |
| * Column result bindings. | |
| * | |
| * @var array | |
| */ | |
| protected $_bindColumn = array(); | |
| /** | |
| * Query parameter bindings; covers bindParam() and bindValue(). | |
| * | |
| * @var array | |
| */ | |
| protected $_bindParam = array(); | |
| /** | |
| * SQL string split into an array at placeholders. | |
| * | |
| * @var array | |
| */ | |
| protected $_sqlSplit = array(); | |
| /** | |
| * Parameter placeholders in the SQL string by position in the split array. | |
| * | |
| * @var array | |
| */ | |
| protected $_sqlParam = array(); | |
| /** | |
| * @var Zend_Db_Profiler_Query | |
| */ | |
| protected $_queryId = null; | |
| /** | |
| * Constructor for a statement. | |
| * | |
| * @param Zend_Db_Adapter_Abstract $adapter | |
| * @param mixed $sql Either a string or Zend_Db_Select. | |
| */ | |
| public function __construct($adapter, $sql) | |
| { | |
| $this->_adapter = $adapter; | |
| if ($sql instanceof Zend_Db_Select) { | |
| $sql = $sql->assemble(); | |
| } | |
| $this->_parseParameters($sql); | |
| $this->_prepare($sql); | |
| $this->_queryId = $this->_adapter->getProfiler()->queryStart($sql); | |
| } | |
| /** | |
| * Internal method called by abstract statment constructor to setup | |
| * the driver level statement | |
| * | |
| * @return void | |
| */ | |
| protected function _prepare($sql) | |
| { | |
| return; | |
| } | |
| /** | |
| * @param string $sql | |
| * @return void | |
| */ | |
| protected function _parseParameters($sql) | |
| { | |
| $sql = $this->_stripQuoted($sql); | |
| // split into text and params | |
| $this->_sqlSplit = preg_split('/(\?|\:[a-zA-Z0-9_]+)/', | |
| $sql, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); | |
| // map params | |
| $this->_sqlParam = array(); | |
| foreach ($this->_sqlSplit as $key => $val) { | |
| if ($val == '?') { | |
| if ($this->_adapter->supportsParameters('positional') === false) { | |
| /** | |
| * @see Zend_Db_Statement_Exception | |
| */ | |
| // require_once 'Zend/Db/Statement/Exception.php'; | |
| throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$val'"); | |
| } | |
| } else if ($val[0] == ':') { | |
| if ($this->_adapter->supportsParameters('named') === false) { | |
| /** | |
| * @see Zend_Db_Statement_Exception | |
| */ | |
| // require_once 'Zend/Db/Statement/Exception.php'; | |
| throw new Zend_Db_Statement_Exception("Invalid bind-variable name '$val'"); | |
| } | |
| } | |
| $this->_sqlParam[] = $val; | |
| } | |
| // set up for binding | |
| $this->_bindParam = array(); | |
| } | |
| /** | |
| * Remove parts of a SQL string that contain quoted strings | |
| * of values or identifiers. | |
| * | |
| * @param string $sql | |
| * @return string | |
| */ | |
| protected function _stripQuoted($sql) | |
| { | |
| // get the character for delimited id quotes, | |
| // this is usually " but in MySQL is ` | |
| $d = $this->_adapter->quoteIdentifier('a'); | |
| $d = $d[0]; | |
| // get the value used as an escaped delimited id quote, | |
| // e.g. \" or "" or \` | |
| $de = $this->_adapter->quoteIdentifier($d); | |
| $de = substr($de, 1, 2); | |
| $de = str_replace('\\', '\\\\', $de); | |
| // get the character for value quoting | |
| // this should be ' | |
| $q = $this->_adapter->quote('a'); | |
| $q = $q[0]; | |
| // get the value used as an escaped quote, | |
| // e.g. \' or '' | |
| $qe = $this->_adapter->quote($q); | |
| $qe = substr($qe, 1, 2); | |
| $qe = str_replace('\\', '\\\\', $qe); | |
| // get a version of the SQL statement with all quoted | |
| // values and delimited identifiers stripped out | |
| // remove "foo\"bar" | |
| $sql = preg_replace("/$q($qe|\\\\{2}|[^$q])*$q/", '', $sql); | |
| // remove 'foo\'bar' | |
| if (!empty($q)) { | |
| $sql = preg_replace("/$q($qe|[^$q])*$q/", '', $sql); | |
| } | |
| return $sql; | |
| } | |
| /** | |
| * Bind a column of the statement result set to a PHP variable. | |
| * | |
| * @param string $column Name the column in the result set, either by | |
| * position or by name. | |
| * @param mixed $param Reference to the PHP variable containing the value. | |
| * @param mixed $type OPTIONAL | |
| * @return bool | |
| */ | |
| public function bindColumn($column, &$param, $type = null) | |
| { | |
| $this->_bindColumn[$column] =& $param; | |
| return true; | |
| } | |
| /** | |
| * Binds a parameter to the specified variable name. | |
| * | |
| * @param mixed $parameter Name the parameter, either integer or string. | |
| * @param mixed $variable Reference to PHP variable containing the value. | |
| * @param mixed $type OPTIONAL Datatype of SQL parameter. | |
| * @param mixed $length OPTIONAL Length of SQL parameter. | |
| * @param mixed $options OPTIONAL Other options. | |
| * @return bool | |
| */ | |
| public function bindParam($parameter, &$variable, $type = null, $length = null, $options = null) | |
| { | |
| if (!is_int($parameter) && !is_string($parameter)) { | |
| /** | |
| * @see Zend_Db_Statement_Exception | |
| */ | |
| // require_once 'Zend/Db/Statement/Exception.php'; | |
| throw new Zend_Db_Statement_Exception('Invalid bind-variable position'); | |
| } | |
| $position = null; | |
| if (($intval = (int) $parameter) > 0 && $this->_adapter->supportsParameters('positional')) { | |
| if ($intval >= 1 || $intval <= count($this->_sqlParam)) { | |
| $position = $intval; | |
| } | |
| } else if ($this->_adapter->supportsParameters('named')) { | |
| if ($parameter[0] != ':') { | |
| $parameter = ':' . $parameter; | |
| } | |
| if (in_array($parameter, $this->_sqlParam) !== false) { | |
| $position = $parameter; | |
| } | |
| } | |
| if ($position === null) { | |
| /** | |
| * @see Zend_Db_Statement_Exception | |
| */ | |
| // require_once 'Zend/Db/Statement/Exception.php'; | |
| throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$parameter'"); | |
| } | |
| // Finally we are assured that $position is valid | |
| $this->_bindParam[$position] =& $variable; | |
| return $this->_bindParam($position, $variable, $type, $length, $options); | |
| } | |
| /** | |
| * Binds a value to a parameter. | |
| * | |
| * @param mixed $parameter Name the parameter, either integer or string. | |
| * @param mixed $value Scalar value to bind to the parameter. | |
| * @param mixed $type OPTIONAL Datatype of the parameter. | |
| * @return bool | |
| */ | |
| public function bindValue($parameter, $value, $type = null) | |
| { | |
| return $this->bindParam($parameter, $value, $type); | |
| } | |
| /** | |
| * Executes a prepared statement. | |
| * | |
| * @param array $params OPTIONAL Values to bind to parameter placeholders. | |
| * @return bool | |
| */ | |
| public function execute(?array $params = null) | |
| { | |
| /* | |
| * Simple case - no query profiler to manage. | |
| */ | |
| if ($this->_queryId === null) { | |
| return $this->_execute($params); | |
| } | |
| /* | |
| * Do the same thing, but with query profiler | |
| * management before and after the execute. | |
| */ | |
| $prof = $this->_adapter->getProfiler(); | |
| $qp = $prof->getQueryProfile($this->_queryId); | |
| if ($qp->hasEnded()) { | |
| $this->_queryId = $prof->queryClone($qp); | |
| $qp = $prof->getQueryProfile($this->_queryId); | |
| } | |
| if ($params !== null) { | |
| $qp->bindParams($params); | |
| } else { | |
| $qp->bindParams($this->_bindParam); | |
| } | |
| $qp->start($this->_queryId); | |
| $retval = $this->_execute($params); | |
| $prof->queryEnd($this->_queryId); | |
| return $retval; | |
| } | |
| /** | |
| * Returns an array containing all of the result set rows. | |
| * | |
| * @param int $style OPTIONAL Fetch mode. | |
| * @param int $col OPTIONAL Column number, if fetch mode is by column. | |
| * @return array Collection of rows, each in a format by the fetch mode. | |
| */ | |
| public function fetchAll($style = null, $col = null) | |
| { | |
| $data = array(); | |
| if ($style === Zend_Db::FETCH_COLUMN && $col === null) { | |
| $col = 0; | |
| } | |
| if ($col === null) { | |
| while ($row = $this->fetch($style)) { | |
| $data[] = $row; | |
| } | |
| } else { | |
| while (false !== ($val = $this->fetchColumn($col))) { | |
| $data[] = $val; | |
| } | |
| } | |
| return $data; | |
| } | |
| /** | |
| * Returns a single column from the next row of a result set. | |
| * | |
| * @param int $col OPTIONAL Position of the column to fetch. | |
| * @return string One value from the next row of result set, or false. | |
| */ | |
| public function fetchColumn($col = 0) | |
| { | |
| $data = array(); | |
| $col = (int) $col; | |
| $row = $this->fetch(Zend_Db::FETCH_NUM); | |
| if (!is_array($row)) { | |
| return false; | |
| } | |
| return $row[$col]; | |
| } | |
| /** | |
| * Fetches the next row and returns it as an object. | |
| * | |
| * @param string $class OPTIONAL Name of the class to create. | |
| * @param array $config OPTIONAL Constructor arguments for the class. | |
| * @return mixed One object instance of the specified class, or false. | |
| */ | |
| public function fetchObject($class = 'stdClass', array $config = array()) | |
| { | |
| $obj = new $class($config); | |
| $row = $this->fetch(Zend_Db::FETCH_ASSOC); | |
| if (!is_array($row)) { | |
| return false; | |
| } | |
| foreach ($row as $key => $val) { | |
| $obj->$key = $val; | |
| } | |
| return $obj; | |
| } | |
| /** | |
| * Retrieve a statement attribute. | |
| * | |
| * @param string $key Attribute name. | |
| * @return mixed Attribute value. | |
| */ | |
| public function getAttribute($key) | |
| { | |
| if (array_key_exists($key, $this->_attribute)) { | |
| return $this->_attribute[$key]; | |
| } | |
| } | |
| /** | |
| * Set a statement attribute. | |
| * | |
| * @param string $key Attribute name. | |
| * @param mixed $val Attribute value. | |
| * @return bool | |
| */ | |
| public function setAttribute($key, $val) | |
| { | |
| $this->_attribute[$key] = $val; | |
| } | |
| /** | |
| * Set the default fetch mode for this statement. | |
| * | |
| * @param int $mode The fetch mode. | |
| * @return bool | |
| * @throws Zend_Db_Statement_Exception | |
| */ | |
| public function setFetchMode($mode) | |
| { | |
| switch ($mode) { | |
| case Zend_Db::FETCH_NUM: | |
| case Zend_Db::FETCH_ASSOC: | |
| case Zend_Db::FETCH_BOTH: | |
| case Zend_Db::FETCH_OBJ: | |
| $this->_fetchMode = $mode; | |
| break; | |
| case Zend_Db::FETCH_BOUND: | |
| default: | |
| $this->closeCursor(); | |
| /** | |
| * @see Zend_Db_Statement_Exception | |
| */ | |
| // require_once 'Zend/Db/Statement/Exception.php'; | |
| throw new Zend_Db_Statement_Exception('invalid fetch mode'); | |
| break; | |
| } | |
| } | |
| /** | |
| * Helper function to map retrieved row | |
| * to bound column variables | |
| * | |
| * @param array $row | |
| * @return bool True | |
| */ | |
| public function _fetchBound($row) | |
| { | |
| foreach ($row as $key => $value) { | |
| // bindColumn() takes 1-based integer positions | |
| // but fetch() returns 0-based integer indexes | |
| if (is_int($key)) { | |
| $key++; | |
| } | |
| // set results only to variables that were bound previously | |
| if (isset($this->_bindColumn[$key])) { | |
| $this->_bindColumn[$key] = $value; | |
| } | |
| } | |
| return true; | |
| } | |
| /** | |
| * Gets the Zend_Db_Adapter_Abstract for this | |
| * particular Zend_Db_Statement object. | |
| * | |
| * @return Zend_Db_Adapter_Abstract | |
| */ | |
| public function getAdapter() | |
| { | |
| return $this->_adapter; | |
| } | |
| /** | |
| * Gets the resource or object setup by the | |
| * _parse | |
| * @return unknown_type | |
| */ | |
| public function getDriverStatement() | |
| { | |
| return $this->_stmt; | |
| } | |
| } | |