PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Erfurt/Sparql/EngineDb/Adapter/EfZendDb.php

http://github.com/AKSW/Erfurt
PHP | 388 lines | 136 code | 47 blank | 205 comment | 19 complexity | 3b7f2b189fe50ea811c6428039c042a7 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the {@link http://aksw.org/Projects/Erfurt Erfurt} project.
  4. *
  5. * @copyright Copyright (c) 2012, {@link http://aksw.org AKSW}
  6. * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
  7. */
  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. * This class was originally adopted from rdfapi-php (@link http://sourceforge.net/projects/rdfapi-php/).
  15. * It was modified and extended in order to fit into Erfurt.
  16. *
  17. * @package Erfurt_Sparql_EngineDb_Adapter
  18. * @author Christian Weiske <cweiske@cweiske.de>
  19. * @author Philipp Frischmuth <pfrischmuth@googlemail.com>
  20. * @license http://www.gnu.org/licenses/lgpl.html LGPL
  21. */
  22. class Erfurt_Sparql_EngineDb_Adapter_EfZendDb
  23. {
  24. /**
  25. * Sparql Query object.
  26. *
  27. * @var Erfurt_Sparql_Query
  28. */
  29. protected $query;
  30. /**
  31. * RDF dataset object.
  32. *
  33. * @var Dataset
  34. */
  35. //protected $dataset;
  36. /**
  37. * Database connection object.
  38. * @var object zenddb connection
  39. */
  40. protected $dbConn;
  41. /**
  42. * Internal ID for our graph model.
  43. * Stored in the database along the statements.
  44. * Can be of different types:
  45. * - array: array of modelIds
  46. * - null: all models
  47. *
  48. * @var array OR null
  49. */
  50. protected $arModelIds;
  51. /**
  52. * Prepared SQL statements are stored in here.
  53. * @var array
  54. */
  55. protected $arPrepared = null;
  56. /**
  57. * If the prepared statement is really prepared, or if we just emulate it.
  58. * @var boolean
  59. */
  60. protected $bRealPrepared = false;
  61. /**
  62. * SQL generator instance
  63. * @var SparqlEngineDb_SqlGenerator
  64. */
  65. protected $sg = null;
  66. /**
  67. * Type sorting instance
  68. * @var SparqlEngineDb_TypeSorter
  69. */
  70. protected $ts = null;
  71. /**
  72. * Prepared statments preparator instance
  73. * @var SparqlEngineDb_Preparator
  74. */
  75. protected $pr = null;
  76. protected $arModelIdMapping = null;
  77. // ------------------------------------------------------------------------
  78. // --- Magic methods ------------------------------------------------------
  79. // ------------------------------------------------------------------------
  80. /**
  81. * Constructor
  82. */
  83. public function __construct($dbConn, $arModelIdMapping = array())
  84. {
  85. $this->dbConn = $dbConn;
  86. $this->arModelIdMapping = $arModelIdMapping;
  87. }
  88. public function getModelIdMapping()
  89. {
  90. return $this->arModelIdMapping;
  91. }
  92. // ------------------------------------------------------------------------
  93. // --- Public methods -----------------------------------------------------
  94. // ------------------------------------------------------------------------
  95. public function getQuery()
  96. {
  97. return $this->query;
  98. }
  99. public function getSqlGenerator()
  100. {
  101. return $this->sg;
  102. }
  103. public function getTypeSorter()
  104. {
  105. return $this->ts;
  106. }
  107. /**
  108. * Create a prepared statement that can be executed later.
  109. *
  110. * @param Dataset $dataset RDF Dataset
  111. * @param Query $query Parsed SPARQL query
  112. *
  113. * @return SparqlEngineDb_PreparedStatement Prepared statment that can
  114. * be execute()d later.
  115. */
  116. /*public function prepare(Dataset $dataset, Query $query)
  117. {
  118. //require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/PreparedStatement.php';
  119. //require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngineDb/Preparator.php';
  120. $this->query = $query;
  121. $this->dataset = $dataset;
  122. $this->sg = new SparqlEngineDb_SqlGenerator ($this->query, $this->dbConn, $this->arModelIds);
  123. $this->rc = new SparqlEngineDb_ResultConverter($this->query, $this->sg, $this);
  124. $this->ts = new SparqlEngineDb_TypeSorter ($this->query, $this->dbConn);
  125. $this->pr = new SparqlEngineDb_Preparator ($this->query, $this->dbConn);
  126. $this->arPrepared = $this->sg->createSql();
  127. $this->ts->setData($this->sg);
  128. if ($this->ts->willBeDataDependent()) {
  129. $this->bRealPrepared = false;
  130. } else {
  131. $this->bRealPrepared = true;
  132. list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
  133. $this->arPreparedQueries = $this->ts->getOrderifiedSqls(
  134. $strSelect,
  135. $strFrom,
  136. $strWhere
  137. );
  138. $this->arDbStatements = $this->pr->prepareInDb(
  139. $this->arPreparedQueries,
  140. $this->sg->getPlaceholders()
  141. );
  142. }
  143. return new SparqlEngineDb_PreparedStatement(
  144. $this
  145. );
  146. }*/
  147. /**
  148. * Execute a prepared statement by filling it with variables
  149. *
  150. * @param array $arVariables Array with (variable name => value) pairs
  151. * @param string $resultform Which form the result should have
  152. *
  153. * @return mixed Result according to $resultform
  154. */
  155. /*public function execute($arVariables, $resultform = false)
  156. {
  157. if ($this->arPrepared === null) {
  158. throw new Exception('You need to prepare() the query first.');
  159. }
  160. if ($this->bRealPrepared) {
  161. return
  162. SparqlEngineDb_ResultConverter::convertFromDbResults(
  163. $this->pr->execute(
  164. $this->arDbStatements,
  165. $arVariables
  166. ),
  167. $this,
  168. $resultform
  169. );
  170. } else {
  171. list($strSelect, $strFrom, $strWhere) = $this->arPrepared;
  172. return SparqlEngineDb_ResultConverter::convertFromDbResults(
  173. $this->_queryMultiple(
  174. $this->ts->getOrderifiedSqls(
  175. $strSelect,
  176. $strFrom,
  177. $this->pr->replacePlaceholdersWithVariables(
  178. $strWhere,
  179. $this->sg->getPlaceholders(),
  180. $arVariables
  181. )
  182. )
  183. ),
  184. $this,
  185. $resultform
  186. );
  187. }
  188. }*/
  189. /**
  190. * Query the database with the given SPARQL query.
  191. *
  192. * @param Erfurt_SparqlQuery $query Parsed SPARQL query.
  193. * @param string $resultform Result form. If set to 'xml' the result will be
  194. * SPARQL Query Results XML Format as described in @link http://www.w3.org/TR/rdf-sparql-XMLres/.
  195. *
  196. * @return array/string array of triple arrays, or XML.
  197. * Format depends on $resultform parameter.
  198. */
  199. public function queryModel(Erfurt_Sparql_Query $query, $resultform = 'plain')
  200. {
  201. $this->query = $query;
  202. require_once 'Erfurt/Sparql/EngineDb/QuerySimplifier.php';
  203. $qsimp = new Erfurt_Sparql_EngineDb_QuerySimplifier();
  204. $qsimp->simplify($this->query);
  205. require_once 'Erfurt/Sparql/EngineDb/QueryOptimizer.php';
  206. $queryOptimizer = new Erfurt_Sparql_EngineDb_QueryOptimizer($this);
  207. $result = $queryOptimizer->optimize($this->query);
  208. if ($result instanceof Erfurt_Sparql_Query) {
  209. $this->query = $result;
  210. }
  211. $resultform = strtolower($resultform);
  212. switch ($resultform) {
  213. case 'xml':
  214. require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Xml.php';
  215. $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Xml();
  216. break;
  217. //require_once 'Erfurt/Exception.php';
  218. //throw new Erfurt_Exception('XML result format not supported yet.');
  219. //require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/EfZendDb/Xml.php';
  220. //$this->rc = new Erfurt_Sparql_EngineDb_ResultRenderer_RapZendDb_Xml();
  221. //break;
  222. case 'extended':
  223. require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Extended.php';
  224. $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Extended();
  225. break;
  226. case 'json':
  227. require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Json.php';
  228. $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Json();
  229. break;
  230. case 'plain':
  231. default:
  232. require_once 'Erfurt/Sparql/EngineDb/ResultRenderer/Plain.php';
  233. $rc = new Erfurt_Sparql_EngineDb_ResultRenderer_Plain();
  234. }
  235. if (is_array($result)) {
  236. $result = $rc->convertFromDbResults($result['data'], $this->query, $this, $result['vars']);
  237. return $result;
  238. }
  239. require_once 'Erfurt/Sparql/EngineDb/SqlGenerator/Adapter/Ef.php';
  240. $this->sg = new Erfurt_Sparql_EngineDb_SqlGenerator_Adapter_Ef($this->query, $this->arModelIdMapping);
  241. require_once 'Erfurt/Sparql/EngineDb/TypeSorter.php';
  242. $this->ts = new Erfurt_Sparql_EngineDb_TypeSorter($this->query, $this);
  243. $this->_setOptions();
  244. $arSqls = $this->sg->createSql();
  245. #var_dump($arSqls);exit;
  246. $this->ts->setData($this->sg);
  247. return $rc->convertFromDbResults($this->_queryMultiple($this->ts->getOrderifiedSqls($arSqls)),
  248. $this->query, $this, $this->sg->arVarAssignments);
  249. }
  250. public function sqlQuery($sql)
  251. {
  252. return $this->dbConn->fetchAll($sql);
  253. }
  254. // ------------------------------------------------------------------------
  255. // --- Protected methods --------------------------------------------------
  256. // ------------------------------------------------------------------------
  257. /**
  258. * Sends the sql to the database and returns the results.
  259. *
  260. * @param array $arSql Array that gets a SQL query string once imploded.
  261. *
  262. * @return mixed
  263. */
  264. protected function _queryDb($arSql, $nOffset, $nLimit)
  265. {
  266. require_once 'Erfurt/Sparql/EngineDb/SqlMerger.php';
  267. $strSql = Erfurt_Sparql_EngineDb_SqlMerger::getSelect($this->query, $arSql);
  268. #var_dump($nLimit, $nOffset);
  269. #echo $strSql;
  270. if ($strSql === '()') {
  271. return array();
  272. }
  273. if ($nLimit === null && $nOffset == 0) {
  274. $ret = @$this->dbConn->query($strSql);
  275. } else if ($nLimit === null) {
  276. $ret = @$this->dbConn->query($strSql . ' LIMIT ' . $nOffset . ', 18446744073709551615');
  277. } else {
  278. $ret = @$this->dbConn->query($strSql . ' LIMIT ' . $nOffset . ', ' . $nLimit);
  279. }
  280. return $ret->fetchAll();
  281. }
  282. /**
  283. * Executes multiple SQL queries and returns an array of results.
  284. *
  285. * @param array $arSqls Array of SQL queries.
  286. * @return array Array of query results.
  287. */
  288. protected function _queryMultiple($arSqls)
  289. {
  290. $arSM = $this->query->getSolutionModifier();
  291. if ($arSM['limit'] === null && $arSM['offset'] === null) {
  292. $nOffset = 0;
  293. $nLimit = null;
  294. $nSql = 0;
  295. } else {
  296. require_once 'Erfurt/Sparql/EngineDb/Offsetter.php';
  297. $offsetter = new Erfurt_Sparql_EngineDb_Offsetter($this, $this->query);
  298. list($nSql, $nOffset) = $offsetter->determineOffset($arSqls);
  299. $nLimit = $arSM['limit'];
  300. }
  301. $nCount = 0;
  302. $arResults = array();
  303. foreach ($arSqls as $nId => $arSql) {
  304. if ($nId < $nSql) {
  305. continue;
  306. }
  307. if ($nLimit != null) {
  308. $nCurrentLimit = $nLimit - $nCount;
  309. } else {
  310. $nCurrentLimit = null;
  311. }
  312. $dbResult = $this->_queryDb($arSql, $nOffset, $nCurrentLimit);
  313. $nCount += count($dbResult);
  314. $arResults[] = $dbResult;
  315. $nOffset = 0;
  316. if ($nLimit !== null && $nCount >= $nLimit) {
  317. break;
  318. }
  319. }
  320. return $arResults;
  321. }
  322. /**
  323. * Set options to subobjects like SqlGenerator
  324. */
  325. protected function _setOptions()
  326. {
  327. // allow changing the statements' table name
  328. //if (isset($GLOBALS['RAP']['conf']['database']['tblStatements'])) {
  329. // $this->sg->setStatementsTable(
  330. // $GLOBALS['RAP']['conf']['database']['tblStatements']
  331. // );
  332. //}
  333. }
  334. }