Skip to content

Commit d96e33d

Browse files
abnegateclaude
andcommitted
fix(joins): map dotted main attribute names in the bounded page
The bounded page now clones the read's main conditions before the outer statement maps them, so a main attribute whose name holds a dot ('rev.score') reached the page unmapped and compiled as table `rev`, column `score`: every MariaDB/MySQL lane failed testJoinComboDottedAttributeNameDoesNotSplitAsAlias with "Attribute not found". The page maps its conditions the way the outer statement does. The equivalence suite gives the authors a 'rev.score' attribute and bounds a read filtered and one ordered by it; both errored before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 76085e5 commit d96e33d

2 files changed

Lines changed: 8 additions & 3 deletions

File tree

‎src/Database/Adapter/SQL.php‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1754,7 +1754,7 @@ public function find(Document $collection, array $queries = [], ?int $limit = 25
17541754
$results = $this->executeSelect($left, Event::DocumentFind, $name);
17551755
} else {
17561756
$bound = $hasJoins && ! $hasAggregation && ! $hasDistinct && $vectorQueries === [] && $this->boundsJoinedSort()
1757-
? $this->boundedPage($queries, $adapterFilterQueries, $joinTablePrefixes, $orderAttributes, $orderTypes, $limit, $offset, $cursor)
1757+
? $this->boundedPage($collectionDoc, $queries, $adapterFilterQueries, $joinTablePrefixes, $orderAttributes, $orderTypes, $limit, $offset, $cursor)
17581758
: null;
17591759

17601760
$builder = $this->newBuilder($name, $alias, $hasPreservingOuterJoin);
@@ -5699,6 +5699,7 @@ protected function boundsJoinedSort(): bool
56995699
* @param array<string, mixed> $cursor
57005700
*/
57015701
private function boundedPage(
5702+
Document $collection,
57025703
array $queries,
57035704
array $adapterFilterQueries,
57045705
array $joinTablePrefixes,
@@ -5758,6 +5759,8 @@ private function boundedPage(
57585759
$searches[] = $query;
57595760
}
57605761

5762+
$this->remapDottedQueryAttributes($conditions, $joinTablePrefixes, $collection);
5763+
57615764
[$mainAttributes, $mainTypes] = $mainOrder;
57625765

57635766
return new BoundedPage(

‎tests/unit/Joins/BoundedJoinSortTest.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ public static function reads(): iterable
151151
yield "{$mode}: inner notes, joined attributes selected" => [$mode, [$innerNotes, Query::orderAsc('rank'), Query::select(['name', 'rank', 'n.rank', 'n.$id'])], false];
152152
yield "{$mode}: notes, every attribute selected" => [$mode, [$notes, Query::orderDesc('rank'), Query::select(['*'])], true];
153153
yield "{$mode}: notes, a main condition" => [$mode, [$notes, Query::notEqual('name', 'cedar'), Query::orderAsc('rank')], true];
154+
yield "{$mode}: notes, a condition on a main attribute whose name holds a dot" => [$mode, [$notes, Query::equal('rev.score', [1, 2])], true];
155+
yield "{$mode}: notes, ordered by a main attribute whose name holds a dot" => [$mode, [$notes, Query::orderDesc('rev.score'), Query::greaterThan('rev.score', 0)], true];
154156
yield "{$mode}: notes, main conditions grouped" => [$mode, [$notes, Query::or([Query::lessThan('rank', 2), Query::isNull('rank')])], true];
155157
yield "{$mode}: inner notes, a main and a joined condition" => [$mode, [$innerNotes, Query::notEqual('name', 'cedar'), Query::lessThan('n.rank', 3), Query::orderAsc('rank')], false];
156158
yield "{$mode}: inner notes, a joined attribute that is not set" => [$mode, [$innerNotes, Query::isNull('n.rank')], false];
@@ -427,7 +429,7 @@ private function database(SQLite $adapter, string $mode): Database
427429
? [Permission::create(Role::any()), Permission::read(Role::user('reader'))]
428430
: [Permission::create(Role::any())];
429431
foreach ([
430-
'authors' => [Attribute::string(key: 'name', size: 32), Attribute::integer(key: 'rank', required: false)],
432+
'authors' => [Attribute::string(key: 'name', size: 32), Attribute::integer(key: 'rank', required: false), Attribute::integer(key: 'rev.score', required: false)],
431433
'notes' => [Attribute::string(key: 'author', size: 16), Attribute::integer(key: 'rank', required: false)],
432434
'tags' => [Attribute::string(key: 'author', size: 16), Attribute::string(key: 'note', size: 16)],
433435
] as $id => $attributes) {
@@ -456,7 +458,7 @@ private function database(SQLite $adapter, string $mode): Database
456458
$database->setTenant($tenant);
457459
}
458460
$attributes = match ($collection) {
459-
'authors' => ['name' => $prefix.' '.$values[0], 'rank' => $values[1]],
461+
'authors' => ['name' => $prefix.' '.$values[0], 'rank' => $values[1], 'rev.score' => $values[1]],
460462
'notes' => ['author' => $tenant === 2 && $id === 'n15' ? 'a05' : $values[0], 'rank' => $values[1]],
461463
default => ['author' => $values[0], 'note' => $values[1]],
462464
};

0 commit comments

Comments
 (0)