Skip to content
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

Fix parameter value processing for objects with unloaded metadata #7471

Merged
merged 1 commit into from Nov 15, 2018
Merged

Fix parameter value processing for objects with unloaded metadata #7471

merged 1 commit into from Nov 15, 2018

Conversation

alcaeus
Copy link
Member

@alcaeus alcaeus commented Nov 13, 2018

When binding an object as query parameter, the query object normally tries to convert this object into its identifier. This however only happened if class metadata for the object was already loaded. If it wasn't loaded, conversion was skipped leading to wrong results. While getMetadataFor is more performance sensitive than hasMetadataFor, we may not assumed that metadata for the bound object has been loaded yet.

The code has been changed to no longer check the metadata factory and call UnitOfWork::getSingleIdentifierValue directly, ignoring any mapping exception in the process. This preserves behaviour where binding any unmapped object to a query will send the entire object to the database.

Copy link
Member

@lcobucci lcobucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some tiny things 👍

lib/Doctrine/ORM/AbstractQuery.php Outdated Show resolved Hide resolved
lib/Doctrine/ORM/AbstractQuery.php Show resolved Hide resolved
tests/Doctrine/Tests/ORM/Query/QueryTest.php Outdated Show resolved Hide resolved
@lcobucci
Copy link
Member

This was the PHPBench report but it's not much relevant since that bit is not covered:

  24 subjects, 240 iterations, 24 revs, 0 rejects, 0 failures, 0 warnings
- (best [mean mode] worst) = 370.000 [39,908.388 39,463.004] 450.000 (μs)
+ (best [mean mode] worst) = 361.000 [39,836.125 39,382.889] 563.000 (μs)
- ⅀T: 9,578,013.000μs μSD/r 1,161.745μs μRSD/r: 5.875%
+ ⅀T: 9,560,670.000μs μSD/r 1,335.070μs μRSD/r: 5.475%
- suite: 133f079af8e76a725b3ce35962ff28c7851c24f3, date: 2018-11-13, stime: 10:34:20
+ suite: 133f079e185b4011810cb48680765ebf38c321c3, date: 2018-11-13, stime: 10:36:57
  +-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+
  | benchmark                                                 | subject                                             | mem_peak    | best          | mean          | mode          | worst         | stdev       | rstdev | diff    |
  +-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+
- | SimpleInsertPerformanceBench                              | benchHydration                                      | 20,343,704b | 262,975.000μs | 271,148.300μs | 270,203.227μs | 276,966.000μs | 4,075.729μs | 1.50%  | 667.85x |
+ | SimpleInsertPerformanceBench                              | benchHydration                                      | 20,343,704b | 269,992.000μs | 278,530.300μs | 275,499.687μs | 292,689.000μs | 7,040.146μs | 2.53%  | 677.19x |
- | SimpleHydrationBench                                      | benchHydration                                      | 67,667,720b | 132,631.000μs | 136,102.900μs | 134,341.123μs | 141,458.000μs | 2,834.684μs | 2.08%  | 335.23x |
+ | SimpleHydrationBench                                      | benchHydration                                      | 67,667,720b | 133,249.000μs | 142,360.300μs | 141,051.824μs | 158,326.000μs | 6,311.889μs | 4.43%  | 346.12x |
- | MixedQueryFetchJoinFullObjectHydrationPerformanceBench    | benchHydration                                      | 17,732,512b | 43,909.000μs  | 45,938.900μs  | 44,994.566μs  | 48,775.000μs  | 1,657.508μs | 3.61%  | 113.15x |
+ | MixedQueryFetchJoinFullObjectHydrationPerformanceBench    | benchHydration                                      | 17,732,408b | 43,624.000μs  | 46,903.700μs  | 45,546.769μs  | 52,319.000μs  | 2,578.879μs | 5.50%  | 114.04x |
- | SimpleQueryPartialObjectHydrationPerformanceBench         | benchHydration                                      | 25,305,536b | 45,104.000μs  | 47,931.300μs  | 46,234.548μs  | 56,894.000μs  | 3,508.759μs | 7.32%  | 118.06x |
+ | SimpleQueryPartialObjectHydrationPerformanceBench         | benchHydration                                      | 25,305,432b | 46,920.000μs  | 49,631.300μs  | 49,180.235μs  | 53,714.000μs  | 1,779.756μs | 3.59%  | 120.67x |
- | SimpleQueryScalarHydrationPerformanceBench                | benchHydration                                      | 14,337,104b | 15,268.000μs  | 16,512.400μs  | 16,114.051μs  | 18,995.000μs  | 1,040.037μs | 6.30%  | 40.67x  |
+ | SimpleQueryScalarHydrationPerformanceBench                | benchHydration                                      | 14,337,104b | 14,850.000μs  | 16,111.500μs  | 15,718.751μs  | 20,012.000μs  | 1,390.834μs | 8.63%  | 39.17x  |
- | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateFixContracts                            | 6,363,736b  | 1,718.000μs   | 1,784.700μs   | 1,754.564μs   | 1,891.000μs   | 51.852μs    | 2.91%  | 4.40x   |
+ | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateFixContracts                            | 6,363,736b  | 1,724.000μs   | 1,869.800μs   | 1,851.573μs   | 2,134.000μs   | 109.495μs   | 5.86%  | 4.55x   |
- | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateFlexContracts                           | 6,501,880b  | 2,107.000μs   | 2,282.500μs   | 2,161.462μs   | 3,372.000μs   | 364.587μs   | 15.97% | 5.62x   |
+ | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateFlexContracts                           | 6,501,776b  | 2,110.000μs   | 2,326.600μs   | 2,176.536μs   | 2,960.000μs   | 270.234μs   | 11.61% | 5.66x   |
- | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateUltraContracts                          | 6,368,440b  | 1,843.000μs   | 1,976.300μs   | 1,917.980μs   | 2,238.000μs   | 129.170μs   | 6.54%  | 4.87x   |
+ | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateUltraContracts                          | 6,368,336b  | 1,796.000μs   | 1,842.900μs   | 1,813.178μs   | 1,929.000μs   | 43.441μs    | 2.36%  | 4.48x   |
- | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateAllContracts                            | 6,588,232b  | 2,499.000μs   | 2,682.500μs   | 2,616.534μs   | 3,269.000μs   | 208.184μs   | 7.76%  | 6.61x   |
+ | SingleTableInheritanceHydrationPerformanceBench           | benchHydrateAllContracts                            | 6,588,128b  | 2,532.000μs   | 2,769.000μs   | 2,621.636μs   | 3,226.000μs   | 231.238μs   | 8.35%  | 6.73x   |
- | SingleTableInheritanceInsertPerformanceBench              | benchInsertFixContracts                             | 5,937,680b  | 3,629.000μs   | 3,862.100μs   | 3,764.526μs   | 4,746.000μs   | 312.493μs   | 8.09%  | 9.51x   |
+ | SingleTableInheritanceInsertPerformanceBench              | benchInsertFixContracts                             | 5,937,680b  | 3,560.000μs   | 3,767.100μs   | 3,728.082μs   | 3,969.000μs   | 118.555μs   | 3.15%  | 9.16x   |
- | SingleTableInheritanceInsertPerformanceBench              | benchInsertFlexContracts                            | 5,950,472b  | 3,829.000μs   | 4,250.100μs   | 3,996.123μs   | 5,537.000μs   | 531.776μs   | 12.51% | 10.47x  |
+ | SingleTableInheritanceInsertPerformanceBench              | benchInsertFlexContracts                            | 5,950,472b  | 3,644.000μs   | 3,787.300μs   | 3,743.315μs   | 3,934.000μs   | 87.044μs    | 2.30%  | 9.21x   |
- | SingleTableInheritanceInsertPerformanceBench              | benchInsertUltraContracts                           | 5,996,000b  | 3,885.000μs   | 4,271.500μs   | 4,079.004μs   | 5,434.000μs   | 444.057μs   | 10.40% | 10.52x  |
+ | SingleTableInheritanceInsertPerformanceBench              | benchInsertUltraContracts                           | 5,996,000b  | 3,660.000μs   | 3,836.700μs   | 3,728.689μs   | 4,128.000μs   | 145.543μs   | 3.79%  | 9.33x   |
- | SingleTableInheritanceInsertPerformanceBench              | benchInsertAllContracts                             | 6,342,696b  | 5,409.000μs   | 5,712.300μs   | 5,597.472μs   | 6,192.000μs   | 254.228μs   | 4.45%  | 14.07x  |
+ | SingleTableInheritanceInsertPerformanceBench              | benchInsertAllContracts                             | 6,342,696b  | 4,952.000μs   | 5,249.600μs   | 5,084.094μs   | 6,202.000μs   | 369.274μs   | 7.03%  | 12.76x  |
- | SimpleQueryArrayHydrationPerformanceBench                 | benchHydration                                      | 14,071,568b | 24,375.000μs  | 26,385.600μs  | 25,465.411μs  | 32,335.000μs  | 2,298.519μs | 8.71%  | 64.99x  |
+ | SimpleQueryArrayHydrationPerformanceBench                 | benchHydration                                      | 14,071,568b | 23,559.000μs  | 24,327.500μs  | 23,941.935μs  | 26,005.000μs  | 749.271μs   | 3.08%  | 59.15x  |
- | MixedQueryFetchJoinPartialObjectHydrationPerformanceBench | benchHydration                                      | 11,838,584b | 25,009.000μs  | 26,833.900μs  | 26,635.149μs  | 28,892.000μs  | 1,032.904μs | 3.85%  | 66.09x  |
+ | MixedQueryFetchJoinPartialObjectHydrationPerformanceBench | benchHydration                                      | 11,838,480b | 25,895.000μs  | 26,653.500μs  | 26,537.241μs  | 28,190.000μs  | 574.283μs   | 2.15%  | 64.80x  |
- | SimpleQueryFullObjectHydrationPerformanceBench            | benchHydration                                      | 62,116,592b | 145,482.000μs | 149,224.200μs | 148,192.372μs | 152,407.000μs | 2,294.034μs | 1.54%  | 367.55x |
+ | SimpleQueryFullObjectHydrationPerformanceBench            | benchHydration                                      | 62,116,488b | 138,155.000μs | 143,178.600μs | 142,548.703μs | 148,454.000μs | 3,421.227μs | 2.39%  | 348.11x |
- | MixedQueryFetchJoinArrayHydrationPerformanceBench         | benchHydration                                      | 31,152,520b | 47,166.000μs  | 48,191.100μs  | 47,810.384μs  | 49,910.000μs  | 861.185μs   | 1.79%  | 118.70x |
+ | MixedQueryFetchJoinArrayHydrationPerformanceBench         | benchHydration                                      | 31,152,520b | 42,573.000μs  | 44,350.600μs  | 43,558.933μs  | 50,699.000μs  | 2,271.497μs | 5.12%  | 107.83x |
- | UnitOfWorkComputeChangesBench                             | benchChangeSetComputation                           | 4,891,920b  | 793.000μs     | 819.800μs     | 805.945μs     | 856.000μs     | 23.151μs    | 2.82%  | 2.02x   |
+ | UnitOfWorkComputeChangesBench                             | benchChangeSetComputation                           | 4,891,920b  | 721.000μs     | 790.400μs     | 774.605μs     | 977.000μs     | 69.230μs    | 8.76%  | 1.92x   |
- | ProxyInitializationTimeBench                              | benchCmsUserInitialization                          | 16,826,024b | 35,593.000μs  | 36,650.200μs  | 36,714.742μs  | 37,523.000μs  | 484.413μs   | 1.32%  | 90.27x  |
+ | ProxyInitializationTimeBench                              | benchCmsUserInitialization                          | 16,826,024b | 31,842.000μs  | 33,874.300μs  | 33,847.315μs  | 36,278.000μs  | 1,169.117μs | 3.45%  | 82.36x  |
- | ProxyInitializationTimeBench                              | benchCmsEmployeeInitialization                      | 16,826,024b | 5,880.000μs   | 6,717.000μs   | 6,852.634μs   | 7,296.000μs   | 389.934μs   | 5.81%  | 16.54x  |
+ | ProxyInitializationTimeBench                              | benchCmsEmployeeInitialization                      | 16,826,024b | 6,034.000μs   | 6,536.100μs   | 6,271.213μs   | 7,928.000μs   | 554.531μs   | 8.48%  | 15.89x  |
- | ProxyInitializationTimeBench                              | benchInitializationOfAlreadyInitializedCmsUsers     | 16,826,048b | 441.000μs     | 492.800μs     | 465.845μs     | 625.000μs     | 54.834μs    | 11.13% | 1.21x   |
+ | ProxyInitializationTimeBench                              | benchInitializationOfAlreadyInitializedCmsUsers     | 16,826,048b | 456.000μs     | 508.600μs     | 506.673μs     | 563.000μs     | 29.114μs    | 5.72%  | 1.24x   |
- | ProxyInitializationTimeBench                              | benchInitializationOfAlreadyInitializedCmsEmployees | 16,826,048b | 370.000μs     | 406.000μs     | 391.292μs     | 450.000μs     | 26.866μs    | 6.62%  | 1.00x   |
+ | ProxyInitializationTimeBench                              | benchInitializationOfAlreadyInitializedCmsEmployees | 16,826,048b | 361.000μs     | 411.300μs     | 386.550μs     | 633.000μs     | 75.777μs    | 18.42% | 1.00x   |
- | ProxyInstantiationTimeBench                               | benchCmsUserInstantiation                           | 4,828,112b  | 65,987.000μs  | 68,989.800μs  | 67,795.219μs  | 79,987.000μs  | 3,798.960μs | 5.51%  | 169.93x |
+ | ProxyInstantiationTimeBench                               | benchCmsUserInstantiation                           | 4,828,112b  | 65,510.000μs  | 66,710.400μs  | 65,979.785μs  | 69,511.000μs  | 1,285.225μs | 1.93%  | 162.19x |
- | ProxyInstantiationTimeBench                               | benchCmsEmployeeInstantiation                       | 4,558,264b  | 47,301.000μs  | 48,635.100μs  | 48,207.912μs  | 51,673.000μs  | 1,204.027μs | 2.48%  | 119.79x |
+ | ProxyInstantiationTimeBench                               | benchCmsEmployeeInstantiation                       | 4,558,264b  | 47,777.000μs  | 49,739.600μs  | 49,092.022μs  | 51,925.000μs  | 1,366.084μs | 2.75%  | 120.93x |
  +-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+

Copy link
Member

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides existing feedback, this looks good! 👍

@alcaeus
Copy link
Member Author

alcaeus commented Nov 13, 2018

Build failures are due to MySQL not being installed at the moment...

@lcobucci
Copy link
Member

Build failures are due to MySQL not being installed at the moment...

@alcaeus failing steps re-executed.

@alcaeus alcaeus requested review from Ocramius and lcobucci and removed request for Majkl578 November 14, 2018 07:24
Copy link
Member

@lcobucci lcobucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alcaeus this is perfect now, I've addressed the minor CS things and we're good to go. Thanks for squashing this 🐛

@lcobucci lcobucci added this to the 2.6.3 milestone Nov 15, 2018
@lcobucci lcobucci self-assigned this Nov 15, 2018
@lcobucci lcobucci added the Bug label Nov 15, 2018
@lcobucci lcobucci merged commit d213053 into doctrine:2.6 Nov 15, 2018
@lcobucci
Copy link
Member

@alcaeus 🚢

@alcaeus alcaeus deleted the fix-unloaded-metadata-parameter-processing branch November 15, 2018 20:11
kdambekalns added a commit to kdambekalns/flow-development-collection that referenced this pull request Nov 21, 2018
When no class schema can be found in `loadMetaDataForClass`, a Doctrine
`MappingException` is now thrown. This makes our code work nicely with the
change in doctrine/orm#7471 that otherwise
leads to errors like this as of ORM 2.6.3:

```
FlowAnnotationDriver.php: No class schema found for "some-non-mapped-class".

89 …\FlowAnnotationDriver_Original::getClassSchema("some-non-mapped-class")
88 …\FlowAnnotationDriver_Original::loadMetadataForClass("some-non-mapped-class", Neos\Flow\Persistence\Doctrine\Mapping\ClassMetadata)
```

Fixes neos#1453
neos-bot pushed a commit to neos/flow that referenced this pull request Nov 21, 2018
When no class schema can be found in `loadMetaDataForClass`, a Doctrine
`MappingException` is now thrown. This makes our code work nicely with the
change in doctrine/orm#7471 that otherwise
leads to errors like this as of ORM 2.6.3:

```
FlowAnnotationDriver.php: No class schema found for "some-non-mapped-class".

89 …\FlowAnnotationDriver_Original::getClassSchema("some-non-mapped-class")
88 …\FlowAnnotationDriver_Original::loadMetadataForClass("some-non-mapped-class", Neos\Flow\Persistence\Doctrine\Mapping\ClassMetadata)
```

Fixes #1453
@@ -410,16 +412,24 @@ public function processParameterValue($value)
return $value;
}

if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
if ($value instanceof Mapping\ClassMetadata) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found out via kcachegrind that this caused massive performance regressions when binding any non-scalar value as parameter.

For example:

$thing = new DateTime();

$query->setParameter('foo', $thing);
$query->getResult();

Regardless of $query, this will lead to an internal class metadata lookup (and internal failure), plus exceptions being allocated and GC'd.

The following won't help either:

$thing = new DateTime();

$query->setParameter('foo', $thing, DateTimeType::NAME);
$query->getResult();

That's because processParameterValue($value) is called even when the type is known.

@alcaeus @Ocramius would it be a good idea to skip the entire processParameterValue()when the type is explicitly passed in?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to #7527

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patch at #7528

Ocramius added a commit to Ocramius/doctrine2 that referenced this pull request Dec 16, 2018
…()` should not be called for a well specified parameter type

As previously reported by @flaushi in doctrine#7471 (comment), we discovered
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance
regression when using any `object` type as parameter.

Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an
exception being thrown and garbage collected, plus multiple associated performance implications:

```php
$query->setParameter('foo', new DateTime());
$query->getResult();
```

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

This is due to following portion of code:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409

Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value.

That call leads to this segment being reached, which leads to the regression:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433

Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object:

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters.
In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter
out all parameters for which the type is given upfront, and later on merge them back in instead.

The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
guilhermeblanco pushed a commit that referenced this pull request Jun 17, 2019
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance
regression when using any `object` type as parameter.

Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an
exception being thrown and garbage collected, plus multiple associated performance implications:

```php
$query->setParameter('foo', new DateTime());
$query->getResult();
```

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

This is due to following portion of code:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409

Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value.

That call leads to this segment being reached, which leads to the regression:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433

Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object:

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters.
In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter
out all parameters for which the type is given upfront, and later on merge them back in instead.

The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
lcobucci pushed a commit that referenced this pull request Jun 17, 2019
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance
regression when using any `object` type as parameter.

Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an
exception being thrown and garbage collected, plus multiple associated performance implications:

```php
$query->setParameter('foo', new DateTime());
$query->getResult();
```

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

This is due to following portion of code:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409

Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value.

That call leads to this segment being reached, which leads to the regression:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433

Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object:

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters.
In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter
out all parameters for which the type is given upfront, and later on merge them back in instead.

The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
lcobucci pushed a commit that referenced this pull request Jun 17, 2019
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance
regression when using any `object` type as parameter.

Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an
exception being thrown and garbage collected, plus multiple associated performance implications:

```php
$query->setParameter('foo', new DateTime());
$query->getResult();
```

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

This is due to following portion of code:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409

Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value.

That call leads to this segment being reached, which leads to the regression:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433

Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object:

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters.
In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter
out all parameters for which the type is given upfront, and later on merge them back in instead.

The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
ixarlie added a commit to surexdirect/doctrine2 that referenced this pull request Jul 10, 2019
v2.6.3

[![Build Status](https://travis-ci.org/doctrine/doctrine2.svg?branch=v2.6.3)](https://travis-ci.org/doctrine/doctrine2)

This release provides fixes for many things, specially:

- Regression in commit order calculation
- BC-break in `EntityManager#find()` using optimistic lock outside of
  transaction
- PHP 7.3 compatibility issues

--------------------------------------------

- Total issues resolved: **8**
- Total pull requests resolved: **26**
- Total contributors: **26**

Documentation
-------------

 - [7472: fix incorrect phpdoc typehint](doctrine#7472) thanks to @seferov
 - [7465: Fixes tiny typo in the 'Working with DateTime instances' documentation](doctrine#7465) thanks to @unguul
 - [7444: Fixed URLs of doctrine-mapping.xsd in docs](doctrine#7444) thanks to @Naitsirch
 - [7441: $hydrationMode throughout can be a string as well as int (for custom modes)](doctrine#7441) thanks to @asgrim
 - [7435: Fix a typo on Documentation](doctrine#7435) thanks to @oguzdumanoglu
 - [7434: Removed FAQ paragraph stating public variables are disallowed](doctrine#7434) thanks to @Naitsirch and @flaushi
 - [7423: Update association-mapping.rst](doctrine#7423) thanks to @ThomasLandauer
 - [7421: JIRA to Github issues on Limitations and Known Issues](doctrine#7421) thanks to @seferov
 - [7412: Some formatting improvements](doctrine#7412) thanks to @ThomasLandauer
 - [7411: Autoload error when following the Getting Started Guide](doctrine#7411) thanks to @ThomasLandauer
 - [7401: &doctrine#91;docs&doctrine#93; Fix docblock in `inheritance-mapping.rst`](doctrine#7401) thanks to @bobdenotter
 - [7397: Update getting-started.rst](doctrine#7397) thanks to @eibt
 - [7394: Class 'Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver' not found](doctrine#7394) thanks to @ekosynth
 - [7378: Typo fix](doctrine#7378) thanks to @BenMorel
 - [7377: Fix query andX doctype](doctrine#7377) thanks to @sserbin
 - [7374: Deprecation message in documentation for YAML](doctrine#7374) thanks to @SenseException and @iltar
 - [7360: Document getPartialReference() properly](doctrine#7360) thanks to @lcobucci

Bug
---

 - [7471: Fix parameter value processing for objects with unloaded metadata](doctrine#7471) thanks to @alcaeus
 - [7367: Fix for BC break in 2.6.2 when calling EM::find() with LockMode::OPTIMISTIC outside of a TX](doctrine#7367) thanks to @timdev
 - [7328: Handle removed parameters by tree walker in Paginator](doctrine#7328) thanks to @plfort
 - [7325: Make code php 7.3 lint-compatible](doctrine#7325) thanks to @paxal
 - [7317: &doctrine#91;XML&doctrine#93; Fix default value of many-to-many order-by to ASC](doctrine#7317) thanks to @alexdenvir
 - [7260: Fix the handling of circular references in the commit order calculator](doctrine#7260) thanks to @stof
 - [6830: fix applying column options on foreign key columns](doctrine#6830) thanks to @Tobion

Improvement
-----------

 - [7428: CI: Test against PHP 7.3](doctrine#7428) thanks to @Majkl578
 - [7363: Fix compatibility with phan](doctrine#7363) thanks to @philippe-unitiz
 - [7345: Correct DOMDocument constructor in test](doctrine#7345) thanks to @guilliamxavier
 - [7307: Fix remaining usages of deprecated ClassLoader and Inflector from doctrine/common](doctrine#7307) thanks to @Majkl578 and @simonwelsh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants