Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
database system
Priority:
Major
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
30 Nov 2012 at 10:01 UTC
Updated:
29 Jul 2014 at 21:36 UTC
Jump to comment: Most recent file
Comments
Comment #1
Letharion commentedInfo from reyero on IRC:
Not being able to enable a core module (locale) on a core supported db-backend (sqlite) sounds like a critical, no?
Comment #2
gábor hojtsySo the problem is that
- sqlite needs to use StatementPrefetch instead of PDOStatement (see comments in the sqlite library)
- StatementPrefetch is custom implemented in our codebase
- fetchObject() in StatementPrefetch takes a $class_name and then makes decisions based on that class name but then never passes that on (so the actual fetching would happen using that $class_name);
- there are no docs on fetchObject() and it is not a method defined in StatementInterface either (so it is hard to tell how people intended this to work)
So a minimal fix at least is to include the class name with the fetch options like current() expects it to be, which makes this fetch into the right object. This does not fix the underlying problem of no documentation and implementation of a method that is not on the interface but is in the pattern of other fetch methods (which are defined on the interface).
The intention of fetchObject() looking at http://php.net/manual/en/pdostatement.fetchobject.php is to "return an instance of the required class with property names that correspond to the column names", so passing on the class name to the fetcher where the column data is filled in is minimally required.
Comment #3
gábor hojtsyOh, the minimal patch.
Comment #4
gábor hojtsyAlso looked at whether I can update StatementInterface for a more complete fix but various interface elements are commented out in there: http://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Database%2..., so if we look at the interface, fetching objects is not possible (both fetchObject() and setFetchMode() are commented out, both of which would be required to be able to fetch an object).
FetchObject() is used numerous times in core, but only locale module attempts to use it according to the PDO interface (which the StatementPrefetch method also exposed, but the interface does not even attempt to define). So with this you cannot make an sqlite based Drupa 8 installation that uses locale module.
Comment #5
gábor hojtsyAlso, we could write tests for this but it would never fail on the testbot, because the testbot does not run sqlite. Is someone running our tests on sqlite?
Comment #6
damien tournoud commentedWhy are we using
PDO::FETCH_CLASSin the first place? This is a *very* broken feature of PDO that we should stay as far from it as we can.Some examples of why it is broken: (1) PDO::FETCH_CLASS builds the object *without calling the constructor*, and (2) PDO::FETCH_CLASS builds the object without respecting the visibility modifiers of either the constructor or the properties that are set.
Being implemented in pure PHP, StatementPrefetch cannot reproduce the brokeness of PDO::FETCH_CLASS in all its glory. In particular, we cannot instantiate an object without calling its constructor before PHP 5.4.
I suggest refactoring the calling code from:
to something like:
Comment #7
gábor hojtsy@Damien: that sounds interesting, because there are clearly attempts at implementing fetchObject() with a classname in the code, they just don't work at all. They don't reproduce the same brokenness, they just don't work at all.
So I guess we should repurpose this issue to throw an exception from fetchObject() if a class name was provided (both in StatementPrefetch and our extension of Statement)?
We can definitely do like you suggested, but then it is not anymore relevant for this issue, I'll open a new one.
Comment #8
gábor hojtsySubmitted #1854838: Locale should not use fetchObject with a classname, WSOD on sqlite as a critical locale module issue then. Demoting this to major since the exposed API does not work at all. It does not document it would not work and it does not throw exceptions that it will not work that way.
Comment #9
damien tournoud commentedI agree.
Comment #10
jose reyero commentedAgree with all of the above and on top of that we should properly document the Query::select() method,
which btw returns StatementInterface|PDOStatement (depending on the driver used)
Comment #11
Crell commentedFetching into a class is a supported feature. We have unit tests for it:
http://drupalcode.org/project/drupal.git/blob/refs/heads/8.x:/core/modul...
The pre/post constructor problem is also known, and there is handling for that in the code somewhere. (You can toggle it in the driver.)
Since that test is still passing on a regular basis, I'm unclear what the problem is here.
Comment #12
gábor hojtsy@Crell: I don't see a test where it invoked fetchObject() with a class name. The method has a $class_name argument to specify where to fetch the data, but never makes it actually to the place (current() method) where it fetches the data. Maybe other way of fetching to classes work and have tests, but definitely not this method. Also, it is not part of the interface definition and is not implemented to match the PDO interface of the method.
Comment #13
damien tournoud commentedPHP 5.2 supports the
PDO::FETCH_PROPS_LATEconstant, that runs the constructor before force-feeding the object with the properties from the database. This is not the default behavior, and there is no way for us to emulate the default behavior in plain PHP.Comment #14
Crell commented@Gabor: Ah, I see the distinction. Then we need a test for that as well.
@Damien: I don't follow. We're not using the default behavior, are we?
Oh, crap. Looking back over the history, we are:
#298309: DatabaseStatement::execute with PDO::FETCH_CLASS calls __construct() after setting object attributes
#310904: Use early fetch and document why
http://drupal.org/node/315092
Damien: So there's no way to do pre-constructor fetch in a custom statement class? Since we're no longer supporting 5.2 does that give us more options, since there appear to be version-dependency bugs in the previous issues?
I'd hate to drop fetch class entirely...
Comment #15
damien tournoud commented@Crell, I would support trying to force
PDO::FETCH_PROPS_LATEagain (in both Statement and StatementPrefetch), as #298309: DatabaseStatement::execute with PDO::FETCH_CLASS calls __construct() after setting object attributes attempted.Comment #16
Crell commentedMe too. I don't have any bandwidth to work on it, though.
Comment #17
catchDuplicate of #1567216: DatabaseStatementPrefetch.fetchAll() implementation does not work when $fetch_style parameter is PDO::FETCH_CLASS.
Comment #18
chx commentedThat's not a duplicate, that's just fetchAll, FETCH_CLASS should not be used at all, I think.
Comment #19
chx commentedBetter issue title. For reasons outlined in #6 we should not be supporting this... feature.
Comment #20
chx commentedOh and I forgot to tag this.
Comment #21
catchHmm I marked the duplicates the wrong way 'round. #1567216: DatabaseStatementPrefetch.fetchAll() implementation does not work when $fetch_style parameter is PDO::FETCH_CLASS this time.
Comment #21.0
chx commentedUpdated issue summary.
Comment #21.1
chx commentedUpdated issue summary.
Comment #22
chx commentedComment #23
amateescu commentedSince this is basically a revert of #310904: Use early fetch and document why, I think it's fair to bring the comment back too. Other than that, RTBC since we now require a PHP version in which that bug is fixed.
Comment #24
dries commentedCommitted to 8.x. Thanks.
Comment #25.0
(not verified) commentedUpdated issue summary.