mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-18 16:18:47 +02:00
N°1213 - Allow NOT IN SELECT in OQL syntax
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user