Source for file FilterGenerator.php
Documentation is available at FilterGenerator.php
* Generates SQL from Sparql FILTER parts
* @author Christian Weiske <cweiske@cweiske.de>
* @var SparqlEngineDb_SqlGenerator
* If the filter is in an optional statement
* Number of parameters for the functions supported.
* First value is minimum, second is maximum.
protected static $arFuncParamNumbers =
array(
'datatype' =>
array(1, 1),
'isblank' =>
array(1, 1),
'isliteral' =>
array(1, 1),
'langmatches' =>
array(2, 2),
'sameterm' =>
array(2, 2),
'xsd:datetime' =>
array(1, 1),
* List of operators and their counterpart if operands are switched.
protected static $arOperatorSwitches =
array(
protected static $arDumbOperators =
array(
protected static $typeXsdBoolean =
'http://www.w3.org/2001/XMLSchema#boolean';
protected static $typeXsdDateTime =
'http://www.w3.org/2001/XMLSchema#dateTime';
protected static $typeXsdDouble =
'http://www.w3.org/2001/XMLSchema#double';
protected static $typeXsdInteger =
'http://www.w3.org/2001/XMLSchema#integer';
protected static $typeXsdString =
'http://www.w3.org/2001/XMLSchema#string';
protected static $typeVariable =
'variable';
public function __construct(SparqlEngineDb_SqlGenerator $sg)
}//public function __construct(SparqlEngineDb_SqlGenerator $sqlgen)
* Creates the SQL representing a Sparql FILTER.
* @param array $tree Filter element tree as returned by
* SparqlParser::parseConstraintTree()
* @param boolean $bOptional If the filter is in an optional statement
* @return string SQL WHERE part with prefixed AND
$this->nUnionCount =
$nUnionCount;
}//public function createFilterSql($tree)
$bDumbParent =
$parent['type'] ==
'equation'
&&
in_array($parent['operator'], self::$arDumbOperators);
throw
new Exception('Unsupported tree type: ' .
$tree['type']);
if (isset
($tree['negated'])) {
$sql =
'!(' .
$sql .
')';
}//protected function createTreeSql($tree, $strParentType)
* Creates the sql for an element of type "value".
* @param array $tree Element
* @param boolean $bDumbParent True if the parent is a boolean equation or null.
'Unknown variable in filter: ' .
$strValue
//convert datetime to datetime if necessary
.
' WHEN ' .
$this->getIsCol($tree) .
' = "' .
self::$typeXsdDateTime .
'"'
} else if ($tree['quoted'] ===
false) {
$strValueNew =
$this->sg->query->getFullUri($strValue);
if ($strValueNew ===
false) {
if ($strValue[0] ==
'<' &&
substr($strValue, -
1) ==
'>') {
$strValue =
substr($strValue, 1, -
1);
'Unexpected value "' .
$strValueNew .
'" (expected datatype)'
$strValue =
$strValueNew;
} else if (isset
($tree['datatype'])) {
switch ($tree['datatype']) {
case self::$typeXsdBoolean:
if (strtolower($strValue) ==
'false') {
//fix: (bool)"false" === true
(bool)
$strValue ?
'TRUE' :
'FALSE',
throw
new SparqlEngineDb_SqlGeneratorException(
'Unsupported datatype "' .
$tree['datatype']
}//protected function createValue($tree)
$strSqlCol =
SparqlEngineDb_SqlGenerator::$arTableColumnNames[$chType]['value'];
$strTable .
'.' .
$strSqlCol .
' != ""',
$cType =
$strTable .
'.l_datatype';
$cValue =
$strTable .
'.object';
$xsd =
'http://www.w3.org/2001/XMLSchema';
.
"(($cType = '' || $cType = '$xsd#string') AND $cValue != '')"
.
" OR ($cType = '$xsd#boolean' AND $cValue != 'false')"
.
" OR (($cType = '$xsd#integer' || $cType = '$xsd#double') AND CAST($cValue AS DECIMAL) != 0)"
//plain check for all unknown datatypes
.
" OR ($cType != '' AND $cType != '$xsd#string' AND $cType != '$xsd#boolean' AND $cType != '$xsd#integer' AND $cType != '$xsd#double' AND $cValue != '')"
}//protected function createBooleanValue($tree)
$strFuncName =
strtolower($tree['name']);
if (!isset
(self::$arFuncParamNumbers[$strFuncName])) {
throw
new SparqlEngineDb_SqlGeneratorException(
'Unsupported FILTER function: ' .
$strFuncName
$nParams =
count($tree['parameter']);
if ($nParams <
self::$arFuncParamNumbers[$strFuncName][0]
||
$nParams >
self::$arFuncParamNumbers[$strFuncName][1]
throw
new SparqlEngineDb_SqlGeneratorException(
'Wrong parameter count for FILTER function: ' .
$strFuncName
.
' (got ' .
$nParams .
', expected '
.
self::$arFuncParamNumbers[$strFuncName][0]
.
'-' .
self::$arFuncParamNumbers[$strFuncName][1]
$strThisFunc =
'createFunction_' .
str_replace(':', '_', $strFuncName);
return $this->$strThisFunc($tree);
}//protected function createFunction($tree)
//switch operands and operator
$tmp =
$tree['operand1'];
$tree['operand1'] =
$tree['operand2'];
$tree['operand2'] =
$tmp;
$tree['operator'] =
self::switchOperator($tree['operator']);
if ($this->isObject($tree['operand1'])) {
$strIsNullEnd =
' OR ' .
$val1 .
' IS NULL)';
if (isset
($tree['operand2']['language'])) {
$strColLanguage =
$this->getLangCol($tree['operand1']);
$strExtra .=
' AND ' .
$strColLanguage .
' = "'
if ($this->isNumber($tree['operand2'])) {
$strExtra .=
' AND (' .
$strColDatatype .
' = "' .
self::$typeXsdDouble .
'"'
.
' OR ' .
$strColDatatype .
' = "' .
self::$typeXsdInteger .
'"'
.
'CAST(' .
$val1 .
' AS DECIMAL)'
.
' ' .
$tree['operator'] .
' '
//I don't check the operator since it is already checked in the parser
.
' ' .
$tree['operator'] .
' '
$tree['operator'], $val1, $val2,
$tree['operand1'], $tree['operand2']
}//protected function createEquation($tree)
* Generates sql code to make sure the datatypes of the two operands match
if (in_array($operator, array('&&', '||'))) {
if ($val1->type !=
self::$typeVariable &&
$val2->type !=
self::$typeVariable) {
//both are not variables -> type needs to be the same
return $val1->type ==
$val2->type ?
'' :
' AND FALSE';
if ($o1 &&
$val2->type !=
self::$typeVariable) {
} else if ($o2 &&
$val1->type !=
self::$typeVariable) {
}//protected function createTypeEquation($operator, $val1, $val2, $tree1, $tree2)
* Creates sql to ensure the type between $val and variable $tree
if ($val->type ==
self::$typeXsdString) {
//string can be empty type or xsd type
return ' AND ' .
$this->getDatatypeCol($tree) .
' = "' .
$val->type .
'"';
}//protected function createSingleTypeCheck($val, $tree)
* SQL generation functions
* Creates an sql statement that returns if the element is a blank node
$this->getValueCol($tree['parameter'][0]) .
' IS NOT NULL',
//We'll see which other cases occur here
return self::mkVal('TRUE', self::$typeXsdBoolean);
}//protected function createFunction_bound($tree)
if (!$this->isObject($tree['parameter'][0])) {
throw
new SparqlEngineDb_SqlGeneratorException(
'datatype\'s first parameter needs to be an object'
}//protected function createFunction_datatype($tree)
* Creates an sql statement that returns if the element is a blank node
throw
new SparqlEngineDb_SqlGeneratorException(
'isBlank\'s first parameter needs to be an object or subject'
$this->getIsCol($tree['parameter'][0]) .
' = "b"',
}//protected function createFunction_isblank($tree)
}//protected function createFunction_isiri($tree)
* Creates an sql statement that returns the language of the object
return $this->getIsCol($tree['parameter'][0]) .
' = "l"';
//This does not take combined functions into account (subfunctions)
}//protected function createFunction_isliteral($tree)
$this->getIsCol($tree['parameter'][0]) .
' = "r"',
return self::mkVal('TRUE', self::$typeXsdBoolean);
}//protected function createFunction_isuri($tree)
* Creates an sql statement that returns the language of the object
if (!$this->isObject($tree['parameter'][0])) {
throw
new SparqlEngineDb_SqlGeneratorException(
'lang\'s first parameter needs to be an object'
}//protected function createFunction_lang($tree)
* Creates an sql statement that checks if the variable
* matches a given language
//those two restrictions are needed until we have a mysql-only
if ($tree['parameter'][0]['type'] !=
'function'
||
$tree['parameter'][0]['name'] !=
'lang'
throw
new SparqlEngineDb_SqlGeneratorException(
'langMatches\' first parameter needs to be a lang() function'
'langMatches\' second parameter needs to be a string'
$lang =
$tree['parameter'][1]['value'];
//language, maybe with different subcode
$sql =
'(' .
$col .
' = "' .
addslashes($lang) .
'" OR '
return self::mkVal($sql, self::$typeXsdBoolean);
}//protected function createFunction_isuri($tree)
* Creates an sql statement that checks if the given part matches
if (isset
($tree['parameter'][2])) {
$sql =
$strVar .
' REGEXP ' .
$strRegex;
$sql =
'CAST(' .
$strVar .
' AS CHAR) REGEXP ' .
$strRegex;
throw
new SparqlEngineDb_SqlGeneratorException(
'Unsupported regex modifier "'
$sql =
$strVar .
' REGEXP ' .
$strRegex;
if ($this->isObject($tree['parameter'][0])) {
$col =
$this->getIsCol($tree['parameter'][0]);
$sql =
"($sql AND $col = 'l')";
return self::mkVal($sql, self::$typeXsdBoolean);
}//protected function createFunction_regex($tree)
* Creates an sql statement that checks if both terms are the same
//FIXME: dead simple implementation that does not cover all cases
}//protected function createFunction_sameterm($tree)
* Creates an sql statement that returns the string representation
if ($this->isObject($tree['parameter'][0])) {
'(CASE ' .
$this->getIsCol($tree['parameter'][0])
}//protected function createFunction_str($tree)
* Creates an sql statement that returns the datetime representation
if ($val->type ==
self::$typeXsdDateTime
||
$val->type ==
self::$typeVariable) {
}//protected function createFunction_xsd_datetime($tree)
protected static function mkVal($value, $type =
null) {
return new SparqlEngineDb_FilterGenerator_Value($value, $type);
protected function getCol($tree, $type)
return $strTable .
'.' .
$strSqlCol;
return $strTable .
'.l_datatype';
return 'STR_TO_DATE(' .
$strValue .
', "%Y-%m-%dT%H:%i:%sZ")';
}//protected function getDateConversionSql($strValue)
return $this->getCol($tree, 'is');
return $strTable .
'.l_language';
return $this->getCol($tree, 'value');
return $tree['type'] ==
'value'
&&
$tree['quoted'] ===
false
&&
floatval($tree['value']) ==
$tree['value'];
}//protected function isNumber($tree)
* Checks if the given tree element is a variable
* and the variable is actually an object in the database.
* @param array $tree Tree element
* @return boolean True if the element is an object
}//protected function isVariable($tree)
* Checks if the given tree element is a variable
* and the variable is actually an object or a subject in the database.
* @param array $tree Tree element
* @return boolean True if the element is an object or an subject
}//protected function isObjectOrSubject($tree)
* Checks if the given tree element is a plain string (no variable)
* @param array $tree Tree element
* @return boolean True if the element is a string
return $tree['type'] ==
'value'
&&
$tree['quoted'] ===
true;
}//protected function isPlainString($tree)
return $tree['type'] ==
'value'
&&
$tree['type']['quoted'] ===
false
}//protected function isValueButNotVariableNorString($tree)
* Checks if the given tree element is a variable
* @param array $tree Tree element
* @return boolean True if the element is a variable
return $tree['type'] ==
'value'
&&
$tree['quoted'] ===
false
}//protected function isVariable($tree)
if (!isset
(self::$arOperatorSwitches[$op])) {
return self::$arOperatorSwitches[$op];
}//protected static function switchOperator($op)
}//class SparqlEngineDb_FilterGenerator
* Value class that holds some arbitrary value
* Objects of this class can transparently be used in strings since
* its __toString() returns the value.
}//class SparqlEngineDb_FilterGenerator_Value
Documentation generated on Fri, 1 Jun 2007 16:49:06 +0200 by phpDocumentor 1.3.2