Add Result::fetchAllKeyValue() and ::iterateKeyValue()#4293
Add Result::fetchAllKeyValue() and ::iterateKeyValue()#4293morozov merged 2 commits intodoctrine:3.0.xfrom
Conversation
b2149b6 to
865800f
Compare
greg0ire
left a comment
There was a problem hiding this comment.
Unlike PDO which requires the result to have exactly two columns, DBAL will require at least two columns in order to allow the ROWNUM columns used by the platforms that do not natively support LIIMIT queries (Oracle, IBM DB2).
Can you please elaborate on this? I'm unfamiliar with these platforms. Is that kind of column always returned in a result set?
| */ | ||
|
|
||
| fetchAllKeyValue() | ||
| ~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
| ~~~~~~~~~~~~~~~~~~~~~ | |
| ~~~~~~~~~~~~~~~~~~ |
| There are also convenience methods for data manipulation queries: | ||
|
|
||
| iterateKeyValue() | ||
| ~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
| ~~~~~~~~~~~~~~~~~~~~~ | |
| ~~~~~~~~~~~~~~~~~ |
Yes. It's appended to the inner query for counting rows and used by the outer query for filtering. For instance, on DB2: $conn = DriverManager::getConnection([
'driver' => 'ibm_db2',
'user' => 'db2inst1',
'password' => 'Passw0rd',
'dbname' => 'doctrine',
]);
$sql = $conn->getDatabasePlatform()
->modifyLimitQuery('SELECT TEST_INT, TEST_STRING from FETCH_TABLE', 1, 1);
echo $sql, PHP_EOL; // formatted for readability
/*
SELECT db22.*
FROM (
SELECT db21.*, ROW_NUMBER() OVER () AS DC_ROWNUM
FROM (
SELECT TEST_INT, TEST_STRING from FETCH_TABLE
) db21
) db22
WHERE db22.DC_ROWNUM >= 2
AND db22.DC_ROWNUM <= 2
*/
$data = $conn->fetchAllAssociative($sql);
var_dump($data);
/*
array(1) {
[0] =>
array(3) {
'TEST_INT' =>
int(2)
'TEST_STRING' =>
string(3) "foo"
'DC_ROWNUM' =>
string(1) "2"
}
}
*/Despite the fact that we selected two columns, the result contains three. UPD: I added a test for it. |
865800f to
59cfeb8
Compare
|
I see, the DBAL does that here: dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php Lines 816 to 820 in 0d4e1a8 Thanks for the explanation, this looks good. Good point about adding a test also, I think you discovered a bug 😅 |
59cfeb8 to
6f6c76b
Compare
Yeah, 4½ years ago (#2374) 😅 |
|
@tswcode does it look like what you're looking for? |
|
Indeed, that looks promising. I will test it as soon as I am back at work (on monday). :) |
SenseException
left a comment
There was a problem hiding this comment.
My thoughts about the behaviour of these methods are written to the related lines of code.
I'm not sure about missing tests for the catched exceptions for rowCount() and columnCount(). There might be value that a DriverException is only internally handled and that the methods are converting them to the expected exceptions.
| fetchAllKeyValue() | ||
| ~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| Execute the query and fetch the first two columns into an associative array as keys and values respectively: |
There was a problem hiding this comment.
From the docblock of fetchAllKeyValue:
The result must contain at least two columns.
SELECT key, value, foobar FROM my_table;What happens to the rest of the columns? first is key, second is value, third (unrelated to rownumber) is... ? Is this defined or currently an open behaviour? If there is a fixed definition of what happens with every other column after the second, it should be put into the documentation. Like that they fetched but ignored by the methods.
This might be an interesting information for design decisions of users.
There was a problem hiding this comment.
What happens to the rest of the columns?
Nothing. As well as nothing happens to other columns when the first column is fetched via fetchFirstColumn().
it should be put into the documentation
How would you put it?
There was a problem hiding this comment.
.. note::
Any additional column to the key and value columns will be ignored by this method.
There was a problem hiding this comment.
While I agree that this note is better than nothing, I wouldn't like the users to rely on this behavior just because it's currently implemented. How about this:
All additional columns will be ignored and are only allowed to be selected by DBAL for its internal purposes.
| iterateKeyValue() | ||
| ~~~~~~~~~~~~~~~~~ | ||
|
|
||
| Execute the query and iterate over the first two columns as keys and values respectively: |
There was a problem hiding this comment.
Same as in my comment in fetchAllKeyValue doc.
The tests are missing because there's no clear understanding of how these methods could throw an exception in any of the existing drivers. Not that it's impossible, they just were never added. The general concept is that the driver-level methods may throw driver exceptions while the wrapper should convert them into a generic or specialized wrapper-level exception (e.g. There's absolutely a lot of work on exception handling (#4160 is just the beginning). |
6f6c76b to
c386883
Compare
The suggestions on improving the documentation have been addressed.
|
Unfortunately I was busy this week, I just noticed that this feature has been added to the branch 3.0.x. @morozov Could you also add it to the branch 2.11.x ? |
Fixes #4289.
The behavior of the newly added methods is a replacement of
PDO::FETCH_KEY_PAIRwhich is implemented at the wrapper level and is available for all supported drivers.Unlike PDO which requires the result to have exactly two columns, DBAL will require at least two columns in order to allow the ROWNUM columns used by the platforms that do not natively support LIIMIT queries (Oracle, IBM DB2).