diff --git a/src/ORM/DataList.php b/src/ORM/DataList.php index d8c53b4bc..420e40ab8 100644 --- a/src/ORM/DataList.php +++ b/src/ORM/DataList.php @@ -963,7 +963,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li */ public function exists() { - return $this->count() > 0; + return $this->dataQuery->exists(); } /** diff --git a/src/ORM/DataQuery.php b/src/ORM/DataQuery.php index 005b215d2..3bc8996b8 100644 --- a/src/ORM/DataQuery.php +++ b/src/ORM/DataQuery.php @@ -453,6 +453,35 @@ class DataQuery return $this->getFinalisedQuery()->count("DISTINCT {$quotedColumn}"); } + /** + * Return whether this dataquery will have records. This will use `EXISTS` statements in SQL which are more + * performant - especially when used in combination with indexed columns (that you're filtering on) + * + * @return bool + */ + public function exists() + { + // Grab a statement selecting "everything" - the engine shouldn't care what's being selected in an "EXISTS" + // statement anyway + $statement = $this->getFinalisedQuery(); + $statement->setSelect('*'); + + // Clear limit, distinct, grouping, and order as it's not relevant for an exists query + $statement->setDistinct(false); + $statement->setOrderBy(null); + $statement->setGroupBy(null); + $statement->setLimit(null); + + // Wrap the whole thing in an "EXISTS" + $sql = 'SELECT EXISTS(' . $statement->sql($params) . ')'; + $result = DB::prepared_query($sql, $params); + $row = $result->first(); + $result = reset($row); + + // Checking for 't' supports PostgreSQL before silverstripe/postgresql@2.2 + return $result === 1 || $result === 't'; + } + /** * Return the maximum value of the given field in this DataList *