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

/classes/db/DBSqlite3_pdo.class.php

http://xe-core.googlecode.com/
PHP | 636 lines | 433 code | 84 blank | 119 comment | 89 complexity | f4961c66ec6c39611e7d3e4f118290fb MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * @class DBSqlite3_pdo
  4. * @author NHN (developers@xpressengine.com)
  5. * @brief class to use SQLite3 with PDO
  6. * @version 0.1
  7. **/
  8. class DBSqlite3_pdo extends DB {
  9. /**
  10. * DB information
  11. **/
  12. var $database = NULL; ///< database
  13. var $prefix = 'xe'; // /< prefix of a tablename (many XEs can be installed in a single DB)
  14. var $comment_syntax = '/* %s */';
  15. /**
  16. * Variables for using PDO
  17. **/
  18. var $handler = NULL;
  19. var $stmt = NULL;
  20. var $bind_idx = 0;
  21. var $bind_vars = array();
  22. /**
  23. * @brief column type used in sqlite3
  24. *
  25. * column_type should be replaced for each DBMS properly
  26. * because column_type uses a commonly defined type in schema/query xml files
  27. **/
  28. var $column_type = array(
  29. 'bignumber' => 'INTEGER',
  30. 'number' => 'INTEGER',
  31. 'varchar' => 'VARCHAR',
  32. 'char' => 'CHAR',
  33. 'text' => 'TEXT',
  34. 'bigtext' => 'TEXT',
  35. 'date' => 'VARCHAR(14)',
  36. 'float' => 'REAL',
  37. );
  38. /**
  39. * @brief constructor
  40. **/
  41. function DBSqlite3_pdo() {
  42. $this->_setDBInfo();
  43. $this->_connect();
  44. }
  45. /**
  46. * @brief create an instance of this class
  47. */
  48. function create()
  49. {
  50. return new DBSqlite3_pdo;
  51. }
  52. /**
  53. * @brief Return if installable
  54. **/
  55. function isSupported() {
  56. return class_exists('PDO');
  57. }
  58. function isConnected() {
  59. return $this->is_connected;
  60. }
  61. /**
  62. * @brief DB settings and connect/close
  63. **/
  64. function _setDBInfo() {
  65. $db_info = Context::getDBInfo();
  66. $this->database = $db_info->master_db["db_database"];
  67. $this->prefix = $db_info->master_db["db_table_prefix"];
  68. //if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
  69. }
  70. /**
  71. * @brief DB Connection
  72. **/
  73. function _connect() {
  74. // override if db information not exists
  75. if(!$this->database) return;
  76. // Attempt to access the database file
  77. try {
  78. // PDO is only supported with PHP5,
  79. // so it is allowed to use try~catch statment in this class.
  80. $this->handler = new PDO('sqlite:'.$this->database);
  81. } catch (PDOException $e) {
  82. $this->setError(-1, 'Connection failed: '.$e->getMessage());
  83. $this->is_connected = false;
  84. return;
  85. }
  86. // Check connections
  87. $this->is_connected = true;
  88. $this->password = md5($this->password);
  89. }
  90. /**
  91. * @brief disconnect to DB
  92. **/
  93. function close() {
  94. if(!$this->is_connected) return;
  95. $this->commit();
  96. }
  97. /**
  98. * @brief Begin a transaction
  99. **/
  100. function begin() {
  101. if(!$this->is_connected || $this->transaction_started) return;
  102. if($this->handler->beginTransaction()) $this->transaction_started = true;
  103. }
  104. /**
  105. * @brief Rollback
  106. **/
  107. function rollback() {
  108. if(!$this->is_connected || !$this->transaction_started) return;
  109. $this->handler->rollBack();
  110. $this->transaction_started = false;
  111. }
  112. /**
  113. * @brief Commit
  114. **/
  115. function commit($force = false) {
  116. if(!$force && (!$this->is_connected || !$this->transaction_started)) return;
  117. try {
  118. $this->handler->commit();
  119. }
  120. catch(PDOException $e){
  121. // There was no transaction started, so just continue.
  122. error_log($e->getMessage());
  123. }
  124. $this->transaction_started = false;
  125. }
  126. /**
  127. * @brief Add or change quotes to the query string variables
  128. **/
  129. function addQuotes($string) {
  130. if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
  131. if(!is_numeric($string)) $string = str_replace("'","''",$string);
  132. return $string;
  133. }
  134. /**
  135. * @brief : Prepare a query statement
  136. **/
  137. function _prepare($query) {
  138. if(!$this->is_connected) return;
  139. // notify to start a query execution
  140. $this->actStart($query);
  141. $this->stmt = $this->handler->prepare($query);
  142. if($this->handler->errorCode() != '00000') {
  143. $this->setError($this->handler->errorCode(), print_r($this->handler->errorInfo(),true));
  144. $this->actFinish();
  145. }
  146. $this->bind_idx = 0;
  147. $this->bind_vars = array();
  148. }
  149. /**
  150. * @brief : Binding params in stmt
  151. **/
  152. function _bind($val) {
  153. if(!$this->is_connected || !$this->stmt) return;
  154. $this->bind_idx ++;
  155. $this->bind_vars[] = $val;
  156. $this->stmt->bindParam($this->bind_idx, $val);
  157. }
  158. /**
  159. * @brief : execute the prepared statement
  160. **/
  161. function _execute() {
  162. if(!$this->is_connected || !$this->stmt) return;
  163. $this->stmt->execute();
  164. if($this->stmt->errorCode() === '00000') {
  165. $output = null;
  166. while($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
  167. unset($obj);
  168. foreach($tmp as $key => $val) {
  169. $pos = strpos($key, '.');
  170. if($pos) $key = substr($key, $pos+1);
  171. $obj->{$key} = str_replace("''","'",$val);
  172. }
  173. $output[] = $obj;
  174. }
  175. } else {
  176. $this->setError($this->stmt->errorCode(),print_r($this->stmt->errorInfo(),true));
  177. }
  178. $this->stmt = null;
  179. $this->actFinish();
  180. if(is_array($output) && count($output)==1) return $output[0];
  181. return $output;
  182. }
  183. /**
  184. * @brief Return the sequence value incremented by 1
  185. **/
  186. function getNextSequence() {
  187. $query = sprintf("insert into %ssequence (seq) values (NULL)", $this->prefix);
  188. $this->_prepare($query);
  189. $result = $this->_execute();
  190. $sequence = $this->handler->lastInsertId();
  191. if($sequence % 10000 == 0) {
  192. $query = sprintf("delete from %ssequence where seq < %d", $this->prefix, $sequence);
  193. $this->_prepare($query);
  194. $result = $this->_execute();
  195. }
  196. return $sequence;
  197. }
  198. /**
  199. * @brief return if the table already exists
  200. **/
  201. function isTableExists($target_name) {
  202. $query = sprintf('pragma table_info(%s%s)', $this->prefix, $target_name);
  203. $this->_prepare($query);
  204. if(!$this->_execute()) return false;
  205. return true;
  206. }
  207. /**
  208. * @brief Add a column to a table
  209. **/
  210. function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
  211. $type = $this->column_type[$type];
  212. if(strtoupper($type)=='INTEGER') $size = '';
  213. $query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name);
  214. if($size) $query .= sprintf(" %s(%s) ", $type, $size);
  215. else $query .= sprintf(" %s ", $type);
  216. if($default) $query .= sprintf(" default '%s' ", $default);
  217. if($notnull) $query .= " not null ";
  218. $this->_prepare($query);
  219. return $this->_execute();
  220. }
  221. /**
  222. * @brief Remove a column from a table
  223. **/
  224. function dropColumn($table_name, $column_name) {
  225. $query = sprintf("alter table %s%s drop column %s ", $this->prefix, $table_name, $column_name);
  226. $this->_query($query);
  227. }
  228. /**
  229. * @brief Return column information of a table
  230. **/
  231. function isColumnExists($table_name, $column_name) {
  232. $query = sprintf("pragma table_info(%s%s)", $this->prefix, $table_name);
  233. $this->_prepare($query);
  234. $output = $this->_execute();
  235. if($output) {
  236. $column_name = strtolower($column_name);
  237. foreach($output as $key => $val) {
  238. $name = strtolower($val->name);
  239. if($column_name == $name) return true;
  240. }
  241. }
  242. return false;
  243. }
  244. /**
  245. * @brief Add an index to a table
  246. * $target_columns = array(col1, col2)
  247. * $is_unique? unique : none
  248. **/
  249. function addIndex($table_name, $index_name, $target_columns, $is_unique = false) {
  250. if(!is_array($target_columns)) $target_columns = array($target_columns);
  251. $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name);
  252. $query = sprintf('CREATE %s INDEX %s ON %s%s (%s)', $is_unique?'UNIQUE':'', $key_name, $this->prefix, $table_name, implode(',',$target_columns));
  253. $this->_prepare($query);
  254. $this->_execute();
  255. }
  256. /**
  257. * @brief Drop an index from a table
  258. **/
  259. function dropIndex($table_name, $index_name, $is_unique = false) {
  260. $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name);
  261. $query = sprintf("DROP INDEX %s", $this->prefix, $table_name, $key_name);
  262. $this->_query($query);
  263. }
  264. /**
  265. * @brief Return index information of a table
  266. **/
  267. function isIndexExists($table_name, $index_name) {
  268. $key_name = sprintf('%s%s_%s', $this->prefix, $table_name, $index_name);
  269. $query = sprintf("pragma index_info(%s)", $key_name);
  270. $this->_prepare($query);
  271. $output = $this->_execute();
  272. if(!$output) return false;
  273. return true;
  274. }
  275. /**
  276. * @brief create a table from xml file
  277. **/
  278. function createTableByXml($xml_doc) {
  279. return $this->_createTable($xml_doc);
  280. }
  281. /**
  282. * @brief create a table from xml file
  283. **/
  284. function createTableByXmlFile($file_name) {
  285. if(!file_exists($file_name)) return;
  286. // read xml file
  287. $buff = FileHandler::readFile($file_name);
  288. return $this->_createTable($buff);
  289. }
  290. /**
  291. * @brief generate a query to create a table using the schema xml
  292. *
  293. * type : number, varchar, text, char, date, \n
  294. * opt : notnull, default, size\n
  295. * index : primary key, index, unique\n
  296. **/
  297. function _createTable($xml_doc) {
  298. // xml parsing
  299. $oXml = new XmlParser();
  300. $xml_obj = $oXml->parse($xml_doc);
  301. // Create a table schema
  302. $table_name = $xml_obj->table->attrs->name;
  303. if($this->isTableExists($table_name)) return;
  304. $table_name = $this->prefix.$table_name;
  305. if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
  306. else $columns = $xml_obj->table->column;
  307. foreach($columns as $column) {
  308. $name = $column->attrs->name;
  309. $type = $column->attrs->type;
  310. if(strtoupper($this->column_type[$type])=='INTEGER') $size = '';
  311. else $size = $column->attrs->size;
  312. $notnull = $column->attrs->notnull;
  313. $primary_key = $column->attrs->primary_key;
  314. $index = $column->attrs->index;
  315. $unique = $column->attrs->unique;
  316. $default = $column->attrs->default;
  317. $auto_increment = $column->attrs->auto_increment;
  318. if($auto_increment) {
  319. $column_schema[] = sprintf('%s %s PRIMARY KEY %s',
  320. $name,
  321. $this->column_type[$type],
  322. $auto_increment?'AUTOINCREMENT':''
  323. );
  324. } else {
  325. $column_schema[] = sprintf('%s %s%s %s %s %s',
  326. $name,
  327. $this->column_type[$type],
  328. $size?'('.$size.')':'',
  329. $notnull?'NOT NULL':'',
  330. $primary_key?'PRIMARY KEY':'',
  331. isset($default)?"DEFAULT '".$default."'":''
  332. );
  333. }
  334. if($unique) $unique_list[$unique][] = $name;
  335. else if($index) $index_list[$index][] = $name;
  336. }
  337. $schema = sprintf('CREATE TABLE %s (%s%s) ;', $table_name," ", implode($column_schema,", "));
  338. $this->_prepare($schema);
  339. $this->_execute();
  340. if($this->isError()) return;
  341. if(count($unique_list)) {
  342. foreach($unique_list as $key => $val) {
  343. $query = sprintf('CREATE UNIQUE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
  344. $this->_prepare($query);
  345. $this->_execute();
  346. if($this->isError()) $this->rollback();
  347. }
  348. }
  349. if(count($index_list)) {
  350. foreach($index_list as $key => $val) {
  351. $query = sprintf('CREATE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
  352. $this->_prepare($query);
  353. $this->_execute();
  354. if($this->isError()) $this->rollback();
  355. }
  356. }
  357. }
  358. function _getConnection($type = null){
  359. return null;
  360. }
  361. /**
  362. * @brief insertAct
  363. * */
  364. function _executeInsertAct($queryObject) {
  365. $query = $this->getInsertSql($queryObject);
  366. if (is_a($query, 'Object'))
  367. return;
  368. $this->_prepare($query);
  369. $val_count = count($val_list);
  370. for ($i = 0; $i < $val_count; $i++)
  371. $this->_bind($val_list[$i]);
  372. return $this->_execute();
  373. }
  374. /**
  375. * @brief updateAct
  376. * */
  377. function _executeUpdateAct($queryObject) {
  378. $query = $this->getUpdateSql($queryObject);
  379. if (is_a($query, 'Object'))
  380. return;
  381. $this->_prepare($query);
  382. return $this->_execute();
  383. }
  384. /**
  385. * @brief deleteAct
  386. * */
  387. function _executeDeleteAct($queryObject) {
  388. $query = $this->getDeleteSql($queryObject);
  389. if (is_a($query, 'Object'))
  390. return;
  391. $this->_prepare($query);
  392. return $this->_execute();
  393. }
  394. /**
  395. * @brief selectAct
  396. *
  397. * To fetch a list of the page conveniently when selecting, \n
  398. * navigation method supported
  399. * */
  400. function _executeSelectAct($queryObject) {
  401. $query = $this->getSelectSql($queryObject);
  402. if (is_a($query, 'Object'))
  403. return;
  404. $this->_prepare($query);
  405. $data = $this->_execute();
  406. // TODO isError is called twice
  407. if ($this->isError())
  408. return;
  409. if ($this->isError())
  410. return $this->queryError($queryObject);
  411. else
  412. return $this->queryPageLimit($queryObject, $data);
  413. }
  414. function queryError($queryObject) {
  415. if ($queryObject->getLimit() && $queryObject->getLimit()->isPageHandler()) {
  416. $buff = new Object ();
  417. $buff->total_count = 0;
  418. $buff->total_page = 0;
  419. $buff->page = 1;
  420. $buff->data = array();
  421. $buff->page_navigation = new PageHandler(/* $total_count */0, /* $total_page */1, /* $page */1, /* $page_count */10); //default page handler values
  422. return $buff;
  423. }else
  424. return;
  425. }
  426. function queryPageLimit($queryObject, $data) {
  427. if ($queryObject->getLimit() && $queryObject->getLimit()->isPageHandler()) {
  428. // Total count
  429. $temp_where = $queryObject->getWhereString(true, false);
  430. $count_query = sprintf('select count(*) as "count" %s %s', 'FROM ' . $queryObject->getFromString(), ($temp_where === '' ? '' : ' WHERE ' . $temp_where));
  431. if ($queryObject->getGroupByString() != '') {
  432. $count_query = sprintf('select count(*) as "count" from (%s) xet', $count_query);
  433. }
  434. $count_query .= ( __DEBUG_QUERY__ & 1 && $output->query_id) ? sprintf(' ' . $this->comment_syntax, $this->query_id) : '';
  435. $this->_prepare($count_query);
  436. $count_output = $this->_execute();
  437. $total_count = (int) $count_output->count;
  438. $list_count = $queryObject->getLimit()->list_count->getValue();
  439. if (!$list_count) $list_count = 20;
  440. $page_count = $queryObject->getLimit()->page_count->getValue();
  441. if (!$page_count) $page_count = 10;
  442. $page = $queryObject->getLimit()->page->getValue();
  443. if (!$page) $page = 1;
  444. // Total pages
  445. if ($total_count) {
  446. $total_page = (int) (($total_count - 1) / $list_count) + 1;
  447. } else
  448. $total_page = 1;
  449. // check the page variables
  450. if ($page > $total_page) {
  451. // If requested page is bigger than total number of pages, return empty list
  452. $buff = new Object ();
  453. $buff->total_count = $total_count;
  454. $buff->total_page = $total_page;
  455. $buff->page = $page;
  456. $buff->data = array();
  457. $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
  458. return $buff;
  459. }
  460. $start_count = ($page - 1) * $list_count;
  461. $this->_prepare($this->getSelectPageSql($queryObject, true, $start_count, $list_count));
  462. $this->stmt->execute();
  463. if ($this->stmt->errorCode() != '00000') {
  464. $this->setError($this->stmt->errorCode(), print_r($this->stmt->errorInfo(), true));
  465. $this->actFinish();
  466. return $buff;
  467. }
  468. $output = null;
  469. $virtual_no = $total_count - ($page - 1) * $list_count;
  470. //$data = $this->_fetch($result, $virtual_no);
  471. while ($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
  472. unset($obj);
  473. foreach ($tmp as $key => $val) {
  474. $pos = strpos($key, '.');
  475. if ($pos)
  476. $key = substr($key, $pos + 1);
  477. $obj->{$key} = $val;
  478. }
  479. $datatemp[$virtual_no--] = $obj;
  480. }
  481. $this->stmt = null;
  482. $this->actFinish();
  483. $buff = new Object ();
  484. $buff->total_count = $total_count;
  485. $buff->total_page = $total_page;
  486. $buff->page = $page;
  487. $buff->data = $datatemp;
  488. $buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
  489. }else {
  490. //$data = $this->_fetch($result);
  491. $buff = new Object ();
  492. $buff->data = $data;
  493. }
  494. return $buff;
  495. }
  496. function getSelectPageSql($query, $with_values = true, $start_count = 0, $list_count = 0) {
  497. $select = $query->getSelectString($with_values);
  498. if ($select == '')
  499. return new Object(-1, "Invalid query");
  500. $select = 'SELECT ' . $select;
  501. $from = $query->getFromString($with_values);
  502. if ($from == '')
  503. return new Object(-1, "Invalid query");
  504. $from = ' FROM ' . $from;
  505. $where = $query->getWhereString($with_values);
  506. if ($where != '')
  507. $where = ' WHERE ' . $where;
  508. $groupBy = $query->getGroupByString();
  509. if ($groupBy != '')
  510. $groupBy = ' GROUP BY ' . $groupBy;
  511. $orderBy = $query->getOrderByString();
  512. if ($orderBy != '')
  513. $orderBy = ' ORDER BY ' . $orderBy;
  514. $limit = $query->getLimitString();
  515. if ($limit != '' && $query->getLimit()) {
  516. $limit = sprintf(' LIMIT %d, %d',$start_count, $list_count);
  517. }
  518. return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit;
  519. }
  520. function getParser() {
  521. return new DBParser('"', '"', $this->prefix);
  522. }
  523. function getUpdateSql($query, $with_values = true, $with_priority = false){
  524. $columnsList = $query->getUpdateString($with_values);
  525. if($columnsList == '') return new Object(-1, "Invalid query");
  526. $tableName = $query->getFirstTableName();
  527. if($tableName == '') return new Object(-1, "Invalid query");
  528. $where = $query->getWhereString($with_values);
  529. if($where != '') $where = ' WHERE ' . $where;
  530. $priority = $with_priority?$query->getPriority():'';
  531. return "UPDATE $priority $tableName SET $columnsList ".$where;
  532. }
  533. function getDeleteSql($query, $with_values = true, $with_priority = false){
  534. $sql = 'DELETE ';
  535. $tables = $query->getTables();
  536. $from = $tables[0]->getName();
  537. $sql .= ' FROM '.$from;
  538. $where = $query->getWhereString($with_values);
  539. if($where != '') $sql .= ' WHERE ' . $where;
  540. return $sql;
  541. }
  542. }
  543. ?>