#360 Wrong COUNT when using JOINS (+ other conditions)

SVN:trunk[1128]
This commit is contained in:
Romain Quetiez
2011-03-11 17:47:03 +00:00
parent cfbf77544e
commit 52a47b193d
2 changed files with 40 additions and 12 deletions

View File

@@ -2161,14 +2161,23 @@ abstract class MetaModel
// //
$aUpdateValues = array(); $aUpdateValues = array();
// 1/a - Get the key and friendly name // 1/a - Get the key and friendly name
// //
// We need one pkey to be the key, let's take the one corresponding to the root class // We need one pkey to be the key, let's take the one corresponding to the root class
// (used to be based on the leaf, but it may happen that this one has no table defined) // (used to be based on the leaf, but it may happen that this one has no table defined)
$sRootClass = self::GetRootClass($sTargetClass); $sRootClass = self::GetRootClass($sTargetClass);
$oSelectedIdField = null;
if ($sTableClass == $sRootClass) if ($sTableClass == $sRootClass)
{ {
$aTranslation[$sTargetAlias]['id'] = new FieldExpressionResolved(self::DBGetKey($sTableClass), $sTableAlias); $oIdField = new FieldExpressionResolved(self::DBGetKey($sTableClass), $sTableAlias);
$aTranslation[$sTargetAlias]['id'] = $oIdField;
if ($bIsOnQueriedClass)
{
// Add this field to the list of queried fields (required for the COUNT to work fine)
$oSelectedIdField = $oIdField;
}
} }
// 1/b - Get the other attributes // 1/b - Get the other attributes
@@ -2227,7 +2236,7 @@ abstract class MetaModel
// 3 - The whole stuff, for this table only // 3 - The whole stuff, for this table only
// //
$oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $aFullText, $bIsOnQueriedClass, $aUpdateValues); $oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $aFullText, $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField);
// 4 - The external keys -> joins... // 4 - The external keys -> joins...
// //

View File

@@ -44,9 +44,10 @@ class SQLQuery
private $m_aFullTextNeedles = array(); private $m_aFullTextNeedles = array();
private $m_bToDelete = true; // The current table must be listed for deletion ? private $m_bToDelete = true; // The current table must be listed for deletion ?
private $m_aValues = array(); // Values to set in case of an update query private $m_aValues = array(); // Values to set in case of an update query
private $m_oSelectedIdField = null;
private $m_aJoinSelects = array(); private $m_aJoinSelects = array();
public function __construct($sTable, $sTableAlias, $aFields, $aFullTextNeedles = array(), $bToDelete = true, $aValues = array()) public function __construct($sTable, $sTableAlias, $aFields, $aFullTextNeedles = array(), $bToDelete = true, $aValues = array(), $oSelectedIdField = null)
{ {
// This check is not needed but for developping purposes // This check is not needed but for developping purposes
//if (!CMDBSource::IsTable($sTable)) //if (!CMDBSource::IsTable($sTable))
@@ -65,6 +66,7 @@ class SQLQuery
$this->m_aFullTextNeedles = $aFullTextNeedles; $this->m_aFullTextNeedles = $aFullTextNeedles;
$this->m_bToDelete = $bToDelete; $this->m_bToDelete = $bToDelete;
$this->m_aValues = $aValues; $this->m_aValues = $aValues;
$this->m_oSelectedIdField = $oSelectedIdField;
} }
public function DisplayHtml() public function DisplayHtml()
@@ -113,7 +115,8 @@ class SQLQuery
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
echo "From ...<br/>\n"; echo "From ...<br/>\n";
echo "<pre style=\"font-size: smaller;\">\n"; echo "<pre style=\"font-size: smaller;\">\n";
print_r($aFrom); print_r($aFrom);
@@ -188,7 +191,8 @@ class SQLQuery
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ... // Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
@@ -222,7 +226,8 @@ class SQLQuery
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom); $sFrom = self::ClauseFrom($aFrom);
$sValues = self::ClauseValues($aSetValues); $sValues = self::ClauseValues($aSetValues);
@@ -239,13 +244,22 @@ class SQLQuery
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom); $sFrom = self::ClauseFrom($aFrom);
$sWhere = self::ClauseWhere($oCondition, $aArgs); $sWhere = self::ClauseWhere($oCondition, $aArgs);
if ($bGetCount) if ($bGetCount)
{ {
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere"; if (count($aSelectedIdFields) > 0)
{
$sIDFields = implode(', ', $aSelectedIdFields);
$sSQL = "SELECT COUNT(DISTINCT $sIDFields) AS COUNT FROM $sFrom WHERE $sWhere";
}
else
{
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
}
} }
else else
{ {
@@ -353,9 +367,9 @@ class SQLQuery
} }
// Purpose: prepare the query data, once for all // Purpose: prepare the query data, once for all
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues) private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
{ {
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues); $sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields);
// Add the full text search condition, based on each and every requested field // Add the full text search condition, based on each and every requested field
// //
@@ -388,7 +402,7 @@ class SQLQuery
return $sTableAlias; return $sTableAlias;
} }
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '') private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '')
{ {
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable); $aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
@@ -429,6 +443,11 @@ class SQLQuery
$aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further! $aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further!
} }
if (!is_null($this->m_oSelectedIdField))
{
$aSelectedIdFields[] = $this->m_oSelectedIdField->Render();
}
// loop on joins, to complete the list of tables/fields/conditions // loop on joins, to complete the list of tables/fields/conditions
// //
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query $aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
@@ -440,7 +459,7 @@ class SQLQuery
$sRightField = $aJoinData["rightfield"]; $sRightField = $aJoinData["rightfield"];
$sRightTableAlias = $aJoinData["righttablealias"]; $sRightTableAlias = $aJoinData["righttablealias"];
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias); $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias);
} }
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom; $aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;