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() : '')); } }