diff --git a/src/Glpi/Search/Provider/SQLProvider.php b/src/Glpi/Search/Provider/SQLProvider.php index 4c638d63e37..6f6470e764f 100644 --- a/src/Glpi/Search/Provider/SQLProvider.php +++ b/src/Glpi/Search/Provider/SQLProvider.php @@ -539,6 +539,15 @@ public static function getSelectCriteria(string $itemtype, int $ID, bool $meta = if (isset($opt["datatype"])) { switch ($opt["datatype"]) { case "count": + if ($opt["use_join_subquery"] ?? false) { + return array_merge([ + QueryFunction::ifnull( + expression: new QueryExpression($DB::quoteName("{$table}{$addtable}.counter")), + value: new QueryExpression($DB::quoteValue('0')), + alias: $NAME, + ), + ], $ADDITONALFIELDS); + } return array_merge([ QueryFunction::count( expression: "$table$addtable.$field", @@ -2716,7 +2725,8 @@ public static function getLeftJoinCriteria( bool $meta = false, string $meta_type = '', array $joinparams = [], - string $field = '' + string $field = '', + bool $use_join_subquery = false ): array { /** @var DBmysql $DB */ global $DB; @@ -2966,18 +2976,44 @@ public static function getLeftJoinCriteria( case 'child': $linkfield = $joinparams['linkfield'] ?? getForeignKeyFieldForTable($cleanrt); - // Child join - $child_join = [ - 'LEFT JOIN' => [ - "$new_table$AS" => [ - 'ON' => [ - $rt => 'id', - $nt => $linkfield, + if ($use_join_subquery) { + $subquery = new QuerySubQuery( + [ + 'SELECT' => [ + $linkfield, + new QueryExpression("COUNT(*)", "counter"), ], + 'FROM' => $new_table, + 'GROUPBY' => $linkfield, ], - ], - ]; - $append_join_criteria($child_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + $nt + ); + + $child_join = [ + 'LEFT JOIN' => [ + [ + 'TABLE' => $subquery, + 'FKEY' => [ + $rt => 'id', + $nt => $linkfield, + ], + ], + ], + ]; + } else { + // Child join + $child_join = [ + 'LEFT JOIN' => [ + "$new_table$AS" => [ + 'ON' => [ + $rt => 'id', + $nt => $linkfield, + ], + ], + ], + ]; + $append_join_criteria($child_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + } $specific_leftjoin_criteria = array_merge_recursive($specific_leftjoin_criteria, $child_join); break; @@ -3057,22 +3093,64 @@ public static function getLeftJoinCriteria( } // Itemtype join - $itemtype_join = [ - 'LEFT JOIN' => [ - "$new_table$AS" => [ - 'ON' => [ - $rt => 'id', - $nt => "{$addmain}{$items_id_column}", - [ - 'AND' => [ - "$nt.{$addmain}{$itemtype_column}" => $used_itemtype, + if ($use_join_subquery) { + $leftjoin = $before_criteria; + $leftjoin['LEFT JOIN']["$new_table$AS"] = [ + 'ON' => [ + $rt => 'id', + $nt => "{$addmain}{$items_id_column}", + [ + 'AND' => [ + "$nt.{$addmain}{$itemtype_column}" => $used_itemtype, + ], + ], + ], + ]; + $leftjoin['INNER JOIN'] = $leftjoin['LEFT JOIN']; + unset($leftjoin['LEFT JOIN']); + $subquery = [ + 'SELECT' => [ + "$ref_table.id", + new QueryExpression("COUNT(DISTINCT $nt.id)", "counter"), + ], + 'FROM' => $ref_table, + 'GROUPBY' => "$ref_table.id", + ] + $leftjoin; + $subtable = new QuerySubQuery( + $subquery, + $nt + ); + + $itemtype_join = [ + 'LEFT JOIN' => [ + [ + 'TABLE' => $subtable, + 'FKEY' => [ + $ref_table => 'id', + $nt => 'id', + ], + ], + ], + ]; + $before_criteria = []; + } else { + $itemtype_join = [ + 'LEFT JOIN' => [ + "$new_table$AS" => [ + 'ON' => [ + $rt => 'id', + $nt => "{$addmain}{$items_id_column}", + [ + 'AND' => [ + "$nt.{$addmain}{$itemtype_column}" => $used_itemtype, + ], ], ], ], ], - ], - ]; - $append_join_criteria($itemtype_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + ]; + $append_join_criteria($itemtype_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + } $specific_leftjoin_criteria = array_merge_recursive($specific_leftjoin_criteria, $itemtype_join); break; @@ -3142,18 +3220,55 @@ public static function getLeftJoinCriteria( break; default: - // Standard join - $standard_join = [ - 'LEFT JOIN' => [ - "$new_table$AS" => [ - 'ON' => [ - $rt => $linkfield, - $nt => 'id', + if ($use_join_subquery) { + $leftjoin = $before_criteria; + $leftjoin['LEFT JOIN']["$new_table$AS"] = [ + 'ON' => [ + $rt => $linkfield, + $nt => 'id', + ], + ]; + $leftjoin['INNER JOIN'] = $leftjoin['LEFT JOIN']; + unset($leftjoin['LEFT JOIN']); + $subquery = [ + 'SELECT' => [ + "$ref_table.id", + new QueryExpression("COUNT(DISTINCT $nt.id)", "counter"), + ], + 'FROM' => $ref_table, + 'GROUPBY' => "$ref_table.id", + ] + $leftjoin; + $subtable = new QuerySubQuery( + $subquery, + $nt + ); + + $standard_join = [ + 'LEFT JOIN' => [ + [ + 'TABLE' => $subtable, + 'FKEY' => [ + $ref_table => 'id', + $nt => 'id', + ], ], ], - ], - ]; - $append_join_criteria($standard_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + ]; + $before_criteria = []; + } else { + // Standard join + $standard_join = [ + 'LEFT JOIN' => [ + "$new_table$AS" => [ + 'ON' => [ + $rt => $linkfield, + $nt => 'id', + ], + ], + ], + ]; + $append_join_criteria($standard_join['LEFT JOIN']["$new_table$AS"]['ON'], $add_criteria); + } $specific_leftjoin_criteria = array_merge_recursive($specific_leftjoin_criteria, $standard_join); $transitemtype = getItemTypeForTable($new_table); if (Session::haveTranslations($transitemtype, $field)) { @@ -4185,7 +4300,8 @@ public static function constructSQL(array &$data) false, '', $searchopt[$val]["joinparams"], - $searchopt[$val]["field"] + $searchopt[$val]["field"], + ($searchopt[$val]['use_join_subquery'] ?? false) ); } } @@ -4894,7 +5010,8 @@ public static function constructAdditionalSqlForMetacriteria( true, $m_itemtype, $sopt["joinparams"], - $sopt["field"] + $sopt["field"], + $sopt['use_join_subquery'] ?? false ); } } diff --git a/src/Search.php b/src/Search.php index 42fe3a98c62..010b5efa200 100644 --- a/src/Search.php +++ b/src/Search.php @@ -701,6 +701,7 @@ public static function addDefaultJoin($itemtype, $ref_table, array &$already_lin * @param string $meta_type Meta item type * @param array $joinparams Array join parameters (condition / joinbefore...) * @param string $field Field to display (needed for translation join) (default '') + * @param bool $use_join_subquery Use a subquery for the join (default false) * * @return string Left join string **/ @@ -713,7 +714,8 @@ public static function addLeftJoin( $meta = false, $meta_type = '', $joinparams = [], - $field = '' + $field = '', + $use_join_subquery = false ) { /** @var DBmysql $DB */ global $DB; @@ -726,7 +728,8 @@ public static function addLeftJoin( (bool) $meta, (string) $meta_type, $joinparams, - $field + $field, + $use_join_subquery ); $iterator = new DBmysqlIterator($DB); $iterator->buildQuery([ diff --git a/src/User.php b/src/User.php index eae4c1062d1..8e70381865f 100644 --- a/src/User.php +++ b/src/User.php @@ -3550,6 +3550,7 @@ public function rawSearchOptions() 'forcegroupby' => true, 'usehaving' => true, 'datatype' => 'count', + 'use_join_subquery' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [ @@ -3570,6 +3571,7 @@ public function rawSearchOptions() 'forcegroupby' => true, 'usehaving' => true, 'datatype' => 'count', + 'use_join_subquery' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child', @@ -3585,6 +3587,7 @@ public function rawSearchOptions() 'forcegroupby' => true, 'usehaving' => true, 'datatype' => 'count', + 'use_join_subquery' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [