diff --git a/application/MantisBT/Db/DriverAbstract.php b/application/MantisBT/Db/DriverAbstract.php index 13eea82f87..3e6503b3fe 100644 --- a/application/MantisBT/Db/DriverAbstract.php +++ b/application/MantisBT/Db/DriverAbstract.php @@ -19,7 +19,8 @@ namespace MantisBT\Db; use MantisBT\Db\PDO\Mysql; -use MantisBT\Exception\Db; +use MantisBT\Exception\Database\ParameterCountMismatch; +use MantisBT\Exception\Database\QueryFailed; use MantisBT\Exception\UnspecifiedException; /** @@ -147,16 +148,10 @@ protected function queryStart( $sql, array $params=null ) { $this->queries++; } - /** - * Called immediately after each db query. - * @param mixed db specific result - * @return void - */ - public function queryEnd( $result ) { - if ( $result !== false ) { - return; - } - } + /** + * Called immediately after each db query. + */ + public function queryEnd() {} /** * Reset internal column details cache @@ -202,36 +197,35 @@ public function perfGetQueries() { } /** - * Verify sql parameters - * @param string $sql query or part of it - * @param array $params query parameters - * @return array (sql, params, type of params) - */ - public function checkSqlParameters($sql, array $params=null) { - $params = (array)$params; // make null array if needed - - // cast booleans to 1/0 int - foreach ($params as $key => $value) { - $params[$key] = is_bool($value) ? (int)$value : $value; - } + * Verify parameters to SQL query string + * @param string $sql SQL query string (or a portion thereof) + * @param array $parameters Query parameters + * @return array An array containing: [0] = SQL query string, [1] = array of parameters + */ + public function checkSqlParameters($queryString, array $parameters = null) { + $expectedParameterCount = substr_count($queryString, '?'); + $actualParameterCount = 0; + if ($parameters !== null) { + $actualParameterCount = count($parameters); + } else { + $parameters = array(); + } - $t_count = substr_count($sql, '?'); + if ($expectedParameterCount !== $actualParameterCount) { + throw new ParameterCountMismatch($queryString, $parameters); + } - if (!$t_count) { - return array($sql, array() ); - } + if ($actualParameterCount === 0) { + return array($queryString, array()); + } else { + // cast booleans to 1/0 int + foreach ($parameters as $parameterName => $parameterValue) { + $parameters[$parameterName] = is_bool($parameterValue) ? (int)$parameterValue : $parameterValue; + } - if ($t_count == count($params)) { - return array($sql, array_values($params)); + return array($queryString, array_values($parameters)); } - - $a = new stdClass; - $a->expected = $t_count; - $a->actual = count($params); - $a->sql = $sql; - $a->params = $params; - throw new Db( ERROR_DB_QUERY_FAILED, $a ); - } + } public function getTableNamePrefix() { return $this->tableNamePrefix; diff --git a/application/MantisBT/Db/DriverInterface.php b/application/MantisBT/Db/DriverInterface.php index 6694ff3ee1..cadbd25c6d 100644 --- a/application/MantisBT/Db/DriverInterface.php +++ b/application/MantisBT/Db/DriverInterface.php @@ -89,12 +89,10 @@ public function dispose(); */ public function queryStart( $sql, array $params=null ); - /** - * Called immediately after each db query. - * @param mixed db specific result - * @return void - */ - public function queryEnd( $result ); + /** + * Called immediately after each db query. + */ + public function queryEnd(); /** * Returns database server info array @@ -102,11 +100,6 @@ public function queryEnd( $result ); */ public function getServerInfo(); - /** - * Returns last error reported by database engine. - * @return string error message - */ - public function getLastError(); /** * Return tables in database WITHOUT current prefix diff --git a/application/MantisBT/Db/PDO/Mysql.php b/application/MantisBT/Db/PDO/Mysql.php index 3e0e755cca..a3daf01fc3 100644 --- a/application/MantisBT/Db/PDO/Mysql.php +++ b/application/MantisBT/Db/PDO/Mysql.php @@ -15,12 +15,14 @@ # # You should have received a copy of the GNU General Public License # along with MantisBT. If not, see . + namespace MantisBT\Db\PDO; -use MantisBT\Db\DriverInterface; -use MantisBT\Db\PDO\PDOAbstract; -use MantisBT\Exception\Db AS DbException; + use \PDO; use \PDOException; +use MantisBT\Db\DriverInterface; +use MantisBT\Db\PDO\PDOAbstract; +use MantisBT\Exception\Database\QueryFailed; /** * MYSQL PDO driver class. @@ -86,9 +88,8 @@ public function databaseExists( $name ) { $sql = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?"; try { $result = $this->execute( $sql, array( $name ) ); - } catch (PDOException $ex) { - throw new DbException(ERROR_DB_QUERY_FAILED, $ex->getMessage()); - return false; + } catch (PDOException $exception) { + throw new QueryFailed($exception->getCode(), $exception->getMessage(), $sql); } if ($result) { $value = $result->fetch(); diff --git a/application/MantisBT/Db/PDO/PDOAbstract.php b/application/MantisBT/Db/PDO/PDOAbstract.php index 302b912cec..95e223796f 100644 --- a/application/MantisBT/Db/PDO/PDOAbstract.php +++ b/application/MantisBT/Db/PDO/PDOAbstract.php @@ -18,12 +18,12 @@ namespace MantisBT\Db\PDO; +use \PDO; +use \PDOException; use MantisBT\Db\DriverAbstract; use MantisBT\Exception\Database\ConnectionFailed; use MantisBT\Exception\Database\DatabaseTypeNotSupported; -use MantisBT\Exception\Db AS DbException; -use \PDO; -use \PDOException; +use MantisBT\Exception\Database\QueryFailed; /** * Abstract PDO database driver class. @@ -32,8 +32,15 @@ */ abstract class PDOAbstract extends DriverAbstract { protected $pdb; - protected $lastError = null; + /** + * Connect to a database using PDO + * @param string $dsn Database Source Name (DSN) for the connection + * @param string $dbHost Hostname or IP address of the database server + * @param string $dbUser Username + * @param string $dbPass Password + * @param array $dbOptions Optional configuration to pass to PDO + */ public function connect($dsn, $dbHost, $dbUser, $dbPass, $dbName, array $dbOptions = null) { $driverStatus = $this->driverInstalled(); if ($driverStatus !== true) { @@ -46,14 +53,13 @@ public function connect($dsn, $dbHost, $dbUser, $dbPass, $dbName, array $dbOptio $this->dbName = $dbName; try { - $this->pdb = new PDO( $this->getDsn(), $this->dbUser, $this->dbPass, $this->getPdoOptions()); + $this->pdb = new PDO($this->getDsn(), $this->dbUser, $this->dbPass, $this->getPdoOptions()); $this->pdb->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); $this->pdb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->postConnect(); } catch (PDOException $exception) { throw new ConnectionFailed($exception->getCode(), $exception->getMessage()); } - return true; } /** @@ -121,43 +127,33 @@ public function getInsertId( $table ) { } } - /** - * Returns last error reported by database engine. - * @return string error message - */ - public function getLastError() { - return $this->lastError; - } + /** + * Execute SQL query + * @param string $sql Query string + * @param array $params Array of parameters to insert into query string + * @return PDOStatement Resulting handle for the executed prepared statement + */ + public function execute($queryString, array $parameters = null) { + list( $sql, $params ) = $this->checkSqlParameters($queryString, $parameters); + $queryString = $this->remapTableNames($queryString); - /** - * Execute SQL query. - * @param string $sql query - * @param array $params query parameters - * @return bool success - */ - public function execute( $sql, array $params=null ) { - list( $sql, $params ) = $this->checkSqlParameters($sql, $params); - $sql = $this->remapTableNames($sql); + $this->queryStart($queryString, $parameters); + + try { + $sth = $this->pdb->prepare($queryString); + $sth->execute($parameters); + } catch (PDOException $exception) { + throw new QueryFailed($exception->getCode(), $exception->getMessage(), $queryString); + } - $result = true; - $this->queryStart( $sql, $params ); + $this->queryEnd(); - try { - $sth = $this->pdb->prepare( $sql ); - $sth->execute( $params ); - } catch ( PDOException $ex ) { - $this->lastError = $ex->getMessage(); - $result = false; - } - - $this->queryEnd( $result ); - return $result == true ? $sth : false; - } + return $sth; + } /** */ public function queryStart( $sql, array $params=null ) { - $this->lastError = null; parent::queryStart( $sql, $params ); } diff --git a/application/MantisBT/Error.php b/application/MantisBT/Error.php index 84bf265586..fd4848b7c6 100644 --- a/application/MantisBT/Error.php +++ b/application/MantisBT/Error.php @@ -82,7 +82,7 @@ public static function error_handler( $type, $error, $file, $line, $context ) { $errorInfo->file = $file; $errorInfo->line = $line; $errorInfo->context = $context; - $errorInfo->trace = debug_backtrace(); + $errorInfo->trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT); self::$allErrors[] = $errorInfo; @@ -135,8 +135,8 @@ public static function shutdown_error_handler() { $errorInfo->message = $error['message']; $errorInfo->file = $error['file']; $errorInfo->line = $error['line']; - $errorInfo->trace = debug_backtrace(); - $errorInfo->context = null; + $errorInfo->trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT); + $errorInfo->context = null; self::$allErrors[] = $errorInfo; } @@ -295,7 +295,6 @@ public static function error_print_stack_trace( $stack ) { # remove the call to the error handler from the stack trace array_shift( $stack ); - foreach( $stack as $frame ) { echo ''; echo '', ( isset( $frame['file'] ) ? htmlentities( $frame['file'], ENT_COMPAT, 'UTF-8' ) : '-' ), '', ( isset( $frame['line'] ) ? $frame['line'] : '-' ), '', ( isset( $frame['class'] ) ? $frame['class'] : '-' ), '', ( isset( $frame['type'] ) ? $frame['type'] : '-' ), '', ( isset( $frame['function'] ) ? $frame['function'] : '-' ), ''; diff --git a/application/MantisBT/Exception/Database/ParameterCountMismatch.php b/application/MantisBT/Exception/Database/ParameterCountMismatch.php new file mode 100644 index 0000000000..9a8b0a51d9 --- /dev/null +++ b/application/MantisBT/Exception/Database/ParameterCountMismatch.php @@ -0,0 +1,18 @@ +responseCode = 500; + } +} diff --git a/application/MantisBT/Exception/Database/QueryFailed.php b/application/MantisBT/Exception/Database/QueryFailed.php new file mode 100644 index 0000000000..3e49df03c7 --- /dev/null +++ b/application/MantisBT/Exception/Database/QueryFailed.php @@ -0,0 +1,14 @@ +responseCode = 500; + } +} diff --git a/application/MantisBT/Exception/Db.php b/application/MantisBT/Exception/Db.php deleted file mode 100644 index f3d06098ad..0000000000 --- a/application/MantisBT/Exception/Db.php +++ /dev/null @@ -1,17 +0,0 @@ -rowCount(); } /** - * Retrieve the next row returned from a specific database query - * @param bool|ADORecordSet $p_result Database Query Record Set to retrieve next result for. - * @return array Database result + * Retrieve the next row returned from a database query. + * @param mixed Result of an executed prepared statement + * @return array An array of the next row of the query results */ -function db_fetch_array( &$result ) { +function db_fetch_array( $result ) { return $result->fetch(); } @@ -382,19 +372,6 @@ function db_field_names( $tableName ) { return is_array( $columns ) ? $columns : array(); } -/** - * send both the error number and error message and query (optional) as paramaters for a triggered error - * @todo Use/Behaviour of this function should be reviewed before 1.2.0 final - */ -function db_error( $query = null ) { - global $g_db; - if( null !== $query ) { - error_parameters( /* $g_db->ErrorNo(), */ $g_db->getLastError(), $query ); - } else { - error_parameters( /* $g_db->ErrorNo(), */ $g_db->getLastError() ); - } -} - /** * close the connection. * Not really necessary most of the time since a connection is automatically closed when a page finishes loading.