Problem/Motivation
Database select query throws an error when trying to fetch all objects as instances of certain class.
The issue is with the column index being set to zero by default in StatementBase class default fetch options definition. That would later on flow to fetchAll method of the PdoResult class and clientFetchAll method of the PdoTrait class.
Code has checks for NULL values and the default column index of zero passes those checks, resulting in class name settings being disregarded.
Steps to reproduce
Create select query, set fetch option with custom class and call fetchAll on the result.
Proposed resolution
Change the setFetchMode method in the StatementBase class to explicitly set the column index to NULL if the fetch mode is set to ClassObject.
/**
* {@inheritdoc}
*/
public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
if (is_int($mode)) {
@trigger_error("Passing the \$mode argument as an integer to setFetchMode() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use a case of \Drupal\Core\Database\Statement\FetchAs enum instead. See https://www.drupal.org/node/3488338", E_USER_DEPRECATED);
$mode = $this->pdoToFetchAs($mode);
}
assert($mode instanceof FetchAs);
$this->fetchMode = $mode;
switch ($mode) {
case FetchAs::ClassObject:
$this->fetchOptions['class'] = $a1;
// NB! Explicitly set the column index to NULL so that fetching all results would not throw an
$this->fetchOptions['column'] = NULL;
if ($a2) {
$this->fetchOptions['constructor_args'] = $a2;
}
break;
case FetchAs::Column:
$this->fetchOptions['column'] = $a1;
break;
}
// If the result object is missing, just do with the properties setting.
try {
if ($this->result) {
return $this->result->setFetchMode($mode, $this->fetchOptions);
}
return TRUE;
}
catch (\LogicException) {
return TRUE;
}
}
Remaining tasks
Review the latest improvements to issue title and description, pull request and possibly accept the merge request.
User interface changes
None.
Introduced terminology
None.
API changes
None.
Data model changes
None.
Release notes snippet
None.
| Comment | File | Size | Author |
|---|
Issue fork drupal-3552669
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
pjotr.savitski commentedComment #3
quietone commentedHi, in Drupal core changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to the Core change policies. Thanks.
Comment #4
pjotr.savitski commented@quietone Didn't know that. Thank you for the information.
Comment #5
pjotr.savitski commentedComment #6
pjotr.savitski commentedA possible solution is to modify the setFetchMode method in the
StatementBaseclass to either remove the column identifier that is initially set to zero in the $fetchOptions parameter. This will allow the clientFetchAll in thePdoTraitclass to be passed the class name instead of the column identifier.The only way for the class name to be used instead of the column identifier is to make sure that column identifier is NULL or missing the key is missing from the array.
Comment #7
pjotr.savitski commentedComment #8
pjotr.savitski commentedComment #9
pjotr.savitski commentedComment #10
pjotr.savitski commentedHope that having the test and possible fix in the issue fork will expedite the process of getting the fix into the released version a bit.
Comment #11
godotislate@pjotr.savitski: Create a merge request if you have a fix and test ready in the branch. Then, depending on whether CI tests fail, you may need to rework your changes until all tests pass. Once that's done, change the status of this issue to "Needs review" and eventually someone in the community will take a look at it.
Comment #13
pjotr.savitski commentedComment #14
pjotr.savitski commented@godotislate Thank you for help and guidance.
Comment #15
smustgrave commentedLeft some comments on the MR thanks!
Comment #16
pjotr.savitski commentedComment #17
smustgrave commentedFeedback appears to be addressed.
Comment #18
godotislateRan the test-only job and it confirms the error in the issue title:
Comment #19
quietone commentedGoing through a checklist of things for RTBC issues.
Thanks for the test!
Un-assigning per Assigning ownership of a Drupal core issue.
The proposed resolution in the issue summary has two options and says that the first is preferred. But the MR implements the second option. That should be explained in the issue summary to help reviewers or anyone researching this change.
The title here is an error statement but is should be a description of what is being fixed or improved. The title is used as the git commit message so it should be meaningful and concise. See List of issue fields. Since I can't think of a title right now I am tagging for that and setting to NW. Something about correctly handling the default column of '0'?
Comment #22
rhezios commentedMerge request !14207 contains the first option by setting the column to NULL. The second option doesn't work with setFetchMode containing constructor args.
Comment #23
pjotr.savitski commentedComment #25
pjotr.savitski commentedComment #26
pjotr.savitski commentedComment #27
pjotr.savitski commentedComment #28
pjotr.savitski commentedComment #29
pjotr.savitski commentedComment #31
godotislateRe-based the MR, since it failed on the automated main re-target.
Tests pass.
Test only fails as expected: https://git.drupalcode.org/issue/drupal-3552669/-/jobs/8640046
IS and title look to have been updated per #19.
lgtm
Comment #32
alexpottI think we should move the fix to
\Drupal\Core\Database\Statement\PdoResult::fetchAllas that's were this problem is coming from.Something like:
Fixing it here would fix this for all calls to the public fetchAll().
Comment #34
dpiEntity Hierarchy ran into this issue in https://git.drupalcode.org/project/entity_hierarchy/-/work_items/3590987, as it passed a class name to
fetchAll($column_index), which broke in #3522561: Fully type StatementInterface methods' parameters. So we had to adapt tosetFetchMode, which is how I ran into this new issue.I adapted safety per @alexpott.
I wanted to improve a little typehinting but Coder is unhappy (despite PHPStan accepting it), so whatever.
Merged with todays
mainbranch.Comment #35
mondrakeLooks good to me. Two tests added to prevent regressions.
Comment #36
dpiSlight rework for @mondrake feedback.
Use the same assertEquals assertion strategy for both class properties.
Comment #37
mondrakeThanks
Comment #38
quietone commentedI've read the comments and updated credit (which does include me for earlier triage). I didn't find anything unanswered here.
Comment #39
alexpottCommitted and pushed eeb5c183295 to main and 7c0abbbf045 to 11.x and 9282211f1a8 to 11.4.x. Thanks!