After #298309: DatabaseStatement::execute with PDO::FETCH_CLASS calls __construct() after setting object attributes was fixed, I get one failed test when running the tests Database > Fetch tests.
Message: There is only one record.
Group: Other
Filename: database_test.test
Line: 188
Function: DatabaseFetchTestCase->testQueryFetchClass()
Instead of returning 1 row, db_query() returns no rows at all.
I am using PHP 5.2.0-8+etch11 (Debian) with PDO Driver for MySQL client library version 5.0.32.
| Comment | File | Size | Author |
|---|---|---|---|
| #22 | pdo_fetch_props_late_fails-310904-22.patch | 1.08 KB | mfer |
| #17 | pdo_fetch_props_late_fails-310904-17.patch | 1.39 KB | mfer |
| #15 | pdo_fetch_props_late_fails-310904-15.patch | 1.41 KB | mfer |
| #13 | pdo_fetch_props_late_fails-310904-13.patch | 1.25 KB | mfer |
| #10 | 310904-1.patch | 1.2 KB | c960657 |
Comments
Comment #1
mfer commentedI just ran the database tests and there were no errors. This was under PHP 5.2.5. I'm guessing there's a PHP bug that was fixed between 5.2.0 and 5.2.5 that covers this but I couldn't find it.
Comment #2
c960657 commentedIt may be related to this bug that was fixed in PHP 5.2.4: http://bugs.php.net/bug.php?id=41971
With the workaround mentioned in the bug report the test passes:
Comment #3
c960657 commentedIt looks like the feature doesn't even work in the CVS version of 5.3.0, unless you call
$result->fetch(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE). Calling$result->fetch()(without parameters) or iterating over rows usingforeach($result ...)does not make the constructor be called early.I just filed this bug for this: http://bugs.php.net/bug.php?id=46139 Whether it is expected behaviour or in fact a bug is hard to say, when there is no documentation.
Comment #4
mfer commented@c960657 it looks like you don't need the $statement->setFetchMode() part. If you remove that but pass in PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'myClass' to your fetch or fetchAll method it works (This is how I have been doing it with PDO).
This looks like a bug with using setFetchMode and then iterating over the resulting PDOStatement object after an execute method has been used on it.
The basics of the problem:
This won't respect the PDO::FETCH_PROPS_LATE flag and the $record may not display correctly.
If we want to use FETCH_PROPS_LATE we may need to do something like:
If we go this route PDO::FETCH_PROPS_LATE isn't needed in DatabaseStatement::execute. If we remove it from there I'd suggest documenting it's need and usage in detail or it will bite someone else the same way it bit me.
Thoughts?
Comment #5
Crell commentedUgh. The latter syntax is just way too ugly. This is definitely a bug in PHP from the sound of it. Rats.
I think the best way forward here is to document the hell out of it, and even link to the PHP bug in a docblock. I guess we'll just have to live with early fetch for Drupal 7, and if someone cares we need to make sure that they can explicitly ask for the late fetch.
Can we get a unit test to allow people to explicitly request late fetch and then setup the backend code and docs to ensure it works?
Comment #6
c960657 commentedAnother option is to make db_query() return a subclass of PDOStatement that compensates for the PHP bug, so that the calling code will work as if the bug wasn't there. A workaround like this would take quite a bit of code, though, and it may also be slightly confusing to users that e.g. get_class($result) != "PDOStatement" (apart from being confusing when debugging this would only be a problem with poorly written code).
Comment #7
mfer commented@c96065 I have a feeling that using/needing PDO::FETCH_PROPS_LATE will be a fairly rare occurrence (please correct me if I'm wrong). I'm with @Crell on going without PDO::FETCH_PROPS_LATE by default and documenting how to use it if necessary.
Comment #8
Crell commentedWe're already using a subclass of PDOStatement, DatabaseStatement, for just such extensions. In fact we've implemented a bunch already. :-)
But yeah, we're not actually using the class-based fetching anywhere in core yet, so until this becomes a problem and we find we need it often I think it's better to just document the heck out of it. So we need a patch that 1) rolls back the late-fetch change and 2) Documents in docblocks this caveat. We can then add docs to the handbook, too.
Comment #9
mfer commentedI'll write the patch and the handbook page unless someone else wants to own this.
Comment #10
c960657 commentedThis patch reverts the change in #298309: DatabaseStatement::execute with PDO::FETCH_CLASS calls __construct() after setting object attributes.
Comment #11
mfer commentedThe patch does undo the change. Now we need a nice comment block explaining what's going on.
Comment #12
mfer commentedAdded documentation page at http://drupal.org/node/315092. I'll craft a patch up later this week with details.
Comment #13
mfer commentedHere's a patch that removed FETCH_PROPS_LATE, points to the bug in a comment, and points to the handbook page on the comment. Please review the documentation and test the patch. It passed all the db tests for me.
Comment #14
webchick1. Comments need to wrap at 80 characters. I would just fix this myself, but...
2. Since this is primarily a documentation issue, can we add a sentence or two of "why"? All of the comments there are /factually/ correct, but don't tell me a) Why adding properties before a __construct() is a bad thing, b) why I might need to work around this problem.
Comment #15
mfer commentedThe attached patch wraps at 80 characters or less and adds a little more detail to the comment. I'm not sure how much detail to go into in the patch. If __construct() needs to do setup before properties are added to the object PDO::FETCH_PROPS_LATE needs to be used. Example cases include using the __set() and __get() magic methods to do something with the properties other than assign them to an object and what you are going to do with them needs to be setup. Should there be more detail? Should extra detail be added to the handbook page?
Comment #16
keith.smith commentedThis new patch has "will will" and "properties properties" in the code comments.
Comment #17
mfer commentedoops oops. Good catch @keith.smith. Re-rolled
Comment #18
c960657 commentedThe patch looks good.
A comment on the handbook page:
I think this behaviour is actually by design. The bug is that you cannot use PDO::FETCH_PROPS_LATE to switch to the reverse behaviour. I suggest dropping the last sentence.
AFAICT the PHP bug is only of concern to the user if he calls setFetchMode() himself - right? In that case it may not be worth mentioning (it may be confuse more than it helps), but if it is mentioned, I think that bug 41971 is also deserves mention, even though it has been fixed in the latest PHP 5.2.x release.
Comment #19
mfer commented@c960657 the handbook page definitely needs some work :)
Comment #20
Crell commentedThe code comment seems to presume that the user is asking why we're using early fetch. I suspect most users won't know the difference. I'd suggest instead something like "Default to an object. Note: db fields will be added to the object before the constructor is run. If you need to assign fields after the constructor is run, do X or see Y." (More formal than that, of course.) I'm flexible as to whether we mention the PHP bug here or on the handbook page or both.
Comment #21
Crell commentedBetter title.
Comment #22
mfer commented@Crell - I made the presumption. I updated to your comment in this patch. I'd suggest more detail as to why, how to set the fields after the constructor is run, and an example be in the handbook. This is a rare use case.
Comment #23
Crell commentedI'm Larry Garfield, and I approve of this patch.
Comment #24
dries commentedCommitted to CVS HEAD. Thanks.
Comment #25
Anonymous (not verified) commentedAutomatically closed -- issue fixed for two weeks with no activity.