PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/s3db3.5.10/pearlib/rdfapi-php/api/sparql/SparqlEngineDb.php

https://github.com/drobbins/s3db
PHP | 391 lines | 202 code | 69 blank | 120 comment | 32 complexity | 31e61e80b8b07b4506e68d83277b3d68 MD5 | raw file
  1. <?php
  2. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngine.php';
  3. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/Offsetter.php';
  4. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/QuerySimplifier.php';
  5. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/ResultConverter.php';
  6. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/SqlGenerator.php';
  7. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/SqlMerger.php';
  8. /**
  9. * SPARQL engine optimized for databases.
  10. * Generates SQL statements to directly query the database,
  11. * letting the database system do all the hard work like
  12. * selecting, joining, filtering and ordering results.
  13. *
  14. * @author Christian Weiske <cweiske@cweiske.de>
  15. * @license http://www.gnu.org/licenses/lgpl.html LGPL
  16. *
  17. * @package sparql
  18. */
  19. class SparqlEngineDb
  20. {
  21. /**
  22. * Sparql Query object.
  23. *
  24. * @var Query
  25. */
  26. protected $query;
  27. /**
  28. * RDF dataset object.
  29. * @var Dataset
  30. */
  31. protected $dataset;
  32. /**
  33. * Database connection object.
  34. * @var ADOConnection
  35. */
  36. protected $dbConn;
  37. /**
  38. * Internal ID for our graph model.
  39. * Stored in the database along the statements.
  40. * Can be of different types:
  41. * - array: array of modelIds
  42. * - null: all models
  43. *
  44. * @var array OR null
  45. */
  46. protected $arModelIds;
  47. /**
  48. * Prepared SQL statements are stored in here.
  49. * @var array
  50. */
  51. protected $arPrepared = null;
  52. /**
  53. * If the prepared statement is really prepared, or if we just emulate it.
  54. * @var boolean
  55. */
  56. protected $bRealPrepared = false;
  57. /**
  58. * SQL generator instance
  59. * @var SparqlEngineDb_SqlGenerator
  60. */
  61. protected $sg = null;
  62. /**
  63. * Type sorting instance
  64. * @var SparqlEngineDb_TypeSorter
  65. */
  66. protected $ts = null;
  67. /**
  68. * Prepared statments preparator instance
  69. * @var SparqlEngineDb_Preparator
  70. */
  71. protected $pr = null;
  72. /**
  73. * Use SparqlEngine::factory() to create the instance
  74. *
  75. * @param mixed $model DbModel or DbStore
  76. * @param mixed $arModelIds Array of modelIds, or NULL to use all models
  77. */
  78. public function __construct($model, $arModelIds = null)
  79. {
  80. //parent::__construct();
  81. if ($model instanceof DbModel) {
  82. $this->dbConn = $model->getDbConn();
  83. $this->arModelIds = array($model->getModelID());
  84. } else if ($model instanceof DbStore) {
  85. $this->dbConn = $model->getDbConn();
  86. $this->arModelIds = $arModelIds;
  87. }
  88. }//public function __construct(DbModel $model, $arModelIds = null)
  89. /**
  90. * Query the database with the given SPARQL query.
  91. *
  92. *
  93. * @param Dataset $dataset RDF Dataset
  94. * @param Query $query Parsed SPARQL query
  95. * @param string $resultform Result form. If set to 'xml' the result will be
  96. * SPARQL Query Results XML Format as described in http://www.w3.org/TR/rdf-sparql-XMLres/ .
  97. *
  98. * @return array/string array of triple arrays, or XML. Format depends on
  99. * $resultform parameter.
  100. */
  101. public function queryModel($dataset, Query $query, $resultform = false)
  102. {
  103. if (isset($GLOBALS['debugSparql']) && $GLOBALS['debugSparql']) {
  104. echo "\n" . 'SPARQL query: ' . $query->getQueryString() . "\n";
  105. }
  106. $this->query = $query;
  107. $this->dataset = $dataset;
  108. $qsimp = new SparqlEngineDb_QuerySimplifier();
  109. $qsimp->simplify($this->query);
  110. $this->sg = new SparqlEngineDb_SqlGenerator ($this->query, $this->dbConn, $this->arModelIds);
  111. $this->rc = new SparqlEngineDb_ResultConverter($this->query, $this->sg, $this);
  112. $this->ts = new SparqlEngineDb_TypeSorter ($this->query, $this->dbConn);
  113. $this->setOptions();
  114. if ($this->query->isEmpty()){
  115. $vartable[0]['patternResult'] = null;
  116. return $this->returnResult($vartable, $resultform);
  117. }
  118. $arSqls = $this->sg->createSql();
  119. $this->ts->setData($this->sg);
  120. return
  121. SparqlEngineDb_ResultConverter::convertFromDbResults(
  122. $this->queryMultiple(
  123. $this->ts->getOrderifiedSqls(
  124. $arSqls
  125. )
  126. ),
  127. $this,
  128. $resultform
  129. );
  130. }//public function queryModel($dataset, Query $query, $resultform = false)
  131. /**
  132. * Create a prepared statement that can be executed later.
  133. *
  134. * @param Dataset $dataset RDF Dataset
  135. * @param Query $query Parsed SPARQL query
  136. *
  137. * @return SparqlEngineDb_PreparedStatement Prepared statment that can
  138. * be execute()d later.
  139. */
  140. public function prepare(Dataset $dataset, Query $query)
  141. {
  142. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/PreparedStatement.php';
  143. require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/Preparator.php';
  144. $this->query = $query;
  145. $this->dataset = $dataset;
  146. $this->sg = new SparqlEngineDb_SqlGenerator ($this->query, $this->dbConn, $this->arModelIds);
  147. $this->rc = new SparqlEngineDb_ResultConverter($this->query, $this->sg, $this);
  148. $this->ts = new SparqlEngineDb_TypeSorter ($this->query, $this->dbConn);
  149. $this->pr = new SparqlEngineDb_Preparator ($this->query, $this->dbConn);
  150. $this->arPrepared = $this->sg->createSql();
  151. $this->ts->setData($this->sg);
  152. if ($this->ts->willBeDataDependent()) {
  153. $this->bRealPrepared = false;
  154. } else {
  155. $this->bRealPrepared = true;
  156. list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
  157. $this->arPreparedQueries = $this->ts->getOrderifiedSqls(
  158. $strSelect,
  159. $strFrom,
  160. $strWhere
  161. );
  162. $this->arDbStatements = $this->pr->prepareInDb(
  163. $this->arPreparedQueries,
  164. $this->sg->getPlaceholders()
  165. );
  166. }
  167. return new SparqlEngineDb_PreparedStatement(
  168. $this
  169. );
  170. }//public function prepare(Dataset $dataset, Query $query)
  171. /**
  172. * Execute a prepared statement by filling it with variables
  173. *
  174. * @param array $arVariables Array with (variable name => value) pairs
  175. * @param string $resultform Which form the result should have
  176. *
  177. * @return mixed Result according to $resultform
  178. */
  179. public function execute($arVariables, $resultform = false)
  180. {
  181. if ($this->arPrepared === null) {
  182. throw new Exception('You need to prepare() the query first.');
  183. }
  184. if ($this->bRealPrepared) {
  185. return
  186. SparqlEngineDb_ResultConverter::convertFromDbResults(
  187. $this->pr->execute(
  188. $this->arDbStatements,
  189. $arVariables
  190. ),
  191. $this,
  192. $resultform
  193. );
  194. } else {
  195. list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
  196. return SparqlEngineDb_ResultConverter::convertFromDbResults(
  197. $this->queryMultiple(
  198. $this->ts->getOrderifiedSqls(
  199. $strSelect,
  200. $strFrom,
  201. $this->pr->replacePlaceholdersWithVariables(
  202. $strWhere,
  203. $this->sg->getPlaceholders(),
  204. $arVariables
  205. )
  206. )
  207. ),
  208. $this,
  209. $resultform
  210. );
  211. }
  212. }//public function execute($arVariables, $resultform)
  213. /**
  214. * Executes multiple SQL queries and returns an array
  215. * of results.
  216. *
  217. * @param array $arSqls Array of SQL queries
  218. * @return array Array of query results
  219. */
  220. protected function queryMultiple($arSqls)
  221. {
  222. $arSM = $this->query->getSolutionModifier();
  223. if ($arSM['limit'] === null && $arSM['offset'] === null) {
  224. $nOffset = 0;
  225. $nLimit = null;
  226. $nSql = 0;
  227. } else {
  228. $offsetter = new SparqlEngineDb_Offsetter($this->dbConn, $this->query);
  229. list($nSql, $nOffset) = $offsetter->determineOffset($arSqls);
  230. $nLimit = $arSM['limit'];
  231. }
  232. $nCount = 0;
  233. $arResults = array();
  234. foreach ($arSqls as $nId => $arSql) {
  235. if ($nId < $nSql) { continue; }
  236. if ($nLimit != null) {
  237. $nCurrentLimit = $nLimit - $nCount;
  238. } else {
  239. $nCurrentLimit = null;
  240. }
  241. $dbResult = $this->queryDb($arSql, $nOffset, $nCurrentLimit);
  242. $nCount += $dbResult->RowCount();
  243. $arResults[] = $dbResult;
  244. $nOffset = 0;
  245. if ($nLimit !== null && $nCount >= $nLimit) {
  246. break;
  247. }
  248. }
  249. return $arResults;
  250. //return array_map(array($this, 'queryDb'), $arSql);
  251. }//protected function queryMultiple($arSql)
  252. /**
  253. * Sends the sql to the database and returns the results.
  254. *
  255. * @internal Switches between ADOConnection::Execute() and
  256. * ADOConnection::SelectLimit() depending on the $query parameter's
  257. * $solutionModifier "limit" and "offset" settings.
  258. * Uses $query variable.
  259. *
  260. * @param array $arSql Array that gets a SQL query string once imploded
  261. *
  262. * @return mixed Anything ADOConnection::Execute() may return
  263. * @throws Exception If Database query does not work
  264. */
  265. function queryDb($arSql, $nOffset, $nLimit)
  266. {
  267. $strSql = SparqlEngineDb_SqlMerger::getSelect($this->query, $arSql);
  268. if ($strSql == '()') {
  269. return new ADORecordSet(false);
  270. }
  271. // I want associative arrays.
  272. $oldmode = $this->dbConn->SetFetchMode(ADODB_FETCH_ASSOC);
  273. if (isset($GLOBALS['debugSparql']) && $GLOBALS['debugSparql']) {
  274. echo 'SQL query: ' . $strSql . "\n";
  275. }
  276. if ($nLimit === null && $nOffset == 0) {
  277. $ret = $this->dbConn->execute($strSql);
  278. } else if ($nLimit === null) {
  279. $ret = $this->dbConn->SelectLimit($strSql, -1, $nOffset);
  280. } else {
  281. $ret = $this->dbConn->SelectLimit($strSql, $nLimit, $nOffset);
  282. }
  283. //... but others maybe not
  284. $this->dbConn->SetFetchMode($oldmode);
  285. if (!$ret) {
  286. //Error occured
  287. throw new Exception(
  288. 'ADOdb error: ' . $this->dbConn->ErrorMsg() . "\n"
  289. . $strSql
  290. );
  291. }
  292. return $ret;
  293. }//function queryDb($sql)
  294. /**
  295. * Set options to subobjects like SqlGenerator
  296. */
  297. protected function setOptions()
  298. {
  299. //allow changing the statements' table name
  300. if (isset($GLOBALS['RAP']['conf']['database']['tblStatements'])) {
  301. $this->sg->setStatementsTable(
  302. $GLOBALS['RAP']['conf']['database']['tblStatements']
  303. );
  304. }
  305. }//protected function setOptions()
  306. /*
  307. * Dumb getters
  308. */
  309. public function getQuery()
  310. {
  311. return $this->query;
  312. }//public function getQuery()
  313. public function getSqlGenerator()
  314. {
  315. return $this->sg;
  316. }//public function getSqlGenerator()
  317. public function getTypeSorter()
  318. {
  319. return $this->ts;
  320. }//public function getTypeSorter()
  321. }//class SparqlEngineDb
  322. ?>