PageRenderTime 70ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/Erfurt/Store/Adapter/EfZendDb.php

https://bitbucket.org/udfr/udfr-erfurt
PHP | 1797 lines | 1259 code | 308 blank | 230 comment | 184 complexity | def6d01e02f3770a7ba9b6cb938151dd MD5 | raw file

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

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

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