Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow running QueryBuilder queries on different connections #46547

Merged
merged 1 commit into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading
Loading