From 7f43c7d5da36b5a0291309ea5ae8c233f11035fb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 12 Aug 2024 13:27:21 +0200 Subject: [PATCH] fix: explicitly forbid offset and limit in partitioned queries as there is no proper way to implement this that isn't very slow Signed-off-by: Robin Appelman --- .../Partitioned/PartitionedQueryBuilder.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php index d7d8767606d3b..ea2047d3089de 100644 --- a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php +++ b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php @@ -99,6 +99,7 @@ * 7. Update, delete and insert statements aren't allowed to contain cross-partition joins. * 8. Queries that "GROUP BY" a column from the joined partition are not allowed. * 9. Any `join` call needs to be made before any `where` call. + * 10. Queries that join cross-partition cannot use "LIMIT" or "OFFSET" in queries. * * [1]: A set of tables which can't be queried together with the rest of the tables, such as when sharding is used. */ @@ -113,6 +114,8 @@ class PartitionedQueryBuilder extends ShardedQueryBuilder { private ?PartitionSplit $mainPartition = null; private bool $hasPositionalParameter = false; private QuoteHelper $quoteHelper; + private ?int $limit = null; + private ?int $offset = null; public function __construct( IQueryBuilder $builder, @@ -397,6 +400,20 @@ public function delete($delete = null, $alias = null) { return parent::delete($delete, $alias); } + public function setMaxResults($maxResults) { + if ($maxResults > 0) { + $this->limit = (int)$maxResults; + } + return parent::setMaxResults($maxResults); + } + + public function setFirstResult($firstResult) { + if ($firstResult > 0) { + $this->offset = (int)$firstResult; + } + return parent::setFirstResult($firstResult); + } + public function executeQuery(?IDBConnection $connection = null): IResult { $this->applySelects(); if ($this->splitQueries && $this->hasPositionalParameter) { @@ -405,6 +422,14 @@ public function executeQuery(?IDBConnection $connection = null): IResult { foreach ($this->splitQueries as $split) { $split->query->setParameters($this->getParameters(), $this->getParameterTypes()); } + if (count($this->splitQueries) > 0) { + if (is_int($this->limit)) { + throw new InvalidPartitionedQueryException("Limit is not allowed in partitioned queries"); + } + if (is_int($this->offset)) { + throw new InvalidPartitionedQueryException("Offset is not allowed in partitioned queries"); + } + } $s = parent::getSQL(); $result = parent::executeQuery($connection);