summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2017-03-30 14:08:31 +0200
committerGitHub <noreply@github.com>2017-03-30 14:08:31 +0200
commitbca72579207c0ba73db97f70d3ba1602439cc075 (patch)
tree19b791be97d0704b369bb226fc4aeccb51fff5c4
parent1ee7e1c0b128b16c3327ca6aa90335ce12fd678f (diff)
parentd4a7cfec7ca61ba48fdb20134409ad2500e0e7a7 (diff)
downloadnextcloud-server-bca72579207c0ba73db97f70d3ba1602439cc075.tar.gz
nextcloud-server-bca72579207c0ba73db97f70d3ba1602439cc075.zip
Merge pull request #3089 from nextcloud/cache-move-single-query
Move all children of a folder in a single query
-rw-r--r--lib/composer/composer/autoload_classmap.php6
-rw-r--r--lib/composer/composer/autoload_static.php6
-rw-r--r--lib/private/DB/AdapterOCI8.php1
-rw-r--r--lib/private/DB/AdapterSqlite.php1
-rw-r--r--lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php7
-rw-r--r--lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php38
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php56
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php30
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php30
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php30
-rw-r--r--lib/private/DB/QueryBuilder/QueryBuilder.php36
-rw-r--r--lib/private/DB/SQLiteSessionInit.php3
-rw-r--r--lib/private/Files/Cache/Cache.php45
-rw-r--r--lib/public/DB/QueryBuilder/IFunctionBuilder.php62
-rw-r--r--lib/public/DB/QueryBuilder/IQueryBuilder.php19
-rw-r--r--tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php106
-rw-r--r--tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php20
-rw-r--r--tests/lib/DB/QueryBuilder/FunctionBuilderTest.php74
18 files changed, 542 insertions, 28 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index f009c0be203..915f5229280 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -84,6 +84,7 @@ return array(
'OCP\\DB' => $baseDir . '/lib/public/DB.php',
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => $baseDir . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
'OCP\\DB\\QueryBuilder\\IExpressionBuilder' => $baseDir . '/lib/public/DB/QueryBuilder/IExpressionBuilder.php',
+ 'OCP\\DB\\QueryBuilder\\IFunctionBuilder' => $baseDir . '/lib/public/DB/QueryBuilder/IFunctionBuilder.php',
'OCP\\DB\\QueryBuilder\\ILiteral' => $baseDir . '/lib/public/DB/QueryBuilder/ILiteral.php',
'OCP\\DB\\QueryBuilder\\IParameter' => $baseDir . '/lib/public/DB/QueryBuilder/IParameter.php',
'OCP\\DB\\QueryBuilder\\IQueryBuilder' => $baseDir . '/lib/public/DB/QueryBuilder/IQueryBuilder.php',
@@ -473,6 +474,11 @@ return array(
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\MySqlExpressionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php',
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\OCIExpressionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php',
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\PgSqlExpressionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\ExpressionBuilder\\SqliteExpressionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\FunctionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\OCIFunctionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\PgSqlFunctionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\SqliteFunctionBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php',
'OC\\DB\\QueryBuilder\\Literal' => $baseDir . '/lib/private/DB/QueryBuilder/Literal.php',
'OC\\DB\\QueryBuilder\\Parameter' => $baseDir . '/lib/private/DB/QueryBuilder/Parameter.php',
'OC\\DB\\QueryBuilder\\QueryBuilder' => $baseDir . '/lib/private/DB/QueryBuilder/QueryBuilder.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 9a6a41d8a37..a4dc2dbb489 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -114,6 +114,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\DB' => __DIR__ . '/../../..' . '/lib/public/DB.php',
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
'OCP\\DB\\QueryBuilder\\IExpressionBuilder' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IExpressionBuilder.php',
+ 'OCP\\DB\\QueryBuilder\\IFunctionBuilder' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IFunctionBuilder.php',
'OCP\\DB\\QueryBuilder\\ILiteral' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ILiteral.php',
'OCP\\DB\\QueryBuilder\\IParameter' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IParameter.php',
'OCP\\DB\\QueryBuilder\\IQueryBuilder' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/IQueryBuilder.php',
@@ -503,6 +504,11 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\MySqlExpressionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php',
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\OCIExpressionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php',
'OC\\DB\\QueryBuilder\\ExpressionBuilder\\PgSqlExpressionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\ExpressionBuilder\\SqliteExpressionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\FunctionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\OCIFunctionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\PgSqlFunctionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php',
+ 'OC\\DB\\QueryBuilder\\FunctionBuilder\\SqliteFunctionBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php',
'OC\\DB\\QueryBuilder\\Literal' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/Literal.php',
'OC\\DB\\QueryBuilder\\Parameter' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/Parameter.php',
'OC\\DB\\QueryBuilder\\QueryBuilder' => __DIR__ . '/../../..' . '/lib/private/DB/QueryBuilder/QueryBuilder.php',
diff --git a/lib/private/DB/AdapterOCI8.php b/lib/private/DB/AdapterOCI8.php
index e23f74345ae..359e4ba1b67 100644
--- a/lib/private/DB/AdapterOCI8.php
+++ b/lib/private/DB/AdapterOCI8.php
@@ -41,7 +41,6 @@ class AdapterOCI8 extends Adapter {
const UNIX_TIMESTAMP_REPLACEMENT = "(cast(sys_extract_utc(systimestamp) as date) - date'1970-01-01') * 86400";
public function fixupStatement($statement) {
- $statement = preg_replace('( LIKE \?)', '$0 ESCAPE \'\\\'', $statement);
$statement = preg_replace('/`(\w+)` ILIKE \?/', 'REGEXP_LIKE(`$1`, \'^\' || REPLACE(?, \'%\', \'.*\') || \'$\', \'i\')', $statement);
$statement = str_replace('`', '"', $statement);
$statement = str_ireplace('NOW()', 'CURRENT_TIMESTAMP', $statement);
diff --git a/lib/private/DB/AdapterSqlite.php b/lib/private/DB/AdapterSqlite.php
index 7a69cb7e8c2..5507699c54a 100644
--- a/lib/private/DB/AdapterSqlite.php
+++ b/lib/private/DB/AdapterSqlite.php
@@ -41,7 +41,6 @@ class AdapterSqlite extends Adapter {
}
public function fixupStatement($statement) {
- $statement = preg_replace('( I?LIKE \?)', '$0 ESCAPE \'\\\'', $statement);
$statement = preg_replace('/`(\w+)` ILIKE \?/', 'LOWER($1) LIKE LOWER(?)', $statement);
$statement = str_replace( '`', '"', $statement );
$statement = str_ireplace( 'NOW()', 'datetime(\'now\')', $statement );
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
index 69c34947feb..179ce72e8e1 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
@@ -156,6 +156,13 @@ class OCIExpressionBuilder extends ExpressionBuilder {
/**
* @inheritdoc
*/
+ public function like($x, $y, $type = null) {
+ return parent::like($x, $y, $type) . " ESCAPE '\\'";
+ }
+
+ /**
+ * @inheritdoc
+ */
public function iLike($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php
new file mode 100644
index 00000000000..e4d7a3902fd
--- /dev/null
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\DB\QueryBuilder\ExpressionBuilder;
+
+
+use OC\DB\QueryBuilder\QueryFunction;
+use OCP\DB\QueryBuilder\ILiteral;
+use OCP\DB\QueryBuilder\IParameter;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\DB\QueryBuilder\IQueryFunction;
+
+class SqliteExpressionBuilder extends ExpressionBuilder {
+ /**
+ * @inheritdoc
+ */
+ public function like($x, $y, $type = null) {
+ return parent::like($x, $y, $type) . " ESCAPE '\\'";
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
new file mode 100644
index 00000000000..6bd98e4ce50
--- /dev/null
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\DB\QueryBuilder\FunctionBuilder;
+
+use OC\DB\QueryBuilder\QueryFunction;
+use OC\DB\QueryBuilder\QuoteHelper;
+use OCP\DB\QueryBuilder\IFunctionBuilder;
+
+class FunctionBuilder implements IFunctionBuilder {
+ /** @var QuoteHelper */
+ protected $helper;
+
+ /**
+ * ExpressionBuilder constructor.
+ *
+ * @param QuoteHelper $helper
+ */
+ public function __construct(QuoteHelper $helper) {
+ $this->helper = $helper;
+ }
+
+ public function md5($input) {
+ return new QueryFunction('MD5(' . $this->helper->quoteColumnName($input) . ')');
+ }
+
+ public function concat($x, $y) {
+ return new QueryFunction('CONCAT(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
+ }
+
+ public function substring($input, $start, $length = null) {
+ if ($length) {
+ return new QueryFunction('SUBSTR(' . $this->helper->quoteColumnName($input) . ', ' . $this->helper->quoteColumnName($start) . ', ' . $this->helper->quoteColumnName($length) . ')');
+ } else {
+ return new QueryFunction('SUBSTR(' . $this->helper->quoteColumnName($input) . ', ' . $this->helper->quoteColumnName($start) . ')');
+ }
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
new file mode 100644
index 00000000000..0f7a7dad236
--- /dev/null
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\DB\QueryBuilder\FunctionBuilder;
+
+use OC\DB\QueryBuilder\QueryFunction;
+
+class OCIFunctionBuilder extends FunctionBuilder {
+ public function md5($input) {
+ return new QueryFunction('LOWER(DBMS_OBFUSCATION_TOOLKIT.md5 (input => UTL_RAW.cast_to_raw(' . $this->helper->quoteColumnName($input) .')))');
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php
new file mode 100644
index 00000000000..27ebf1a04f9
--- /dev/null
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\DB\QueryBuilder\FunctionBuilder;
+
+use OC\DB\QueryBuilder\QueryFunction;
+
+class PgSqlFunctionBuilder extends FunctionBuilder {
+ public function concat($x, $y) {
+ return new QueryFunction($this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y));
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
new file mode 100644
index 00000000000..e985b7306a4
--- /dev/null
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\DB\QueryBuilder\FunctionBuilder;
+
+use OC\DB\QueryBuilder\QueryFunction;
+
+class SqliteFunctionBuilder extends FunctionBuilder {
+ public function concat($x, $y) {
+ return new QueryFunction($this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y));
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index d5dd9cf0366..eac13b452ac 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -26,11 +26,17 @@ namespace OC\DB\QueryBuilder;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
+use Doctrine\DBAL\Platforms\SqlitePlatform;
use OC\DB\OracleConnection;
use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\MySqlExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\OCIExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\PgSqlExpressionBuilder;
+use OC\DB\QueryBuilder\ExpressionBuilder\SqliteExpressionBuilder;
+use OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder;
+use OC\DB\QueryBuilder\FunctionBuilder\OCIFunctionBuilder;
+use OC\DB\QueryBuilder\FunctionBuilder\PgSqlFunctionBuilder;
+use OC\DB\QueryBuilder\FunctionBuilder\SqliteFunctionBuilder;
use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
@@ -110,12 +116,42 @@ class QueryBuilder implements IQueryBuilder {
return new PgSqlExpressionBuilder($this->connection);
} else if ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
return new MySqlExpressionBuilder($this->connection);
+ } else if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
+ return new SqliteExpressionBuilder($this->connection);
} else {
return new ExpressionBuilder($this->connection);
}
}
/**
+ * Gets an FunctionBuilder used for object-oriented construction of query functions.
+ * This producer method is intended for convenient inline usage. Example:
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->select('u')
+ * ->from('users', 'u')
+ * ->where($qb->fun()->md5('u.id'));
+ * </code>
+ *
+ * For more complex function construction, consider storing the function
+ * builder object in a local variable.
+ *
+ * @return \OCP\DB\QueryBuilder\IFunctionBuilder
+ */
+ public function func() {
+ if ($this->connection instanceof OracleConnection) {
+ return new OCIFunctionBuilder($this->helper);
+ } else if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
+ return new SqliteFunctionBuilder($this->helper);
+ } else if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
+ return new PgSqlFunctionBuilder($this->helper);
+ } else {
+ return new FunctionBuilder($this->helper);
+ }
+ }
+
+ /**
* Gets the type of the currently built query.
*
* @return integer
diff --git a/lib/private/DB/SQLiteSessionInit.php b/lib/private/DB/SQLiteSessionInit.php
index f8e6dcef8ad..0e947b9918e 100644
--- a/lib/private/DB/SQLiteSessionInit.php
+++ b/lib/private/DB/SQLiteSessionInit.php
@@ -58,6 +58,9 @@ class SQLiteSessionInit implements EventSubscriber {
$sensitive = ($this->caseSensitiveLike) ? 'true' : 'false';
$args->getConnection()->executeUpdate('PRAGMA case_sensitive_like = ' . $sensitive);
$args->getConnection()->executeUpdate('PRAGMA journal_mode = ' . $this->journalMode);
+ /** @var \PDO $pdo */
+ $pdo = $args->getConnection()->getWrappedConnection();
+ $pdo->sqliteCreateFunction('md5', 'md5', 1);
}
public function getSubscribedEvents() {
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index 2b04226f20e..1f3f2433e45 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -37,6 +37,7 @@
namespace OC\Files\Cache;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use Doctrine\DBAL\Driver\Statement;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
@@ -130,7 +131,7 @@ class Cache implements ICache {
$where = 'WHERE `fileid` = ?';
$params = array($file);
}
- $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
+ $sql = 'SELECT `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
`storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
FROM `*PREFIX*filecache` ' . $where;
$result = $this->connection->executeQuery($sql, $params);
@@ -522,27 +523,35 @@ class Cache implements ICache {
throw new \Exception('Invalid target storage id: ' . $targetStorageId);
}
- // sql for final update
- $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
-
+ $this->connection->beginTransaction();
if ($sourceData['mimetype'] === 'httpd/unix-directory') {
- //find all child entries
- $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
- $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
- $childEntries = $result->fetchAll();
+ //update all child entries
$sourceLength = strlen($sourcePath);
- $this->connection->beginTransaction();
- $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
-
- foreach ($childEntries as $child) {
- $newTargetPath = $targetPath . substr($child['path'], $sourceLength);
- $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
+ $query = $this->connection->getQueryBuilder();
+
+ $fun = $query->func();
+ $newPathFunction = $fun->concat(
+ $query->createNamedParameter($targetPath),
+ $fun->substring('path', $query->createNamedParameter($sourceLength + 1, IQueryBuilder::PARAM_INT))// +1 for the leading slash
+ );
+ $query->update('filecache')
+ ->set('storage', $query->createNamedParameter($targetStorageId, IQueryBuilder::PARAM_INT))
+ ->set('path_hash', $fun->md5($newPathFunction))
+ ->set('path', $newPathFunction)
+ ->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath) . '/%')));
+
+ try {
+ $query->execute();
+ } catch (\OC\DatabaseException $e) {
+ $this->connection->rollBack();
+ throw $e;
}
- $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
- $this->connection->commit();
- } else {
- $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), \OC_Util::basename($targetPath), $newParentId, $sourceId]);
}
+
+ $sql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` = ? WHERE `fileid` = ?';
+ $this->connection->executeQuery($sql, array($targetStorageId, $targetPath, md5($targetPath), \OC_Util::basename($targetPath), $newParentId, $sourceId));
+ $this->connection->commit();
} else {
$this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
}
diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
new file mode 100644
index 00000000000..6c1f596966d
--- /dev/null
+++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\DB\QueryBuilder;
+
+/**
+ * This class provides a builder for sql some functions
+ *
+ * @since 12.0.0
+ */
+interface IFunctionBuilder {
+ /**
+ * Calculates the MD5 hash of a given input
+ *
+ * @param mixed $input The input to be hashed
+ *
+ * @return IQueryFunction
+ * @since 12.0.0
+ */
+ public function md5($input);
+
+ /**
+ * Combines two input strings
+ *
+ * @param mixed $x The first input string
+ * @param mixed $y The seccond input string
+ *
+ * @return IQueryFunction
+ * @since 12.0.0
+ */
+ public function concat($x, $y);
+
+ /**
+ * Takes a substring from the input string
+ *
+ * @param mixed $input The input string
+ * @param mixed $start The start of the substring, note that counting starts at 1
+ * @param mixed $length The length of the substring
+ *
+ * @return IQueryFunction
+ * @since 12.0.0
+ */
+ public function substring($input, $start, $length = null);
+}
diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php
index 8ef8a96b25f..a176bb917a3 100644
--- a/lib/public/DB/QueryBuilder/IQueryBuilder.php
+++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php
@@ -95,6 +95,25 @@ interface IQueryBuilder {
public function expr();
/**
+ * Gets an FunctionBuilder used for object-oriented construction of query functions.
+ * This producer method is intended for convenient inline usage. Example:
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->select('u')
+ * ->from('users', 'u')
+ * ->where($qb->fun()->md5('u.id'));
+ * </code>
+ *
+ * For more complex function construction, consider storing the function
+ * builder object in a local variable.
+ *
+ * @return \OCP\DB\QueryBuilder\IFunctionBuilder
+ * @since 12.0.0
+ */
+ public function func();
+
+ /**
* Gets the type of the currently built query.
*
* @return integer
diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php
new file mode 100644
index 00000000000..c71e83f5fd6
--- /dev/null
+++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\DB\QueryBuilder;
+
+use OC\DB\QueryBuilder\Literal;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class ExpressionBuilderDBTest extends TestCase {
+ /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
+ protected $connection;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ }
+
+ public function likeProvider() {
+ $connection = \OC::$server->getDatabaseConnection();
+
+ return [
+ ['foo', 'bar', false],
+ ['foo', 'foo', true],
+ ['foo', 'f%', true],
+ ['foo', '%o', true],
+ ['foo', '%', true],
+ ['foo', 'fo_', true],
+ ['foo', 'foo_', false],
+ ['foo', $connection->escapeLikeParameter('fo_'), false],
+ ['foo', $connection->escapeLikeParameter('f%'), false],
+ ];
+ }
+
+ /**
+ * @dataProvider likeProvider
+ *
+ * @param string $param1
+ * @param string $param2
+ * @param boolean $match
+ */
+ public function testLike($param1, $param2, $match) {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select(new Literal('1'))
+ ->from('users')
+ ->where($query->expr()->like($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
+
+ $this->assertEquals($match, $query->execute()->fetchColumn());
+ }
+
+ public function ilikeProvider() {
+ $connection = \OC::$server->getDatabaseConnection();
+
+ return [
+ ['foo', 'bar', false],
+ ['foo', 'foo', true],
+ ['foo', 'Foo', true],
+ ['foo', 'f%', true],
+ ['foo', '%o', true],
+ ['foo', '%', true],
+ ['foo', 'fo_', true],
+ ['foo', 'foo_', false],
+ ['foo', $connection->escapeLikeParameter('fo_'), false],
+ ['foo', $connection->escapeLikeParameter('f%'), false],
+ ];
+ }
+
+ /**
+ * @dataProvider ilikeProvider
+ *
+ * @param string $param1
+ * @param string $param2
+ * @param boolean $match
+ */
+ public function testILike($param1, $param2, $match) {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select(new Literal('1'))
+ ->from('users')
+ ->where($query->expr()->iLike($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
+
+ $this->assertEquals($match, $query->execute()->fetchColumn());
+ }
+}
diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
index 4122f300c86..ff58b3f6e0b 100644
--- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
@@ -352,24 +352,26 @@ class ExpressionBuilderTest extends TestCase {
return [
['eq', '5', IQueryBuilder::PARAM_STR, false, 3],
['eq', '5', IQueryBuilder::PARAM_STR, true, 1],
- ['neq', '5', IQueryBuilder::PARAM_STR, false, 6],
- ['neq', '5', IQueryBuilder::PARAM_STR, true, 4],
+ ['neq', '5', IQueryBuilder::PARAM_STR, false, 8],
+ ['neq', '5', IQueryBuilder::PARAM_STR, true, 6],
['lt', '5', IQueryBuilder::PARAM_STR, false, 3],
['lt', '5', IQueryBuilder::PARAM_STR, true, 1],
['lte', '5', IQueryBuilder::PARAM_STR, false, 6],
['lte', '5', IQueryBuilder::PARAM_STR, true, 4],
- ['gt', '5', IQueryBuilder::PARAM_STR, false, 3],
+ ['gt', '5', IQueryBuilder::PARAM_STR, false, 5],
['gt', '5', IQueryBuilder::PARAM_STR, true, 1],
- ['gte', '5', IQueryBuilder::PARAM_STR, false, 6],
+ ['gte', '5', IQueryBuilder::PARAM_STR, false, 8],
['gte', '5', IQueryBuilder::PARAM_STR, true, 4],
['like', '%5%', IQueryBuilder::PARAM_STR, false, 3],
['like', '%5%', IQueryBuilder::PARAM_STR, true, 1],
- ['notLike', '%5%', IQueryBuilder::PARAM_STR, false, 6],
- ['notLike', '%5%', IQueryBuilder::PARAM_STR, true, 4],
+ ['like', 'under_%', IQueryBuilder::PARAM_STR, false, 2],
+ ['like', 'under\_%', IQueryBuilder::PARAM_STR, false, 1],
+ ['notLike', '%5%', IQueryBuilder::PARAM_STR, false, 8],
+ ['notLike', '%5%', IQueryBuilder::PARAM_STR, true, 6],
['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 3],
['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 1],
- ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 6],
- ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 4],
+ ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 8],
+ ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 6],
];
}
@@ -392,6 +394,8 @@ class ExpressionBuilderTest extends TestCase {
$this->createConfig($appId, 7, 4);
$this->createConfig($appId, 8, 5);
$this->createConfig($appId, 9, 6);
+ $this->createConfig($appId, 10, 'under_score');
+ $this->createConfig($appId, 11, 'underscore');
$query = $this->connection->getQueryBuilder();
$query->select($query->createFunction('COUNT(*) AS `count`'))
diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
new file mode 100644
index 00000000000..c270e105fc1
--- /dev/null
+++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\DB\QueryBuilder;
+
+use OC\DB\QueryBuilder\Literal;
+use Test\TestCase;
+
+/**
+ * Class FunctionBuilderTest
+ *
+ * @group DB
+ *
+ * @package Test\DB\QueryBuilder
+ */
+class FunctionBuilderTest extends TestCase {
+ /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
+ protected $connection;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ }
+
+ public function testConcat() {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select($query->func()->concat($query->createNamedParameter('foo'), new Literal("'bar'")));
+
+ $this->assertEquals('foobar', $query->execute()->fetchColumn());
+ }
+
+ public function testMd5() {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select($query->func()->md5($query->createNamedParameter('foobar')));
+
+ $this->assertEquals(md5('foobar'), $query->execute()->fetchColumn());
+ }
+
+ public function testSubstring() {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2), $query->createNamedParameter(2)));
+
+ $this->assertEquals('oo', $query->execute()->fetchColumn());
+ }
+
+ public function testSubstringNoLength() {
+ $query = $this->connection->getQueryBuilder();
+
+ $query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2)));
+
+ $this->assertEquals('oobar', $query->execute()->fetchColumn());
+ }
+}