From 8d9ea9dcddefb0e262113222e4f7c2fae49c6725 Mon Sep 17 00:00:00 2001 From: Romain Quetiez Date: Fri, 27 Mar 2009 14:36:14 +0000 Subject: [PATCH] OQL: Fixed a number of bugs, and implemented new features - bug: a JOIN b on b.extkey = a.id - bug: operators precedence (still a shift-reduce conflict with JOINS) - changed pkey into id (preserved the compatibility for DBObjectSearch::AddCondition() - allow implicit class name in WHERE condition - bug: wrong report on typo error - suggest an alternative in case of typo error SVN:code[12] --- core/MyHelpers.class.inc.php | 108 ++++ core/dbobject.class.php | 14 +- core/dbobjectsearch.class.php | 166 ++--- core/expression.class.inc.php | 56 +- core/filterdef.class.inc.php | 8 +- core/metamodel.class.php | 91 ++- core/oql/oql-parser.php | 843 ++++++++++++++------------ core/oql/oql-parser.y | 72 ++- core/oql/oqlexception.class.inc.php | 50 +- core/oql/oqlinterpreter.class.inc.php | 4 + core/oql/oqlquery.class.inc.php | 106 +++- core/sqlquery.class.inc.php | 38 +- core/test.class.inc.php | 7 +- pages/ITopConsultant.php | 5 +- pages/testlist.inc.php | 33 +- 15 files changed, 989 insertions(+), 612 deletions(-) diff --git a/core/MyHelpers.class.inc.php b/core/MyHelpers.class.inc.php index 532ca87c6..59ba892d0 100644 --- a/core/MyHelpers.class.inc.php +++ b/core/MyHelpers.class.inc.php @@ -94,6 +94,113 @@ class MyHelpers echo "\n\n"; } + public static function var_dump_string($var) + { + ob_start(); + print_r($var); + $sRet = ob_get_clean(); + return $sRet; + } + + protected static function first_diff_line($s1, $s2) + { + $aLines1 = explode("\n", $s1); + $aLines2 = explode("\n", $s2); + for ($i = 0 ; $i < min(count($aLines1), count($aLines2)) ; $i++) + { + if ($aLines1[$i] != $aLines2[$i]) return $i; + } + return false; + } + + protected static function highlight_line($sMultiline, $iLine, $sHighlightStart = '', $sHightlightEnd = '') + { + $aLines = explode("\n", $sMultiline); + $aLines[$iLine] = $sHighlightStart.$aLines[$iLine].$sHightlightEnd; + return implode("\n", $aLines); + } + + protected static function first_diff($s1, $s2) + { + // do not work fine with multiline strings + $iLen1 = strlen($s1); + $iLen2 = strlen($s2); + for ($i = 0 ; $i < min($iLen1, $iLen2) ; $i++) + { + if ($s1[$i] !== $s2[$i]) return $i; + } + return false; + } + + protected static function last_diff($s1, $s2) + { + // do not work fine with multiline strings + $iLen1 = strlen($s1); + $iLen2 = strlen($s2); + for ($i = 0 ; $i < min(strlen($s1), strlen($s2)) ; $i++) + { + if ($s1[$iLen1 - $i - 1] !== $s2[$iLen2 - $i - 1]) return array($iLen1 - $i, $iLen2 - $i); + } + return false; + } + + protected static function text_cmp_html($sText1, $sText2, $sHighlight) + { + $iDiffPos = self::first_diff_line($sText1, $sText2); + $sDisp1 = self::highlight_line($sText1, $iDiffPos, '
', '
'); + $sDisp2 = self::highlight_line($sText2, $iDiffPos, '
', '
'); + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "
$sDisp1
$sDisp2
\n"; + } + + protected static function string_cmp_html($s1, $s2, $sHighlight) + { + $iDiffPos = self::first_diff($s1, $s2); + if ($iDiffPos === false) + { + echo "strings are identical"; + return; + } + $sStart = substr($s1, 0, $iDiffPos); + + $aLastDiff = self::last_diff($s1, $s2); + $sEnd = substr($s1, $aLastDiff[0]); + + $sMiddle1 = substr($s1, $iDiffPos, $aLastDiff[0] - $iDiffPos); + $sMiddle2 = substr($s2, $iDiffPos, $aLastDiff[1] - $iDiffPos); + + echo "

$sStart$sMiddle1$sEnd

\n"; + echo "

$sStart$sMiddle2$sEnd

\n"; + } + + protected static function object_cmp_html($oObj1, $oObj2, $sHighlight) + { + $sObj1 = self::var_dump_string($oObj1); + $sObj2 = self::var_dump_string($oObj2); + return self::text_cmp_html($sObj1, $sObj2, $sHighlight); + } + + public static function var_cmp_html($var1, $var2, $sHighlight = 'color:red; font-weight:bold;') + { + if (is_object($var1)) + { + return self::object_cmp_html($var1, $var2, $sHighlight); + } + else if (count(explode("\n", $var1)) > 1) + { + // multiline string + return self::text_cmp_html($var1, $var2, $sHighlight); + } + else + { + return self::string_cmp_html($var1, $var2, $sHighlight); + } + } + public static function get_callstack_html($iLevelsToIgnore = 0, $aCallStack = null) { if ($aCallStack == null) $aCallStack = debug_backtrace(); @@ -176,6 +283,7 @@ class MyHelpers { if (!is_array($aData)) trigger_error("make_table_from_assoc_array: Error - the passed argument is not an array", E_USER_ERROR); $aFirstRow = reset($aData); + if (count($aData) == 0) return ''; if (!is_array($aFirstRow)) trigger_error("make_table_from_assoc_array: Error - the passed argument is not a bi-dimensional array", E_USER_ERROR); $sOutput = ""; $sOutput .= "\n"; diff --git a/core/dbobject.class.php b/core/dbobject.class.php index f96b4cf2f..93b221bca 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -113,7 +113,7 @@ abstract class DBObject $aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey); if (empty($aRow)) { - trigger_error("Failed to reload object of class '".get_class($this)."', pkey = ".$this->m_iKey, E_USER_ERROR); + trigger_error("Failed to reload object of class '".get_class($this)."', id = ".$this->m_iKey, E_USER_ERROR); } $this->FromRow($aRow); @@ -133,7 +133,7 @@ abstract class DBObject $sMyClass = $oRemoteExtKeyAtt->GetTargetClass(); $oMyselfSearch = new DBObjectSearch($sMyClass); - $oMyselfSearch->AddCondition('pkey', $this->m_iKey, '='); + $oMyselfSearch->AddCondition('id', $this->m_iKey, '='); $oLinkSearch = new DBObjectSearch($sLinkClass); $oLinkSearch->AddCondition_PointingTo($oMyselfSearch, $sExtKeyToMe); @@ -157,7 +157,7 @@ abstract class DBObject // Get the key // - $sKeyField = "pkey"; + $sKeyField = "id"; if (!array_key_exists($sKeyField, $aRow)) { // #@# Bug ? @@ -168,7 +168,7 @@ abstract class DBObject $iPKey = $aRow[$sKeyField]; if (!self::IsValidPKey($iPKey)) { - trigger_error("An object PKey must be an integer value ($iPKey)", E_USER_NOTICE); + trigger_error("An object id must be an integer value ($iPKey)", E_USER_NOTICE); } $this->m_iKey = $iPKey; } @@ -367,7 +367,7 @@ abstract class DBObject { if (!self::IsValidPKey($iNewKey)) { - trigger_error("An object PKey must be an integer value ($iNewKey)", E_USER_ERROR); + trigger_error("An object id must be an integer value ($iNewKey)", E_USER_ERROR); } if ($this->m_bIsInDB && !empty($this->m_iKey) && ($this->m_iKey != $iNewKey)) @@ -660,7 +660,7 @@ abstract class DBObject if (count($aChanges) != 0) { $oFilter = new DBObjectSearch(get_class($this)); - $oFilter->AddCondition('pkey', $this->m_iKey, '='); + $oFilter->AddCondition('id', $this->m_iKey, '='); $sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges); CMDBSource::Query($sSQL); @@ -691,7 +691,7 @@ abstract class DBObject public function DBDelete() { $oFilter = new DBObjectSearch(get_class($this)); - $oFilter->AddCondition('pkey', $this->m_iKey, '='); + $oFilter->AddCondition('id', $this->m_iKey, '='); $sSQL = MetaModel::MakeDeleteQuery($oFilter); CMDBSource::Query($sSQL); diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index 45afef985..e7fa9dd95 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -162,7 +162,7 @@ class DBObjectSearch public function __DescribeHTML() { - $sConditionDesc = $this->DescribeConditions(); + $sConditionDesc = $this->DescribeConditions(); if (!empty($sConditionDesc)) { return "Objects of class '$this->m_sClass', $sConditionDesc"; @@ -179,8 +179,8 @@ class DBObjectSearch public function ResetCondition() { $this->m_oSearchCondition = new TrueExpression(); - // ? is that enough, do I need to rebuild the list after the subqueries ? - $this->m_aClasses = array($this->m_sClassAlias => $this->m_sClass); + // ? is that usefull/enough, do I need to rebuild the list after the subqueries ? + // $this->m_aClasses = array($this->m_sClassAlias => $this->m_sClass); } public function AddConditionExpression($oExpression) @@ -190,6 +190,11 @@ class DBObjectSearch public function AddCondition($sFilterCode, $value, $sOpCode = null) { + // #@# backward compatibility for pkey/id + if (strtolower(trim($sFilterCode)) == 'pkey') $sFilterCode = 'id'; +// #@# todo - obsolete smoothly, first send exceptions +// throw new CoreException('SibusQL has been obsoleted, please update your queries', array('sibusql'=>$sQuery, 'oql'=>$oFilter->ToOQL())); + MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->m_sClass)); $oFilterDef = MetaModel::GetClassFilterDef($this->m_sClass, $sFilterCode); @@ -215,11 +220,13 @@ class DBObjectSearch break; case "IN": + if (!is_array($value)) $value = array($value); $sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')'; $sOQLCondition = $oField->Render()." IN $sListExpr"; break; case "NOTIN": + if (!is_array($value)) $value = array($value); $sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')'; $sOQLCondition = $oField->Render()." NOT IN $sListExpr"; break; @@ -271,7 +278,7 @@ class DBObjectSearch $sOrigAlias = $this->m_sClassAlias; if (array_key_exists($sOrigAlias, $aClassAliases)) { - $this->m_sClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); + $this->m_sClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->m_sClass); // Translate the condition expression with the new alias $aAliasTranslation[$sOrigAlias]['*'] = $this->m_sClassAlias; } @@ -316,19 +323,13 @@ class DBObjectSearch } else { - $sOrigAlias = $oFilter->GetClassAlias(); - $sKeyClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); - if ($sKeyClassAlias != $sOrigAlias) - { - // Translate the condition expression with the new alias - $aAliasTranslation[$sOrigAlias]['*'] = $sKeyClassAlias; - } + $oFilter->AddToNamespace($aClassAliases, $aAliasTranslation); // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!! - $oNewFilter = clone $oFilter; - $oNewFilter->ResetCondition(); + // $oNewFilter = clone $oFilter; + // $oNewFilter->ResetCondition(); - $this->m_aPointingTo[$sExtKeyAttCode] = $oNewFilter; + $this->m_aPointingTo[$sExtKeyAttCode] = $oFilter; } } @@ -340,7 +341,7 @@ class DBObjectSearch return $res; } - public function AddCondition_ReferencedBy_InNameSpace(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, &$aClassAliases, &$aAliasTranslation) + protected function AddCondition_ReferencedBy_InNameSpace(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, &$aClassAliases, &$aAliasTranslation) { $sForeignClass = $oFilter->GetClass(); $sForeignClassAlias = $oFilter->GetClassAlias(); @@ -359,19 +360,13 @@ class DBObjectSearch } else { - $sOrigAlias = $oFilter->GetClassAlias(); - $sKeyClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); - if ($sKeyClassAlias != $sOrigAlias) - { - // Translate the condition expression with the new alias - $aAliasTranslation[$sOrigAlias]['*'] = $sKeyClassAlias; - } + $oFilter->AddToNamespace($aClassAliases, $aAliasTranslation); // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!! - $oNewFilter = clone $oFilter; - $oNewFilter->ResetCondition(); + //$oNewFilter = clone $oFilter; + //$oNewFilter->ResetCondition(); - $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oNewFilter; + $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oFilter; } } @@ -593,47 +588,36 @@ class DBObjectSearch return $retValue; } - public function ToSibusQL() + public function ToOQL() { - $aConds = array(); // string conditions, to be merged into a logical AND - foreach($this->m_aFullText as $sFullText) - { - $aConds[] = "* HAS ".self::Value2Expression($sFullText); - } - // #@# todo - changer ToSibusQL en ToOQL et l'implementer ! - // $aConds[] = $this->m_oSearchCondition->ToSibusQL - /* - foreach($this->m_aCriteria as $aCritInfo) - { - $aConds[] = $aCritInfo["filtercode"]." ".$aCritInfo["opcode"]." ".self::Value2Expression($aCritInfo["value"]); - } - */ + $sRes = "SELECT ".$this->GetClass().' AS '.$this->GetClassAlias(); + $sRes .= $this->ToOQL_Joins(); + $sRes .= " WHERE ".$this->m_oSearchCondition->Render(); + return $sRes; + } + + protected function ToOQL_Joins() + { + $sRes = ''; foreach($this->m_aPointingTo as $sExtKey=>$oFilter) { - $aConds[] = $sExtKey." IN (".$oFilter->ToSibusQL().")"; + $sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.' = '.$oFilter->GetClassAlias().'.id'; + $sRes .= $oFilter->ToOQL_Joins(); } foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences) { foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) { - $aConds[] = "PKEY IS ".$sForeignExtKeyAttCode." IN (".$oForeignFilter->ToSibusQL().")"; + $sRes .= ' JOIN '.$oForeignFilter->GetClass().' AS '.$oForeignFilter->GetClassAlias().' ON '.$oForeignFilter->GetClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetClassAlias().'.id'; + $sRes .= $oForeignFilter->ToOQL_Joins(); } } - foreach($this->m_aRelatedTo as $aRelatedTo) - { - $oFilter = $aRelatedTo['flt']; - $sRelCode = $aRelatedTo['relcode']; - $iMaxDepth = $aRelatedTo['maxdepth']; - - $aConds[] = "RELATED ($sRelCode, $iMaxDepth) TO (".$oFilter->ToSibuSQL().")"; - } + return $sRes; + } - $sValue = $this->GetClass(); - if (count($aConds) > 0) - { - $sValue .= ": ".implode(" AND ", $aConds); - } - return $sValue; + public function ToSibusQL() + { + return "NONONO"; } static private function privProcessParams($sQuery, array $aParams, $oDbObject) @@ -659,7 +643,7 @@ class DBObjectSearch if (strpos($sParameterName, "this.") === 0) { $sAttCode = substr($sParameterName, strlen("this.")); - if ($sAttCode == 'pkey') + if ($sAttCode == 'id') { $sValue = $oDbObject->GetKey(); } @@ -717,19 +701,37 @@ class DBObjectSearch $sFltCode = $oExpression->GetName(); if (empty($sClassAlias)) { - $iPos = $oExpression->GetPosition(); - throw new OqlNormalizeException('Missing class specification', $sQuery, 0, $iPos, ''); + // Try to find an alias + // Build an array of field => array of aliases + $aFieldClasses = array(); + foreach($aClassAliases as $sAlias => $sReal) + { + foreach(MetaModel::GetFiltersList($sReal) as $sAnFltCode) + { + $aFieldClasses[$sAnFltCode][] = $sAlias; + } + } + if (!array_key_exists($sFltCode, $aFieldClasses)) + { + throw new OqlNormalizeException('Unknown filter code', $sQuery, $oExpression->GetNameDetails(), array_keys($aFieldClasses)); + } + if (count($aFieldClasses[$sFltCode]) > 1) + { + throw new OqlNormalizeException('Ambiguous filter code', $sQuery, $oExpression->GetNameDetails()); + } + $sClassAlias = $aFieldClasses[$sFltCode][0]; } - if (!array_key_exists($sClassAlias, $aClassAliases)) + else { - $iPos = $oExpression->GetPosition(); - throw new OqlNormalizeException('Unknown class', $sQuery, 0, $iPos, $sClassAlias, array_keys($aClassAliases)); - } - $sClass = $aClassAliases[$sClassAlias]; - if (!MetaModel::IsValidFilterCode($sClass, $sFltCode)) - { - $iPos = $oExpression->GetPosition(); - throw new OqlNormalizeException('Unknown filter code', $sQuery, 0, $iPos, "$sFltCode in class $sClassAlias", MetaModel::GetFiltersList($sClass)); + if (!array_key_exists($sClassAlias, $aClassAliases)) + { + throw new OqlNormalizeException('Unknown class [alias]', $sQuery, $oExpression->GetParentDetails(), array_keys($aClassAliases)); + } + $sClass = $aClassAliases[$sClassAlias]; + if (!MetaModel::IsValidFilterCode($sClass, $sFltCode)) + { + throw new OqlNormalizeException('Unknown filter code', $sQuery, $oExpression->GetNameDetails(), MetaModel::GetFiltersList($sClass)); + } } return new FieldExpression($sFltCode, $sClassAlias); @@ -768,11 +770,11 @@ class DBObjectSearch if (!MetaModel::IsValidClass($sClass)) { - throw new OqlNormalizeException('Unknown class', $sQuery, 0, 0, $sClass, MetaModel::GetClasses()); + throw new OqlNormalizeException('Unknown class', $sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses()); } $oResultFilter = new DBObjectSearch($sClass, $sClassAlias); - $oResultFilter->m_aClasses = array($sClassAlias => $sClass); + $aAliases = array($sClassAlias => $sClass); // Maintain an array of filters, because the flat list is in fact referring to a tree // And this will be an easy way to dispatch the conditions @@ -788,17 +790,17 @@ class DBObjectSearch $sJoinClassAlias = $oJoinSpec->GetClassAlias(); if (!MetaModel::IsValidClass($sJoinClass)) { - throw new OqlNormalizeException('Unknown class', $sQuery, 0, 0, $sJoinClass, MetaModel::GetClasses()); + throw new OqlNormalizeException('Unknown class', $sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses()); } - if (array_key_exists($sJoinClassAlias, $oResultFilter->m_aClasses)) + if (array_key_exists($sJoinClassAlias, $aAliases)) { if ($sJoinClassAlias != $sJoinClass) { - throw new OqlNormalizeException('Duplicate class alias', $sQuery, 0, 0, $sJoinClassAlias); + throw new OqlNormalizeException('Duplicate class alias', $sQuery, $oJoinSpec->GetClassAliasDetails()); } else { - throw new OqlNormalizeException('Duplicate class name', $sQuery, 0, 0, $sJoinClass); + throw new OqlNormalizeException('Duplicate class name', $sQuery, $oJoinSpec->GetClassDetails()); } } @@ -813,24 +815,24 @@ class DBObjectSearch $sPKeyDescriptor = $oRightField->GetName(); if ($sPKeyDescriptor != 'id') { - throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sQuery, 0, $oRightField->GetPosition(), $sPKeyDescriptor, array('id')); + throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sQuery, $oRightField->GetNameDetails(), array('id')); } - $oResultFilter->m_aClasses[$sJoinClassAlias] = $sJoinClass; + $aAliases[$sJoinClassAlias] = $sJoinClass; $aJoinItems[$sJoinClassAlias] = new DBObjectSearch($sJoinClass, $sJoinClassAlias); if (!array_key_exists($sFromClass, $aJoinItems)) { - throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sQuery, 0, $oLeftField->GetPosition(), $sFromClass, array_keys($aJoinItems)); + throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sQuery, $oLeftField->GetParentDetails(), array_keys($aJoinItems)); } if (!array_key_exists($sToClass, $aJoinItems)) { - throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sQuery, 0, $oRightField->GetPosition(), $sToClass, array_keys($aJoinItems)); + throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sQuery, $oRightField->GetParentDetails(), array_keys($aJoinItems)); } - $aExtKeys = array_keys(MetaModel::GetExternalKeys($oResultFilter->m_aClasses[$sFromClass])); + $aExtKeys = array_keys(MetaModel::GetExternalKeys($aAliases[$sFromClass])); if (!in_array($sExtKeyAttCode, $aExtKeys)) { - throw new OqlNormalizeException('Unknown external key in join condition (left expression)', $sQuery, 0, $oLeftField->GetPosition(), $sExtKeyAttCode, $aExtKeys); + throw new OqlNormalizeException('Unknown external key in join condition (left expression)', $sQuery, $oLeftField->GetNameDetails(), $aExtKeys); } if ($sFromClass == $sJoinClassAlias) @@ -847,7 +849,7 @@ class DBObjectSearch $oConditionTree = $oOqlQuery->GetCondition(); if ($oConditionTree instanceof Expression) { - $oResultFilter->m_oSearchCondition = $oResultFilter->OQLExpressionToCondition($sQuery, $oConditionTree, $oResultFilter->m_aClasses); + $oResultFilter->m_oSearchCondition = $oResultFilter->OQLExpressionToCondition($sQuery, $oConditionTree, $aAliases); } return $oResultFilter; @@ -934,6 +936,10 @@ class DBObjectSearch } } } + +// #@# todo - obsolete smoothly, first give the OQL version ! +// throw new CoreException('SibusQL has been obsoleted, please update your queries', array('sibusql'=>$sQuery, 'oql'=>$oFilter->ToOQL())); + return $oFilter; } diff --git a/core/expression.class.inc.php b/core/expression.class.inc.php index 427fcb4ad..76409cdc1 100644 --- a/core/expression.class.inc.php +++ b/core/expression.class.inc.php @@ -22,6 +22,8 @@ abstract class Expression // recursively builds an array of class => fieldname abstract public function ListRequiredFields(); + abstract public function IsTrue(); + public function RequiresField($sClass, $sFieldName) { // #@# todo - optimize : this is called quite often when building a single query ! @@ -50,6 +52,8 @@ abstract class Expression public function LogAnd($oExpr) { + if ($this->IsTrue()) return clone $oExpr; + if ($oExpr->IsTrue()) return clone $this; return new BinaryExpression($this, 'AND', $oExpr); } @@ -57,7 +61,6 @@ abstract class Expression { return new BinaryExpression($this, 'OR', $oExpr); } - } @@ -90,6 +93,16 @@ class BinaryExpression extends Expression $this->m_sOperator = $sOperator; } + public function IsTrue() + { + // return true if we are certain that it will be true + if ($this->m_sOperator == 'AND') + { + if ($this->m_oLeftExpr->IsTrue() && $this->m_oLeftExpr->IsTrue()) return true; + } + return false; + } + public function GetLeftExpr() { return $this->m_oLeftExpr; @@ -139,6 +152,12 @@ class UnaryExpression extends Expression $this->m_value = $value; } + public function IsTrue() + { + // return true if we are certain that it will be true + return ($this->m_value == 1); + } + public function GetValue() { return $this->m_value; @@ -179,6 +198,11 @@ class TrueExpression extends ScalarExpression { parent::__construct(1); } + + public function IsTrue() + { + return true; + } } class FieldExpression extends UnaryExpression @@ -194,6 +218,12 @@ class FieldExpression extends UnaryExpression $this->m_sName = $sName; } + public function IsTrue() + { + // return true if we are certain that it will be true + return false; + } + public function GetParent() {return $this->m_sParent;} public function GetName() {return $this->m_sName;} @@ -251,6 +281,12 @@ class ListExpression extends Expression $this->m_aExpressions = $aExpressions; } + public function IsTrue() + { + // return true if we are certain that it will be true + return false; + } + public function GetItems() { return $this->m_aExpressions; @@ -300,6 +336,12 @@ class FunctionExpression extends Expression $this->m_aArgs = $aArgExpressions; } + public function IsTrue() + { + // return true if we are certain that it will be true + return false; + } + public function GetVerb() { return $this->m_sVerb; @@ -353,6 +395,12 @@ class IntervalExpression extends Expression $this->m_sUnit = $sUnit; } + public function IsTrue() + { + // return true if we are certain that it will be true + return false; + } + public function GetValue() { return $this->m_oValue; @@ -389,6 +437,12 @@ class CharConcatExpression extends Expression $this->m_aExpressions = $aExpressions; } + public function IsTrue() + { + // return true if we are certain that it will be true + return false; + } + public function GetItems() { return $this->m_aExpressions; diff --git a/core/filterdef.class.inc.php b/core/filterdef.class.inc.php index 46ec424ed..ec09f50a0 100644 --- a/core/filterdef.class.inc.php +++ b/core/filterdef.class.inc.php @@ -107,10 +107,10 @@ class FilterPrivateKey extends FilterDefinition { static protected function ListExpectedParams() { - return array_merge(parent::ListExpectedParams(), array("pkey_field")); + return array_merge(parent::ListExpectedParams(), array("id_field")); } - public function GetType() {return "PKey";} + public function GetType() {return "PrivateKey";} public function GetTypeDesc() {return "Match against object identifier";} public function GetLabel() @@ -139,7 +139,7 @@ class FilterPrivateKey extends FilterDefinition public function GetFilterSQLExpr($sOpCode, $value) { - $sFieldName = $this->Get("pkey_field"); + $sFieldName = $this->Get("id_field"); // #@# not obliged to quote... these are numbers !!! $sQValue = CMDBSource::Quote($value); switch($sOpCode) @@ -162,7 +162,7 @@ class FilterPrivateKey extends FilterDefinition } public function TemporaryGetSQLCol() { - return $this->Get("pkey_field"); + return $this->Get("id_field"); } } diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 96bb44dac..ed6dfc87f 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -274,7 +274,7 @@ abstract class MetaModel final static public function DBGetTable($sClass, $sAttCode = null) { self::_check_subclass($sClass); - if (empty($sAttCode) || ($sAttCode == "pkey")) + if (empty($sAttCode) || ($sAttCode == "id")) { $sTableRaw = self::$m_aClassParams[$sClass]["db_table"]; if (empty($sTableRaw)) @@ -801,19 +801,19 @@ abstract class MetaModel } } - // Add a 'pkey' filter + // Add a 'id' filter // - if (array_key_exists('pkey', self::$m_aAttribDefs[$sClass])) + if (array_key_exists('id', self::$m_aAttribDefs[$sClass])) { - trigger_error("Class $sClass, 'pkey' is a reserved keyword, it cannot be used as an attribute code", E_USER_ERROR); + trigger_error("Class $sClass, 'id' is a reserved keyword, it cannot be used as an attribute code", E_USER_ERROR); } - if (array_key_exists('pkey', self::$m_aFilterDefs[$sClass])) + if (array_key_exists('id', self::$m_aFilterDefs[$sClass])) { - trigger_error("Class $sClass, 'pkey' is a reserved keyword, it cannot be used as a filter code", E_USER_ERROR); + trigger_error("Class $sClass, 'id' is a reserved keyword, it cannot be used as a filter code", E_USER_ERROR); } - $oFilter = new FilterPrivateKey('pkey', array('pkey_field' => self::DBGetKey($sClass))); - self::$m_aFilterDefs[$sClass]['pkey'] = $oFilter; - self::$m_aFilterOrigins[$sClass]['pkey'] = $sClass; + $oFilter = new FilterPrivateKey('id', array('id_field' => self::DBGetKey($sClass))); + self::$m_aFilterDefs[$sClass]['id'] = $oFilter; + self::$m_aFilterOrigins[$sClass]['id'] = $sClass; // Add a 'class' attribute/filter to the root classes and their children // @@ -1270,8 +1270,8 @@ abstract class MetaModel if (empty($aExpectedAtts) && $bIsOnQueriedClass) { - // default to the whole list of attributes + the very std pkey/finalclass - $aExpectedAtts['pkey'] = 'pkey'; + // default to the whole list of attributes + the very std id/finalclass + $aExpectedAtts['id'] = 'id'; foreach (self::GetAttributesList($sClass) as $sAttCode) { $aExpectedAtts[$sAttCode] = $sAttCode; // alias == attcode @@ -1337,7 +1337,6 @@ abstract class MetaModel // Filter on objects referencing me foreach ($oFilter->GetCriteria_ReferencedBy() as $sForeignClass => $aKeysAndFilters) { - $sForeignClassAlias = $oFilter->GetClassAlias(); foreach ($aKeysAndFilters as $sForeignKeyAttCode => $oForeignFilter) { $oForeignKeyAttDef = self::GetAttributeDef($sForeignClass, $sForeignKeyAttCode); @@ -1352,8 +1351,10 @@ abstract class MetaModel //self::DbgTrace($oSelectForeign->RenderSelect(array())); $oSelectForeign = self::MakeQuery($sGlobalTargetAlias, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oForeignFilter, $aExpAtts); - $sForeignKeyField = $oForeignKeyAttDef->GetSQLExpr(); - $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyField); + $sForeignClassAlias = $oForeignFilter->GetClassAlias(); + $sForeignKeyTable = $aTranslation[$sForeignClassAlias][$sForeignKeyAttCode][0]; + $sForeignKeyColumn = $aTranslation[$sForeignClassAlias][$sForeignKeyAttCode][1]; + $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable); } } @@ -1415,7 +1416,7 @@ abstract class MetaModel $sTargetClass = $oFilter->GetClass(); $sTargetAlias = $oFilter->GetClassAlias(); $sTable = self::DBGetTable($sTableClass); - $sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTable, $sTable); + $sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTargetAlias.'_'.$sTable, $sTable); $bIsOnQueriedClass = ($sTargetAlias == $sGlobalTargetAlias); @@ -1432,12 +1433,12 @@ abstract class MetaModel // if ($bIsOnQueriedClass) { - $aSelect[$aExpectedAtts['pkey']] = new FieldExpression(self::DBGetKey($sTableClass), $sTableAlias); + $aSelect[$aExpectedAtts['id']] = new FieldExpression(self::DBGetKey($sTableClass), $sTableAlias); } // We need one pkey to be the key, let's take the one corresponding to the leaf if ($sTableClass == $sTargetClass) { - $aTranslation[$sTargetAlias]['pkey'] = array($sTableAlias, self::DBGetKey($sTableClass)); + $aTranslation[$sTargetAlias]['id'] = array($sTableAlias, self::DBGetKey($sTableClass)); } // 1/b - Get the other attributes @@ -1481,10 +1482,6 @@ abstract class MetaModel // foreach(self::$m_aFilterDefs[$sTargetClass] as $sFltCode => $oFltAtt) { - // Skip pkey - // no, this is a bug now! ?!?!? - // if ($sFltCode == 'pkey') continue; - // Skip this filter if not defined in this table if (self::$m_aFilterOrigins[$sTargetClass][$sFltCode] != $sTableClass) continue; @@ -1579,23 +1576,25 @@ abstract class MetaModel return $oSelectBase; } - public static function GenerateUniqueAlias(&$aAliases, $sNewName, $sRealName, $iTentative = 0) + public static function GenerateUniqueAlias(&$aAliases, $sNewName, $sRealName) { - // Algo: Build an alias, then check it amongst the contents of $aAliases - - if ($iTentative == 0) $sProposedAlias = $sNewName; - else $sProposedAlias = $sNewName.$iTentative; - - foreach($aAliases as $sAlias=>$sNameWeDontCare) + if (!array_key_exists($sNewName, $aAliases)) { - // If the name is already used, then recursively try to get another one - if ($sProposedAlias == $sAlias) return self::GenerateUniqueAlias($aAliases, $sNewName, $sRealName, $iTentative + 1); + $aAliases[$sNewName] = $sRealName; + return $sNewName; } - - // The proposed alias has been proven to be unique - // Record it and return its value - $aAliases[$sProposedAlias] = $sRealName; - return $sProposedAlias; + + for ($i = 1 ; $i < 100 ; $i++) + { + $sAnAlias = $sNewName.$i; + if (!array_key_exists($sAnAlias, $aAliases)) + { + // Create that new alias + $aAliases[$sAnAlias] = $sRealName; + return $sAnAlias; + } + } + throw new CoreException('Failed to create an alias', array('aliases' => $aAliases, 'new'=>$sNewName)); } public static function CheckDefinitions() @@ -1630,7 +1629,7 @@ abstract class MetaModel if (empty($sNameAttCode)) { // let's try this !!! - // $aErrors[$sClass][] = "Missing value for name definition: the framework will (should...) replace it by the pkey"; + // $aErrors[$sClass][] = "Missing value for name definition: the framework will (should...) replace it by the id"; // $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); } else if(!self::IsValidAttCode($sClass, $sNameAttCode)) @@ -2013,7 +2012,7 @@ abstract class MetaModel { $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; } - $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "pkey"); + $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "id"); if (count($aWrongRecords) == 0) return; if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); @@ -2069,7 +2068,7 @@ abstract class MetaModel // skip the current table if ($sFriendTable == $sTable) continue; - $sFindRelatedRec = "SELECT DISTINCT maintable.`$sFriendKey` AS pkey FROM `$sFriendTable` AS maintable WHERE maintable.`$sFriendKey` IN ($sDeleteKeys)"; + $sFindRelatedRec = "SELECT DISTINCT maintable.`$sFriendKey` AS id FROM `$sFriendTable` AS maintable WHERE maintable.`$sFriendKey` IN ($sDeleteKeys)"; self::DBCheckIntegrity_Check2Delete($sFindRelatedRec, "Cascading deletion of record in friend table `$sTable`", $sFriendClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel, true); } } @@ -2085,7 +2084,7 @@ abstract class MetaModel { $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; } - $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "pkey"); + $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "id"); if (count($aWrongRecords) == 0) return; if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); @@ -2150,7 +2149,7 @@ abstract class MetaModel $aAllowedValues = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); $sAllowedValues = implode(",", CMDBSource::Quote($aAllowedValues, true)); - $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` AS maintable WHERE `$sFinalClassField` NOT IN ($sAllowedValues)"; + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE `$sFinalClassField` NOT IN ($sAllowedValues)"; self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "final class (field `$sFinalClassField`) is wrong (expected a value in {".$sAllowedValues."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); } @@ -2168,13 +2167,13 @@ abstract class MetaModel // Check that any record found here has its counterpart in the root table // and which refers to a child class // - $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` as maintable LEFT JOIN `$sRootTable` ON maintable.`$sKeyField` = `$sRootTable`.`$sRootKey` AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses) WHERE `$sRootTable`.`$sRootKey` IS NULL"; + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` as maintable LEFT JOIN `$sRootTable` ON maintable.`$sKeyField` = `$sRootTable`.`$sRootKey` AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses) WHERE `$sRootTable`.`$sRootKey` IS NULL"; self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in `$sTable`, but no counterpart in root table `$sRootTable` (inc. records pointing to a class in {".$sExpectedClasses."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); // Check that any record found in the root table and referring to a child class // has its counterpart here (detect orphan nodes -root or in the middle of the hierarchy) // - $sSelWrongRecs = "SELECT DISTINCT maintable.`$sRootKey` AS pkey FROM `$sRootTable` AS maintable LEFT JOIN `$sTable` ON maintable.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND maintable.`$sFinalClassField` IN ($sExpectedClasses)"; + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sRootKey` AS id FROM `$sRootTable` AS maintable LEFT JOIN `$sTable` ON maintable.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND maintable.`$sFinalClassField` IN ($sExpectedClasses)"; self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in root table `$sRootTable`, but no counterpart in table `$sTable` (root records pointing to a class in {".$sExpectedClasses."})", $sRootClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); } @@ -2194,7 +2193,7 @@ abstract class MetaModel $sExtKeyField = $oAttDef->GetSQLExpr(); // Note: a class/table may have an external key on itself - $sSelBase = "SELECT DISTINCT maintable.`$sKeyField` AS pkey, maintable.`$sExtKeyField` AS extkey FROM `$sTable` AS maintable LEFT JOIN `$sRemoteTable` ON maintable.`$sExtKeyField` = `$sRemoteTable`.`$sRemoteKey`"; + $sSelBase = "SELECT DISTINCT maintable.`$sKeyField` AS id, maintable.`$sExtKeyField` AS extkey FROM `$sTable` AS maintable LEFT JOIN `$sRemoteTable` ON maintable.`$sExtKeyField` = `$sRemoteTable`.`$sRemoteKey`"; $sSelWrongRecs = $sSelBase." WHERE `$sRemoteTable`.`$sRemoteKey` IS NULL"; if ($oAttDef->IsNullAllowed()) @@ -2239,7 +2238,7 @@ abstract class MetaModel $sMyAttributeField = $oAttDef->GetSQLExpr(); $sDefaultValue = $oAttDef->GetDefaultValue(); - $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` AS maintable WHERE maintable.`$sMyAttributeField` NOT IN ($sExpectedValues)"; + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE maintable.`$sMyAttributeField` NOT IN ($sExpectedValues)"; self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record having a column ('$sAttCode') with an unexpected value", $sMyAttributeField, CMDBSource::Quote($sDefaultValue), $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); } } @@ -2464,7 +2463,7 @@ abstract class MetaModel public static function MakeSingleRow($sClass, $iKey) { $oFilter = new DBObjectSearch($sClass); - $oFilter->AddCondition('pkey', $iKey, '='); + $oFilter->AddCondition('id', $iKey, '='); $sSQL = self::MakeSelectQuery($oFilter); //echo "$sSQL
\n"; @@ -2496,7 +2495,7 @@ abstract class MetaModel // @#@ possible improvement: check that the class is valid ! $sRootClass = self::GetRootClass($sClass); $sFinalClassField = self::DBGetClassField($sRootClass); - trigger_error("Empty class name for object $sClass::{$aRow["pkey"]} (root class '$sRootClass', field '{$sFinalClassField}' is empty)", E_USER_ERROR); + trigger_error("Empty class name for object $sClass::{$aRow["id"]} (root class '$sRootClass', field '{$sFinalClassField}' is empty)", E_USER_ERROR); } else { diff --git a/core/oql/oql-parser.php b/core/oql/oql-parser.php index faf64faee..4fdffa704 100644 --- a/core/oql/oql-parser.php +++ b/core/oql/oql-parser.php @@ -131,14 +131,14 @@ class OQLParserRaw#line 102 "oql-parser.php" const NOT_EQ = 18; const LOG_AND = 19; const LOG_OR = 20; - const GT = 21; - const LT = 22; - const GE = 23; - const LE = 24; - const MATH_DIV = 25; - const MATH_MULT = 26; - const MATH_PLUS = 27; - const MATH_MINUS = 28; + const MATH_DIV = 21; + const MATH_MULT = 22; + const MATH_PLUS = 23; + const MATH_MINUS = 24; + const GT = 25; + const LT = 26; + const GE = 27; + const LE = 28; const LIKE = 29; const NOT_LIKE = 30; const IN = 31; @@ -160,9 +160,9 @@ class OQLParserRaw#line 102 "oql-parser.php" const F_DATE_SUB = 47; const F_ROUND = 48; const F_FLOOR = 49; - const YY_NO_ACTION = 186; - const YY_ACCEPT_ACTION = 185; - const YY_ERROR_ACTION = 184; + const YY_NO_ACTION = 205; + const YY_ACCEPT_ACTION = 204; + const YY_ERROR_ACTION = 203; /* Next are that tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement @@ -214,99 +214,111 @@ class OQLParserRaw#line 102 "oql-parser.php" ** shifting non-terminals after a reduce. ** self::$yy_default Default action for each state. */ - const YY_SZ_ACTTAB = 369; + const YY_SZ_ACTTAB = 419; static public $yy_action = array( - /* 0 */ 6, 67, 66, 5, 61, 62, 60, 65, 35, 67, - /* 10 */ 66, 82, 30, 83, 13, 81, 75, 74, 68, 81, - /* 20 */ 75, 74, 68, 8, 29, 20, 42, 44, 41, 43, - /* 30 */ 36, 37, 38, 39, 63, 58, 57, 56, 59, 55, - /* 40 */ 54, 48, 47, 23, 40, 40, 31, 49, 4, 6, - /* 50 */ 27, 52, 14, 61, 62, 60, 94, 35, 67, 66, - /* 60 */ 64, 2, 69, 70, 73, 22, 40, 50, 15, 18, - /* 70 */ 26, 21, 18, 19, 33, 42, 44, 41, 43, 36, - /* 80 */ 37, 38, 39, 63, 58, 57, 56, 59, 55, 54, - /* 90 */ 48, 47, 6, 4, 40, 27, 61, 62, 60, 3, - /* 100 */ 35, 67, 66, 46, 24, 1, 18, 69, 70, 73, - /* 110 */ 80, 25, 16, 19, 35, 77, 17, 158, 42, 44, - /* 120 */ 41, 43, 36, 37, 38, 39, 63, 58, 57, 56, - /* 130 */ 59, 55, 54, 48, 47, 72, 40, 158, 158, 158, - /* 140 */ 93, 92, 105, 158, 158, 158, 158, 71, 84, 85, - /* 150 */ 99, 98, 97, 100, 101, 104, 103, 102, 96, 95, - /* 160 */ 89, 88, 72, 158, 79, 158, 158, 158, 158, 158, - /* 170 */ 158, 158, 158, 158, 71, 84, 85, 99, 98, 97, - /* 180 */ 100, 101, 104, 103, 102, 96, 95, 89, 88, 72, - /* 190 */ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - /* 200 */ 158, 71, 84, 85, 99, 98, 97, 100, 101, 104, - /* 210 */ 103, 102, 96, 95, 89, 88, 185, 90, 78, 31, - /* 220 */ 158, 158, 158, 158, 86, 12, 158, 87, 158, 31, - /* 230 */ 32, 158, 158, 53, 34, 81, 75, 74, 68, 40, - /* 240 */ 31, 158, 158, 158, 158, 86, 11, 158, 87, 40, - /* 250 */ 158, 32, 28, 158, 45, 158, 81, 75, 74, 68, - /* 260 */ 40, 31, 158, 158, 158, 158, 86, 11, 158, 87, - /* 270 */ 158, 158, 32, 158, 158, 91, 158, 81, 75, 74, - /* 280 */ 68, 40, 158, 158, 76, 31, 158, 158, 158, 158, - /* 290 */ 86, 12, 158, 87, 158, 31, 32, 158, 158, 51, - /* 300 */ 34, 81, 75, 74, 68, 40, 31, 158, 158, 158, - /* 310 */ 158, 86, 9, 158, 87, 40, 158, 32, 158, 158, - /* 320 */ 158, 158, 81, 75, 74, 68, 40, 31, 158, 158, - /* 330 */ 158, 158, 86, 10, 158, 87, 158, 158, 32, 158, - /* 340 */ 158, 158, 158, 81, 75, 74, 68, 40, 31, 158, - /* 350 */ 158, 158, 158, 86, 7, 158, 87, 158, 158, 32, - /* 360 */ 158, 158, 158, 158, 81, 75, 74, 68, 40, + /* 0 */ 5, 57, 8, 4, 95, 96, 97, 6, 93, 76, + /* 10 */ 77, 89, 2, 53, 86, 50, 54, 25, 52, 55, + /* 20 */ 51, 46, 47, 49, 56, 70, 94, 110, 109, 108, + /* 30 */ 107, 111, 112, 115, 114, 113, 106, 71, 98, 99, + /* 40 */ 100, 104, 103, 26, 66, 38, 42, 9, 81, 5, + /* 50 */ 62, 44, 82, 95, 96, 97, 3, 93, 76, 77, + /* 60 */ 39, 102, 92, 75, 74, 73, 72, 75, 74, 73, + /* 70 */ 72, 10, 66, 41, 91, 94, 110, 109, 108, 107, + /* 80 */ 111, 112, 115, 114, 113, 106, 71, 98, 99, 100, + /* 90 */ 104, 103, 5, 63, 90, 22, 95, 96, 97, 61, + /* 100 */ 93, 76, 77, 65, 64, 60, 83, 11, 80, 79, + /* 110 */ 91, 33, 91, 22, 21, 18, 16, 12, 94, 110, + /* 120 */ 109, 108, 107, 111, 112, 115, 114, 113, 106, 71, + /* 130 */ 98, 99, 100, 104, 103, 204, 105, 87, 42, 23, + /* 140 */ 43, 24, 66, 88, 30, 28, 84, 45, 36, 6, + /* 150 */ 22, 20, 58, 15, 32, 37, 1, 76, 77, 101, + /* 160 */ 116, 75, 74, 73, 72, 41, 13, 66, 7, 160, + /* 170 */ 67, 93, 24, 42, 35, 78, 173, 173, 88, 34, + /* 180 */ 28, 84, 45, 40, 42, 173, 20, 173, 15, 69, + /* 190 */ 37, 173, 173, 173, 59, 173, 75, 74, 73, 72, + /* 200 */ 41, 42, 173, 173, 173, 173, 88, 34, 28, 84, + /* 210 */ 45, 41, 173, 173, 20, 173, 15, 173, 37, 173, + /* 220 */ 173, 173, 68, 173, 75, 74, 73, 72, 41, 173, + /* 230 */ 173, 173, 85, 42, 173, 173, 173, 173, 88, 30, + /* 240 */ 28, 84, 45, 173, 173, 173, 20, 173, 15, 173, + /* 250 */ 37, 173, 173, 173, 173, 173, 75, 74, 73, 72, + /* 260 */ 41, 42, 173, 173, 173, 173, 88, 17, 28, 84, + /* 270 */ 45, 173, 173, 173, 20, 173, 15, 42, 37, 173, + /* 280 */ 173, 48, 44, 173, 75, 74, 73, 72, 41, 173, + /* 290 */ 173, 173, 173, 42, 173, 173, 173, 173, 88, 27, + /* 300 */ 28, 84, 45, 173, 41, 173, 20, 173, 15, 173, + /* 310 */ 37, 173, 173, 173, 173, 173, 75, 74, 73, 72, + /* 320 */ 41, 42, 173, 173, 173, 173, 88, 173, 28, 84, + /* 330 */ 45, 173, 173, 173, 20, 173, 15, 173, 31, 173, + /* 340 */ 173, 173, 173, 173, 75, 74, 73, 72, 41, 173, + /* 350 */ 173, 173, 173, 42, 173, 173, 173, 173, 88, 173, + /* 360 */ 28, 84, 45, 173, 173, 173, 20, 173, 14, 173, + /* 370 */ 173, 173, 173, 173, 173, 173, 75, 74, 73, 72, + /* 380 */ 41, 42, 173, 173, 173, 173, 88, 173, 28, 84, + /* 390 */ 45, 42, 173, 173, 19, 173, 88, 173, 29, 84, + /* 400 */ 45, 173, 173, 173, 75, 74, 73, 72, 41, 173, + /* 410 */ 173, 173, 173, 173, 75, 74, 73, 72, 41, ); static public $yy_lookahead = array( - /* 0 */ 7, 16, 17, 10, 11, 12, 13, 62, 15, 16, - /* 10 */ 17, 62, 67, 8, 9, 70, 71, 72, 73, 70, - /* 20 */ 71, 72, 73, 7, 54, 54, 33, 34, 35, 36, + /* 0 */ 7, 6, 70, 10, 11, 12, 13, 73, 15, 16, + /* 10 */ 17, 8, 9, 18, 56, 83, 84, 54, 23, 24, + /* 20 */ 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, /* 30 */ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - /* 40 */ 47, 48, 49, 1, 74, 74, 54, 56, 61, 7, - /* 50 */ 63, 59, 5, 11, 12, 13, 69, 15, 16, 17, - /* 60 */ 8, 9, 75, 76, 77, 2, 74, 55, 5, 57, - /* 70 */ 55, 2, 57, 4, 54, 33, 34, 35, 36, 37, + /* 40 */ 47, 48, 49, 1, 81, 54, 54, 68, 62, 7, + /* 50 */ 58, 59, 62, 11, 12, 13, 3, 15, 16, 17, + /* 60 */ 74, 82, 8, 77, 78, 79, 80, 77, 78, 79, + /* 70 */ 80, 7, 81, 81, 20, 33, 34, 35, 36, 37, /* 80 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - /* 90 */ 48, 49, 7, 61, 74, 63, 11, 12, 13, 3, - /* 100 */ 15, 16, 17, 74, 55, 7, 57, 75, 76, 77, - /* 110 */ 64, 14, 6, 4, 15, 56, 54, 78, 33, 34, + /* 90 */ 48, 49, 7, 55, 66, 57, 11, 12, 13, 56, + /* 100 */ 15, 16, 17, 11, 12, 13, 8, 9, 31, 32, + /* 110 */ 20, 55, 20, 57, 2, 54, 6, 5, 33, 34, /* 120 */ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - /* 130 */ 45, 46, 47, 48, 49, 6, 74, 78, 78, 78, - /* 140 */ 11, 12, 13, 78, 78, 78, 78, 18, 19, 20, - /* 150 */ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - /* 160 */ 31, 32, 6, 78, 8, 78, 78, 78, 78, 78, - /* 170 */ 78, 78, 78, 78, 18, 19, 20, 21, 22, 23, - /* 180 */ 24, 25, 26, 27, 28, 29, 30, 31, 32, 6, - /* 190 */ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - /* 200 */ 78, 18, 19, 20, 21, 22, 23, 24, 25, 26, - /* 210 */ 27, 28, 29, 30, 31, 32, 51, 52, 53, 54, - /* 220 */ 78, 78, 78, 78, 59, 60, 78, 62, 78, 54, - /* 230 */ 65, 78, 78, 58, 59, 70, 71, 72, 73, 74, - /* 240 */ 54, 78, 78, 78, 78, 59, 60, 78, 62, 74, - /* 250 */ 78, 65, 66, 78, 68, 78, 70, 71, 72, 73, - /* 260 */ 74, 54, 78, 78, 78, 78, 59, 60, 78, 62, - /* 270 */ 78, 78, 65, 78, 78, 68, 78, 70, 71, 72, - /* 280 */ 73, 74, 78, 78, 53, 54, 78, 78, 78, 78, - /* 290 */ 59, 60, 78, 62, 78, 54, 65, 78, 78, 58, - /* 300 */ 59, 70, 71, 72, 73, 74, 54, 78, 78, 78, - /* 310 */ 78, 59, 60, 78, 62, 74, 78, 65, 78, 78, - /* 320 */ 78, 78, 70, 71, 72, 73, 74, 54, 78, 78, - /* 330 */ 78, 78, 59, 60, 78, 62, 78, 78, 65, 78, - /* 340 */ 78, 78, 78, 70, 71, 72, 73, 74, 54, 78, - /* 350 */ 78, 78, 78, 59, 60, 78, 62, 78, 78, 65, - /* 360 */ 78, 78, 78, 78, 70, 71, 72, 73, 74, + /* 130 */ 45, 46, 47, 48, 49, 51, 52, 53, 54, 2, + /* 140 */ 54, 4, 81, 59, 60, 61, 62, 63, 55, 73, + /* 150 */ 57, 67, 76, 69, 14, 71, 7, 16, 17, 21, + /* 160 */ 22, 77, 78, 79, 80, 81, 5, 81, 72, 14, + /* 170 */ 19, 15, 4, 54, 65, 81, 85, 85, 59, 60, + /* 180 */ 61, 62, 63, 64, 54, 85, 67, 85, 69, 59, + /* 190 */ 71, 85, 85, 85, 75, 85, 77, 78, 79, 80, + /* 200 */ 81, 54, 85, 85, 85, 85, 59, 60, 61, 62, + /* 210 */ 63, 81, 85, 85, 67, 85, 69, 85, 71, 85, + /* 220 */ 85, 85, 75, 85, 77, 78, 79, 80, 81, 85, + /* 230 */ 85, 85, 53, 54, 85, 85, 85, 85, 59, 60, + /* 240 */ 61, 62, 63, 85, 85, 85, 67, 85, 69, 85, + /* 250 */ 71, 85, 85, 85, 85, 85, 77, 78, 79, 80, + /* 260 */ 81, 54, 85, 85, 85, 85, 59, 60, 61, 62, + /* 270 */ 63, 85, 85, 85, 67, 85, 69, 54, 71, 85, + /* 280 */ 85, 58, 59, 85, 77, 78, 79, 80, 81, 85, + /* 290 */ 85, 85, 85, 54, 85, 85, 85, 85, 59, 60, + /* 300 */ 61, 62, 63, 85, 81, 85, 67, 85, 69, 85, + /* 310 */ 71, 85, 85, 85, 85, 85, 77, 78, 79, 80, + /* 320 */ 81, 54, 85, 85, 85, 85, 59, 85, 61, 62, + /* 330 */ 63, 85, 85, 85, 67, 85, 69, 85, 71, 85, + /* 340 */ 85, 85, 85, 85, 77, 78, 79, 80, 81, 85, + /* 350 */ 85, 85, 85, 54, 85, 85, 85, 85, 59, 85, + /* 360 */ 61, 62, 63, 85, 85, 85, 67, 85, 69, 85, + /* 370 */ 85, 85, 85, 85, 85, 85, 77, 78, 79, 80, + /* 380 */ 81, 54, 85, 85, 85, 85, 59, 85, 61, 62, + /* 390 */ 63, 54, 85, 85, 67, 85, 59, 85, 61, 62, + /* 400 */ 63, 85, 85, 85, 77, 78, 79, 80, 81, 85, + /* 410 */ 85, 85, 85, 85, 77, 78, 79, 80, 81, ); - const YY_SHIFT_USE_DFLT = -16; - const YY_SHIFT_MAX = 34; + const YY_SHIFT_USE_DFLT = -8; + const YY_SHIFT_MAX = 45; static public $yy_shift_ofst = array( - /* 0 */ 42, -7, -7, 85, 85, 85, 85, 129, -15, 156, - /* 10 */ 183, 183, 183, -15, 99, 99, 99, 69, 109, 99, - /* 20 */ 109, 99, 99, 99, 96, 99, 96, 16, 52, 63, - /* 30 */ 5, 97, 98, 47, 106, + /* 0 */ 42, -7, -7, 85, 85, 85, 85, 85, 85, 85, + /* 10 */ 141, 141, 156, 156, -5, -5, 156, 92, 137, 138, + /* 20 */ 138, 156, 168, 156, 156, 168, 156, 54, 77, 77, + /* 30 */ 90, 151, 156, 53, 90, 64, 53, 151, 112, 98, + /* 40 */ 3, 155, 140, 161, 110, 149, ); - const YY_REDUCE_USE_DFLT = -56; - const YY_REDUCE_MAX = 27; + const YY_REDUCE_USE_DFLT = -69; + const YY_REDUCE_MAX = 37; static public $yy_reduce_ofst = array( - /* 0 */ 165, 186, 207, 231, 273, 294, 252, -13, -55, 32, - /* 10 */ 32, 32, 32, -51, 175, 241, -8, 49, 12, -30, - /* 20 */ 15, -29, 20, 62, 59, 29, -9, 46, + /* 0 */ 84, 119, 147, 179, 207, 239, 267, 299, 327, 337, + /* 10 */ -14, -10, 223, -8, -68, -68, 130, 76, 93, -21, + /* 20 */ -21, 86, 38, -37, -9, 56, 61, -66, 109, 109, + /* 30 */ -66, 96, 94, 43, -66, 28, -42, 96, ); static public $yyExpectedTokens = array( /* 0 */ array(1, 7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), @@ -316,45 +328,45 @@ static public $yy_action = array( /* 4 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), /* 5 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), /* 6 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), - /* 7 */ array(6, 11, 12, 13, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), - /* 8 */ array(16, 17, ), - /* 9 */ array(6, 8, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), - /* 10 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), - /* 11 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), - /* 12 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), - /* 13 */ array(16, 17, ), - /* 14 */ array(15, ), - /* 15 */ array(15, ), + /* 7 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 8 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 9 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 10 */ array(16, 17, ), + /* 11 */ array(16, 17, ), + /* 12 */ array(15, ), + /* 13 */ array(15, ), + /* 14 */ array(6, 18, 23, 24, 25, 26, 27, 28, 29, 30, ), + /* 15 */ array(6, 18, 23, 24, 25, 26, 27, 28, 29, 30, ), /* 16 */ array(15, ), - /* 17 */ array(2, 4, ), - /* 18 */ array(4, ), - /* 19 */ array(15, ), - /* 20 */ array(4, ), + /* 17 */ array(11, 12, 13, 20, ), + /* 18 */ array(2, 4, ), + /* 19 */ array(21, 22, ), + /* 20 */ array(21, 22, ), /* 21 */ array(15, ), - /* 22 */ array(15, ), + /* 22 */ array(4, ), /* 23 */ array(15, ), - /* 24 */ array(3, ), - /* 25 */ array(15, ), - /* 26 */ array(3, ), - /* 27 */ array(7, ), - /* 28 */ array(8, 9, ), - /* 29 */ array(2, 5, ), - /* 30 */ array(8, 9, ), - /* 31 */ array(14, ), - /* 32 */ array(7, ), - /* 33 */ array(5, ), - /* 34 */ array(6, ), - /* 35 */ array(), - /* 36 */ array(), - /* 37 */ array(), - /* 38 */ array(), - /* 39 */ array(), - /* 40 */ array(), - /* 41 */ array(), - /* 42 */ array(), - /* 43 */ array(), - /* 44 */ array(), - /* 45 */ array(), + /* 24 */ array(15, ), + /* 25 */ array(4, ), + /* 26 */ array(15, ), + /* 27 */ array(8, 20, ), + /* 28 */ array(31, 32, ), + /* 29 */ array(31, 32, ), + /* 30 */ array(20, ), + /* 31 */ array(19, ), + /* 32 */ array(15, ), + /* 33 */ array(3, ), + /* 34 */ array(20, ), + /* 35 */ array(7, ), + /* 36 */ array(3, ), + /* 37 */ array(19, ), + /* 38 */ array(2, 5, ), + /* 39 */ array(8, 9, ), + /* 40 */ array(8, 9, ), + /* 41 */ array(14, ), + /* 42 */ array(14, ), + /* 43 */ array(5, ), + /* 44 */ array(6, ), + /* 45 */ array(7, ), /* 46 */ array(), /* 47 */ array(), /* 48 */ array(), @@ -415,19 +427,31 @@ static public $yy_action = array( /* 103 */ array(), /* 104 */ array(), /* 105 */ array(), + /* 106 */ array(), + /* 107 */ array(), + /* 108 */ array(), + /* 109 */ array(), + /* 110 */ array(), + /* 111 */ array(), + /* 112 */ array(), + /* 113 */ array(), + /* 114 */ array(), + /* 115 */ array(), + /* 116 */ array(), ); static public $yy_default = array( - /* 0 */ 184, 128, 184, 184, 184, 184, 184, 184, 184, 184, - /* 10 */ 120, 131, 118, 184, 184, 184, 184, 114, 113, 184, - /* 20 */ 114, 184, 184, 184, 111, 184, 111, 184, 184, 184, - /* 30 */ 184, 184, 184, 184, 184, 142, 168, 169, 170, 171, - /* 40 */ 141, 166, 164, 167, 165, 129, 140, 183, 182, 109, - /* 50 */ 112, 116, 117, 115, 181, 180, 175, 174, 173, 176, - /* 60 */ 177, 179, 178, 172, 124, 126, 144, 143, 139, 145, - /* 70 */ 146, 149, 148, 147, 138, 137, 110, 108, 107, 119, - /* 80 */ 123, 136, 127, 125, 150, 151, 122, 121, 163, 162, - /* 90 */ 106, 130, 134, 133, 132, 161, 160, 154, 153, 152, - /* 100 */ 155, 156, 159, 158, 157, 135, + /* 0 */ 203, 146, 203, 203, 203, 203, 203, 203, 203, 203, + /* 10 */ 203, 203, 203, 203, 140, 139, 203, 203, 125, 138, + /* 20 */ 137, 203, 124, 203, 203, 125, 203, 203, 135, 136, + /* 30 */ 129, 142, 203, 122, 149, 203, 122, 141, 203, 203, + /* 40 */ 203, 158, 203, 203, 203, 203, 176, 177, 127, 178, + /* 50 */ 165, 175, 173, 168, 166, 174, 179, 167, 150, 147, + /* 60 */ 153, 120, 126, 123, 152, 151, 160, 169, 148, 128, + /* 70 */ 180, 194, 157, 156, 155, 154, 162, 163, 159, 182, + /* 80 */ 181, 144, 145, 143, 130, 121, 119, 118, 131, 132, + /* 90 */ 134, 170, 133, 161, 183, 198, 197, 196, 195, 199, + /* 100 */ 200, 171, 164, 202, 201, 117, 193, 187, 186, 185, + /* 110 */ 184, 188, 189, 192, 191, 190, 172, ); /* The next thing included is series of defines which control ** various aspects of the generated parser. @@ -444,10 +468,10 @@ static public $yy_action = array( ** self::YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ - const YYNOCODE = 79; + const YYNOCODE = 86; const YYSTACKDEPTH = 100; - const YYNSTATE = 106; - const YYNRULE = 78; + const YYNSTATE = 117; + const YYNRULE = 86; const YYERRORSYMBOL = 50; const YYERRSYMDT = 'yy0'; const YYFALLBACK = 0; @@ -535,9 +559,9 @@ static public $yy_action = array( 'PAR_CLOSE', 'COMA', 'INTERVAL', 'F_DAY', 'F_MONTH', 'F_YEAR', 'DOT', 'NAME', 'NUMVAL', 'STRVAL', 'NOT_EQ', 'LOG_AND', - 'LOG_OR', 'GT', 'LT', 'GE', - 'LE', 'MATH_DIV', 'MATH_MULT', 'MATH_PLUS', - 'MATH_MINUS', 'LIKE', 'NOT_LIKE', 'IN', + 'LOG_OR', 'MATH_DIV', 'MATH_MULT', 'MATH_PLUS', + 'MATH_MINUS', 'GT', 'LT', 'GE', + 'LE', 'LIKE', 'NOT_LIKE', 'IN', 'NOT_IN', 'F_IF', 'F_ELT', 'F_COALESCE', 'F_CONCAT', 'F_SUBSTR', 'F_TRIM', 'F_DATE', 'F_DATE_FORMAT', 'F_CURRENT_DATE', 'F_NOW', 'F_TIME', @@ -545,11 +569,13 @@ static public $yy_action = array( 'F_ROUND', 'F_FLOOR', 'error', 'result', 'query', 'condition', 'class_name', 'join_statement', 'where_statement', 'join_item', 'join_condition', 'field_id', - 'expression', 'operator', 'scalar', 'list_operator', - 'list', 'func_name', 'arg_list', 'scalar_list', - 'argument', 'interval_unit', 'num_scalar', 'str_scalar', - 'num_value', 'str_value', 'name', 'log_operator', - 'num_operator', 'str_operator', + 'expression_prio4', 'expression_basic', 'scalar', 'func_name', + 'arg_list', 'list_operator', 'list', 'expression_prio1', + 'operator1', 'expression_prio2', 'operator2', 'expression_prio3', + 'operator3', 'operator4', 'scalar_list', 'argument', + 'interval_unit', 'num_scalar', 'str_scalar', 'num_value', + 'str_value', 'name', 'num_operator1', 'num_operator2', + 'str_operator', ); /** @@ -569,72 +595,80 @@ static public $yy_action = array( /* 9 */ "join_item ::= JOIN class_name AS_ALIAS class_name ON join_condition", /* 10 */ "join_item ::= JOIN class_name ON join_condition", /* 11 */ "join_condition ::= field_id EQ field_id", - /* 12 */ "condition ::= expression", - /* 13 */ "expression ::= PAR_OPEN expression PAR_CLOSE", - /* 14 */ "expression ::= expression operator expression", - /* 15 */ "expression ::= scalar", - /* 16 */ "expression ::= field_id", - /* 17 */ "expression ::= expression list_operator list", - /* 18 */ "expression ::= func_name PAR_OPEN arg_list PAR_CLOSE", - /* 19 */ "list ::= PAR_OPEN scalar_list PAR_CLOSE", - /* 20 */ "scalar_list ::= scalar", - /* 21 */ "scalar_list ::= scalar_list COMA scalar", - /* 22 */ "arg_list ::=", - /* 23 */ "arg_list ::= argument", - /* 24 */ "arg_list ::= arg_list COMA argument", - /* 25 */ "argument ::= expression", - /* 26 */ "argument ::= INTERVAL expression interval_unit", - /* 27 */ "interval_unit ::= F_DAY", - /* 28 */ "interval_unit ::= F_MONTH", - /* 29 */ "interval_unit ::= F_YEAR", - /* 30 */ "scalar ::= num_scalar", - /* 31 */ "scalar ::= str_scalar", - /* 32 */ "num_scalar ::= num_value", - /* 33 */ "str_scalar ::= str_value", - /* 34 */ "field_id ::= class_name DOT name", - /* 35 */ "class_name ::= name", - /* 36 */ "name ::= NAME", - /* 37 */ "num_value ::= NUMVAL", - /* 38 */ "str_value ::= STRVAL", - /* 39 */ "operator ::= log_operator", - /* 40 */ "operator ::= num_operator", - /* 41 */ "operator ::= str_operator", - /* 42 */ "operator ::= EQ", - /* 43 */ "operator ::= NOT_EQ", - /* 44 */ "log_operator ::= LOG_AND", - /* 45 */ "log_operator ::= LOG_OR", - /* 46 */ "num_operator ::= GT", - /* 47 */ "num_operator ::= LT", - /* 48 */ "num_operator ::= GE", - /* 49 */ "num_operator ::= LE", - /* 50 */ "num_operator ::= MATH_DIV", - /* 51 */ "num_operator ::= MATH_MULT", - /* 52 */ "num_operator ::= MATH_PLUS", - /* 53 */ "num_operator ::= MATH_MINUS", - /* 54 */ "str_operator ::= LIKE", - /* 55 */ "str_operator ::= NOT_LIKE", - /* 56 */ "list_operator ::= IN", - /* 57 */ "list_operator ::= NOT_IN", - /* 58 */ "func_name ::= F_IF", - /* 59 */ "func_name ::= F_ELT", - /* 60 */ "func_name ::= F_COALESCE", - /* 61 */ "func_name ::= F_CONCAT", - /* 62 */ "func_name ::= F_SUBSTR", - /* 63 */ "func_name ::= F_TRIM", - /* 64 */ "func_name ::= F_DATE", - /* 65 */ "func_name ::= F_DATE_FORMAT", - /* 66 */ "func_name ::= F_CURRENT_DATE", - /* 67 */ "func_name ::= F_NOW", - /* 68 */ "func_name ::= F_TIME", - /* 69 */ "func_name ::= F_TO_DAYS", - /* 70 */ "func_name ::= F_FROM_DAYS", - /* 71 */ "func_name ::= F_YEAR", - /* 72 */ "func_name ::= F_MONTH", - /* 73 */ "func_name ::= F_DAY", - /* 74 */ "func_name ::= F_DATE_ADD", - /* 75 */ "func_name ::= F_DATE_SUB", - /* 76 */ "func_name ::= F_ROUND", - /* 77 */ "func_name ::= F_FLOOR", + /* 12 */ "condition ::= expression_prio4", + /* 13 */ "expression_basic ::= scalar", + /* 14 */ "expression_basic ::= field_id", + /* 15 */ "expression_basic ::= func_name PAR_OPEN arg_list PAR_CLOSE", + /* 16 */ "expression_basic ::= PAR_OPEN expression_prio4 PAR_CLOSE", + /* 17 */ "expression_basic ::= expression_basic list_operator list", + /* 18 */ "expression_prio1 ::= expression_basic", + /* 19 */ "expression_prio1 ::= expression_prio1 operator1 expression_basic", + /* 20 */ "expression_prio2 ::= expression_prio1", + /* 21 */ "expression_prio2 ::= expression_prio2 operator2 expression_prio1", + /* 22 */ "expression_prio3 ::= expression_prio2", + /* 23 */ "expression_prio3 ::= expression_prio3 operator3 expression_prio2", + /* 24 */ "expression_prio4 ::= expression_prio3", + /* 25 */ "expression_prio4 ::= expression_prio4 operator4 expression_prio3", + /* 26 */ "list ::= PAR_OPEN scalar_list PAR_CLOSE", + /* 27 */ "scalar_list ::= scalar", + /* 28 */ "scalar_list ::= scalar_list COMA scalar", + /* 29 */ "arg_list ::=", + /* 30 */ "arg_list ::= argument", + /* 31 */ "arg_list ::= arg_list COMA argument", + /* 32 */ "argument ::= expression_prio4", + /* 33 */ "argument ::= INTERVAL expression_prio4 interval_unit", + /* 34 */ "interval_unit ::= F_DAY", + /* 35 */ "interval_unit ::= F_MONTH", + /* 36 */ "interval_unit ::= F_YEAR", + /* 37 */ "scalar ::= num_scalar", + /* 38 */ "scalar ::= str_scalar", + /* 39 */ "num_scalar ::= num_value", + /* 40 */ "str_scalar ::= str_value", + /* 41 */ "field_id ::= name", + /* 42 */ "field_id ::= class_name DOT name", + /* 43 */ "class_name ::= name", + /* 44 */ "name ::= NAME", + /* 45 */ "num_value ::= NUMVAL", + /* 46 */ "str_value ::= STRVAL", + /* 47 */ "operator1 ::= num_operator1", + /* 48 */ "operator2 ::= num_operator2", + /* 49 */ "operator2 ::= str_operator", + /* 50 */ "operator2 ::= EQ", + /* 51 */ "operator2 ::= NOT_EQ", + /* 52 */ "operator3 ::= LOG_AND", + /* 53 */ "operator4 ::= LOG_OR", + /* 54 */ "num_operator1 ::= MATH_DIV", + /* 55 */ "num_operator1 ::= MATH_MULT", + /* 56 */ "num_operator2 ::= MATH_PLUS", + /* 57 */ "num_operator2 ::= MATH_MINUS", + /* 58 */ "num_operator2 ::= GT", + /* 59 */ "num_operator2 ::= LT", + /* 60 */ "num_operator2 ::= GE", + /* 61 */ "num_operator2 ::= LE", + /* 62 */ "str_operator ::= LIKE", + /* 63 */ "str_operator ::= NOT_LIKE", + /* 64 */ "list_operator ::= IN", + /* 65 */ "list_operator ::= NOT_IN", + /* 66 */ "func_name ::= F_IF", + /* 67 */ "func_name ::= F_ELT", + /* 68 */ "func_name ::= F_COALESCE", + /* 69 */ "func_name ::= F_CONCAT", + /* 70 */ "func_name ::= F_SUBSTR", + /* 71 */ "func_name ::= F_TRIM", + /* 72 */ "func_name ::= F_DATE", + /* 73 */ "func_name ::= F_DATE_FORMAT", + /* 74 */ "func_name ::= F_CURRENT_DATE", + /* 75 */ "func_name ::= F_NOW", + /* 76 */ "func_name ::= F_TIME", + /* 77 */ "func_name ::= F_TO_DAYS", + /* 78 */ "func_name ::= F_FROM_DAYS", + /* 79 */ "func_name ::= F_YEAR", + /* 80 */ "func_name ::= F_MONTH", + /* 81 */ "func_name ::= F_DAY", + /* 82 */ "func_name ::= F_DATE_ADD", + /* 83 */ "func_name ::= F_DATE_SUB", + /* 84 */ "func_name ::= F_ROUND", + /* 85 */ "func_name ::= F_FLOOR", ); /** @@ -1012,71 +1046,79 @@ static public $yy_action = array( array( 'lhs' => 57, 'rhs' => 4 ), array( 'lhs' => 58, 'rhs' => 3 ), array( 'lhs' => 53, 'rhs' => 1 ), - array( 'lhs' => 60, 'rhs' => 3 ), - array( 'lhs' => 60, 'rhs' => 3 ), - array( 'lhs' => 60, 'rhs' => 1 ), - array( 'lhs' => 60, 'rhs' => 1 ), - array( 'lhs' => 60, 'rhs' => 3 ), - array( 'lhs' => 60, 'rhs' => 4 ), - array( 'lhs' => 64, 'rhs' => 3 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 4 ), + array( 'lhs' => 61, 'rhs' => 3 ), + array( 'lhs' => 61, 'rhs' => 3 ), array( 'lhs' => 67, 'rhs' => 1 ), array( 'lhs' => 67, 'rhs' => 3 ), - array( 'lhs' => 66, 'rhs' => 0 ), - array( 'lhs' => 66, 'rhs' => 1 ), - array( 'lhs' => 66, 'rhs' => 3 ), - array( 'lhs' => 68, 'rhs' => 1 ), - array( 'lhs' => 68, 'rhs' => 3 ), array( 'lhs' => 69, 'rhs' => 1 ), - array( 'lhs' => 69, 'rhs' => 1 ), - array( 'lhs' => 69, 'rhs' => 1 ), - array( 'lhs' => 62, 'rhs' => 1 ), - array( 'lhs' => 62, 'rhs' => 1 ), - array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 69, 'rhs' => 3 ), array( 'lhs' => 71, 'rhs' => 1 ), + array( 'lhs' => 71, 'rhs' => 3 ), + array( 'lhs' => 60, 'rhs' => 1 ), + array( 'lhs' => 60, 'rhs' => 3 ), + array( 'lhs' => 66, 'rhs' => 3 ), + array( 'lhs' => 74, 'rhs' => 1 ), + array( 'lhs' => 74, 'rhs' => 3 ), + array( 'lhs' => 64, 'rhs' => 0 ), + array( 'lhs' => 64, 'rhs' => 1 ), + array( 'lhs' => 64, 'rhs' => 3 ), + array( 'lhs' => 75, 'rhs' => 1 ), + array( 'lhs' => 75, 'rhs' => 3 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 62, 'rhs' => 1 ), + array( 'lhs' => 62, 'rhs' => 1 ), + array( 'lhs' => 77, 'rhs' => 1 ), + array( 'lhs' => 78, 'rhs' => 1 ), + array( 'lhs' => 59, 'rhs' => 1 ), array( 'lhs' => 59, 'rhs' => 3 ), array( 'lhs' => 54, 'rhs' => 1 ), - array( 'lhs' => 74, 'rhs' => 1 ), + array( 'lhs' => 81, 'rhs' => 1 ), + array( 'lhs' => 79, 'rhs' => 1 ), + array( 'lhs' => 80, 'rhs' => 1 ), + array( 'lhs' => 68, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), array( 'lhs' => 72, 'rhs' => 1 ), array( 'lhs' => 73, 'rhs' => 1 ), - array( 'lhs' => 61, 'rhs' => 1 ), - array( 'lhs' => 61, 'rhs' => 1 ), - array( 'lhs' => 61, 'rhs' => 1 ), - array( 'lhs' => 61, 'rhs' => 1 ), - array( 'lhs' => 61, 'rhs' => 1 ), - array( 'lhs' => 75, 'rhs' => 1 ), - array( 'lhs' => 75, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 76, 'rhs' => 1 ), - array( 'lhs' => 77, 'rhs' => 1 ), - array( 'lhs' => 77, 'rhs' => 1 ), + array( 'lhs' => 82, 'rhs' => 1 ), + array( 'lhs' => 82, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 83, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 84, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), array( 'lhs' => 63, 'rhs' => 1 ), array( 'lhs' => 63, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), - array( 'lhs' => 65, 'rhs' => 1 ), ); /** @@ -1099,71 +1141,79 @@ static public $yy_action = array( 10 => 10, 11 => 11, 12 => 12, - 16 => 12, - 25 => 12, - 27 => 12, - 28 => 12, - 29 => 12, - 30 => 12, - 31 => 12, - 13 => 13, - 14 => 14, - 17 => 14, + 13 => 12, + 14 => 12, + 18 => 12, + 20 => 12, + 22 => 12, + 24 => 12, + 32 => 12, + 34 => 12, + 35 => 12, + 36 => 12, + 37 => 12, + 38 => 12, 15 => 15, - 58 => 15, - 59 => 15, - 60 => 15, - 61 => 15, - 62 => 15, - 63 => 15, - 64 => 15, - 65 => 15, - 66 => 15, - 67 => 15, - 68 => 15, - 69 => 15, - 70 => 15, - 71 => 15, - 72 => 15, - 73 => 15, - 74 => 15, - 75 => 15, - 76 => 15, - 77 => 15, - 18 => 18, - 19 => 19, - 20 => 20, - 23 => 20, - 21 => 21, - 24 => 21, - 22 => 22, + 16 => 16, + 17 => 17, + 19 => 17, + 21 => 17, + 23 => 17, + 25 => 17, 26 => 26, - 32 => 32, - 33 => 32, - 34 => 34, - 35 => 35, - 37 => 35, - 39 => 35, - 40 => 35, - 41 => 35, - 42 => 35, - 43 => 35, - 44 => 35, - 45 => 35, - 46 => 35, - 47 => 35, - 48 => 35, - 49 => 35, - 50 => 35, - 51 => 35, - 52 => 35, - 53 => 35, - 54 => 35, - 55 => 35, - 56 => 35, - 57 => 35, - 36 => 36, - 38 => 38, + 27 => 27, + 30 => 27, + 28 => 28, + 31 => 28, + 29 => 29, + 33 => 33, + 39 => 39, + 40 => 39, + 41 => 41, + 42 => 42, + 43 => 43, + 66 => 43, + 67 => 43, + 68 => 43, + 69 => 43, + 70 => 43, + 71 => 43, + 72 => 43, + 73 => 43, + 74 => 43, + 75 => 43, + 76 => 43, + 77 => 43, + 78 => 43, + 79 => 43, + 80 => 43, + 81 => 43, + 82 => 43, + 83 => 43, + 84 => 43, + 85 => 43, + 44 => 44, + 45 => 45, + 47 => 45, + 48 => 45, + 49 => 45, + 50 => 45, + 51 => 45, + 52 => 45, + 53 => 45, + 54 => 45, + 55 => 45, + 56 => 45, + 57 => 45, + 58 => 45, + 59 => 45, + 60 => 45, + 61 => 45, + 62 => 45, + 63 => 45, + 64 => 45, + 65 => 45, + 46 => 46, ); /* Beginning here are the reduction cases. A typical example ** follows: @@ -1173,23 +1223,23 @@ static public $yy_action = array( */ #line 7 "oql-parser.y" function yy_r0(){ $this->my_result = $this->yystack[$this->yyidx + 0]->minor; } -#line 1180 "oql-parser.php" +#line 1230 "oql-parser.php" #line 10 "oql-parser.y" function yy_r2(){ $this->_retvalue = new OqlQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } -#line 1185 "oql-parser.php" +#line 1235 "oql-parser.php" #line 13 "oql-parser.y" function yy_r3(){ $this->_retvalue = new OqlQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); } -#line 1190 "oql-parser.php" +#line 1240 "oql-parser.php" #line 17 "oql-parser.y" function yy_r4(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } -#line 1193 "oql-parser.php" +#line 1243 "oql-parser.php" #line 18 "oql-parser.y" function yy_r5(){ $this->_retvalue = null; } -#line 1196 "oql-parser.php" +#line 1246 "oql-parser.php" #line 20 "oql-parser.y" function yy_r6(){ // insert the join statement on top of the existing list @@ -1197,90 +1247,94 @@ static public $yy_action = array( // and return the updated array $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } -#line 1204 "oql-parser.php" +#line 1254 "oql-parser.php" #line 26 "oql-parser.y" function yy_r7(){ $this->_retvalue = Array($this->yystack[$this->yyidx + 0]->minor); } -#line 1209 "oql-parser.php" +#line 1259 "oql-parser.php" #line 32 "oql-parser.y" function yy_r9(){ // create an array with one single item $this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } -#line 1215 "oql-parser.php" +#line 1265 "oql-parser.php" #line 37 "oql-parser.y" function yy_r10(){ // create an array with one single item $this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); } -#line 1221 "oql-parser.php" +#line 1271 "oql-parser.php" #line 42 "oql-parser.y" function yy_r11(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, '=', $this->yystack[$this->yyidx + 0]->minor); } -#line 1224 "oql-parser.php" +#line 1274 "oql-parser.php" #line 44 "oql-parser.y" function yy_r12(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } -#line 1227 "oql-parser.php" -#line 46 "oql-parser.y" - function yy_r13(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; } -#line 1230 "oql-parser.php" -#line 47 "oql-parser.y" - function yy_r14(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } -#line 1233 "oql-parser.php" +#line 1277 "oql-parser.php" #line 48 "oql-parser.y" - function yy_r15(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } -#line 1236 "oql-parser.php" -#line 51 "oql-parser.y" - function yy_r18(){ $this->_retvalue = new FunctionOqlExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } -#line 1239 "oql-parser.php" -#line 54 "oql-parser.y" - function yy_r19(){ + function yy_r15(){ $this->_retvalue = new FunctionOqlExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 1280 "oql-parser.php" +#line 49 "oql-parser.y" + function yy_r16(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; } +#line 1283 "oql-parser.php" +#line 50 "oql-parser.y" + function yy_r17(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 1286 "oql-parser.php" +#line 65 "oql-parser.y" + function yy_r26(){ $this->_retvalue = new ListOqlExpression($this->yystack[$this->yyidx + -1]->minor); } -#line 1244 "oql-parser.php" -#line 57 "oql-parser.y" - function yy_r20(){ +#line 1291 "oql-parser.php" +#line 68 "oql-parser.y" + function yy_r27(){ $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); } -#line 1249 "oql-parser.php" -#line 60 "oql-parser.y" - function yy_r21(){ +#line 1296 "oql-parser.php" +#line 71 "oql-parser.y" + function yy_r28(){ array_push($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; } -#line 1255 "oql-parser.php" -#line 65 "oql-parser.y" - function yy_r22(){ +#line 1302 "oql-parser.php" +#line 76 "oql-parser.y" + function yy_r29(){ $this->_retvalue = array(); } -#line 1260 "oql-parser.php" -#line 76 "oql-parser.y" - function yy_r26(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } -#line 1263 "oql-parser.php" -#line 85 "oql-parser.y" - function yy_r32(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor); } -#line 1266 "oql-parser.php" -#line 88 "oql-parser.y" - function yy_r34(){ $this->_retvalue = new FieldOqlExpression($this->m_iCol, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor); } -#line 1269 "oql-parser.php" -#line 89 "oql-parser.y" - function yy_r35(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } -#line 1272 "oql-parser.php" -#line 91 "oql-parser.y" - function yy_r36(){ +#line 1307 "oql-parser.php" +#line 87 "oql-parser.y" + function yy_r33(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 1310 "oql-parser.php" +#line 96 "oql-parser.y" + function yy_r39(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor); } +#line 1313 "oql-parser.php" +#line 99 "oql-parser.y" + function yy_r41(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor); } +#line 1316 "oql-parser.php" +#line 100 "oql-parser.y" + function yy_r42(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor); } +#line 1319 "oql-parser.php" +#line 101 "oql-parser.y" + function yy_r43(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } +#line 1322 "oql-parser.php" +#line 103 "oql-parser.y" + function yy_r44(){ if ($this->yystack[$this->yyidx + 0]->minor[0] == '`') { - $this->_retvalue = substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2); + $name = substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2); } else { - $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + $name = $this->yystack[$this->yyidx + 0]->minor; } + $this->_retvalue = new OqlName($name, $this->m_iColPrev); } -#line 1284 "oql-parser.php" -#line 103 "oql-parser.y" - function yy_r38(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2)); } -#line 1287 "oql-parser.php" +#line 1335 "oql-parser.php" +#line 115 "oql-parser.y" + function yy_r45(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } +#line 1338 "oql-parser.php" +#line 116 "oql-parser.y" + function yy_r46(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2)); } +#line 1341 "oql-parser.php" /** * placeholder for the left hand side in a reduce operation. @@ -1395,7 +1449,7 @@ static public $yy_action = array( #line 3 "oql-parser.y" throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN); -#line 1403 "oql-parser.php" +#line 1457 "oql-parser.php" } /** @@ -1547,7 +1601,7 @@ throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCo } } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); } -}#line 151 "oql-parser.y" +}#line 164 "oql-parser.y" @@ -1575,18 +1629,21 @@ class OQLParser extends OQLParserRaw // Data used when an exception is raised protected $m_iLine; // still not used protected $m_iCol; + protected $m_iColPrev; // this is the interesting one, because the parser will reduce on the next token protected $m_sSourceQuery; public function __construct($sQuery) { $this->m_iLine = 0; $this->m_iCol = 0; + $this->m_iColPrev = 0; $this->m_sSourceQuery = $sQuery; // no constructor - parent::__construct(); } public function doParse($token, $value, $iCurrPosition = 0) { + $this->m_iColPrev = $this->m_iCol; $this->m_iCol = $iCurrPosition; return parent::DoParse($token, $value); @@ -1610,4 +1667,4 @@ class OQLParser extends OQLParserRaw } } -#line 1620 "oql-parser.php" +#line 1677 "oql-parser.php" diff --git a/core/oql/oql-parser.y b/core/oql/oql-parser.y index 02df9f519..b86423b77 100644 --- a/core/oql/oql-parser.y +++ b/core/oql/oql-parser.y @@ -41,14 +41,25 @@ join_item(A) ::= JOIN class_name(X) ON join_condition(C). join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); } -condition(A) ::= expression(X). { A = X; } +condition(A) ::= expression_prio4(X). { A = X; } -expression(A) ::= PAR_OPEN expression(X) PAR_CLOSE. { A = X; } -expression(A) ::= expression(X) operator(Y) expression(Z). { A = new BinaryOqlExpression(X, Y, Z); } -expression(A) ::= scalar(X). { A=X; } -expression(A) ::= field_id(X). { A = X; } -expression(A) ::= expression(X) list_operator(Y) list(Z). { A = new BinaryOqlExpression(X, Y, Z); } -expression(A) ::= func_name(X) PAR_OPEN arg_list(Y) PAR_CLOSE. { A = new FunctionOqlExpression(X, Y); } +expression_basic(A) ::= scalar(X). { A = X; } +expression_basic(A) ::= field_id(X). { A = X; } +expression_basic(A) ::= func_name(X) PAR_OPEN arg_list(Y) PAR_CLOSE. { A = new FunctionOqlExpression(X, Y); } +expression_basic(A) ::= PAR_OPEN expression_prio4(X) PAR_CLOSE. { A = X; } +expression_basic(A) ::= expression_basic(X) list_operator(Y) list(Z). { A = new BinaryOqlExpression(X, Y, Z); } + +expression_prio1(A) ::= expression_basic(X). { A = X; } +expression_prio1(A) ::= expression_prio1(X) operator1(Y) expression_basic(Z). { A = new BinaryOqlExpression(X, Y, Z); } + +expression_prio2(A) ::= expression_prio1(X). { A = X; } +expression_prio2(A) ::= expression_prio2(X) operator2(Y) expression_prio1(Z). { A = new BinaryOqlExpression(X, Y, Z); } + +expression_prio3(A) ::= expression_prio2(X). { A = X; } +expression_prio3(A) ::= expression_prio3(X) operator3(Y) expression_prio2(Z). { A = new BinaryOqlExpression(X, Y, Z); } + +expression_prio4(A) ::= expression_prio3(X). { A = X; } +expression_prio4(A) ::= expression_prio4(X) operator4(Y) expression_prio3(Z). { A = new BinaryOqlExpression(X, Y, Z); } list(A) ::= PAR_OPEN scalar_list(X) PAR_CLOSE. { @@ -72,8 +83,8 @@ arg_list(A) ::= arg_list(L) COMA argument(X). { array_push(L, X); A = L; } -argument(A) ::= expression(X). { A = X; } -argument(A) ::= INTERVAL expression(X) interval_unit(Y). { A = new IntervalOqlExpression(X, Y); } +argument(A) ::= expression_prio4(X). { A = X; } +argument(A) ::= INTERVAL expression_prio4(X) interval_unit(Y). { A = new IntervalOqlExpression(X, Y); } interval_unit(A) ::= F_DAY(X). { A = X; } interval_unit(A) ::= F_MONTH(X). { A = X; } @@ -85,40 +96,42 @@ scalar(A) ::= str_scalar(X). { A = X; } num_scalar(A) ::= num_value(X). { A = new ScalarOqlExpression(X); } str_scalar(A) ::= str_value(X). { A = new ScalarOqlExpression(X); } -field_id(A) ::= class_name(X) DOT name(Y). { A = new FieldOqlExpression($this->m_iCol, Y, X); } -class_name(A) ::= name(X). {A=X;} +field_id(A) ::= name(X). { A = new FieldOqlExpression(X); } +field_id(A) ::= class_name(X) DOT name(Y). { A = new FieldOqlExpression(Y, X); } +class_name(A) ::= name(X). { A=X; } name(A) ::= NAME(X). { if (X[0] == '`') { - A = substr(X, 1, strlen(X) - 2); + $name = substr(X, 1, strlen(X) - 2); } else { - A = X; + $name = X; } + A = new OqlName($name, $this->m_iColPrev); } num_value(A) ::= NUMVAL(X). {A=X;} str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));} -operator(A) ::= log_operator(X). {A=X;} -operator(A) ::= num_operator(X). {A=X;} -operator(A) ::= str_operator(X). {A=X;} -operator(A) ::= EQ(X). {A=X;} -operator(A) ::= NOT_EQ(X). {A=X;} -log_operator(A) ::= LOG_AND(X). {A=X;} -log_operator(A) ::= LOG_OR(X). {A=X;} +operator1(A) ::= num_operator1(X). {A=X;} +operator2(A) ::= num_operator2(X). {A=X;} +operator2(A) ::= str_operator(X). {A=X;} +operator2(A) ::= EQ(X). {A=X;} +operator2(A) ::= NOT_EQ(X). {A=X;} +operator3(A) ::= LOG_AND(X). {A=X;} +operator4(A) ::= LOG_OR(X). {A=X;} -num_operator(A) ::= GT(X). {A=X;} -num_operator(A) ::= LT(X). {A=X;} -num_operator(A) ::= GE(X). {A=X;} -num_operator(A) ::= LE(X). {A=X;} -num_operator(A) ::= MATH_DIV(X). {A=X;} -num_operator(A) ::= MATH_MULT(X). {A=X;} -num_operator(A) ::= MATH_PLUS(X). {A=X;} -num_operator(A) ::= MATH_MINUS(X). {A=X;} +num_operator1(A) ::= MATH_DIV(X). {A=X;} +num_operator1(A) ::= MATH_MULT(X). {A=X;} +num_operator2(A) ::= MATH_PLUS(X). {A=X;} +num_operator2(A) ::= MATH_MINUS(X). {A=X;} +num_operator2(A) ::= GT(X). {A=X;} +num_operator2(A) ::= LT(X). {A=X;} +num_operator2(A) ::= GE(X). {A=X;} +num_operator2(A) ::= LE(X). {A=X;} str_operator(A) ::= LIKE(X). {A=X;} str_operator(A) ::= NOT_LIKE(X). {A=X;} @@ -175,18 +188,21 @@ class OQLParser extends OQLParserRaw // Data used when an exception is raised protected $m_iLine; // still not used protected $m_iCol; + protected $m_iColPrev; // this is the interesting one, because the parser will reduce on the next token protected $m_sSourceQuery; public function __construct($sQuery) { $this->m_iLine = 0; $this->m_iCol = 0; + $this->m_iColPrev = 0; $this->m_sSourceQuery = $sQuery; // no constructor - parent::__construct(); } public function doParse($token, $value, $iCurrPosition = 0) { + $this->m_iColPrev = $this->m_iCol; $this->m_iCol = $iCurrPosition; return parent::DoParse($token, $value); diff --git a/core/oql/oqlexception.class.inc.php b/core/oql/oqlexception.class.inc.php index 3395df05f..512a3077f 100644 --- a/core/oql/oqlexception.class.inc.php +++ b/core/oql/oqlexception.class.inc.php @@ -11,26 +11,66 @@ class OQLException extends CoreException $this->m_sUnexpected = $sUnexpected; $this->m_aExpecting = $aExpecting; - if (is_null($this->m_aExpecting)) + if (is_null($this->m_aExpecting) || (count($this->m_aExpecting) == 0)) { - $sMessage = "$sIssue - found '$sUnexpected' at $iCol in '$sInput'"; + $sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput'"; } else { - $sExpectations = '{'.implode(', ', $aExpecting).'}'; - $sMessage = "$sIssue - found '$sUnexpected' at $iCol in '$sInput', expecting $sExpectations"; + $sExpectations = '{'.implode(', ', $this->m_aExpecting).'}'; + $sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting); + $sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput', expecting $sExpectations, I would suggest to use '$sSuggest'"; } // make sure everything is assigned properly parent::__construct($sMessage, 0); } - + public function getHtmlDesc($sHighlightHtmlBegin = '', $sHighlightHtmlEnd = '') { $sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: "); $sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol)); $sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected))).$sHighlightHtmlEnd; $sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected))); + + if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0)) + { + $sExpectations = '{'.implode(', ', $this->m_aExpecting).'}'; + $sRet .= ", expecting ".htmlentities($sExpectations); + $sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting); + if (strlen($sSuggest) > 0) + { + $sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest)."$sHighlightHtmlEnd'"; + } + } + + return $sRet; + } + + static protected function FindClosestString($sInput, $aDictionary) + { + // no shortest distance found, yet + $fShortest = -1; + $sRet = ''; + + // loop through words to find the closest + foreach ($aDictionary as $sSuggestion) + { + // calculate the distance between the input string and the suggested one + $fDist = levenshtein($sInput, $sSuggestion); + if ($fDist == 0) + { + // Exact match + return $sSuggestion; + } + + if ($fShortest < 0 || ($fDist < 4 && $fDist <= $fShortest)) + { + // set the closest match, and shortest distance + $sRet = $sSuggestion; + $fShortest = $fDist; + } + } return $sRet; } } diff --git a/core/oql/oqlinterpreter.class.inc.php b/core/oql/oqlinterpreter.class.inc.php index b9a2ba5cc..a464413da 100644 --- a/core/oql/oqlinterpreter.class.inc.php +++ b/core/oql/oqlinterpreter.class.inc.php @@ -2,6 +2,10 @@ class OqlNormalizeException extends OQLException { + public function __construct($sIssue, $sInput, OqlName $oName, $aExpecting = null) + { + parent::__construct($sIssue, $sInput, 0, $oName->GetPos(), $oName->GetValue(), $aExpecting); + } } class OqlInterpreterException extends OQLException diff --git a/core/oql/oqlquery.class.inc.php b/core/oql/oqlquery.class.inc.php index 5173704d7..ad71950b3 100644 --- a/core/oql/oqlquery.class.inc.php +++ b/core/oql/oqlquery.class.inc.php @@ -1,30 +1,70 @@ m_iPos = $iPos; + $this->m_sValue = $sValue; + } + + public function GetValue() + { + return $this->m_sValue; + } + + public function GetPos() + { + return $this->m_iPos; + } + + public function __toString() + { + return $this->m_sValue; + } +} + class OqlJoinSpec { - protected $m_sClass; - protected $m_sClassAlias; + protected $m_oClass; + protected $m_oClassAlias; protected $m_oLeftField; protected $m_oRightField; protected $m_oNextJoinspec; - public function __construct($sClass, $sClassAlias, BinaryExpression $oExpression) + public function __construct($oClass, $oClassAlias, BinaryExpression $oExpression) { - $this->m_sClass = $sClass; - $this->m_sClassAlias = $sClassAlias; + $this->m_oClass = $oClass; + $this->m_oClassAlias = $oClassAlias; $this->m_oLeftField = $oExpression->GetLeftExpr(); $this->m_oRightField = $oExpression->GetRightExpr(); } public function GetClass() { - return $this->m_sClass; + return $this->m_oClass->GetValue(); } public function GetClassAlias() { - return $this->m_sClassAlias; + return $this->m_oClassAlias->GetValue(); } + + public function GetClassDetails() + { + return $this->m_oClass; + } + public function GetClassAliasDetails() + { + return $this->m_oClassAlias; + } + public function GetLeftField() { return $this->m_oLeftField; @@ -45,18 +85,30 @@ class ScalarOqlExpression extends ScalarExpression class FieldOqlExpression extends FieldExpression { - protected $m_iPosition; // position in the source string - - public function __construct($iPosition, $sName, $sParent = '') + protected $m_oParent; + protected $m_oName; + + public function __construct($oName, $oParent = null) { - $this->m_iPosition = $iPosition; - parent::__construct($sName, $sParent); + if (is_null($oParent)) + { + $oParent = new OqlName('', 0); + } + $this->m_oParent = $oParent; + $this->m_oName = $oName; + + parent::__construct($oName->GetValue(), $oParent->GetValue()); } - public function GetPosition() + public function GetParentDetails() { - return $this->m_iPosition; - } + return $this->m_oParent; + } + + public function GetNameDetails() + { + return $this->m_oName; + } } class ListOqlExpression extends ListExpression @@ -72,27 +124,37 @@ class IntervalOqlExpression extends IntervalExpression } class OqlQuery { - protected $m_sClass; - protected $m_sClassAlias; + protected $m_oClass; + protected $m_oClassAlias; protected $m_aJoins; // array of OqlJoinSpec protected $m_oCondition; // condition tree (expressions) - public function __construct($sClass, $sClassAlias = '', $oCondition = null, $aJoins = null) + public function __construct($oClass, $oClassAlias = '', $oCondition = null, $aJoins = null) { - $this->m_sClass = $sClass; - $this->m_sClassAlias = $sClassAlias; + $this->m_oClass = $oClass; + $this->m_oClassAlias = $oClassAlias; $this->m_aJoins = $aJoins; $this->m_oCondition = $oCondition; } public function GetClass() { - return $this->m_sClass; + return $this->m_oClass->GetValue(); } public function GetClassAlias() { - return $this->m_sClassAlias; + return $this->m_oClassAlias->GetValue(); } + + public function GetClassDetails() + { + return $this->m_oClass; + } + public function GetClassAliasDetails() + { + return $this->m_oClassAlias; + } + public function GetJoins() { return $this->m_aJoins; diff --git a/core/sqlquery.class.inc.php b/core/sqlquery.class.inc.php index 4e747de53..06a8bd35f 100644 --- a/core/sqlquery.class.inc.php +++ b/core/sqlquery.class.inc.php @@ -104,8 +104,9 @@ class SQLQuery $oSQLQuery = $aJoinInfo["select"]; $sLeftField = $aJoinInfo["leftfield"]; $sRightField = $aJoinInfo["rightfield"]; + $sRightTableAlias = $aJoinInfo["righttablealias"]; - echo "
  • Join '$sJoinType', $sLeftField, $sRightField".$oSQLQuery->DisplayHtml()."
  • \n"; + echo "
  • Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."
  • \n"; } echo ""; } @@ -131,28 +132,35 @@ class SQLQuery $this->m_oConditionExpr->LogAnd($oConditionExpr); } - private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField) + private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField, $sRightTableAlias = '') { assert((get_class($oSQLQuery) == __CLASS__) || is_subclass_of($oSQLQuery, __CLASS__)); if (!CMDBSource::IsField($this->m_sTable, $sLeftField)) { trigger_error("Unknown field '$sLeftField' in table '".$this->m_sTable, E_USER_ERROR); } - if (!CMDBSource::IsField($oSQLQuery->m_sTable, $sRightField)) + if (empty($sRightTableAlias)) { - trigger_error("Unknown field '$sRightField' in table '".$oSQLQuery->m_sTable."'", E_USER_ERROR); + $sRightTableAlias = $oSQLQuery->m_sTableAlias; } +// #@# Could not be verified here because the namespace is unknown - do we need to check it there? +// +// if (!CMDBSource::IsField($sRightTable, $sRightField)) +// { +// trigger_error("Unknown field '$sRightField' in table '".$sRightTable."'", E_USER_ERROR); +// } $this->m_aJoinSelects[] = array( "jointype" => $sJoinType, "select" => $oSQLQuery, "leftfield" => $sLeftField, - "rightfield" => $sRightField + "rightfield" => $sRightField, + "righttablealias" => $sRightTableAlias ); } - public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField) + public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRigthtTable = '') { - $this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField); + $this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRigthtTable); } public function AddLeftJoin($oSQLQuery, $sLeftField, $sRightField) { @@ -259,9 +267,9 @@ class SQLQuery $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]); break; case "inner": - $sFrom .= " INNER JOIN `".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; - $sFrom .= " ON ".$aJoinInfo["joincondition"]; + $sFrom .= " INNER JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]); + $sFrom .= ") ON ".$aJoinInfo["joincondition"]; break; case "left": $sFrom .= " LEFT JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; @@ -339,7 +347,7 @@ class SQLQuery return $sTableAlias; } - private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = "first", $sCallerAlias = "", $sLeftField = "", $sRightField = "") + private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '') { $aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable); @@ -347,7 +355,11 @@ class SQLQuery // Handle the various kinds of join (or first table in the list) // - $sJoinCond = "`$sCallerAlias`.`$sLeftField` = `{$this->m_sTableAlias}`.`$sRightField`"; + if (empty($sRightTableAlias)) + { + $sRightTableAlias = $this->m_sTableAlias; + } + $sJoinCond = "`$sCallerAlias`.`$sLeftField` = `$sRightTableAlias`.`$sRightField`"; switch ($sJoinType) { case "first": @@ -355,6 +367,7 @@ class SQLQuery break; case "inner": case "left": + // table or tablealias ??? $aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond"); break; } @@ -386,8 +399,9 @@ class SQLQuery $oRightSelect = $aJoinData["select"]; $sLeftField = $aJoinData["leftfield"]; $sRightField = $aJoinData["rightfield"]; + $sRightTableAlias = $aJoinData["righttablealias"]; - $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField); + $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias); } $aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom; diff --git a/core/test.class.inc.php b/core/test.class.inc.php index e5cffe37f..bcf94eb91 100644 --- a/core/test.class.inc.php +++ b/core/test.class.inc.php @@ -337,15 +337,18 @@ abstract class TestBizModel extends TestHandler static protected function show_list($oObjectSet) { $oObjectSet->Rewind(); + $aData = array(); while ($oItem = $oObjectSet->Fetch()) { $aValues = array(); foreach(MetaModel::GetAttributesList(get_class($oItem)) as $sAttCode) { - $aValues[] = $oItem->GetAsHTML($sAttCode); + $aValues[$sAttCode] = $oItem->GetAsHTML($sAttCode); } - echo $oItem->GetKey()." => ".implode(", ", $aValues)."
    \n"; + //echo $oItem->GetKey()." => ".implode(", ", $aValues)."
    \n"; + $aData[] = $aValues; } + echo MyHelpers::make_table_from_assoc_array($aData); } static protected function search_and_show_list(DBObjectSearch $oMyFilter) diff --git a/pages/ITopConsultant.php b/pages/ITopConsultant.php index 7dd161166..f17ed1933 100644 --- a/pages/ITopConsultant.php +++ b/pages/ITopConsultant.php @@ -42,7 +42,7 @@ function ShowClass($sClass, $sBaseArgs) $aProps["Subclasses (children + pure PHP)"] = sexyclasslist(MetaModel::GetSubclasses($sClass), $sBaseArgs); $aProps["Description"] = MetaModel::GetClassDescription($sClass); - $aProps["Autoincrement pkey?"] = MetaModel::IsAutoIncrementKey($sClass); + $aProps["Autoincrement id?"] = MetaModel::IsAutoIncrementKey($sClass); $aProps["Key label"] = MetaModel::GetKeyLabel($sClass); $aProps["Name attribute"] = MetaModel::GetNameAttributeCode($sClass); $aProps["Reconciliation keys"] = implode(", ", MetaModel::GetReconcKeys($sClass)); @@ -188,7 +188,8 @@ function DebugQuery($sConfigFile) echo "

    Follow up the query build

    \n"; MetaModel::StartDebugQuery(); - $oFlt = DBObjectSearch::FromSibuSQL($sQuery); + $oFlt = DBObjectSearch::FromOQL($sQuery); + echo "

    To OQL: ".$oFlt->ToOQL()."

    "; $sSQL = MetaModel::MakeSelectQuery($oFlt); MetaModel::StopDebugQuery(); diff --git a/pages/testlist.inc.php b/pages/testlist.inc.php index 571c5a566..af834e991 100644 --- a/pages/testlist.inc.php +++ b/pages/testlist.inc.php @@ -706,6 +706,7 @@ class TestQueriesOnFarm extends TestBizModel throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)"); return false; } + echo "

    To OQL: ".$oMyFilter->ToOQL()."

    "; $this->search_and_show_list($oMyFilter); @@ -721,25 +722,21 @@ class TestQueriesOnFarm extends TestBizModel $oFilter2 = DBObjectSearch::unserialize($sSerialize); try { - $sQuery2 = MetaModel::MakeSelectQuery($oFilter2); + $sQuery2 = MetaModel::MakeSelectQuery($oFilter2); } catch (Exception $e) { echo "

    Could not compute the query after unserialize

    \n"; echo "

    Query 1: $sQuery1

    \n"; - MyHelpers::var_dump_html($oMyFilter, true); - echo "

    Query 2: FAILED

    \n"; - MyHelpers::var_dump_html($oFilter2, true); + MyHelpers::var_cmp_html($oMyFilter, $oFilter2); throw $e; } //if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same! if ($sQuery1 != $sQuery2) { echo "

    serialize/unserialize mismatch :-(

    \n"; - echo "

    Query 1: $sQuery1

    \n"; - MyHelpers::var_dump_html($oMyFilter, true); - echo "

    Query 2: $sQuery2

    \n"; - MyHelpers::var_dump_html($oFilter2, true); + MyHelpers::var_cmp_html($sQuery1, $sQuery2); + MyHelpers::var_cmp_html($oMyFilter, $oFilter2); return false; } return true; @@ -782,10 +779,14 @@ class TestQueriesOnFarm extends TestBizModel $aQueries = array( 'SELECT Animal' => true, + 'SELECT Animal WHERE Animal.pkey = 1' => false, + 'SELECT Animal WHERE Animal.id = 1' => true, 'SELECT Aniiimal' => false, 'SELECTe Animal' => false, 'SELECT * FROM Animal' => false, 'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true, + 'SELECT Animal AS zoo WHERE species = \'human\'' => true, + 'SELECT Animal AS zoo WHERE espece = \'human\'' => false, 'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true, 'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false, 'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true, @@ -793,6 +794,7 @@ class TestQueriesOnFarm extends TestBizModel 'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false, 'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true, 'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true, + 'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true, 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, 'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true, 'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true, @@ -802,6 +804,7 @@ class TestQueriesOnFarm extends TestBizModel 'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true, 'SELECT Mammal AS m WHERE (1 + 2' => false, 'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true, + 'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true, 'SELECT Mammal AS m WHERE 1/0' => true, 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, 'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true, @@ -813,20 +816,30 @@ class TestQueriesOnFarm extends TestBizModel 'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false, 'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true, 'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false, + 'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false, + 'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false, 'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true, 'SELECT Group AS G WHERE G.leader_speed < 100000' => true, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true, + 'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, + 'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true, + 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true, 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true, 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true, - 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.pkey = 1' => true, + 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.id = 1' => true, 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => false, 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, - 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => true, + 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.speed = 0' => true, + 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true, + 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true, + 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id JOIN Mammal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.name=\'chloe\' OR Child.name=\'bizounours\'' => true, ); //$aQueries = array( // 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,