PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/php/DB/sqlite.php

https://bitbucket.org/adarshj/convenient_website
PHP | 942 lines | 405 code | 84 blank | 453 comment | 64 complexity | ead5de4d3b593938cc3a1fa3f5dcb668 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-2-Clause, GPL-2.0, LGPL-3.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * The PEAR DB driver for PHP's sqlite extension
  5. * for interacting with SQLite databases
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * LICENSE: This source file is subject to version 3.0 of the PHP license
  10. * that is available through the world-wide-web at the following URI:
  11. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  12. * the PHP License and are unable to obtain it through the web, please
  13. * send a note to license@php.net so we can mail you a copy immediately.
  14. *
  15. * @category Database
  16. * @package DB
  17. * @author Urs Gehrig <urs@circle.ch>
  18. * @author Mika Tuupola <tuupola@appelsiini.net>
  19. * @author Daniel Convissor <danielc@php.net>
  20. * @copyright 1997-2005 The PHP Group
  21. * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
  22. * @version CVS: $Id: sqlite.php,v 1.109 2005/03/10 01:22:48 danielc Exp $
  23. * @link http://pear.php.net/package/DB
  24. */
  25. /**
  26. * Obtain the DB_common class so it can be extended from
  27. */
  28. require_once 'DB/common.php';
  29. /**
  30. * The methods PEAR DB uses to interact with PHP's sqlite extension
  31. * for interacting with SQLite databases
  32. *
  33. * These methods overload the ones declared in DB_common.
  34. *
  35. * NOTICE: This driver needs PHP's track_errors ini setting to be on.
  36. * It is automatically turned on when connecting to the database.
  37. * Make sure your scripts don't turn it off.
  38. *
  39. * @category Database
  40. * @package DB
  41. * @author Urs Gehrig <urs@circle.ch>
  42. * @author Mika Tuupola <tuupola@appelsiini.net>
  43. * @author Daniel Convissor <danielc@php.net>
  44. * @copyright 1997-2005 The PHP Group
  45. * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
  46. * @version Release: 1.7.6
  47. * @link http://pear.php.net/package/DB
  48. */
  49. class DB_sqlite extends DB_common
  50. {
  51. // {{{ properties
  52. /**
  53. * The DB driver type (mysql, oci8, odbc, etc.)
  54. * @var string
  55. */
  56. var $phptype = 'sqlite';
  57. /**
  58. * The database syntax variant to be used (db2, access, etc.), if any
  59. * @var string
  60. */
  61. var $dbsyntax = 'sqlite';
  62. /**
  63. * The capabilities of this DB implementation
  64. *
  65. * The 'new_link' element contains the PHP version that first provided
  66. * new_link support for this DBMS. Contains false if it's unsupported.
  67. *
  68. * Meaning of the 'limit' element:
  69. * + 'emulate' = emulate with fetch row by number
  70. * + 'alter' = alter the query
  71. * + false = skip rows
  72. *
  73. * @var array
  74. */
  75. var $features = array(
  76. 'limit' => 'alter',
  77. 'new_link' => false,
  78. 'numrows' => true,
  79. 'pconnect' => true,
  80. 'prepare' => false,
  81. 'ssl' => false,
  82. 'transactions' => false,
  83. );
  84. /**
  85. * A mapping of native error codes to DB error codes
  86. *
  87. * {@internal Error codes according to sqlite_exec. See the online
  88. * manual at http://sqlite.org/c_interface.html for info.
  89. * This error handling based on sqlite_exec is not yet implemented.}}
  90. *
  91. * @var array
  92. */
  93. var $errorcode_map = array(
  94. );
  95. /**
  96. * The raw database connection created by PHP
  97. * @var resource
  98. */
  99. var $connection;
  100. /**
  101. * The DSN information for connecting to a database
  102. * @var array
  103. */
  104. var $dsn = array();
  105. /**
  106. * SQLite data types
  107. *
  108. * @link http://www.sqlite.org/datatypes.html
  109. *
  110. * @var array
  111. */
  112. var $keywords = array (
  113. 'BLOB' => '',
  114. 'BOOLEAN' => '',
  115. 'CHARACTER' => '',
  116. 'CLOB' => '',
  117. 'FLOAT' => '',
  118. 'INTEGER' => '',
  119. 'KEY' => '',
  120. 'NATIONAL' => '',
  121. 'NUMERIC' => '',
  122. 'NVARCHAR' => '',
  123. 'PRIMARY' => '',
  124. 'TEXT' => '',
  125. 'TIMESTAMP' => '',
  126. 'UNIQUE' => '',
  127. 'VARCHAR' => '',
  128. 'VARYING' => '',
  129. );
  130. /**
  131. * The most recent error message from $php_errormsg
  132. * @var string
  133. * @access private
  134. */
  135. var $_lasterror = '';
  136. // }}}
  137. // {{{ constructor
  138. /**
  139. * This constructor calls <kbd>$this->DB_common()</kbd>
  140. *
  141. * @return void
  142. */
  143. function DB_sqlite()
  144. {
  145. $this->DB_common();
  146. }
  147. // }}}
  148. // {{{ connect()
  149. /**
  150. * Connect to the database server, log in and open the database
  151. *
  152. * Don't call this method directly. Use DB::connect() instead.
  153. *
  154. * PEAR DB's sqlite driver supports the following extra DSN options:
  155. * + mode The permissions for the database file, in four digit
  156. * chmod octal format (eg "0600").
  157. *
  158. * Example of connecting to a database in read-only mode:
  159. * <code>
  160. * require_once 'DB.php';
  161. *
  162. * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
  163. * $options = array(
  164. * 'portability' => DB_PORTABILITY_ALL,
  165. * );
  166. *
  167. * $db =& DB::connect($dsn, $options);
  168. * if (PEAR::isError($db)) {
  169. * die($db->getMessage());
  170. * }
  171. * </code>
  172. *
  173. * @param array $dsn the data source name
  174. * @param bool $persistent should the connection be persistent?
  175. *
  176. * @return int DB_OK on success. A DB_Error object on failure.
  177. */
  178. function connect($dsn, $persistent = false)
  179. {
  180. if (!PEAR::loadExtension('sqlite')) {
  181. return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  182. }
  183. $this->dsn = $dsn;
  184. if ($dsn['dbsyntax']) {
  185. $this->dbsyntax = $dsn['dbsyntax'];
  186. }
  187. if ($dsn['database']) {
  188. if (!file_exists($dsn['database'])) {
  189. if (!touch($dsn['database'])) {
  190. return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  191. }
  192. if (!isset($dsn['mode']) ||
  193. !is_numeric($dsn['mode']))
  194. {
  195. $mode = 0644;
  196. } else {
  197. $mode = octdec($dsn['mode']);
  198. }
  199. if (!chmod($dsn['database'], $mode)) {
  200. return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  201. }
  202. if (!file_exists($dsn['database'])) {
  203. return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  204. }
  205. }
  206. if (!is_file($dsn['database'])) {
  207. return $this->sqliteRaiseError(DB_ERROR_INVALID);
  208. }
  209. if (!is_readable($dsn['database'])) {
  210. return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  211. }
  212. } else {
  213. return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  214. }
  215. $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
  216. // track_errors must remain on for simpleQuery()
  217. ini_set('track_errors', 1);
  218. $php_errormsg = '';
  219. if (!$this->connection = @$connect_function($dsn['database'])) {
  220. return $this->raiseError(DB_ERROR_NODBSELECTED,
  221. null, null, null,
  222. $php_errormsg);
  223. }
  224. return DB_OK;
  225. }
  226. // }}}
  227. // {{{ disconnect()
  228. /**
  229. * Disconnects from the database server
  230. *
  231. * @return bool TRUE on success, FALSE on failure
  232. */
  233. function disconnect()
  234. {
  235. $ret = @sqlite_close($this->connection);
  236. $this->connection = null;
  237. return $ret;
  238. }
  239. // }}}
  240. // {{{ simpleQuery()
  241. /**
  242. * Sends a query to the database server
  243. *
  244. * NOTICE: This method needs PHP's track_errors ini setting to be on.
  245. * It is automatically turned on when connecting to the database.
  246. * Make sure your scripts don't turn it off.
  247. *
  248. * @param string the SQL query string
  249. *
  250. * @return mixed + a PHP result resrouce for successful SELECT queries
  251. * + the DB_OK constant for other successful queries
  252. * + a DB_Error object on failure
  253. */
  254. function simpleQuery($query)
  255. {
  256. $ismanip = DB::isManip($query);
  257. $this->last_query = $query;
  258. $query = $this->modifyQuery($query);
  259. $php_errormsg = '';
  260. $result = @sqlite_query($query, $this->connection);
  261. $this->_lasterror = $php_errormsg ? $php_errormsg : '';
  262. $this->result = $result;
  263. if (!$this->result) {
  264. return $this->sqliteRaiseError(null);
  265. }
  266. // sqlite_query() seems to allways return a resource
  267. // so cant use that. Using $ismanip instead
  268. if (!$ismanip) {
  269. $numRows = $this->numRows($result);
  270. if (is_object($numRows)) {
  271. // we've got PEAR_Error
  272. return $numRows;
  273. }
  274. return $result;
  275. }
  276. return DB_OK;
  277. }
  278. // }}}
  279. // {{{ nextResult()
  280. /**
  281. * Move the internal sqlite result pointer to the next available result
  282. *
  283. * @param resource $result the valid sqlite result resource
  284. *
  285. * @return bool true if a result is available otherwise return false
  286. */
  287. function nextResult($result)
  288. {
  289. return false;
  290. }
  291. // }}}
  292. // {{{ fetchInto()
  293. /**
  294. * Places a row from the result set into the given array
  295. *
  296. * Formating of the array and the data therein are configurable.
  297. * See DB_result::fetchInto() for more information.
  298. *
  299. * This method is not meant to be called directly. Use
  300. * DB_result::fetchInto() instead. It can't be declared "protected"
  301. * because DB_result is a separate object.
  302. *
  303. * @param resource $result the query result resource
  304. * @param array $arr the referenced array to put the data in
  305. * @param int $fetchmode how the resulting array should be indexed
  306. * @param int $rownum the row number to fetch (0 = first row)
  307. *
  308. * @return mixed DB_OK on success, NULL when the end of a result set is
  309. * reached or on failure
  310. *
  311. * @see DB_result::fetchInto()
  312. */
  313. function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  314. {
  315. if ($rownum !== null) {
  316. if (!@sqlite_seek($this->result, $rownum)) {
  317. return null;
  318. }
  319. }
  320. if ($fetchmode & DB_FETCHMODE_ASSOC) {
  321. $arr = @sqlite_fetch_array($result, SQLITE_ASSOC);
  322. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  323. $arr = array_change_key_case($arr, CASE_LOWER);
  324. }
  325. } else {
  326. $arr = @sqlite_fetch_array($result, SQLITE_NUM);
  327. }
  328. if (!$arr) {
  329. return null;
  330. }
  331. if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  332. /*
  333. * Even though this DBMS already trims output, we do this because
  334. * a field might have intentional whitespace at the end that
  335. * gets removed by DB_PORTABILITY_RTRIM under another driver.
  336. */
  337. $this->_rtrimArrayValues($arr);
  338. }
  339. if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  340. $this->_convertNullArrayValuesToEmpty($arr);
  341. }
  342. return DB_OK;
  343. }
  344. // }}}
  345. // {{{ freeResult()
  346. /**
  347. * Deletes the result set and frees the memory occupied by the result set
  348. *
  349. * This method is not meant to be called directly. Use
  350. * DB_result::free() instead. It can't be declared "protected"
  351. * because DB_result is a separate object.
  352. *
  353. * @param resource $result PHP's query result resource
  354. *
  355. * @return bool TRUE on success, FALSE if $result is invalid
  356. *
  357. * @see DB_result::free()
  358. */
  359. function freeResult(&$result)
  360. {
  361. // XXX No native free?
  362. if (!is_resource($result)) {
  363. return false;
  364. }
  365. $result = null;
  366. return true;
  367. }
  368. // }}}
  369. // {{{ numCols()
  370. /**
  371. * Gets the number of columns in a result set
  372. *
  373. * This method is not meant to be called directly. Use
  374. * DB_result::numCols() instead. It can't be declared "protected"
  375. * because DB_result is a separate object.
  376. *
  377. * @param resource $result PHP's query result resource
  378. *
  379. * @return int the number of columns. A DB_Error object on failure.
  380. *
  381. * @see DB_result::numCols()
  382. */
  383. function numCols($result)
  384. {
  385. $cols = @sqlite_num_fields($result);
  386. if (!$cols) {
  387. return $this->sqliteRaiseError();
  388. }
  389. return $cols;
  390. }
  391. // }}}
  392. // {{{ numRows()
  393. /**
  394. * Gets the number of rows in a result set
  395. *
  396. * This method is not meant to be called directly. Use
  397. * DB_result::numRows() instead. It can't be declared "protected"
  398. * because DB_result is a separate object.
  399. *
  400. * @param resource $result PHP's query result resource
  401. *
  402. * @return int the number of rows. A DB_Error object on failure.
  403. *
  404. * @see DB_result::numRows()
  405. */
  406. function numRows($result)
  407. {
  408. $rows = @sqlite_num_rows($result);
  409. if ($rows === null) {
  410. return $this->sqliteRaiseError();
  411. }
  412. return $rows;
  413. }
  414. // }}}
  415. // {{{ affected()
  416. /**
  417. * Determines the number of rows affected by a data maniuplation query
  418. *
  419. * 0 is returned for queries that don't manipulate data.
  420. *
  421. * @return int the number of rows. A DB_Error object on failure.
  422. */
  423. function affectedRows()
  424. {
  425. return @sqlite_changes($this->connection);
  426. }
  427. // }}}
  428. // {{{ dropSequence()
  429. /**
  430. * Deletes a sequence
  431. *
  432. * @param string $seq_name name of the sequence to be deleted
  433. *
  434. * @return int DB_OK on success. A DB_Error object on failure.
  435. *
  436. * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  437. * DB_sqlite::nextID(), DB_sqlite::createSequence()
  438. */
  439. function dropSequence($seq_name)
  440. {
  441. return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  442. }
  443. /**
  444. * Creates a new sequence
  445. *
  446. * @param string $seq_name name of the new sequence
  447. *
  448. * @return int DB_OK on success. A DB_Error object on failure.
  449. *
  450. * @see DB_common::createSequence(), DB_common::getSequenceName(),
  451. * DB_sqlite::nextID(), DB_sqlite::dropSequence()
  452. */
  453. function createSequence($seq_name)
  454. {
  455. $seqname = $this->getSequenceName($seq_name);
  456. $query = 'CREATE TABLE ' . $seqname .
  457. ' (id INTEGER UNSIGNED PRIMARY KEY) ';
  458. $result = $this->query($query);
  459. if (DB::isError($result)) {
  460. return($result);
  461. }
  462. $query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
  463. BEGIN
  464. DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
  465. END ";
  466. $result = $this->query($query);
  467. if (DB::isError($result)) {
  468. return($result);
  469. }
  470. }
  471. // }}}
  472. // {{{ nextId()
  473. /**
  474. * Returns the next free id in a sequence
  475. *
  476. * @param string $seq_name name of the sequence
  477. * @param boolean $ondemand when true, the seqence is automatically
  478. * created if it does not exist
  479. *
  480. * @return int the next id number in the sequence.
  481. * A DB_Error object on failure.
  482. *
  483. * @see DB_common::nextID(), DB_common::getSequenceName(),
  484. * DB_sqlite::createSequence(), DB_sqlite::dropSequence()
  485. */
  486. function nextId($seq_name, $ondemand = true)
  487. {
  488. $seqname = $this->getSequenceName($seq_name);
  489. do {
  490. $repeat = 0;
  491. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  492. $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
  493. $this->popErrorHandling();
  494. if ($result === DB_OK) {
  495. $id = @sqlite_last_insert_rowid($this->connection);
  496. if ($id != 0) {
  497. return $id;
  498. }
  499. } elseif ($ondemand && DB::isError($result) &&
  500. $result->getCode() == DB_ERROR_NOSUCHTABLE)
  501. {
  502. $result = $this->createSequence($seq_name);
  503. if (DB::isError($result)) {
  504. return $this->raiseError($result);
  505. } else {
  506. $repeat = 1;
  507. }
  508. }
  509. } while ($repeat);
  510. return $this->raiseError($result);
  511. }
  512. // }}}
  513. // {{{ getDbFileStats()
  514. /**
  515. * Get the file stats for the current database
  516. *
  517. * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
  518. * atime, mtime, ctime, blksize, blocks or a numeric key between
  519. * 0 and 12.
  520. *
  521. * @param string $arg the array key for stats()
  522. *
  523. * @return mixed an array on an unspecified key, integer on a passed
  524. * arg and false at a stats error
  525. */
  526. function getDbFileStats($arg = '')
  527. {
  528. $stats = stat($this->dsn['database']);
  529. if ($stats == false) {
  530. return false;
  531. }
  532. if (is_array($stats)) {
  533. if (is_numeric($arg)) {
  534. if (((int)$arg <= 12) & ((int)$arg >= 0)) {
  535. return false;
  536. }
  537. return $stats[$arg ];
  538. }
  539. if (array_key_exists(trim($arg), $stats)) {
  540. return $stats[$arg ];
  541. }
  542. }
  543. return $stats;
  544. }
  545. // }}}
  546. // {{{ escapeSimple()
  547. /**
  548. * Escapes a string according to the current DBMS's standards
  549. *
  550. * In SQLite, this makes things safe for inserts/updates, but may
  551. * cause problems when performing text comparisons against columns
  552. * containing binary data. See the
  553. * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
  554. *
  555. * @param string $str the string to be escaped
  556. *
  557. * @return string the escaped string
  558. *
  559. * @since Method available since Release 1.6.1
  560. * @see DB_common::escapeSimple()
  561. */
  562. function escapeSimple($str)
  563. {
  564. return @sqlite_escape_string($str);
  565. }
  566. // }}}
  567. // {{{ modifyLimitQuery()
  568. /**
  569. * Adds LIMIT clauses to a query string according to current DBMS standards
  570. *
  571. * @param string $query the query to modify
  572. * @param int $from the row to start to fetching (0 = the first row)
  573. * @param int $count the numbers of rows to fetch
  574. * @param mixed $params array, string or numeric data to be used in
  575. * execution of the statement. Quantity of items
  576. * passed must match quantity of placeholders in
  577. * query: meaning 1 placeholder for non-array
  578. * parameters or 1 placeholder per array element.
  579. *
  580. * @return string the query string with LIMIT clauses added
  581. *
  582. * @access protected
  583. */
  584. function modifyLimitQuery($query, $from, $count, $params = array())
  585. {
  586. return "$query LIMIT $count OFFSET $from";
  587. }
  588. // }}}
  589. // {{{ modifyQuery()
  590. /**
  591. * Changes a query string for various DBMS specific reasons
  592. *
  593. * This little hack lets you know how many rows were deleted
  594. * when running a "DELETE FROM table" query. Only implemented
  595. * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
  596. *
  597. * @param string $query the query string to modify
  598. *
  599. * @return string the modified query string
  600. *
  601. * @access protected
  602. * @see DB_common::setOption()
  603. */
  604. function modifyQuery($query)
  605. {
  606. if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
  607. if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  608. $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  609. 'DELETE FROM \1 WHERE 1=1', $query);
  610. }
  611. }
  612. return $query;
  613. }
  614. // }}}
  615. // {{{ sqliteRaiseError()
  616. /**
  617. * Produces a DB_Error object regarding the current problem
  618. *
  619. * @param int $errno if the error is being manually raised pass a
  620. * DB_ERROR* constant here. If this isn't passed
  621. * the error information gathered from the DBMS.
  622. *
  623. * @return object the DB_Error object
  624. *
  625. * @see DB_common::raiseError(),
  626. * DB_sqlite::errorNative(), DB_sqlite::errorCode()
  627. */
  628. function sqliteRaiseError($errno = null)
  629. {
  630. $native = $this->errorNative();
  631. if ($errno === null) {
  632. $errno = $this->errorCode($native);
  633. }
  634. $errorcode = @sqlite_last_error($this->connection);
  635. $userinfo = "$errorcode ** $this->last_query";
  636. return $this->raiseError($errno, null, null, $userinfo, $native);
  637. }
  638. // }}}
  639. // {{{ errorNative()
  640. /**
  641. * Gets the DBMS' native error message produced by the last query
  642. *
  643. * {@internal This is used to retrieve more meaningfull error messages
  644. * because sqlite_last_error() does not provide adequate info.}}
  645. *
  646. * @return string the DBMS' error message
  647. */
  648. function errorNative()
  649. {
  650. return $this->_lasterror;
  651. }
  652. // }}}
  653. // {{{ errorCode()
  654. /**
  655. * Determines PEAR::DB error code from the database's text error message
  656. *
  657. * @param string $errormsg the error message returned from the database
  658. *
  659. * @return integer the DB error number
  660. */
  661. function errorCode($errormsg)
  662. {
  663. static $error_regexps;
  664. if (!isset($error_regexps)) {
  665. $error_regexps = array(
  666. '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
  667. '/^no such index:/' => DB_ERROR_NOT_FOUND,
  668. '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
  669. '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
  670. '/is not unique/' => DB_ERROR_CONSTRAINT,
  671. '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
  672. '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
  673. '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
  674. '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
  675. '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
  676. '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
  677. '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
  678. );
  679. }
  680. foreach ($error_regexps as $regexp => $code) {
  681. if (preg_match($regexp, $errormsg)) {
  682. return $code;
  683. }
  684. }
  685. // Fall back to DB_ERROR if there was no mapping.
  686. return DB_ERROR;
  687. }
  688. // }}}
  689. // {{{ tableInfo()
  690. /**
  691. * Returns information about a table
  692. *
  693. * @param string $result a string containing the name of a table
  694. * @param int $mode a valid tableInfo mode
  695. *
  696. * @return array an associative array with the information requested.
  697. * A DB_Error object on failure.
  698. *
  699. * @see DB_common::tableInfo()
  700. * @since Method available since Release 1.7.0
  701. */
  702. function tableInfo($result, $mode = null)
  703. {
  704. if (is_string($result)) {
  705. /*
  706. * Probably received a table name.
  707. * Create a result resource identifier.
  708. */
  709. $id = @sqlite_array_query($this->connection,
  710. "PRAGMA table_info('$result');",
  711. SQLITE_ASSOC);
  712. $got_string = true;
  713. } else {
  714. $this->last_query = '';
  715. return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null,
  716. 'This DBMS can not obtain tableInfo' .
  717. ' from result sets');
  718. }
  719. if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  720. $case_func = 'strtolower';
  721. } else {
  722. $case_func = 'strval';
  723. }
  724. $count = count($id);
  725. $res = array();
  726. if ($mode) {
  727. $res['num_fields'] = $count;
  728. }
  729. for ($i = 0; $i < $count; $i++) {
  730. if (strpos($id[$i]['type'], '(') !== false) {
  731. $bits = explode('(', $id[$i]['type']);
  732. $type = $bits[0];
  733. $len = rtrim($bits[1],')');
  734. } else {
  735. $type = $id[$i]['type'];
  736. $len = 0;
  737. }
  738. $flags = '';
  739. if ($id[$i]['pk']) {
  740. $flags .= 'primary_key ';
  741. }
  742. if ($id[$i]['notnull']) {
  743. $flags .= 'not_null ';
  744. }
  745. if ($id[$i]['dflt_value'] !== null) {
  746. $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
  747. }
  748. $flags = trim($flags);
  749. $res[$i] = array(
  750. 'table' => $case_func($result),
  751. 'name' => $case_func($id[$i]['name']),
  752. 'type' => $type,
  753. 'len' => $len,
  754. 'flags' => $flags,
  755. );
  756. if ($mode & DB_TABLEINFO_ORDER) {
  757. $res['order'][$res[$i]['name']] = $i;
  758. }
  759. if ($mode & DB_TABLEINFO_ORDERTABLE) {
  760. $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  761. }
  762. }
  763. return $res;
  764. }
  765. // }}}
  766. // {{{ getSpecialQuery()
  767. /**
  768. * Obtains the query string needed for listing a given type of objects
  769. *
  770. * @param string $type the kind of objects you want to retrieve
  771. * @param array $args SQLITE DRIVER ONLY: a private array of arguments
  772. * used by the getSpecialQuery(). Do not use
  773. * this directly.
  774. *
  775. * @return string the SQL query string or null if the driver doesn't
  776. * support the object type requested
  777. *
  778. * @access protected
  779. * @see DB_common::getListOf()
  780. */
  781. function getSpecialQuery($type, $args = array())
  782. {
  783. if (!is_array($args)) {
  784. return $this->raiseError('no key specified', null, null, null,
  785. 'Argument has to be an array.');
  786. }
  787. switch ($type) {
  788. case 'master':
  789. return 'SELECT * FROM sqlite_master;';
  790. case 'tables':
  791. return "SELECT name FROM sqlite_master WHERE type='table' "
  792. . 'UNION ALL SELECT name FROM sqlite_temp_master '
  793. . "WHERE type='table' ORDER BY name;";
  794. case 'schema':
  795. return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  796. . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  797. . "WHERE type!='meta' "
  798. . 'ORDER BY tbl_name, type DESC, name;';
  799. case 'schemax':
  800. case 'schema_x':
  801. /*
  802. * Use like:
  803. * $res = $db->query($db->getSpecialQuery('schema_x',
  804. * array('table' => 'table3')));
  805. */
  806. return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  807. . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  808. . "WHERE tbl_name LIKE '{$args['table']}' "
  809. . "AND type!='meta' "
  810. . 'ORDER BY type DESC, name;';
  811. case 'alter':
  812. /*
  813. * SQLite does not support ALTER TABLE; this is a helper query
  814. * to handle this. 'table' represents the table name, 'rows'
  815. * the news rows to create, 'save' the row(s) to keep _with_
  816. * the data.
  817. *
  818. * Use like:
  819. * $args = array(
  820. * 'table' => $table,
  821. * 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
  822. * 'save' => "NULL, titel, content, datetime"
  823. * );
  824. * $res = $db->query( $db->getSpecialQuery('alter', $args));
  825. */
  826. $rows = strtr($args['rows'], $this->keywords);
  827. $q = array(
  828. 'BEGIN TRANSACTION',
  829. "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
  830. "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
  831. "DROP TABLE {$args['table']}",
  832. "CREATE TABLE {$args['table']} ({$args['rows']})",
  833. "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
  834. "DROP TABLE {$args['table']}_backup",
  835. 'COMMIT',
  836. );
  837. /*
  838. * This is a dirty hack, since the above query will not get
  839. * executed with a single query call so here the query method
  840. * will be called directly and return a select instead.
  841. */
  842. foreach ($q as $query) {
  843. $this->query($query);
  844. }
  845. return "SELECT * FROM {$args['table']};";
  846. default:
  847. return null;
  848. }
  849. }
  850. // }}}
  851. }
  852. /*
  853. * Local variables:
  854. * tab-width: 4
  855. * c-basic-offset: 4
  856. * End:
  857. */
  858. ?>