PageRenderTime 72ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/Erfurt/Store/Adapter/Mssql.php

https://bitbucket.org/udfr/udfr-erfurt
PHP | 1570 lines | 1110 code | 287 blank | 173 comment | 168 complexity | b90729041084063ab0a90cd2ee082334 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. require_once 'Erfurt/Store/Adapter/Interface.php';
  3. require_once 'Erfurt/Store/Sql/Interface.php';
  4. /**
  5. * Erfurt RDF Store - Adapter for the {@link http://www4.wiwiss.fu-berlin.de/bizer/rdfapi/ RAP} schema (modified) with
  6. * Zend_Db database abstraction layer.
  7. *
  8. * @package erfurt
  9. * @subpackage store
  10. * @author Philipp Frischmuth <pfrischmuth@googlemail.com>
  11. * @copyright Copyright (c) 2008 {@link http://aksw.org aksw}
  12. * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
  13. * @version $Id: RapZendDb.php 2532 2009-02-06 08:15:41Z pfrischmuth $
  14. */
  15. class Erfurt_Store_Adapter_Mssql implements Erfurt_Store_Adapter_Interface, Erfurt_Store_Sql_Interface
  16. {
  17. // ------------------------------------------------------------------------
  18. // --- Private properties -------------------------------------------------
  19. // ------------------------------------------------------------------------
  20. private $_modelCache = array();
  21. private $_modelInfoCache = null;
  22. private $_dbConn = false;
  23. /** @var array */
  24. private $_titleProperties = array(
  25. 'http://www.w3.org/2000/01/rdf-schema#label',
  26. 'http://purl.org/dc/elements/1.1/title'
  27. );
  28. // ------------------------------------------------------------------------
  29. // --- Magic methods ------------------------------------------------------
  30. // ------------------------------------------------------------------------
  31. /**
  32. * Constructor
  33. *
  34. * @param array $adapterOptions This adapter class needs the following parameters:
  35. * - 'host'
  36. * - 'username'
  37. * - 'password'
  38. * - 'dbname'
  39. */
  40. public function __construct($adapterOptions = array())
  41. {
  42. $adapter = $adapterOptions['dbtype'];
  43. $host = isset($adapterOptions['host']) ? $adapterOptions['host'] : 'localhost';
  44. $username = $adapterOptions['username'];
  45. $password = $adapterOptions['password'];
  46. $dbname = $adapterOptions['dbname'];
  47. $adapterOptions = array(
  48. 'host' => $host,
  49. 'username' => $username,
  50. 'password' => $password,
  51. 'dbname' => $dbname,
  52. 'profiler' => false
  53. );
  54. if (extension_loaded('sqlsrv')) {
  55. require_once 'Zend/Db/Adapter/Sqlsrv.php';
  56. $this->_dbConn = new Zend_Db_Adapter_Sqlsrv($adapterOptions);
  57. } else {
  58. require_once 'Erfurt/Exception.php';
  59. throw new Erfurt_Exception('Sqlsrv extension not found.', -1);
  60. }
  61. try {
  62. // try to initialize the connection
  63. $this->_dbConn->getConnection();
  64. } catch (Zend_Db_Adapter_Exception $e) {
  65. // maybe wrong login credentials or db-server not running?!
  66. require_once 'Erfurt/Exception.php';
  67. throw new Erfurt_Exception('Could not connect to database with name: "' . $dbname . '". Please check your credentials and whether the database exists and the server is running.', -1);
  68. } catch (Zend_Exception $e) {
  69. // maybe a needed php extension is not loaded?!
  70. require_once 'Erfurt/Exception.php';
  71. throw new Erfurt_Exception('An error with the specified database adapter occured.', -1);
  72. }
  73. // we want indexed results
  74. //$this->_dbConn->setFetchMode(Zend_Db::FETCH_NUM);
  75. // load title properties for model titles
  76. $config = Erfurt_App::getInstance()->getConfig();
  77. if (isset($config->properties->title)) {
  78. $this->_titleProperties = $config->properties->title->toArray();
  79. }
  80. }
  81. public function __destruct()
  82. {
  83. #$log = Erfurt_App::getInstance()->getLog();
  84. #$profiles = $this->_dbConn->getProfiler()->getQueryProfiles();
  85. #foreach ($profiles as $profile) {
  86. # $debugStr = 'Query: ' . $profile->getQuery() . PHP_EOL;
  87. # $debugStr .= 'Time: ' . $profile->getElapsedSecs() . PHP_EOL;
  88. #
  89. # $log->debug($debugStr);
  90. #}
  91. }
  92. // ------------------------------------------------------------------------
  93. // --- Public methods (derived from Erfurt_Store_Adapter_Abstract) --------
  94. // ------------------------------------------------------------------------
  95. /** @see Erfurt_Store_Adapter_Interface */
  96. public function addMultipleStatements($graphUri, array $statementsArray, array $options = array())
  97. {
  98. $modelInfoCache = $this->_getModelInfos();
  99. $graphId = $modelInfoCache[$graphUri]['modelId'];
  100. $sqlQuery = 'INSERT INTO ef_stmt (g,s,p,o,s_r,p_r,o_r,st,ot,ol,od,od_r) VALUES ';
  101. $insertArray = array();
  102. $counter = 0;
  103. foreach ($statementsArray as $subject => $predicatesArray) {
  104. foreach ($predicatesArray as $predicate => $objectsArray) {
  105. foreach ($objectsArray as $object) {
  106. $sqlString = '';
  107. $s = $subject;
  108. $p = $predicate;
  109. $o = $object;
  110. // check whether the subject is a blank node
  111. if (substr((string)$s, 0, 2) === '_:') {
  112. $s = substr((string)$s, 2);
  113. $subjectIs = '1';
  114. } else {
  115. $subjectIs = '0';
  116. }
  117. // check the type of the object
  118. if ($o['type'] === 'uri') {
  119. $objectIs = '0';
  120. $lang = false;
  121. $dType = false;
  122. } else if ($o['type'] === 'bnode') {
  123. if (substr((string)$o['value'], 0, 2) === '_:') {
  124. $o['value'] = substr((string)$o['value'], 2);
  125. }
  126. $objectIs = '1';
  127. $lang = false;
  128. $dType = false;
  129. } else {
  130. $objectIs = '2';
  131. $lang = isset($o['lang']) ? $o['lang'] : '';
  132. $dType = isset($o['datatype']) ? $o['datatype'] : '';
  133. }
  134. $sRef = false;
  135. if (strlen((string)$s) > $this->_getSchemaRefThreshold()) {
  136. $subjectHash = md5((string)$s);
  137. try {
  138. $sRef = $this->_insertValueInto('ef_uri', $graphId, $s, $subjectHash);
  139. } catch (Erfurt_Store_Adapter_Exception $e) {
  140. $this->_dbConn->rollback();
  141. require_once 'Erfurt/Store/Adapter/Exception.php';
  142. throw new Erfurt_Store_Adapter_Exception($e->getMessage());
  143. }
  144. $s = substr((string)$s, 0, 128) . $subjectHash;
  145. }
  146. $pRef = false;
  147. if (strlen((string)$p) > $this->_getSchemaRefThreshold()) {
  148. $predicateHash = md5((string)$p);
  149. try {
  150. $pRef = $this->_insertValueInto('ef_uri', $graphId, $p, $predicateHash);
  151. } catch (Erfurt_Store_Adapter_Exception $e) {
  152. $this->_dbConn->rollback();
  153. require_once 'Erfurt/Store/Adapter/Exception.php';
  154. throw new Erfurt_Store_Adapter_Exception($e->getMessage());
  155. }
  156. $p = substr((string)$p, 0, 128) . $predicateHash;
  157. }
  158. $oRef = false;
  159. if (strlen((string)$o['value']) > $this->_getSchemaRefThreshold()) {
  160. $objectHash = md5((string)$o['value']);
  161. if ($o['type'] === 'literal') {
  162. $tableName = 'ef_lit';
  163. } else {
  164. $tableName = 'ef_uri';
  165. }
  166. try {
  167. $oRef = $this->_insertValueInto($tableName, $graphId, $o['value'], $objectHash);
  168. } catch (Erfurt_Store_Adapter_Exception $e) {
  169. $this->_dbConn->rollback();
  170. require_once 'Erfurt/Store/Adapter/Exception.php';
  171. throw new Erfurt_Store_Adapter_Exception($e->getMessage());
  172. }
  173. $o['value'] = substr((string)$o['value'], 0, 128) . $objectHash;
  174. }
  175. $oValue = addslashes($o['value']);
  176. $sqlString .= "($graphId,'$s','$p','$oValue',";
  177. #$data = array(
  178. # 'g' => $graphId,
  179. # 's' => $subject,
  180. # 'p' => $predicate,
  181. # 'o' => $object['value'],
  182. # 'st' => $subjectIs,
  183. # 'ot' => $objectIs
  184. #);
  185. if ($sRef !== false) {
  186. $sqlString .= "$sRef,";
  187. } else {
  188. $sqlString .= "NULL,";
  189. }
  190. if ($pRef !== false) {
  191. $sqlString .= "$pRef,";
  192. } else {
  193. $sqlString .= "NULL,";
  194. }
  195. if ($oRef !== false) {
  196. $sqlString .= "$oRef,";
  197. } else {
  198. $sqlString .= "NULL,";
  199. }
  200. $sqlString .= "$subjectIs,$objectIs,'$lang',";
  201. #$data['ol'] = $lang;
  202. if (strlen((string)$dType) > $this->_getSchemaRefThreshold()) {
  203. $dTypeHash = md5((string)$dType);
  204. try {
  205. $dtRef = $this->_insertValueInto('ef_uri', $graphId, $dType, $dTypeHash);
  206. } catch (Erfurt_Store_Adapter_Exception $e) {
  207. $this->_dbConn->rollback();
  208. require_once 'Erfurt/Store/Adapter/Exception.php';
  209. throw new Erfurt_Store_Adapter_Exception($e->getMessage());
  210. }
  211. $dType = substr((string)$data['od'], 0, 128) . $dTypeHash;
  212. $data['od_r'] = $dtRef;
  213. $sqlString .= "'$dType',$dtRef)";
  214. } else {
  215. #$data['od'] = $dType;
  216. $sqlString .= "'$dType',NULL)";
  217. }
  218. // $insertArray[] = $sqlString;
  219. $counter++;
  220. $finalquery = 'IF NOT EXISTS(Select g, s, p, o, st, ot, ol, od from ef_stmt
  221. WHERE
  222. g = \''.$graphId.'\' AND
  223. s = \''.$s.'\' AND
  224. p = \''.$p.'\' AND
  225. o = \''.$oValue.'\' AND
  226. st = \''.$subjectIs.'\' AND
  227. ot = \''.$objectIs.'\' AND
  228. ol = \''.$lang.'\' AND
  229. od = \''.$dType.'\'
  230. )'.$sqlQuery. $sqlString;
  231. $this->sqlQuery((string)$finalquery);
  232. }
  233. }
  234. }
  235. if (defined('_EFDEBUG')) {
  236. $logger = Erfurt_App::getInstance()->getLog();
  237. $logger->info('ZendDb multiple statements added: ' . $counter);
  238. }
  239. if ($counter > 100) {
  240. $this->_optimizeTables();
  241. }
  242. }
  243. protected function _getNormalizedErrorCode()
  244. {
  245. if ($this->_dbConn instanceof Zend_Db_Adapter_Mysqli) {
  246. switch($this->_dbConn->getConnection()->errno) {
  247. case 1062:
  248. // duplicate entry
  249. return 1000;
  250. }
  251. } else {
  252. return -1;
  253. }
  254. }
  255. /** @see Erfurt_Store_Adapter_Interface */
  256. public function addStatement($graphUri, $subject, $predicate, $object, array $options = array())
  257. {
  258. $statementArray = array();
  259. $statementArray["$subject"] = array();
  260. $statementArray["$subject"]["$predicate"] = array();
  261. $statementArray["$subject"]["$predicate"][] = $object;
  262. try {
  263. $this->addMultipleStatements($graphUri, $statementArray);
  264. } catch (Erfurt_Store_Adapter_Exception $e) {
  265. require_once 'Erfurt/Store/Adapter/Exception.php';
  266. throw new Erfurt_Store_Adapter_Exception('Insertion of statement failed:' .
  267. $e->getMessage());
  268. }
  269. }
  270. /** @see Erfurt_Store_Adapter_Interface */
  271. public function countWhereMatches($graphIris, $whereSpec, $countSpec, $distinct = false)
  272. {
  273. $query = new Erfurt_Sparql_SimpleQuery();
  274. if(!$distinct){
  275. $query->setProloguePart("COUNT DISTINCT $countSpec"); // old way: distinct has no effect !!!
  276. } else {
  277. $query->setProloguePart("COUNT-DISTINCT $countSpec"); // i made a (unccol) hack to fix this, the "-" ist there because i didnt want to change tokenization
  278. }
  279. $query->setFrom($graphIris)
  280. ->setWherePart($whereSpec);
  281. $result = $this->sparqlQuery($query);
  282. if ($result) {
  283. return $result;
  284. }
  285. return 0;
  286. }
  287. /** @see Erfurt_Store_Sql_Interface */
  288. public function createTable($tableName, array $columns)
  289. {
  290. if ($this->_dbConn instanceof Zend_Db_Adapter_Mysqli) {
  291. return $this->_createTableMysql($tableName, $columns);
  292. }
  293. }
  294. /** @see Erfurt_Store_Adapter_Interface */
  295. public function createModel($graphUri, $type = Erfurt_Store::MODEL_TYPE_OWL)
  296. {
  297. $data = array(
  298. 'uri' => &$graphUri
  299. );
  300. $baseUri = $graphUri;
  301. if ($baseUri !== '') {
  302. $data['base'] = $baseUri;
  303. }
  304. // insert the new model into the database
  305. $this->_dbConn->insert('ef_graph', $data);
  306. $graphId = $this->lastInsertId();
  307. $uriRef = false;
  308. if (strlen($graphUri) > $this->_getSchemaRefThreshold()) {
  309. $uriHash = md5($uri);
  310. $uriData = array(
  311. 'g' => $graphid,
  312. 'v' => $uri,
  313. 'vh' => $uriHash);
  314. $uriRef = $this->_insertValueInto('ef_uri', $uriData);
  315. $updateData = array(
  316. 'uri' => $uriHash,
  317. 'uri_r' => $uriRef);
  318. $this->_dbConn->update('ef_graph', $updateData, "id = graphId");
  319. }
  320. $baseRef = false;
  321. if (strlen($baseUri) > $this->_getSchemaRefThreshold()) {
  322. $baseHash = md5($baseUri);
  323. $baseData = array(
  324. 'g' => $graphid,
  325. 'v' => $baseUri,
  326. 'vh' => $baseHash);
  327. $baseRef = $this->_insertValueInto('ef_uri', $baseData);
  328. $updateData = array(
  329. 'base' => $baseHash,
  330. 'base_r' => $baseRef);
  331. $this->_dbConn->update('ef_graph', $updateData, "id = graphId");
  332. }
  333. // invalidate the cache and fetch model infos again
  334. require_once 'Erfurt/App.php';
  335. $cache = Erfurt_App::getInstance()->getCache();
  336. $cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('model_info'));
  337. $this->_modelInfoCache = null;
  338. if ($type === Erfurt_Store::MODEL_TYPE_OWL) {
  339. $this->addStatement($graphUri, $graphUri, EF_RDF_TYPE, array('type' => 'uri', 'value' => EF_OWL_ONTOLOGY));
  340. $this->_modelInfoCache = null;
  341. }
  342. }
  343. /** @see Erfurt_Store_Adapter_Interface */
  344. public function deleteMatchingStatements($graphUri, $subject, $predicate, $object, array $options = array())
  345. {
  346. $modelInfoCache = $this->_getModelInfos();
  347. $modelId = $modelInfoCache[$graphUri]['modelId'];
  348. if ($subject !== null && strlen($subject) > $this->_getSchemaRefThreshold()) {
  349. $subject = substr($subject, 0, 128) . md5($subject);
  350. }
  351. if ($predicate !== null && strlen($predicate) > $this->_getSchemaRefThreshold()) {
  352. $predicate = substr($predicate, 0, 128) . md5($predicate);
  353. }
  354. if ($object !== null && strlen($object['value']) > $this->_getSchemaRefThreshold()) {
  355. $object = substr($object['value'], 0, 128) . md5($object['value']);
  356. }
  357. $operator = array('0' => '', '1' => 'AND');
  358. $firstparam = 0;
  359. // determine the rows, which should be deleted by the given parameters
  360. if ($subject !== null) {
  361. $whereString .= " $operator[$firstparam] s = '$subject'";
  362. $firstparam = 1;
  363. }
  364. if ($predicate !== null) {
  365. $whereString .= " $operator[$firstparam] p = '$predicate'";
  366. $firstparam = 1;
  367. }
  368. if (null !== $subject) {
  369. if (substr($subject, 0, 2) === '_:') {
  370. $whereString .= " $operator[$firstparam] st = 1";
  371. $firstparam = 1;
  372. } else {
  373. $whereString .= " $operator[$firstparam] st = 0";
  374. $firstparam = 1;
  375. }
  376. }
  377. if (null !== $object) {
  378. if (isset($object['value'])) {
  379. $whereString .= $operator[$firstparam]. 'o = \''.$object['value'].'\'';
  380. $firstparam = 1;
  381. }
  382. if (isset($object['type'])) {
  383. switch ($object['type']) {
  384. case 'uri':
  385. $whereString .= $operator[$firstparam].' ot = 0';
  386. $firstparam = 1;
  387. break;
  388. case 'literal':
  389. $whereString .= $operator[$firstparam].' ot = 2';
  390. $firstparam = 1;
  391. break;
  392. case 'bnode':
  393. $whereString .= $operator[$firstparam].' ot = 1';
  394. $firstparam = 1;
  395. break;
  396. }
  397. }
  398. if (isset($object['lang'])) {
  399. $whereString .= $operator[$firstparam].' ol = \''. $object['lang'] . '\'';
  400. $firstparam = 1;
  401. }
  402. if (isset($object['datatype'])) {
  403. if (strlen($object['datatype']) > $this->_getSchemaRefThreshold()) {
  404. $whereString .= $operator[$firstparam].' od = \'' . substr($object['datatype'], 0, 128) .
  405. md5($object['datatype']) . '\'';
  406. $firstparam = 1;
  407. } else {
  408. $whereString .= $operator[$firstparam].' od = \'' . $object['datatype'] . '\'';
  409. $firstparam = 1;
  410. }
  411. }
  412. }
  413. // remove the specified statements from the database
  414. $ret = $this->_dbConn->delete('ef_stmt', $whereString);
  415. // Clean up ef_uri and ef_lit table
  416. $this->_cleanUpValueTables($graphUri);
  417. // return number of affected rows (>0 means there were triples deleted)
  418. return $ret;
  419. }
  420. /** @see Erfurt_Store_Adapter_Interface */
  421. public function deleteMultipleStatements($graphUri, array $statementsArray)
  422. {
  423. $modelInfoCache = $this->_getModelInfos();
  424. $modelId = $modelInfoCache[$graphUri]['modelId'];
  425. $this->_dbConn->beginTransaction();
  426. try {
  427. foreach ($statementsArray as $subject => $predicatesArray) {
  428. foreach ($predicatesArray as $predicate => $objectsArray) {
  429. foreach ($objectsArray as $object) {
  430. $whereString = 'g = ' . $modelId . ' ';
  431. // check whether the subject is a blank node
  432. if (substr($subject, 0, 2) === '_:') {
  433. $subject = substr($subject, 2);
  434. $whereString .= 'AND st = 1 ';
  435. } else {
  436. $whereString .= 'AND st = 0 ';
  437. }
  438. // check the type of the object
  439. if ($object['type'] === 'uri') {
  440. $whereString .= 'AND ot = 0 ';
  441. } else if ($object['type'] === 'bnode') {
  442. $whereString .= 'AND ot = 1 ';
  443. } else {
  444. $whereString .= 'AND ot = 2 ';
  445. $whereString .= isset($object['lang']) ? 'AND ol = \'' . $object['lang'] . '\' ' : '';
  446. $whereString .= isset($object['datatype']) ? 'AND od = \'' . $object['datatype'] .
  447. '\' ' : '';
  448. }
  449. if (strlen((string)$subject) > $this->_getSchemaRefThreshold()) {
  450. $subjectHash = md5((string)$subject);
  451. $subject = substr((string)$subject, 0, 128) . $subjectHash;
  452. }
  453. if (strlen((string)$predicate) > $this->_getSchemaRefThreshold()) {
  454. $predicateHash = md5((string)$predicate);
  455. $predicate = substr((string)$predicate, 0, 128) . $predicateHash;
  456. }
  457. if (strlen((string)$object['value']) > $this->_getSchemaRefThreshold()) {
  458. $objectHash = md5((string)$object['value']);
  459. $object = substr((string)$object['value'], 0, 128) . $objectHash;
  460. } else {
  461. $object = $object['value'];
  462. }
  463. $whereString .= 'AND s = \'' . $subject . '\' ';
  464. $whereString .= 'AND p = \'' . $predicate . '\' ';
  465. $whereString .= 'AND o = \'' . str_replace('\'', '\\\'', $object) . '\' ';
  466. $this->_dbConn->delete('ef_stmt', $whereString);
  467. }
  468. }
  469. }
  470. // if everything went ok... commit the changes to the database
  471. $this->_dbConn->commit();
  472. $this->_cleanUpValueTables($graphUri);
  473. } catch (Exception $e) {
  474. // something went wrong... rollback
  475. $this->_dbConn->rollback();
  476. require_once 'Erfurt/Store/Adapter/Exception.php';
  477. throw new Erfurt_Store_Adapter_Exception('Bulk deletion of statements failed.'.$e->getMessage());
  478. }
  479. }
  480. /** @see Erfurt_Store_Adapter_Interface */
  481. public function deleteModel($graphUri)
  482. {
  483. $modelInfoCache = $this->_getModelInfos();
  484. if (isset($modelInfoCache[$graphUri]['modelId'])) {
  485. $graphId = $modelInfoCache[$graphUri]['modelId'];
  486. } else {
  487. require_once 'Erfurt/Store/Adapter/Exception.php';
  488. throw new Erfurt_Store_Adapter_Exception('Model deletion failed: No db id found for model URL.');
  489. }
  490. // remove all rows with the specified modelID from the models, statements and namespaces tables
  491. $this->_dbConn->delete('ef_graph', "id = $graphId");
  492. $this->_dbConn->delete('ef_stmt', "g = $graphId");
  493. $this->_dbConn->delete('ef_uri', "g = $graphId");
  494. $this->_dbConn->delete('ef_lit', "g = $graphId");
  495. // invalidate the cache and fetch model infos again
  496. require_once 'Erfurt/App.php';
  497. $cache = Erfurt_App::getInstance()->getCache();
  498. $tags = array('model_info', $modelInfoCache[$graphUri]['modelId']);
  499. #$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags);
  500. $this->_modelCache = array();
  501. $this->_modelInfoCache = null;
  502. }
  503. /** @see Erfurt_Store_Adapter_Interface */
  504. public function exportRdf($modelIri, $serializationType = 'xml', $filename = false)
  505. {
  506. require_once 'Erfurt/Store/Adapter/Exception.php';
  507. throw new Erfurt_Store_Adapter_Exception('Not implemented yet.');
  508. }
  509. /** @see Erfurt_Store_Adapter_Interface */
  510. public function getAvailableModels()
  511. {
  512. $modelInfoCache = $this->_getModelInfos();
  513. $models = array();
  514. foreach ($modelInfoCache as $mInfo) {
  515. $models[$mInfo['modelIri']] = true;
  516. }
  517. return $models;
  518. }
  519. public function getBackendName()
  520. {
  521. return 'ZendDb';
  522. }
  523. /** @see Erfurt_Store_Adapter_Interface */
  524. public function getBlankNodePrefix()
  525. {
  526. return 'bNode';
  527. }
  528. /**
  529. * Returns a list of graph uris, where each graph in the list contains at least
  530. * one statement where the given resource uri is subject.
  531. *
  532. * @param string $resourceUri
  533. * @return array
  534. */
  535. public function getGraphsUsingResource($resourceUri)
  536. {
  537. $sqlQuery = 'SELECT DISTINCT g.uri FROM ef_stmt s
  538. LEFT JOIN ef_graph g ON ( g.id = s.g)
  539. WHERE s.s = \'' . $resourceUri . '\'';
  540. $sqlResult = $this->sqlQuery($sqlQuery);
  541. $result = array();
  542. foreach ($sqlResult as $row) {
  543. $result[] = $row['uri'];
  544. }
  545. return $result;
  546. }
  547. /**
  548. * Recursively gets owl:imported model IRIs starting with $modelIri as root.
  549. *
  550. * @param string $modelIri
  551. */
  552. public function getImportsClosure($modelIri)
  553. {
  554. $modelInfoCache = $this->_getModelInfos();
  555. if (isset($modelInfoCache["$modelIri"]['imports'])) {
  556. return $modelInfoCache["$modelIri"]['imports'];
  557. } else {
  558. return array();
  559. }
  560. }
  561. /** @see Erfurt_Store_Adapter_Interface */
  562. public function getModel($modelIri)
  563. {
  564. // if model is already in cache return the cached value
  565. if (isset($this->_modelCache[$modelIri])) {
  566. return $this->_modelCache[$modelIri];
  567. }
  568. $modelInfoCache = $this->_getModelInfos();
  569. $baseUri = $modelInfoCache[$modelIri]['baseIri'];
  570. if ($baseUri === '') {
  571. $baseUri = null;
  572. }
  573. // choose the right type for the model instance and instanciate it
  574. if ($modelInfoCache[$modelIri]['type'] === 'owl') {
  575. require_once 'Erfurt/Owl/Model.php';
  576. $m = new Erfurt_Owl_Model($modelIri, $baseUri);
  577. } else if ($this->_modelInfoCache[$modelIri]['type'] === 'rdfs') {
  578. require_once 'Erfurt/Rdfs/Model.php';
  579. $m = new Erfurt_Rdfs_Model($modelIri, $baseUri);
  580. } else {
  581. require_once 'Erfurt/Rdf/Model.php';
  582. $m = new Erfurt_Rdf_Model($modelIri, $baseUri);
  583. }
  584. $this->_modelCache[$modelIri] = $m;
  585. return $m;
  586. }
  587. /** @see Erfurt_Store_Adapter_Interface */
  588. public function getNewModel($graphUri, $baseUri = '', $type = 'owl')
  589. {
  590. $data = array(
  591. 'uri' => &$graphUri
  592. );
  593. if ($baseUri !== '') {
  594. $data['base'] = $baseUri;
  595. }
  596. // insert the new model into the database
  597. $this->_dbConn->insert('ef_graph', $data);
  598. $graphId = $this->lastInsertId();
  599. $uriRef = false;
  600. if (strlen($graphUri) > $this->_getSchemaRefThreshold()) {
  601. $uriHash = md5($uri);
  602. $uriData = array(
  603. 'g' => $graphid,
  604. 'v' => $uri,
  605. 'vh' => $uriHash);
  606. $uriRef = $this->_insertValueInto('ef_uri', $uriData);
  607. $updateData = array(
  608. 'uri' => $uriHash,
  609. 'uri_r' => $uriRef);
  610. $this->_dbConn->update('ef_graph', $updateData, "id = graphId");
  611. }
  612. $baseRef = false;
  613. if (strlen($baseUri) > $this->_getSchemaRefThreshold()) {
  614. $baseHash = md5($baseUri);
  615. $baseData = array(
  616. 'g' => $graphid,
  617. 'v' => $baseUri,
  618. 'vh' => $baseHash);
  619. $baseRef = $this->_insertValueInto('ef_uri', $baseData);
  620. $updateData = array(
  621. 'base' => $baseHash,
  622. 'base_r' => $baseRef);
  623. $this->_dbConn->update('ef_graph', $updateData, "id = graphId");
  624. }
  625. // invalidate the cache and fetch model infos again
  626. require_once 'Erfurt/App.php';
  627. $cache = Erfurt_App::getInstance()->getCache();
  628. $cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('model_info'));
  629. $this->_modelInfoCache = null;
  630. if ($type === 'owl') {
  631. $this->addStatement($graphUri, $graphUri, EF_RDF_TYPE, array('type' => 'uri', 'value' => EF_OWL_ONTOLOGY));
  632. $this->_modelInfoCache = null;
  633. }
  634. // instanciate the model
  635. $m = $this->getModel($graphUri);
  636. return $m;
  637. }
  638. /** @see Erfurt_Store_Adapter_Interface */
  639. public function getSupportedExportFormats()
  640. {
  641. return array();
  642. }
  643. /** @see Erfurt_Store_Adapter_Interface */
  644. public function getSupportedImportFormats()
  645. {
  646. return array();
  647. }
  648. /** @see Erfurt_Store_Adapter_Interface */
  649. public function importRdf($modelUri, $data, $type, $locator)
  650. {
  651. // TODO fix or remove
  652. if ($this->_dbConn instanceof Zend_Db_Adapter_Mysqli) {
  653. require_once 'Erfurt/Syntax/RdfParser.php';
  654. $parser = Erfurt_Syntax_RdfParser::rdfParserWithFormat($type);
  655. $parsedArray = $parser->parse($data, $locator, $modelUri, false);
  656. $modelInfoCache = $this->_getModelInfos();
  657. $modelId = $modelInfoCache["$modelUri"]['modelId'];
  658. // create file
  659. $tmpDir = Erfurt_App::getInstance()->getTmpDir();
  660. $filename = $tmpDir . 'import' . md5((string)time()) . '.csv';
  661. $fileHandle = fopen($filename, 'w');
  662. $count = 0;
  663. $longStatements = array();
  664. foreach ($parsedArray as $s => $pArray) {
  665. if (substr($s, 0, 2) === '_:') {
  666. $s = substr($s, 2);
  667. $sType = '1';
  668. } else {
  669. $sType = '0';
  670. }
  671. foreach ($pArray as $p => $oArray) {
  672. foreach ($oArray as $o) {
  673. // to long values need to be put in a different table, so we can't bulk insert these
  674. // values, for they need a foreign key
  675. if (strlen($s) > $this->_getSchemaRefThreshold() ||
  676. strlen($p) > $this->_getSchemaRefThreshold() ||
  677. strlen($o['value']) > $this->_getSchemaRefThreshold() ||
  678. (isset($o['datatype']) && strlen($o['datatype']) > $this->_getSchemaRefThreshold())) {
  679. $longStatements[] = array(
  680. 's' => $s,
  681. 'p' => $p,
  682. 'o' => $o
  683. );
  684. continue;
  685. }
  686. if ($o['type'] === 'literal') {
  687. $oType = '2';
  688. } else if ($o['type'] === 'bnode') {
  689. if (substr($o['value'], 0, 2) === '_:') {
  690. $o['value'] = substr($o['value'], 2);
  691. }
  692. $oType = '1';
  693. } else {
  694. $oType = '0';
  695. }
  696. $lineString = $modelId . ';' . $s . ';' . $p . ';' . $o['value'] . ';';
  697. $lineString .= "\N;\N;\N;";
  698. $lineString .= $sType . ';' . $oType . ';';
  699. if (isset($o['lang'])) {
  700. $lineString .= $o['lang'];
  701. } else {
  702. $lineString .= "\N";
  703. }
  704. $lineString .= ';';
  705. if (isset($o['datatype'])) {
  706. $lineString .= $o['datatype'] . ";\N";
  707. } else {
  708. $lineString .= "\N;\N";
  709. }
  710. $lineString .= PHP_EOL;
  711. $count++;
  712. fputs($fileHandle, $lineString);
  713. }
  714. }
  715. }
  716. fclose($fileHandle);
  717. if ($count > 10000) {
  718. $this->_dbConn->getConnection()->query('ALTER TABLE ef_stmt DISABLE KEYS');
  719. }
  720. $sql = "LOAD DATA INFILE '$filename' IGNORE INTO TABLE ef_stmt
  721. FIELDS TERMINATED BY ';'
  722. (g, s, p, o, s_r, p_r, o_r, st, ot, ol, od, od_r);";
  723. $this->_dbConn->getConnection()->query('START TRANSACTION;');
  724. $this->_dbConn->getConnection()->query($sql);
  725. $this->_dbConn->getConnection()->query('COMMIT');
  726. // Delete the temp file
  727. unlink($filename);
  728. // Now add the long-value-statements
  729. foreach($longStatements as $stm) {
  730. $sId = false;
  731. $pId = false;
  732. $oId = false;
  733. $dtId = false;
  734. $s = $stm['s'];
  735. $p = $stm['p'];
  736. $o = $stm['o']['value'];
  737. if (strlen($s) > $this->_getSchemaRefThreshold()) {
  738. $sHash = md5($s);
  739. $sId = $this->_insertValueInto('ef_uri', $modelId, $s, $sHash);
  740. $s = substr($s, 0, 128) . $sHash;
  741. }
  742. if (strlen($p) > $this->_getSchemaRefThreshold()) {
  743. $pHash = md5($p);
  744. $pId = $this->_insertValueInto('ef_uri', $modelId, $p, $pHash);
  745. $p = substr($p, 0, 128) . $pHash;
  746. }
  747. if (strlen($o) > $this->_getSchemaRefThreshold()) {
  748. $oHash = md5($o);
  749. if ($stm['o']['type'] === 'literal') {
  750. $oId = $this->_insertValueInto('ef_lit', $modelId, $o, $oHash);
  751. } else {
  752. $oId = $this->_insertValueInto('ef_uri', $modelId, $o, $oHash);
  753. }
  754. $o = substr($o, 0, 128) . $oHash;
  755. }
  756. if (isset($stm['o']['datatype']) && strlen($stm['o']['datatype']) > $this->_getSchemaRefThreshold()) {
  757. $oDtHash = md5($stm['o']['datatype']);
  758. $dtId = $this->_insertValueInto('ef_uri', $modelId, $stm['o']['datatype'], $oDtHash);
  759. $oDt = substr($oDt, 0, 128) . $oDtHash;
  760. }
  761. $sql = "INSERT INTO ef_stmt
  762. (g,s,p,o,s_r,p_r,o_r,st,ot,ol,od,od_r)
  763. VALUES ($modelId,'$s','$p','$o',";
  764. if ($sId !== false) {
  765. $sql .= $sId . ',';
  766. } else {
  767. $sql .= "NULL,";
  768. }
  769. if ($pId !== false) {
  770. $sql .= $pId . ',';
  771. } else {
  772. $sql .= "NULL,";
  773. }
  774. if ($oId !== false) {
  775. $sql .= $oId . ',';
  776. } else {
  777. $sql .= "NULL,";
  778. }
  779. if (substr($stm['s'], 0, 2) === '_:') {
  780. $sql .= '1,';
  781. } else {
  782. $sql .= '0,';
  783. }
  784. if ($stm['o']['type'] === 'literal') {
  785. $sql .= '2,';
  786. } else if ($stm['o']['type'] === 'uri') {
  787. $sql .= '0,';
  788. } else {
  789. $sql .= '1,';
  790. }
  791. if (isset($stm['o']['lang'])) {
  792. $sql .= '"' . $stm['o']['lang'] . '",';
  793. } else {
  794. $sql .= "NULL,";
  795. }
  796. if (isset($stm['o']['datatype'])) {
  797. if ($dtId !== false) {
  798. $sql .= '"' . $oDt . '",' . $dtId . ')';
  799. } else {
  800. $sql .= '"' . $stm['o']['datatype'] . '",' . "\N)";
  801. }
  802. } else {
  803. $sql .= "NULL,NULL)";
  804. }
  805. //$this->_dbConn->getConnection()->query($sql);
  806. }
  807. if ($count > 10000) {
  808. $this->_dbConn->getConnection()->query('ALTER TABLE ef_stmt ENABLE KEYS');
  809. }
  810. $this->_optimizeTables();
  811. } else {
  812. require_once 'Erfurt/Store/Adapter/Exception.php';
  813. throw new Erfurt_Store_Adapter_Exception('CSV import not supported for this database server.');
  814. }
  815. }
  816. public function init()
  817. {
  818. $this->_modelInfoCache = null;
  819. }
  820. /** @see Erfurt_Store_Adapter_Interface */
  821. public function isModelAvailable($modelIri)
  822. {
  823. $modelInfoCache = $this->_getModelInfos();
  824. if (isset($modelInfoCache[$modelIri])) {
  825. return true;
  826. } else {
  827. return false;
  828. }
  829. }
  830. /** @see Erfurt_Store_Sql_Interface */
  831. public function lastInsertId()
  832. {
  833. return $this->_dbConn->lastInsertId();
  834. }
  835. /** @see Erfurt_Store_Sql_Interface */
  836. public function listTables($prefix = '')
  837. {
  838. return $this->_dbConn->listTables();
  839. }
  840. /** @see Erfurt_Store_Adapter_Interface */
  841. public function sparqlAsk($query)
  842. {
  843. //TODO works for me...., why hasnt this be enabled earlier? is the same as sparqlQuery... looks like the engine supports it. but there is probably a reason for this not to be supported
  844. $start = microtime(true);
  845. require_once 'Erfurt/Sparql/EngineDb/Adapter/EfZendDb.php';
  846. $engine = new Erfurt_Sparql_EngineDb_Adapter_EfZendDb($this->_dbConn, $this->_getModelInfos());
  847. require_once 'Erfurt/Sparql/Parser.php';
  848. $parser = new Erfurt_Sparql_Parser();
  849. if(!($query instanceof Erfurt_Sparql_Query))
  850. $query = $parser->parse((string)$query);
  851. $result = $engine->queryModel($query);
  852. // Debug executed SPARQL queries in debug mode (7)
  853. $logger = Erfurt_App::getInstance()->getLog();
  854. $time = (microtime(true) - $start)*1000;
  855. $debugText = 'SPARQL Query (' . $time . ' ms)';
  856. $logger->debug($debugText);
  857. return $result;
  858. }
  859. /** @see Erfurt_Store_Adapter_Interface */
  860. public function sparqlQuery($query, $options=array())
  861. {
  862. $resultform =(isset($options[STORE_RESULTFORMAT]))?$options[STORE_RESULTFORMAT]:STORE_RESULTFORMAT_PLAIN;
  863. $start = microtime(true);
  864. require_once 'Erfurt/Sparql/EngineDb/Adapter/EfZendDb.php';
  865. $engine = new Erfurt_Sparql_EngineDb_Adapter_EfZendDb($this->_dbConn, $this->_getModelInfos());
  866. require_once 'Erfurt/Sparql/Parser.php';
  867. $parser = new Erfurt_Sparql_Parser();
  868. if(!($query instanceof Erfurt_Sparql_Query)) {
  869. $query = $parser->parse((string)$query);
  870. }
  871. $result = $engine->queryModel($query, $resultform);
  872. // Debug executed SPARQL queries in debug mode (7)
  873. $logger = Erfurt_App::getInstance()->getLog();
  874. $time = (microtime(true) - $start)*1000;
  875. $debugText = 'SPARQL Query (' . $time . ' ms)';
  876. $logger->debug($debugText);
  877. return $result;
  878. }
  879. /** @see Erfurt_Store_Sql_Interface */
  880. public function sqlQuery($sqlQuery, $limit = PHP_INT_MAX, $offset = 0)
  881. {
  882. $start = microtime(true);
  883. // add limit/offset
  884. if ($limit < PHP_INT_MAX) {
  885. $sqlQuery = sprintf('%s LIMIT %d OFFSET %d', (string)$sqlQuery, (int)$limit, (int)$offset);
  886. }
  887. $queryType = strtolower(substr($sqlQuery, 0, 6));
  888. if ( $queryType === 'insert' ||
  889. $queryType === 'update' ||
  890. $queryType === 'create' ||
  891. $queryType === 'if not' ||
  892. $queryType === 'delete') {
  893. // Handle without ZendDb
  894. $result = $this->_dbConn->query($sqlQuery);
  895. //SQLSRVCHANGE - Hack - result kommt immer falsch zurück - Queries werden aber ausgeführt....?
  896. if($result != NULL)
  897. {
  898. $result = true;
  899. }
  900. if ($result !== true) {
  901. require_once 'Erfurt/Store/Adapter/Exception.php';
  902. throw new Erfurt_Store_Adapter_Exception(/*var_dump($result).'<br>'.$sqlQuery.'<br>*/'SQL query failed: ' .
  903. $this->_dbConn->getConnection()->error);
  904. }
  905. } else {
  906. try {
  907. $result = $this->_dbConn->fetchAll($sqlQuery);
  908. //SQLSRV - Result ist immer true und es kommt keine Exception...
  909. } catch (Zend_Db_Exception $e) { #return false;
  910. require_once 'Erfurt/Store/Adapter/Exception.php';
  911. throw new Erfurt_Store_Adapter_Exception($e->getMessage());
  912. }
  913. }
  914. // Debug executed SQL queries in debug mode (7)
  915. $logger = Erfurt_App::getInstance()->getLog();
  916. $time = (microtime(true) - $start)*1000;
  917. $debugText = 'SQL Query (' . $time . ' ms)';
  918. $logger->debug($debugText);
  919. return $result;
  920. }
  921. // ------------------------------------------------------------------------
  922. // --- Private methods ----------------------------------------------------
  923. // ------------------------------------------------------------------------
  924. /**
  925. * @throws Erfurt_Exception Throws exception if something goes wrong while initialization of database.
  926. */
  927. private function _createTables()
  928. {
  929. return $this->_createTablesSqlsrv();
  930. }
  931. /**
  932. * This internal function creates the table structure for MS SQL Server databases.
  933. */
  934. private function _createTablesSqlsrv()
  935. {
  936. //#####################################################################
  937. // Create table ef_info if not existing
  938. $sqlsrv ='IF NOT EXISTS
  939. ( SELECT * FROM SysObjects WHERE [Name] = \'ef_info\')
  940. CREATE TABLE ef_info (
  941. id TINYINT NOT NULL IDENTITY(1,1),
  942. schema_id VARCHAR(10) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL
  943. ) ON [PRIMARY]';
  944. $success = $this->_dbConn->query($sqlsrv);
  945. if (!$success) {
  946. require_once 'Erfurt/Store/Adapter/Exception.php';
  947. throw new Erfurt_Store_Adapter_Exception('Creation of table "ef_info" failed: ' .
  948. $this->_dbConn->getConnection()->error);
  949. }
  950. // Insert id of the current schema into the ef_info table.
  951. $sql = 'INSERT INTO ef_info (schema_id) VALUES (1.0)';
  952. $success = false;
  953. $success = $this->_dbConn->query($sql);
  954. if (!$success) {
  955. require_once 'Erfurt/Store/Adapter/Exception.php';
  956. throw new Erfurt_Store_Adapter_Exception('Insertion of "schema_id" into "ef_info" failed: ' .
  957. $this->_dbConn->getConnection()->error);
  958. }
  959. //#####################################################################
  960. // Create table ef_graph if not existing
  961. $sqlsrv ='IF NOT EXISTS
  962. ( SELECT * FROM SysObjects WHERE [Name] = \'ef_graph\')
  963. BEGIN
  964. CREATE TABLE ef_graph (
  965. id TINYINT NOT NULL IDENTITY(1,1),
  966. uri VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  967. uri_r INT NULL,
  968. base VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  969. base_r INT NULL
  970. ) ON [PRIMARY]
  971. CREATE UNIQUE INDEX unique_uri ON ef_graph (uri)
  972. END';
  973. $success = $this->_dbConn->query($sqlsrv);
  974. if (!$success) {
  975. require_once 'Erfurt/Store/Adapter/Exception.php';
  976. throw new Erfurt_Store_Adapter_Exception('Creation of table "ef_info" failed: ' .
  977. $this->_dbConn->getConnection()->error);
  978. }
  979. //#####################################################################
  980. // Create table ef_stmt if not existing
  981. $sqlsrv ='IF NOT EXISTS
  982. ( SELECT * FROM SysObjects WHERE [Name] = \'ef_stmt\')
  983. BEGIN
  984. CREATE TABLE ef_stmt (
  985. id TINYINT NOT NULL IDENTITY(1,1),
  986. g INT NOT NULL,
  987. s VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  988. p VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  989. o VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  990. s_r INT DEFAULT NULL,
  991. p_r INT DEFAULT NULL,
  992. o_r INT DEFAULT NULL,
  993. st TINYINT NOT NULL,
  994. ot TINYINT NOT NULL,
  995. ol VARCHAR(50)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  996. od VARCHAR(160)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  997. od_r INT DEFAULT NULL,
  998. ) ON [PRIMARY]
  999. CREATE UNIQUE NONCLUSTERED INDEX unique_stmt ON ef_stmt (g,s,p,o,st,ot,ol,od)
  1000. CREATE NONCLUSTERED INDEX idx_g_p_o_ot ON ef_stmt (g, p, o, ot)
  1001. CREATE NONCLUSTERED INDEX idx_g_o_ot ON ef_stmt (g, o, ot)
  1002. END';
  1003. $success = $this->_dbConn->query($sqlsrv);
  1004. if (!$success) {
  1005. require_once 'Erfurt/Store/Adapter/Exception.php';
  1006. throw new Erfurt_Store_Adapter_Exception('Creation of table "ef_info" failed: ' .
  1007. $this->_dbConn->getConnection()->error);
  1008. }
  1009. //#####################################################################
  1010. // Create table ef_uri if not existing
  1011. $sqlsrv ='IF NOT EXISTS
  1012. ( SELECT * FROM SysObjects WHERE [Name] = \'ef_uri\')
  1013. BEGIN
  1014. CREATE TABLE ef_uri (
  1015. id TINYINT NOT NULL IDENTITY(1,1),
  1016. g INT NOT NULL,
  1017. v TEXT COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  1018. vh VARCHAR(32)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL
  1019. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  1020. CREATE UNIQUE NONCLUSTERED INDEX unique_uri ON ef_uri (g,vh)
  1021. END';
  1022. $success = $this->_dbConn->query($sqlsrv);
  1023. if (!$success) {
  1024. require_once 'Erfurt/Store/Adapter/Exception.php';
  1025. throw new Erfurt_Store_Adapter_Exception('Creation of table "ef_uri" failed: ' .
  1026. $this->_dbConn->getConnection()->error);
  1027. }
  1028. //#####################################################################
  1029. // Create table ef_lit if not existing
  1030. //v would b UTF8 - not shure if SQL_Latin1_general_CP850_bin is the right type
  1031. $sqlsrv ='IF NOT EXISTS
  1032. ( SELECT * FROM SysObjects WHERE [Name] = \'ef_lit\')
  1033. BEGIN
  1034. CREATE TABLE ef_lit (
  1035. id TINYINT NOT NULL IDENTITY(1,1),
  1036. g INT NOT NULL,
  1037. v TEXT COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
  1038. vh VARCHAR(32)COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL
  1039. ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
  1040. CREATE UNIQUE NONCLUSTERED INDEX unique_lit ON ef_lit (g,vh)
  1041. END';
  1042. $success = $this->_dbConn->query($sqlsrv);
  1043. if (!$success) {
  1044. require_once 'Erfurt/Store/Adapter/Exception.php';
  1045. throw new Erfurt_Store_Adapter_Exception('Creation of table "ef_uri" failed: ' .
  1046. $this->_dbConn->getConnection()->error);
  1047. }
  1048. }
  1049. protected function _getModelInfos()
  1050. {
  1051. if (null === $this->_modelInfoCache) {
  1052. try {
  1053. // try to fetch model and namespace infos... if all tables are present this should not lead to an error.
  1054. $this->_fetchModelInfos();
  1055. } catch (Erfurt_Exception $e) {
  1056. // error while fetching model and namespace infos... should only be the case if the tables aren't present,
  1057. // for db connection is already established (in constructor)... so let's check for tables
  1058. if (!$this->_isSetup()) {
  1059. $this->_createTables();
  1060. try {
  1061. Erfurt_App::getInstance()->getStore()->checkSetup();

Large files files are truncated, but you can click here to view the full file