Skip to content

Commit

Permalink
feat: allow running QueryBuilder queries on different connections
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Appelman <robin@icewind.nl>
  • Loading branch information
icewind1991 committed Jul 15, 2024
1 parent f94b0c3 commit e699bf6
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 44 deletions.
15 changes: 8 additions & 7 deletions lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use OC\DB\Exceptions\DbalException;
use OCP\DB\IResult;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
* Base class for creating classes that extend the builtin query builder
Expand Down Expand Up @@ -46,12 +47,12 @@ public function getState() {
return $this->builder->getState();
}

public function execute() {
public function execute(?IDBConnection $connection = null) {
try {
if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::SELECT) {
return $this->executeQuery();
return $this->executeQuery($connection);
} else {
return $this->executeStatement();
return $this->executeStatement($connection);
}
} catch (DBALException $e) {
// `IQueryBuilder->execute` never wrapped the exception, but `executeQuery` and `executeStatement` do
Expand Down Expand Up @@ -280,11 +281,11 @@ public function getColumnName($column, $tableAlias = '') {
return $this->builder->getColumnName($column, $tableAlias);
}

public function executeQuery(): IResult {
return $this->builder->executeQuery();
public function executeQuery(?IDBConnection $connection = null): IResult {
return $this->builder->executeQuery($connection);
}

public function executeStatement(): int {
return $this->builder->executeStatement();
public function executeStatement(?IDBConnection $connection = null): int {
return $this->builder->executeStatement($connection);
}
}
76 changes: 42 additions & 34 deletions lib/private/DB/QueryBuilder/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Query\QueryException;
use OC\DB\ConnectionAdapter;
use OC\DB\Exceptions\DbalException;
use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\MySqlExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\OCIExpressionBuilder;
Expand All @@ -22,14 +23,14 @@
use OC\DB\QueryBuilder\FunctionBuilder\OCIFunctionBuilder;
use OC\DB\QueryBuilder\FunctionBuilder\PgSqlFunctionBuilder;
use OC\DB\QueryBuilder\FunctionBuilder\SqliteFunctionBuilder;
use OC\DB\ResultAdapter;
use OC\SystemConfig;
use OCP\DB\IResult;
use OCP\DB\QueryBuilder\ICompositeExpression;
use OCP\DB\QueryBuilder\ILiteral;
use OCP\DB\QueryBuilder\IParameter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\IDBConnection;
use Psr\Log\LoggerInterface;

class QueryBuilder implements IQueryBuilder {
Expand Down Expand Up @@ -168,15 +169,7 @@ public function getState() {
return $this->queryBuilder->getState();
}

/**
* Executes this query using the bound parameters and their types.
*
* Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
* for insert, update and delete statements.
*
* @return IResult|int
*/
public function execute() {
private function prepareForExecute() {
if ($this->systemConfig->getValue('log_query', false)) {
try {
$params = [];
Expand Down Expand Up @@ -253,48 +246,63 @@ public function execute() {
'exception' => $exception,
]);
}
}

$result = $this->queryBuilder->execute();
if (is_int($result)) {
return $result;
/**
* Executes this query using the bound parameters and their types.
*
* Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
* for insert, update and delete statements.
*
* @return IResult|int
*/
public function execute(?IDBConnection $connection = null) {
try {
if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::SELECT) {
return $this->executeQuery($connection);
} else {
return $this->executeStatement($connection);
}
} catch (DBALException $e) {
// `IQueryBuilder->execute` never wrapped the exception, but `executeQuery` and `executeStatement` do
/** @var \Doctrine\DBAL\Exception $previous */
$previous = $e->getPrevious();
throw $previous;
}
return new ResultAdapter($result);
}

public function executeQuery(): IResult {
public function executeQuery(?IDBConnection $connection = null): IResult {
if ($this->getType() !== \Doctrine\DBAL\Query\QueryBuilder::SELECT) {
throw new \RuntimeException('Invalid query type, expected SELECT query');
}

try {
$result = $this->execute();
} catch (\Doctrine\DBAL\Exception $e) {
throw \OC\DB\Exceptions\DbalException::wrap($e);
$this->prepareForExecute();
if (!$connection) {
$connection = $this->connection;
}

if ($result instanceof IResult) {
return $result;
}

throw new \RuntimeException('Invalid return type for query');
return $connection->executeQuery(
$this->getSQL(),
$this->getParameters(),
$this->getParameterTypes(),
);
}

public function executeStatement(): int {
public function executeStatement(?IDBConnection $connection = null): int {
if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::SELECT) {
throw new \RuntimeException('Invalid query type, expected INSERT, DELETE or UPDATE statement');
}

try {
$result = $this->execute();
} catch (\Doctrine\DBAL\Exception $e) {
throw \OC\DB\Exceptions\DbalException::wrap($e);
}

if (!is_int($result)) {
throw new \RuntimeException('Invalid return type for statement');
$this->prepareForExecute();
if (!$connection) {
$connection = $this->connection;
}

return $result;
return $connection->executeStatement(
$this->getSQL(),
$this->getParameters(),
$this->getParameterTypes(),
);
}


Expand Down
10 changes: 7 additions & 3 deletions lib/public/DB/QueryBuilder/IQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Doctrine\DBAL\ParameterType;
use OCP\DB\Exception;
use OCP\DB\IResult;
use OCP\IDBConnection;

/**
* This class provides a wrapper around Doctrine's QueryBuilder
Expand Down Expand Up @@ -146,34 +147,37 @@ public function getState();
* that interface changed in a breaking way the adapter \OCP\DB\QueryBuilder\IStatement is returned
* to bridge old code to the new API
*
* @param ?IDBConnection $connection (optional) the connection to run the query against. since 30.0
* @return IResult|int
* @throws Exception since 21.0.0
* @since 8.2.0
* @deprecated 22.0.0 Use executeQuery or executeStatement
*/
public function execute();
public function execute(?IDBConnection $connection = null);

/**
* Execute for select statements
*
* @param ?IDBConnection $connection (optional) the connection to run the query against. since 30.0
* @return IResult
* @since 22.0.0
*
* @throws Exception
* @throws \RuntimeException in case of usage with non select query
*/
public function executeQuery(): IResult;
public function executeQuery(?IDBConnection $connection = null): IResult;

/**
* Execute insert, update and delete statements
*
* @param ?IDBConnection $connection (optional) the connection to run the query against. since 30.0
* @return int the number of affected rows
* @since 22.0.0
*
* @throws Exception
* @throws \RuntimeException in case of usage with select query
*/
public function executeStatement(): int;
public function executeStatement(?IDBConnection $connection = null): int;

/**
* Gets the complete SQL string formed by the current specifications of this QueryBuilder.
Expand Down

0 comments on commit e699bf6

Please sign in to comment.