java-topology/defects/doctrine/patch/doctrine-0003-sqlwalker-partialfield-set.patch
russell@unturf.com d4ed2dff91 ORM wave: 24 defects patched across 10 ORMs (157 sites, 62 ecosystems)
Hibernate (5 HIGH): addColumn/addReferencedColumn/addIndex ArrayList→LinkedHashSet (19x)
  FK second-pass LinkedHashSet, orderHierarchy LinkedHashSet
MyBatis (1 MEDIUM): sortConstructorMappings indexOf→HashMap (12x)
EF Core (2 HIGH + 1 MEDIUM): FindGenerationProperty HashSet (250x),
  AddPrincipals HashSet (250x), FK discovery HashSet (6x)
Diesel (3 MEDIUM): SQLite/MySQL row position()→BTreeMap (51x)
SQLAlchemy (2 HIGH): _values_bindparam Set (500x), evaluated_keys Set (500x)
Peewee (1 MEDIUM): _SortedFieldList.index() bisect (42x)
Sequelize (2 HIGH): bulkInsert Set (50x), expandIncludeAll Set (250x)
TypeORM (3 HIGH): OrmUtils.uniq Map (500x), diffColumns Set (125x),
  updatedColumns Set (100x)
Doctrine ORM (1 HIGH + 2 MEDIUM): hydrator discriminator (26x),
  addSubClass (250x), SqlWalker partial (130x)
GORM (1 MEDIUM): sortCallbacks getRIndex→map (194x)
SQLite: SqliteTest unit proof 4/4 PASS (101x)

Unit tests: all PASS — Hibernate/MyBatis/EfCore/Diesel/SQLAlchemy/Peewee/
  Sequelize/TypeORM/Doctrine/GORM
Whitepaper: 157 sites, 62 ecosystems; PDF 752K
2026-03-27 13:34:26 -04:00

34 lines
1.6 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fixes doctrine-0003: SqlWalker::walkObjectExpression in_array per field.
--- a/src/Doctrine/ORM/Query/SqlWalker.php
+++ b/src/Doctrine/ORM/Query/SqlWalker.php
@@ DEFECT doctrine-0003: SqlWalker.php:1405,1445 walkObjectExpression()
private function walkObjectExpression(...): string
{
+ // FIX doctrine-0003: convert partialFieldSet from array to set for O(1) lookup.
+ // Previously: in_array($fieldName, $partialFieldSet) is O(|partialFieldSet|) per field.
+ // Called for every fieldMapping in every class/subclass in the DQL result.
+ $partialFieldSetFlip = $partialFieldSet !== null ? array_flip($partialFieldSet) : null;
foreach ($class->fieldMappings as $fieldName => $mapping) {
- if ($partialFieldSet && ! in_array($fieldName, $partialFieldSet, true)) {
+ if ($partialFieldSetFlip !== null && ! isset($partialFieldSetFlip[$fieldName])) {
continue;
}
// ... build SQL
}
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
- if (isset($mapping->inherited) || ($partialFieldSet && ! in_array($fieldName, $partialFieldSet, true))) {
+ if (isset($mapping->inherited) || ($partialFieldSetFlip !== null && ! isset($partialFieldSetFlip[$fieldName]))) {
continue;
}
}
}
# BEFORE: in_array($field, $partialFieldSet) — O(P) per field across all mappings.
# Total: O(F × P) for F field mappings, P partial field set size.
# AFTER: isset($partialFieldSetFlip[$field]) — O(1).
# Triggered by: any DQL query using SELECT PARTIAL entity.{field1,field2,...}.