From f07f0ba1c710298f2d6c7a8dcba5509727e13097 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 5 Feb 2021 10:15:14 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B03618=20-=20Count=20on=20union=20with=20d?= =?UTF-8?q?ifferent=20conditions=20fails=20(Fix=20multi-column=20attribute?= =?UTF-8?q?s=20sql=20generation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/oql/expression.class.inc.php | 29 ++++++++++ core/querybuilderexpressions.class.inc.php | 8 +++ core/sqlobjectquerybuilder.class.inc.php | 24 +++------ test/core/OQLTest.php | 62 +++++++++++++++++++--- 4 files changed, 101 insertions(+), 22 deletions(-) diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index 141bf4198..2291b339a 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -1672,6 +1672,35 @@ class FieldExpression extends UnaryExpression // Has been resolved into an SQL expression class FieldExpressionResolved extends FieldExpression { + protected $m_aAdditionalExpressions; + + public function __construct($mExpression, $sParent = '') + { + $this->m_aAdditionalExpressions = array(); + if (is_array($mExpression)) + { + foreach ($mExpression as $sSuffix => $sExpression) + { + if ($sSuffix == '') + { + $sName = $sExpression; + } + $this->m_aAdditionalExpressions[$sSuffix] = new FieldExpressionResolved($sExpression, $sParent); + } + } + else + { + $sName = $mExpression; + } + + parent::__construct($sName, $sParent); + } + + public function AdditionalExpressions() + { + return $this->m_aAdditionalExpressions; + } + public function GetUnresolvedFields($sAlias, &$aUnresolved) { } diff --git a/core/querybuilderexpressions.class.inc.php b/core/querybuilderexpressions.class.inc.php index 5f3aca1cf..c713610a8 100644 --- a/core/querybuilderexpressions.class.inc.php +++ b/core/querybuilderexpressions.class.inc.php @@ -178,6 +178,14 @@ class QueryBuilderExpressions foreach ($this->m_aSelectExpr as $sColAlias => $oExpr) { $this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved); + if ($this->m_aSelectExpr[$sColAlias] instanceof FieldExpressionResolved) + { + // Split the field with the relevant alias + foreach ($this->m_aSelectExpr[$sColAlias]->AdditionalExpressions() as $sSuffix => $oAdditionalExpr) + { + $this->m_aSelectExpr[$sColAlias.$sSuffix] = $oAdditionalExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved); + } + } } if ($this->m_aGroupByExpr) { diff --git a/core/sqlobjectquerybuilder.class.inc.php b/core/sqlobjectquerybuilder.class.inc.php index b1ecb1d43..4d85480ba 100644 --- a/core/sqlobjectquerybuilder.class.inc.php +++ b/core/sqlobjectquerybuilder.class.inc.php @@ -239,24 +239,16 @@ class SQLObjectQueryBuilder continue; } $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); - foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr) + $oFieldSQLExp = new FieldExpressionResolved($oAttDef->GetSQLExpressions(), $sClassAlias); + /** + * @var string $sPluginClass + * @var iQueryModifier $oQueryModifier + */ + foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) { - if (!empty($sColId)) - { - // Multi column attributes - $oBuild->m_oQBExpressions->AddSelect($sSelectedClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias)); - } - $oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sClassAlias); - /** - * @var string $sPluginClass - * @var iQueryModifier $oQueryModifier - */ - foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier) - { - $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sClass, $sAttCode, $sColId, $oFieldSQLExp, $oBaseSQLQuery); - } - $aTranslation[$sClassAlias][$sAttCode.$sColId] = $oFieldSQLExp; + $oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sClass, $sAttCode, '', $oFieldSQLExp, $oBaseSQLQuery); } + $aTranslation[$sClassAlias][$sAttCode] = $oFieldSQLExp; } // Translate the selected columns diff --git a/test/core/OQLTest.php b/test/core/OQLTest.php index 54b0293d7..3a3f0cf9d 100644 --- a/test/core/OQLTest.php +++ b/test/core/OQLTest.php @@ -50,6 +50,7 @@ class OQLTest extends ItopDataTestCase /** * @dataProvider NestedQueryProvider + * @depends testOQLSetup * * @param $sQuery * @@ -435,9 +436,7 @@ class OQLTest extends ItopDataTestCase { return [ 'Bug 3660 1' => [ - "SELECT UserRequest AS U - JOIN lnkContactToTicket AS l ON l.ticket_id=U.id - JOIN Team AS T ON l.contact_id=T.id", + "SELECT UserRequest AS U JOIN lnkContactToTicket AS l ON l.ticket_id=U.id JOIN Team AS T ON l.contact_id=T.id", "SELECT `U` FROM `UserRequest` AS `U` INNER JOIN `lnkContactToTicket` AS `l` ON `U`.`id` = `l`.`ticket_id` @@ -445,13 +444,64 @@ class OQLTest extends ItopDataTestCase ON `l`.`contact_id` = `T`.`id`", ], 'Bug 3660 2' => [ - "SELECT UserRequest AS U - JOIN lnkContactToTicket AS l ON l.ticket_id=U.id - JOIN Contact AS C ON l.contact_id=C.id", + "SELECT UserRequest AS U JOIN lnkContactToTicket AS l ON l.ticket_id=U.id JOIN Contact AS C ON l.contact_id=C.id", "SELECT `U` FROM `UserRequest` AS `U` INNER JOIN `lnkContactToTicket` AS `l` ON `U`.`id` = `l`.`ticket_id`", ], ]; } + + /** + * @dataProvider MakeSelectQueryForCountProvider + * + * @param $sOQL + * @param $sExpectedSQL + * + * @throws \CoreException + * @throws \MissingQueryArgument + * @throws \OQLException + */ + public function testMakeSelectQueryForCount($sOQL, $sExpectedSQL) + { + $oFilter = DBSearch::FromOQL($sOQL); + // Avoid adding all the fields for counts or "group by" requests + $aCountAttToLoad = array(); + $sMainClass = null; + foreach ($oFilter->GetSelectedClasses() as $sClassAlias => $sClass) { + $aCountAttToLoad[$sClassAlias] = array(); + if (empty($sMainClass)) { + $sMainClass = $sClass; + } + } + $sSQL = $oFilter->MakeSelectQuery([], [], $aCountAttToLoad, null, 0, 0, true); + static::assertEquals($sExpectedSQL, $sSQL); + } + + public function MakeSelectQueryForCountProvider() + { + return [ + 'Bug 3618' => [ + "SELECT UserRequest WHERE private_log LIKE '%Auteur : %' UNION SELECT Problem", + "SELECT COUNT(*) AS COUNT FROM (SELECT + 1 + FROM ( +SELECT + DISTINCT `UserRequest_Ticket`.`id` AS `UserRequestid` + FROM + `ticket` AS `UserRequest_Ticket` + WHERE ((`UserRequest_Ticket`.`private_log` LIKE '%Auteur : %') AND COALESCE((`UserRequest_Ticket`.`finalclass` IN ('UserRequest')), 1)) + + UNION + SELECT + DISTINCT `Problem`.`id` AS `Problemid` + FROM + `ticket_problem` AS `Problem` + WHERE 1 + +) as __selects__ +) AS _union_alderaan_", + ], + ]; + } }