-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Result::fetchAllKeyValue() and ::iterateKeyValue() #4293
Conversation
b2149b6
to
865800f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
@@ -379,6 +379,22 @@ Execute the query and fetch all results into an array: | |||
) | |||
*/ | |||
|
|||
fetchAllKeyValue() | |||
~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~ |
@@ -425,6 +441,18 @@ Retrieve associative array of the first result row. | |||
|
|||
There are also convenience methods for data manipulation queries: | |||
|
|||
iterateKeyValue() | |||
~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ |
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). :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. note::
Any additional column to the key and value columns will be ignored by this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_PAIR
which 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).