diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
index 46bb536dfd211be5a36d8bd6afeb7a0f9503ac41..ffa758e4da7e2443d87b11ad2021d51f5cf62d79 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
@@ -85,4 +85,12 @@ class FunctionBuilder implements IFunctionBuilder {
 	public function min($field) {
 		return new QueryFunction('MIN(' . $this->helper->quoteColumnName($field) . ')');
 	}
+
+	public function greatest($x, $y) {
+		return new QueryFunction('GREATEST(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
+	}
+
+	public function least($x, $y) {
+		return new QueryFunction('LEAST(' . $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
index 21898cf3f9350006902d3455bdc391d751505236..f37ac20ecabf0c7fde9e1d164b9686bdd9a95619 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
@@ -30,4 +30,13 @@ class SqliteFunctionBuilder extends FunctionBuilder {
 	public function concat($x, $y) {
 		return new QueryFunction('(' . $this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y) . ')');
 	}
+
+	public function greatest($x, $y) {
+		return new QueryFunction('MAX(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
+	}
+
+	public function least($x, $y) {
+		return new QueryFunction('MIN(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
+	}
+
 }
diff --git a/lib/private/Files/Cache/Propagator.php b/lib/private/Files/Cache/Propagator.php
index 989a4d0c7d58704bc0905a1d3c9cc11c51efa442..41b4c2bb07028dd0d22949c3780b995288b3dee4 100644
--- a/lib/private/Files/Cache/Propagator.php
+++ b/lib/private/Files/Cache/Propagator.php
@@ -91,7 +91,7 @@ class Propagator implements IPropagator {
 		}, $parentHashes);
 
 		$builder->update('filecache')
-			->set('mtime', $builder->createFunction('GREATEST(' . $builder->getColumnName('mtime') . ', ' . $builder->createNamedParameter((int)$time, IQueryBuilder::PARAM_INT) . ')'))
+			->set('mtime', $builder->func()->greatest('mtime', $builder->createNamedParameter((int)$time, IQueryBuilder::PARAM_INT)))
 			->set('etag', $builder->createNamedParameter($etag, IQueryBuilder::PARAM_STR))
 			->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
 			->andWhere($builder->expr()->in('path_hash', $hashParams));
@@ -102,7 +102,10 @@ class Propagator implements IPropagator {
 			// we need to do size separably so we can ignore entries with uncalculated size
 			$builder = $this->connection->getQueryBuilder();
 			$builder->update('filecache')
-				->set('size', $builder->func()->add('size', $builder->createNamedParameter($sizeDifference)))
+				->set('size', $builder->func()->greatest(
+					$builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT),
+					$builder->func()->add('size', $builder->createNamedParameter($sizeDifference)))
+				)
 				->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
 				->andWhere($builder->expr()->in('path_hash', $hashParams))
 				->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
index 861a576914a93b3d10718a2812e7f3c49ea670c0..d82d3ada8cfe232a545423c02ad419c44939851a 100644
--- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php
+++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
@@ -109,6 +109,8 @@ interface IFunctionBuilder {
 	/**
 	 * Takes the maximum of all rows in a column
 	 *
+	 * If you want to get the maximum value of multiple columns in the same row, use `greatest` instead
+	 *
 	 * @param mixed $field the column to maximum
 	 *
 	 * @return IQueryFunction
@@ -119,10 +121,38 @@ interface IFunctionBuilder {
 	/**
 	 * Takes the minimum of all rows in a column
 	 *
+	 * If you want to get the minimum value of multiple columns in the same row, use `least` instead
+	 *
 	 * @param mixed $field the column to minimum
 	 *
 	 * @return IQueryFunction
 	 * @since 18.0.0
 	 */
 	public function min($field);
+
+	/**
+	 * Takes the maximum of multiple values
+	 *
+	 * If you want to get the maximum value of all rows in a column, use `max` instead
+	 *
+	 * @param mixed $x the first input field or number
+	 * @param mixed $y the first input field or number
+	 *
+	 * @return IQueryFunction
+	 * @since 18.0.0
+	 */
+	public function greatest($x, $y);
+
+	/**
+	 * Takes the minimum of multiple values
+	 *
+	 * If you want to get the minimum value of all rows in a column, use `min` instead
+	 *
+	 * @param mixed $x the first input field or number
+	 * @param mixed $y the first input field or number
+	 *
+	 * @return IQueryFunction
+	 * @since 18.0.0
+	 */
+	public function least($x, $y);
 }
diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
index d7617125faa4634b17440dbd19f59f7e7bcc7171..3d9baf35b1cb5c8f055546a6789863222fe9282e 100644
--- a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
@@ -198,4 +198,24 @@ class FunctionBuilderTest extends TestCase {
 
 		$this->assertEquals(10, $query->execute()->fetchColumn());
 	}
+
+	public function testGreatest() {
+		$query = $this->connection->getQueryBuilder();
+
+		$query->select($query->func()->greatest($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
+		$query->from('appconfig')
+			->setMaxResults(1);
+
+		$this->assertEquals(2, $query->execute()->fetchColumn());
+	}
+
+	public function testLeast() {
+		$query = $this->connection->getQueryBuilder();
+
+		$query->select($query->func()->least($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
+		$query->from('appconfig')
+			->setMaxResults(1);
+
+		$this->assertEquals(1, $query->execute()->fetchColumn());
+	}
 }
diff --git a/tests/lib/Files/Cache/PropagatorTest.php b/tests/lib/Files/Cache/PropagatorTest.php
index ce6b84ee4d05a66e5b1cfa8c8759a51a8e5d2ba1..c1822c902825a6f97faa3a8f1e259d910ae31309 100644
--- a/tests/lib/Files/Cache/PropagatorTest.php
+++ b/tests/lib/Files/Cache/PropagatorTest.php
@@ -81,6 +81,17 @@ class PropagatorTest extends TestCase {
 		}
 	}
 
+	public function testSizePropagationNoNegative() {
+		$paths = ['', 'foo', 'foo/bar'];
+		$oldInfos = $this->getFileInfos($paths);
+		$this->storage->getPropagator()->propagateChange('foo/bar/file.txt', time(), -100);
+		$newInfos = $this->getFileInfos($paths);
+
+		foreach ($oldInfos as $i => $oldInfo) {
+			$this->assertEquals(-1, $newInfos[$i]->getSize());
+		}
+	}
+
 	public function testBatchedPropagation() {
 		$this->storage->mkdir('foo/baz');
 		$this->storage->mkdir('asd');