diff --git a/src/Database/Helpers.php b/src/Database/Helpers.php index c52490ca3..532a8e2d6 100644 --- a/src/Database/Helpers.php +++ b/src/Database/Helpers.php @@ -266,4 +266,27 @@ public static function toPairs(array $rows, $key = NULL, $value = NULL) return $return; } + + /** + * Finds duplicate columns in select statement + * @param \PDOStatement + * @return string + */ + public static function findDuplicates(\PDOStatement $statement) + { + $cols = []; + for ($i = 0; $i < $statement->columnCount(); $i++) { + $meta = $statement->getColumnMeta($i); + $cols[$meta['name']][] = isset($meta['table']) ? $meta['table'] : ''; + } + $duplicates = []; + foreach ($cols as $name => $tables) { + if (count($tables) > 1) { + $tables = array_filter(array_unique($tables)); + $duplicates[] = "'$name'" . ($tables ? ' (from ' . implode(', ', $tables) . ')' : ''); + } + } + return implode(', ', $duplicates); + } + } diff --git a/src/Database/ResultSet.php b/src/Database/ResultSet.php index b8dcc1f8c..579c010b1 100644 --- a/src/Database/ResultSet.php +++ b/src/Database/ResultSet.php @@ -253,6 +253,10 @@ public function fetch() if (!$data) { $this->pdoStatement->closeCursor(); return FALSE; + + } elseif ($this->result === NULL && count($data) !== $this->pdoStatement->columnCount()) { + $duplicates = Helpers::findDuplicates($this->pdoStatement); + trigger_error("Found duplicate columns in database result set: $duplicates.", E_USER_NOTICE); } $row = new Row; @@ -262,10 +266,6 @@ public function fetch() } } - if ($this->result === NULL && count($data) !== $this->pdoStatement->columnCount()) { - trigger_error('Found duplicate columns in database result set.', E_USER_NOTICE); - } - $this->resultKey++; return $this->result = $row; } diff --git a/tests/Database/ResultSet.fetch().phpt b/tests/Database/ResultSet.fetch().phpt index 1dbac5a36..8e3a16937 100644 --- a/tests/Database/ResultSet.fetch().phpt +++ b/tests/Database/ResultSet.fetch().phpt @@ -12,12 +12,27 @@ require __DIR__ . '/connect.inc.php'; // create $connection Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName}-nette_test1.sql"); -test(function () use ($context) { +test(function () use ($context, $driverName) { $res = $context->query('SELECT name, name FROM author'); - + switch ($driverName) { + case 'mysql': + $message = "Found duplicate columns in database result set: 'name' (from author)."; + break; + case 'pgsql': + $message = "Found duplicate columns in database result set: 'name'%a%"; + break; + case 'sqlite': + $message = "Found duplicate columns in database result set: 'name' (from author)."; + break; + case 'sqlsrv': + $message = "Found duplicate columns in database result set: 'name'."; + break; + default: + Assert::fail("Unsupported driver $driverName"); + } Assert::error(function () use ($res) { $res->fetch(); - }, E_USER_NOTICE, 'Found duplicate columns in database result set.'); + }, E_USER_NOTICE, $message); $res->fetch(); }); @@ -35,3 +50,27 @@ test(function () use ($context, $driverName) { // tests closeCursor() foreach ($res as $row) {} } }); + + +test(function () use ($context, $driverName) { + $res = $context->query('SELECT book.id, author.id, author.name, translator.name FROM book JOIN author ON (author.id = book.author_id) JOIN author translator ON (translator.id = book.translator_id)'); + switch ($driverName) { + case 'mysql': + $message = "Found duplicate columns in database result set: 'id' (from book, author), 'name' (from author, translator)."; + break; + case 'pgsql': + $message = "Found duplicate columns in database result set: 'id'%a% 'name'%a%"; + break; + case 'sqlite': + $message = "Found duplicate columns in database result set: 'id' (from book, author), 'name' (from author)."; + break; + case 'sqlsrv': + $message = "Found duplicate columns in database result set: 'id', 'name'."; + break; + default: + Assert::fail("Unsupported driver $driverName"); + } + Assert::error(function() use ($res) { + $res->fetch(); + }, E_USER_NOTICE, $message); +});