Skip to content

Commit 37aace4

Browse files
committed
Pre-filter duplicates in SQL adapter to prevent race-condition overcount
1 parent 2b4fd1e commit 37aace4

1 file changed

Lines changed: 48 additions & 0 deletions

File tree

src/Database/Adapter/SQL.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,54 @@ public function createDocuments(Document $collection, array $documents, bool $ig
24762476
if (empty($documents)) {
24772477
return $documents;
24782478
}
2479+
2480+
// Pre-filter duplicates inside the transaction to prevent race conditions.
2481+
// Query which UIDs already exist and remove them from the batch.
2482+
if ($ignore) {
2483+
$collectionId = $collection->getId();
2484+
$name = $this->filter($collectionId);
2485+
$uids = \array_filter(\array_map(fn (Document $doc) => $doc->getId(), $documents));
2486+
2487+
if (!empty($uids)) {
2488+
$placeholders = [];
2489+
$binds = [];
2490+
foreach (\array_values(\array_unique($uids)) as $i => $uid) {
2491+
$key = ':_dup_uid_' . $i;
2492+
$placeholders[] = $key;
2493+
$binds[$key] = $uid;
2494+
}
2495+
2496+
$tenantFilter = '';
2497+
if ($this->sharedTables) {
2498+
$tenantFilter = ' AND _tenant = :_dup_tenant';
2499+
$binds[':_dup_tenant'] = $this->getTenant();
2500+
}
2501+
2502+
$sql = 'SELECT _uid FROM ' . $this->getSQLTable($name)
2503+
. ' WHERE _uid IN (' . \implode(', ', $placeholders) . ')'
2504+
. $tenantFilter;
2505+
2506+
$stmt = $this->getPDO()->prepare($sql);
2507+
foreach ($binds as $k => $v) {
2508+
$stmt->bindValue($k, $v, $this->getPDOType($v));
2509+
}
2510+
$stmt->execute();
2511+
$existingUids = \array_flip(\array_column($stmt->fetchAll(), '_uid'));
2512+
$stmt->closeCursor();
2513+
2514+
if (!empty($existingUids)) {
2515+
$documents = \array_values(\array_filter(
2516+
$documents,
2517+
fn (Document $doc) => !isset($existingUids[$doc->getId()])
2518+
));
2519+
}
2520+
}
2521+
2522+
if (empty($documents)) {
2523+
return [];
2524+
}
2525+
}
2526+
24792527
$spatialAttributes = $this->getSpatialAttributes($collection);
24802528
$collection = $collection->getId();
24812529
try {

0 commit comments

Comments
 (0)