From: Alexander Ebert Date: Sat, 9 Mar 2019 18:53:20 +0000 (+0100) Subject: In debug mode: Throw errors if reading from prepared statements without executing... X-Git-Tag: 5.2.0_Alpha_1~236 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=e71908190aa3b1f5fa32ede74c1670902d708936;p=GitHub%2FWoltLab%2FWCF.git In debug mode: Throw errors if reading from prepared statements without executing them See #2819 --- diff --git a/wcfsetup/install/files/lib/system/database/Database.class.php b/wcfsetup/install/files/lib/system/database/Database.class.php index 37120ee87b..0d6f6b73f9 100644 --- a/wcfsetup/install/files/lib/system/database/Database.class.php +++ b/wcfsetup/install/files/lib/system/database/Database.class.php @@ -5,6 +5,7 @@ use wcf\system\database\editor\DatabaseEditor; use wcf\system\database\exception\DatabaseException as GenericDatabaseException; use wcf\system\database\exception\DatabaseQueryException; use wcf\system\database\exception\DatabaseTransactionException; +use wcf\system\database\statement\DebugPreparedStatement; use wcf\system\database\statement\PreparedStatement; use wcf\system\WCF; @@ -115,6 +116,10 @@ abstract class Database { $this->failsafeTest = $failsafeTest; $this->tryToCreateDatabase = $tryToCreateDatabase; + if (defined('ENABLE_DEBUG_MODE') && ENABLE_DEBUG_MODE) { + $this->preparedStatementClassName = DebugPreparedStatement::class; + } + // connect database $this->connect(); } diff --git a/wcfsetup/install/files/lib/system/database/statement/DebugPreparedStatement.class.php b/wcfsetup/install/files/lib/system/database/statement/DebugPreparedStatement.class.php new file mode 100644 index 0000000000..43073a8566 --- /dev/null +++ b/wcfsetup/install/files/lib/system/database/statement/DebugPreparedStatement.class.php @@ -0,0 +1,98 @@ + + * @package WoltLabSuite\Core\System\Database\Statement + */ +class DebugPreparedStatement extends PreparedStatement { + protected $debugDidExecuteOnce = false; + + /** + * @inheritDoc + */ + public function __call($name, $arguments) { + if ($name === 'fetchAll' || $name === 'fetchColumn') { + $this->debugThrowIfNotExecutedBefore(); + } + + return parent::__call($name, $arguments); + } + + /** + * @inheritDoc + */ + public function execute(array $parameters = []) { + $this->debugDidExecuteOnce = true; + + parent::execute($parameters); + } + + /** + * @inheritDoc + */ + public function fetchArray($type = null) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchArray($type); + } + + /** + * @inheritDoc + */ + public function fetchSingleRow($type = null) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchSingleRow($type); + } + + /** + * @inheritDoc + */ + public function fetchSingleColumn($columnNumber = 0) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchSingleColumn($columnNumber); + } + + /** + * @inheritDoc + */ + public function fetchObject($className) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchObject($className); + } + + /** + * @inheritDoc + */ + public function fetchObjects($className, $keyProperty = null) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchObjects($className, $keyProperty); + } + + /** + * @inheritDoc + */ + public function fetchMap($keyColumn, $valueColumn, $uniqueKey = true) { + $this->debugThrowIfNotExecutedBefore(); + + return parent::fetchMap($keyColumn, $valueColumn, $uniqueKey); + } + + /** + * @inheritDoc + */ + protected function debugThrowIfNotExecutedBefore() { + if (!$this->debugDidExecuteOnce) { + throw new \RuntimeException('Attempted to fetch data from a statement without executing it at least once.'); + } + } +}