diff options
Diffstat (limited to 'vendor/fguillot/picodb/lib/PicoDb/StatementHandler.php')
-rw-r--r-- | vendor/fguillot/picodb/lib/PicoDb/StatementHandler.php | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/vendor/fguillot/picodb/lib/PicoDb/StatementHandler.php b/vendor/fguillot/picodb/lib/PicoDb/StatementHandler.php new file mode 100644 index 00000000..a7021b36 --- /dev/null +++ b/vendor/fguillot/picodb/lib/PicoDb/StatementHandler.php @@ -0,0 +1,353 @@ +<?php + +namespace PicoDb; + +use PDO; +use PDOException; +use PDOStatement; + +/** + * Statement Handler + * + * @package PicoDb + * @author Frederic Guillot + */ +class StatementHandler +{ + /** + * Database instance + * + * @access protected + * @var Database + */ + protected $db = null; + + /** + * Flag to calculate query time + * + * @access protected + * @var boolean + */ + protected $stopwatch = false; + + /** + * Start time + * + * @access protected + * @var float + */ + protected $startTime = 0; + + /** + * Execution time of all queries + * + * @access protected + * @var float + */ + protected $executionTime = 0; + + /** + * Flag to log generated SQL queries + * + * @access protected + * @var boolean + */ + protected $logQueries = false; + + /** + * Run explain command on each query + * + * @access protected + * @var boolean + */ + protected $explain = false; + + /** + * Number of SQL queries executed + * + * @access protected + * @var integer + */ + protected $nbQueries = 0; + + /** + * SQL query + * + * @access protected + * @var string + */ + protected $sql = ''; + + /** + * Positional SQL parameters + * + * @access protected + * @var array + */ + protected $positionalParams = array(); + + /** + * Named SQL parameters + * + * @access protected + * @var array + */ + protected $namedParams = array(); + + /** + * Flag to use named params + * + * @access protected + * @var boolean + */ + protected $useNamedParams = false; + + /** + * LOB params + * + * @access protected + * @var array + */ + protected $lobParams = array(); + + /** + * Constructor + * + * @access public + * @param Database $db + */ + public function __construct(Database $db) + { + $this->db = $db; + } + + /** + * Enable query logging + * + * @access public + * @return $this + */ + public function withLogging() + { + $this->logQueries = true; + return $this; + } + + /** + * Record query execution time + * + * @access public + * @return $this + */ + public function withStopWatch() + { + $this->stopwatch = true; + return $this; + } + + /** + * Execute explain command on query + * + * @access public + * @return $this + */ + public function withExplain() + { + $this->explain = true; + return $this; + } + + /** + * Set SQL query + * + * @access public + * @param string $sql + * @return $this + */ + public function withSql($sql) + { + $this->sql = $sql; + return $this; + } + + /** + * Set positional parameters + * + * @access public + * @param array $params + * @return $this + */ + public function withPositionalParams(array $params) + { + $this->positionalParams = $params; + return $this; + } + + /** + * Set named parameters + * + * @access public + * @param array $params + * @return $this + */ + public function withNamedParams(array $params) + { + $this->namedParams = $params; + $this->useNamedParams = true; + return $this; + } + + /** + * Bind large object parameter + * + * @access public + * @param $name + * @param $fp + * @return $this + */ + public function withLobParam($name, &$fp) + { + $this->lobParams[$name] =& $fp; + return $this; + } + + /** + * Get number of queries executed + * + * @access public + * @return int + */ + public function getNbQueries() + { + return $this->nbQueries; + } + + /** + * Execute a prepared statement + * + * Note: returns false on duplicate keys instead of SQLException + * + * @access public + * @return PDOStatement|false + */ + public function execute() + { + try { + $this->beforeExecute(); + + $pdoStatement = $this->db->getConnection()->prepare($this->sql); + $this->bindParams($pdoStatement); + $pdoStatement->execute(); + + $this->afterExecute(); + return $pdoStatement; + } catch (PDOException $e) { + return $this->handleSqlError($e); + } + } + + /** + * Bind parameters to PDOStatement + * + * @access protected + * @param PDOStatement $pdoStatement + */ + protected function bindParams(PDOStatement $pdoStatement) + { + $i = 1; + + foreach ($this->lobParams as $name => $variable) { + if (! $this->useNamedParams) { + $parameter = $i; + $i++; + } else { + $parameter = $name; + } + + $pdoStatement->bindParam($parameter, $variable, PDO::PARAM_LOB); + } + + foreach ($this->positionalParams as $value) { + $pdoStatement->bindValue($i, $value, PDO::PARAM_STR); + $i++; + } + + foreach ($this->namedParams as $name => $value) { + $pdoStatement->bindValue($name, $value, PDO::PARAM_STR); + } + } + + /** + * Method executed before query execution + * + * @access protected + */ + protected function beforeExecute() + { + if ($this->logQueries) { + $this->db->setLogMessage($this->sql); + } + + if ($this->stopwatch) { + $this->startTime = microtime(true); + } + } + + /** + * Method executed after query execution + * + * @access protected + */ + protected function afterExecute() + { + if ($this->stopwatch) { + $duration = microtime(true) - $this->startTime; + $this->executionTime += $duration; + $this->db->setLogMessage('query_duration='.$duration); + $this->db->setLogMessage('total_execution_time='.$this->executionTime); + } + + if ($this->explain) { + $this->db->setLogMessages($this->db->getDriver()->explain($this->sql, $this->positionalParams)); + } + + $this->nbQueries++; + $this->cleanup(); + } + + /** + * Reset internal properties after execution + * The same object instance is used + * + * @access protected + */ + protected function cleanup() + { + $this->sql = ''; + $this->useNamedParams = false; + $this->positionalParams = array(); + $this->namedParams = array(); + $this->lobParams = array(); + } + + /** + * Handle PDOException + * + * @access public + * @param PDOException $e + * @return bool + * @throws SQLException + */ + public function handleSqlError(PDOException $e) + { + $this->cleanup(); + $this->db->cancelTransaction(); + $this->db->setLogMessage($e->getMessage()); + + if ($this->db->getDriver()->isDuplicateKeyError($e->getCode())) { + return false; + } + + throw new SQLException('SQL error'.($this->logQueries ? ': '.$e->getMessage() : '')); + } +} |