Source for file RdqlDbEngine.php
Documentation is available at RdqlDbEngine.php
// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
* This class performs as RDQL query on a DbModel.
* Provided an rdql query parsed into an array of php variables and constraints
* at first the engine generates an sql statement and queries the database for
* tuples matching all patterns from the WHERE clause of the given RDQL query.
* Subsequently the result set is is filtered with evaluated boolean expressions
* from the AND clause of the given RDQL query.
* @version $Id: fsource_rdql__rdqlRdqlDbEngine.php.html 443 2007-06-01 16:25:38Z cax $
* @author Radoslaw Oldakowski <radol@gmx.de>
* Parsed query variables and constraints.
* @var array ['selectVars'][] = ?VARNAME
* ['patterns'][]['subject']['value'] = VARorURI
* ['predicate']['value'] = VARorURI
* ['object']['value'] = VARorURIorLiterl
* ['is_literal'] = boolean
* ['filters'][]['string'] = string
* ['evalFilterStr'] = string
* ['reqexEqExprs'][]['var'] = ?VARNAME
* ['operator'] = (eq | ne)
* ['strEqExprs'][]['var'] = ?VARNAME
* ['operator'] = (eq | ne)
* ['value_type'] = ('variable' | 'URI' | 'Literal')
* ['value_lang'] = string
* ['value_dtype'] = string
* ['numExpr']['vars'][] = ?VARNAME
* ( [] stands for an integer index - 0..N )
* When an RDQL query is performed on a DbModel, in first step the engine searches
* in database for triples matching the Rdql-WHERE clause. A recordSet is returned.
* $rsIndexes maps select and filter variables to their corresponding indexes
* in the returned recordSet.
* @var array [?VARNAME]['value'] = integer
* Perform an RDQL Query on the given DbModel.
* @param object DbModel $dbModel
* @param array &$parsedQuery (the same format as $this->parsedQuery)
* @param boolean $returnNodes
* @return array [][?VARNAME] = object Node (if $returnNodes = TRUE)
* OR array [][?VARNAME] = string
function & queryModel(&$dbModel, &$parsedQuery, $returnNodes =
TRUE) {
$this->parsedQuery =
&$parsedQuery;
$sql =
$this->generateSql($dbModel->modelID);
$recordSet =
& $dbModel->dbConn->execute($sql);
$queryResult =
$this->filterQueryResult($recordSet);
return $this->toNodes($queryResult);
* Generate an SQL string to query the database for tuples matching all patterns
* @param integer $modelID
function generateSql($modelID) {
$sql =
$this->generateSql_SelectClause();
$sql .=
$this->generateSql_FromClause();
$sql .=
$this->generateSql_WhereClause($modelID);
* Generate SQL SELECT clause.
function generateSql_SelectClause() {
$this->rsIndexes =
array();
foreach ($this->parsedQuery['selectVars'] as $var)
$sql_select .=
$this->_generateSql_SelectVar($var, $index);
if (isset
($this->parsedQuery['filters'])) {
foreach ($this->parsedQuery['filters'] as $n =>
$filter) {
// variables from numeric expressions
foreach ($filter['numExprVars'] as $numVar)
$sql_select .=
$this->_generateSql_SelectVar($numVar, $index);
// variables from regex equality expressions
foreach ($filter['regexEqExprs'] as $regexEqExpr)
$sql_select .=
$this->_generateSql_SelectVar($regexEqExpr['var'], $index);
// variables from string equality expressions
foreach ($filter['strEqExprs'] as $strEqVar)
$sql_select .=
$this->_generateSql_SelectVar($strEqVar['var'], $index);
return rtrim($sql_select, " , ");
* Generate SQL FROM clause
function generateSql_FromClause() {
foreach ($this->parsedQuery['patterns'] as $n =>
$v)
$sql_from .=
' statements s' .
($n+
1) .
' , ';
return rtrim($sql_from, ' , ');
* Generate an SQL WHERE clause
* @param integer $modelID
function generateSql_WhereClause($modelID) {
$count_patterns =
count($this->parsedQuery['patterns']);
foreach ($this->parsedQuery['patterns'] as $n =>
$pattern) {
$sql_where .=
' s' .
($n+
1) .
'.modelID=' .
$modelID .
' AND';
foreach ($pattern as $key =>
$val_1)
if ($val_1['value'] &&
$val_1['value']{0}==
'?') {
$sql_tmp =
' s' .
($n+
1) .
'.' .
$key .
'=';
// find internal bindings
if ($pattern['subject']['value'] ==
$pattern['predicate']['value'])
$sql_where .=
$sql_tmp .
's' .
($n+
1) .
'.predicate AND';
elseif ($pattern['subject']['value'] ==
$pattern['object']['value'])
$sql_where .=
$sql_tmp .
's' .
($n+
1) .
'.object AND';
if ($pattern['predicate']['value'] ==
$pattern['object']['value'])
$sql_where .=
$sql_tmp .
's' .
($n+
1) .
'.object AND';
// find external bindings
for ($i=
$n+
1; $i<
$count_patterns; $i++
)
foreach ($this->parsedQuery['patterns'][$i] as $key2 =>
$val_2)
if ($val_1['value']==
$val_2['value']) {
$sql_where .=
$sql_tmp .
's' .
($i+
1) .
'.' .
$key2 .
' AND';
$sql_where .=
' s' .
($n+
1) .
'.' .
$key .
"='" .
$val_1['value'] .
"' AND";
if ($key ==
'object' && isset
($val_1['is_literal'])) {
$sql_where .=
' s' .
($n+
1) .
".object_is='l' AND";
$sql_where .=
' s' .
($n+
1) .
".l_datatype='" .
$val_1['l_dtype'] .
"' AND";
$sql_where .=
' s' .
($n+
1) .
".l_language='" .
$val_1['l_lang'] .
"' AND";
return rtrim($sql_where, ' AND');
* Filter tuples containing variables matching all patterns from the WHERE clause
* of an RDQL query. As a result of a database query using ADOdb these tuples
* are returned as an ADORecordSet object, which is then passed to this function.
* @param object ADORecordSet &$recordSet
* @return array [][?VARNAME]['value'] = string
function filterQueryResult(&$recordSet) {
if (isset
($this->parsedQuery['filters'])) {
while (!$recordSet->EOF) {
foreach ($this->parsedQuery['filters'] as $filter) {
$evalFilterStr =
$filter['evalFilterStr'];
// evaluate regex equality expressions of each filter
foreach ($filter['regexEqExprs'] as $i =>
$expr) {
preg_match($expr['regex'], $recordSet->fields[$this->rsIndexes[$expr['var']]['value']], $match);
$op =
substr($expr['operator'], 0,1);
if (($op !=
'!' &&
!isset
($match[0])) ||
($op ==
'!' && isset
($match[0])))
$evalFilterStr =
str_replace("##RegEx_$i##", 'FALSE', $evalFilterStr);
$evalFilterStr =
str_replace("##RegEx_$i##", 'TRUE', $evalFilterStr);
// evaluate string equality expressions
foreach ($filter['strEqExprs'] as $i =>
$expr) {
switch ($expr['value_type']) {
if (($recordSet->fields[$this->rsIndexes[$expr['var']]['value']] ==
$recordSet->fields[$this->rsIndexes[$expr['value']]['value']] &&
$expr['operator'] ==
'eq') ||
($recordSet->fields[$this->rsIndexes[$expr['var']]['value']] !=
$recordSet->fields[$this->rsIndexes[$expr['value']]['value']] &&
$expr['operator'] ==
'ne'))
if (isset
($this->rsIndexes[$expr['var']]['nType']) &&
$recordSet->fields[$this->rsIndexes[$expr['var']]['nType']] ==
'l') {
if ($expr['operator'] ==
'ne')
if (($recordSet->fields[$this->rsIndexes[$expr['var']]['value']] ==
$expr['value'] &&
$expr['operator'] ==
'eq') ||
($recordSet->fields[$this->rsIndexes[$expr['var']]['value']] !=
$expr['value'] &&
$expr['operator'] ==
'ne'))
if (!isset
($this->rsIndexes[$expr['var']]['nType']) ||
$recordSet->fields[$this->rsIndexes[$expr['var']]['nType']] !=
'l') {
if ($expr['operator'] ==
'ne')
$filterLiteral=
new Literal($expr['value'],$expr['value_lang']);
$filterLiteral->setDatatype($expr['value_dtype']);
$resultLiteral=
new Literal($recordSet->fields[$this->rsIndexes[$expr['var']]['value']]);
$resultLiteral->setDatatype($recordSet->fields[$this->rsIndexes[$expr['var']]['l_dtype']]);
$resultLiteral->setLanguage($recordSet->fields[$this->rsIndexes[$expr['var']]['l_lang']]);
$equal=
$resultLiteral->equals($filterLiteral);
if (($equal &&
$expr['operator'] ==
'eq') ||
(!$equal &&
$expr['operator'] ==
'ne'))
$evalFilterStr =
str_replace("##strEqExpr_$i##", $exprBoolVal, $evalFilterStr);
// evaluate numerical expressions
foreach ($filter['numExprVars'] as $varName) {
$varValue =
"'" .
$recordSet->fields[$this->rsIndexes[$varName]['value']] .
"'";
$evalFilterStr =
str_replace($varName, $varValue, $evalFilterStr);
eval
("\$filterBoolVal = $evalFilterStr; \$eval_filter_ok = TRUE;");
if (!isset
($eval_filter_ok))
$queryResult[] =
$this->_convertRsRowToQueryResultRow($recordSet->fields);
while (!$recordSet->EOF) {
$queryResult[] =
$this->_convertRsRowToQueryResultRow($recordSet->fields);
* Serialize variable values of $queryResult to string.
* @param array &$queryResult [][?VARNAME]['value'] = string
* @return array [][?VARNAME] = string
// if a result set is empty return only variable sames
if (count($queryResult) ==
0) {
foreach ($this->parsedQuery['selectVars'] as $selectVar)
$res[0][$selectVar] =
NULL;
foreach ($queryResult as $n =>
$var)
foreach ($var as $varname =>
$varProperties)
if ($varProperties['nType'] ==
'r' ||
$varProperties['nType'] ==
'b')
$res[$n][$varname] =
'<' .
$varProperties['value'] .
'>';
$res[$n][$varname] =
'"' .
$varProperties['value'] .
'"';
if ($varProperties['l_lang'] !=
NULL)
$res[$n][$varname] .=
' (xml:lang="' .
$varProperties['l_lang'] .
'")';
if ($varProperties['l_dtype'] !=
NULL)
$res[$n][$varname] .=
' (rdf:datatype="' .
$varProperties['l_dtype'] .
'")';
* Convert variable values of $queryResult to objects (Node).
* @param array &$queryResult [][?VARNAME]['value'] = string
* @return array [][?VARNAME] = object Node
function toNodes(&$queryResult) {
// if a result set is empty return only variable sames
if (count($queryResult) ==
0) {
foreach ($this->parsedQuery['selectVars'] as $selectVar)
$res[0][$selectVar] =
NULL;
foreach ($queryResult as $n =>
$var)
foreach ($var as $varname =>
$varProperties)
if ($varProperties['nType'] ==
'r')
$res[$n][$varname] =
new Resource($varProperties['value']);
elseif ($varProperties['nType'] ==
'b')
$res[$n][$varname] =
new BlankNode($varProperties['value']);
$res[$n][$varname] =
new Literal($varProperties['value'], $varProperties['l_lang']);
if ($varProperties['l_dtype'] !=
NULL)
$res[$n][$varname]->setDataType($varProperties['l_dtype']);
* Generate a piece of an sql select statement for a variable.
* Look first if the given variable is defined as a pattern object.
* (So you can select the node type, literal lang and dtype)
* If not found - look for subjects and select node label and type.
* If there is no result either go to predicates.
* Predicates are always resources therefore select only the node label.
function _generateSql_SelectVar ($varName, &$index) {
foreach ($this->parsedQuery['patterns'] as $n =>
$pattern)
if ($varName ==
$pattern['object']['value']) {
// select the object label
$sql_select .=
" s" .++
$n .
".object as _" .
ltrim($varName, "?") .
" , ";
$this->rsIndexes[$varName]['value'] =
$index++
;
$sql_select .=
" s" .
$n .
".object_is , ";
$this->rsIndexes[$varName]['nType'] =
$index++
;
// select the object language
$sql_select .=
" s" .
$n .
".l_language , ";
$this->rsIndexes[$varName]['l_lang'] =
$index++
;
// select the object dtype
$sql_select .=
" s" .
$n .
".l_datatype , ";
$this->rsIndexes[$varName]['l_dtype'] =
$index++
;
foreach ($this->parsedQuery['patterns'] as $n =>
$pattern)
if ($varName ==
$pattern['subject']['value']) {
// select the object label
$sql_select .=
" s" .++
$n .
".subject as _" .
ltrim($varName, "?") .
" , ";
$this->rsIndexes[$varName]['value'] =
$index++
;
$sql_select .=
" s" .
$n .
".subject_is , ";
$this->rsIndexes[$varName]['nType'] =
$index++
;
foreach ($this->parsedQuery['patterns'] as $n =>
$pattern)
if ($varName ==
$pattern['predicate']['value']) {
// select the object label
$sql_select .=
" s" .++
$n .
".predicate as _" .
ltrim($varName, "?") .
" , ";
$this->rsIndexes[$varName]['value'] =
$index++
;
* Converts a single row of ADORecordSet->fields array to the format of
* $queryResult array using pointers to indexes ($this->rsIndexes) in RecordSet->fields.
* @param array &$record [] = string
* @return array [?VARNAME]['value'] = string
function _convertRsRowToQueryResultRow(&$record) {
// return only select variables (without conditional variables from the AND clause)
foreach ($this->parsedQuery['selectVars'] as $selectVar) {
$resultRow[$selectVar]['value'] =
$record[$this->rsIndexes[$selectVar]['value']];
if (isset
($this->rsIndexes[$selectVar]['nType']))
$resultRow[$selectVar]['nType'] =
$record[$this->rsIndexes[$selectVar]['nType']];
$resultRow[$selectVar]['nType'] =
'r';
if ($resultRow[$selectVar]['nType'] ==
'l') {
$resultRow[$selectVar]['l_lang'] =
$record[$this->rsIndexes[$selectVar]['l_lang']];
$resultRow[$selectVar]['l_dtype'] =
$record[$this->rsIndexes[$selectVar]['l_dtype']];
} // end: Class RdqlDbEngine
Documentation generated on Fri, 1 Jun 2007 16:51:04 +0200 by phpDocumentor 1.3.2