N°1213 - Allow NOT IN SELECT in OQL syntax

This commit is contained in:
Eric
2019-12-04 13:58:56 +01:00
parent 8b4fdb54ea
commit 58da108e85
5 changed files with 68 additions and 12 deletions

View File

@@ -699,16 +699,27 @@ class DBObjectSearch extends DBSearch
}
}
public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array())
/**
* Rename aliases of nested queries to avoid duplicates with main query
*
* @param array $aClassAliases array of alias => class for the main query
* @param array $aAliasTranslation translation table of main query to apply to nested queries
*/
public function RenameNestedQueriesAliasesInNameSpace($aClassAliases, $aAliasTranslation = array())
{
// Recurse in nested queries
$this->GetCriteria()->Browse(function($oNode) use ($aClassAliases, $aAliasTranslation) {
$this->GetCriteria()->Browse(function ($oNode) use ($aClassAliases, $aAliasTranslation) {
if ($oNode instanceof NestedQueryExpression)
{
$oNestedQuery = $oNode->GetNestedQuery();
$oNestedQuery->RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation);
}
});
}
public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array())
{
// Recurse in nested queries
$this->RenameNestedQueriesAliasesInNameSpace($aClassAliases, $aAliasTranslation);
$this->AddToNameSpace($aClassAliases, $aAliasTranslation);
$this->TranslateConditions($aAliasTranslation, false, false);
}
@@ -1168,7 +1179,9 @@ class DBObjectSearch extends DBSearch
}
$aAliasTranslation = array();
$oLeftFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
$oLeftFilter->MergeWith_InNamespace($oRightFilter, $aRootClasses, $aAliasTranslation);
$oRightFilter->RenameNestedQueriesAliasesInNameSpace($aRootClasses, $aAliasTranslation);
$oLeftFilter->TransferConditionExpression($oRightFilter, $aAliasTranslation);
$aSearches[] = $oLeftFilter;
}

View File

@@ -382,13 +382,7 @@ class OQLClassTreeBuilder
*/
private function TranslateNestedRequests()
{
$this->oDBObjetSearch->GetCriteria()->Browse(function($oNode) {
if ($oNode instanceof NestedQueryExpression)
{
$oNestedQuery = $oNode->GetNestedQuery();
$aClassAliases = $this->oDBObjetSearch->GetJoinedClasses();
$oNestedQuery->RenameAliasesInNameSpace($aClassAliases);
}
});
$aClassAliases = $this->oDBObjetSearch->GetJoinedClasses();
$this->oDBObjetSearch->RenameNestedQueriesAliasesInNameSpace($aClassAliases);
}
}

View File

@@ -495,6 +495,7 @@ class OQLToSQLTest extends ItopDataTestCase
"SELECT t 143" => array("SELECT `t` FROM TriggerOnObjectUpdate AS `t` WHERE (`t`.`target_class` IN ('appUserPreferences'))", array('t.friendlyname' => true), $aArgs),
);
$aData["SELECT UNION 1"] = array("SELECT `User` FROM User AS `User` WHERE 1 UNION SELECT `User` FROM User AS `User` WHERE (`User`.`id` = 3)", array(), array(), null, array(), 0, 0);
$aData["SELECT 1"] = array("SELECT `UserInternal` FROM UserInternal AS `UserInternal` WHERE ((`UserInternal`.`login` = 'admin') AND (`UserInternal`.`status` = 'enabled'))", unserialize('a:1:{s:12:"friendlyname";b:1;}'), array(), null, array(), 0, 0);
$aData["SELECT 2"] = array("SELECT `Contact` FROM Contact AS `Contact` WHERE (`Contact`.`id` = '987654321')", array(), array(), null, array(), 0, 0);
$aData["SELECT 3"] = array("SELECT `Organization` FROM Organization AS `Organization` WHERE 1", array(), array(), null, array(), 4, 0);

View File

@@ -17,6 +17,8 @@ use DBSearch;
*/
class DBSearchIntersectTest extends ItopDataTestCase
{
const USE_TRANSACTION = false;
protected function setUp()
{
parent::setUp();
@@ -132,14 +134,25 @@ class DBSearchIntersectTest extends ItopDataTestCase
$oRightSearch = DBSearch::FromOQL($sRightSelect);
$oResultSearch = $oLeftSearch->Intersect($oRightSearch);
$sOQLResult = $oResultSearch->ToOQL();
CMDBSource::TestQuery($oResultSearch->MakeSelectQuery());
$this->assertEquals($sResult, $oResultSearch->ToOQL());
$this->assertEquals($sResult, $sOQLResult);
}
public function IntersectProvider()
{
$aTests = array();
$aTests['Nested selects 2'] = array(
'left' => "SELECT `U` FROM UserRequest AS `U` WHERE U.agent_id = 3",
'right' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))",
'result' => "SELECT `U` FROM UserRequest AS `U` JOIN Person AS `P` ON `U`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE ((`U`.`agent_id` = 3) AND (`U`.`org_id` IN (SELECT `Organization1` FROM Organization AS `Organization1` WHERE (`Organization1`.`id` = `U`.`org_id`))))");
$aTests['Nested selects'] = array(
'left' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))",
'right' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE UserRequest.agent_id = 3",
'result' => "SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE ((`UserRequest`.`org_id` IN (SELECT `Organization1` FROM Organization AS `Organization1` WHERE (`Organization1`.`id` = `UserRequest`.`org_id`))) AND (`UserRequest`.`agent_id` = 3))");
$aTests['Multiple selected classes inverted'] = array(
'left' => "SELECT `L`, `P` FROM Person AS `P` JOIN Location AS `L` ON `P`.location_id = `L`.id WHERE 1",
'right' => "SELECT Person WHERE org_id = 3",

View File

@@ -10,6 +10,7 @@
namespace Combodo\iTop\Test\UnitTest\Core;
use CMDBSource;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use DBObjectSearch;
use DBSearch;
@@ -390,4 +391,38 @@ class OQLTest extends ItopDataTestCase
);
}
/**
* @dataProvider MakeSelectQueryProvider
* @param $sOQL
* @param $sExpectedExceptionClass
*/
public function testMakeSelectQuery($sOQL, $sExpectedExceptionClass = '')
{
$sExceptionClass = '';
try
{
$oSearch = DBSearch::FromOQL($sOQL);
CMDBSource::TestQuery($oSearch->MakeSelectQuery());
}
catch (Exception $e)
{
$sExceptionClass = get_class($e);
}
static::assertEquals($sExpectedExceptionClass, $sExceptionClass);
}
public function MakeSelectQueryProvider()
{
return array(
array("SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `Toto`.`org_id`)))", 'OqlNormalizeException'),
array("SELECT `UserRequest` FROM UserRequest AS `UserRequest` JOIN Person AS `P` ON `UserRequest`.agent_id = `P`.id JOIN Organization AS `Organization` ON `P`.org_id = `Organization`.id WHERE (`UserRequest`.`org_id` IN (SELECT `Organization` FROM Organization AS `Organization` WHERE (`Organization`.`id` = `UserRequest`.`org_id`)))"),
array("SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE ((`U`.`status` = 'enabled') AND (`L`.`allowed_org_id` = `P`.`org_id`)) UNION SELECT `U` FROM User AS `U` WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE (`U`.`status` = 'enabled')))))))"),
array("SELECT `Ur` FROM UserRequest AS `Ur` WHERE (`Ur`.`id` NOT IN (SELECT `Ur` FROM UserRequest AS `Ur` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `Ur`.id WHERE 1))"),
array("SELECT `T` FROM Ticket AS `T` WHERE ((`T`.`finalclass` IN ('userrequest', 'change')) AND (`T`.`id` NOT IN (SELECT `Ur` FROM UserRequest AS `Ur` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `Ur`.id WHERE 1 UNION SELECT `C` FROM Change AS `C` JOIN lnkFunctionalCIToTicket AS `lnk` ON `lnk`.ticket_id = `C`.id WHERE 1)))"),
array("SELECT `PhysicalDevice` FROM PhysicalDevice AS `PhysicalDevice` WHERE ((`PhysicalDevice`.`status` = 'production') AND (`PhysicalDevice`.`id` NOT IN (SELECT `p` FROM PhysicalDevice AS `p` JOIN lnkFunctionalCIToProviderContract AS `l` ON `l`.functionalci_id = `p`.id WHERE 1)))"),
array("SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN Person AS `P` ON `U`.contactid = `P`.id JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE ((`U1`.`status` = 'enabled') AND (`L`.`allowed_org_id` = `P`.`org_id`)) UNION SELECT `U` FROM User AS `U` WHERE ((`U`.`status` = 'enabled') AND (`U`.`id` NOT IN (SELECT `U` FROM User AS `U` JOIN URP_UserOrg AS `L` ON `L`.userid = `U`.id WHERE (`U`.`status` = 'enabled')))))))", "OqlNormalizeException"),
);
}
}