DB
[ class tree: DB ] [ index: DB ] [ all elements ]

Source for file sqlite.php

Documentation is available at sqlite.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's sqlite extension
  7.  * for interacting with SQLite databases
  8.  *
  9.  * PHP versions 4 and 5
  10.  *
  11.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12.  * that is available through the world-wide-web at the following URI:
  13.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14.  * the PHP License and are unable to obtain it through the web, please
  15.  * send a note to license@php.net so we can mail you a copy immediately.
  16.  *
  17.  * @category   Database
  18.  * @package    DB
  19.  * @author     Urs Gehrig <urs@circle.ch>
  20.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  21.  * @author     Daniel Convissor <danielc@php.net>
  22.  * @copyright  1997-2007 The PHP Group
  23.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  24.  * @version    CVS: $Id: sqlite.php,v 1.118 2007/11/26 22:57:18 aharvey Exp $
  25.  * @link       http://pear.php.net/package/DB
  26.  */
  27.  
  28. /**
  29.  * Obtain the DB_common class so it can be extended from
  30.  */
  31. require_once 'DB/common.php';
  32.  
  33. /**
  34.  * The methods PEAR DB uses to interact with PHP's sqlite extension
  35.  * for interacting with SQLite databases
  36.  *
  37.  * These methods overload the ones declared in DB_common.
  38.  *
  39.  * NOTICE:  This driver needs PHP's track_errors ini setting to be on.
  40.  * It is automatically turned on when connecting to the database.
  41.  * Make sure your scripts don't turn it off.
  42.  *
  43.  * @category   Database
  44.  * @package    DB
  45.  * @author     Urs Gehrig <urs@circle.ch>
  46.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  47.  * @author     Daniel Convissor <danielc@php.net>
  48.  * @copyright  1997-2007 The PHP Group
  49.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  50.  * @version    Release: 1.7.14RC1
  51.  * @link       http://pear.php.net/package/DB
  52.  */
  53. class DB_sqlite extends DB_common
  54. {
  55.     // {{{ properties
  56.  
  57.     /**
  58.      * The DB driver type (mysql, oci8, odbc, etc.)
  59.      * @var string 
  60.      */
  61.     var $phptype = 'sqlite';
  62.  
  63.     /**
  64.      * The database syntax variant to be used (db2, access, etc.), if any
  65.      * @var string 
  66.      */
  67.     var $dbsyntax = 'sqlite';
  68.  
  69.     /**
  70.      * The capabilities of this DB implementation
  71.      *
  72.      * The 'new_link' element contains the PHP version that first provided
  73.      * new_link support for this DBMS.  Contains false if it's unsupported.
  74.      *
  75.      * Meaning of the 'limit' element:
  76.      *   + 'emulate' = emulate with fetch row by number
  77.      *   + 'alter'   = alter the query
  78.      *   + false     = skip rows
  79.      *
  80.      * @var array 
  81.      */
  82.     var $features = array(
  83.         'limit'         => 'alter',
  84.         'new_link'      => false,
  85.         'numrows'       => true,
  86.         'pconnect'      => true,
  87.         'prepare'       => false,
  88.         'ssl'           => false,
  89.         'transactions'  => false,
  90.     );
  91.  
  92.     /**
  93.      * A mapping of native error codes to DB error codes
  94.      *
  95.      * {@internal  Error codes according to sqlite_exec.  See the online
  96.      * manual at http://sqlite.org/c_interface.html for info.
  97.      * This error handling based on sqlite_exec is not yet implemented.}}}
  98.      *
  99.      * @var array 
  100.      */
  101.     var $errorcode_map = array(
  102.     );
  103.  
  104.     /**
  105.      * The raw database connection created by PHP
  106.      * @var resource 
  107.      */
  108.     var $connection;
  109.  
  110.     /**
  111.      * The DSN information for connecting to a database
  112.      * @var array 
  113.      */
  114.     var $dsn = array();
  115.  
  116.  
  117.     /**
  118.      * SQLite data types
  119.      *
  120.      * @link http://www.sqlite.org/datatypes.html
  121.      *
  122.      * @var array 
  123.      */
  124.     var $keywords = array (
  125.         'BLOB'      => '',
  126.         'BOOLEAN'   => '',
  127.         'CHARACTER' => '',
  128.         'CLOB'      => '',
  129.         'FLOAT'     => '',
  130.         'INTEGER'   => '',
  131.         'KEY'       => '',
  132.         'NATIONAL'  => '',
  133.         'NUMERIC'   => '',
  134.         'NVARCHAR'  => '',
  135.         'PRIMARY'   => '',
  136.         'TEXT'      => '',
  137.         'TIMESTAMP' => '',
  138.         'UNIQUE'    => '',
  139.         'VARCHAR'   => '',
  140.         'VARYING'   => '',
  141.     );
  142.  
  143.     /**
  144.      * The most recent error message from $php_errormsg
  145.      * @var string 
  146.      * @access private
  147.      */
  148.     var $_lasterror '';
  149.  
  150.  
  151.     // }}}
  152.     // {{{ constructor
  153.  
  154.     /**
  155.      * This constructor calls <kbd>$this->DB_common()</kbd>
  156.      *
  157.      * @return void 
  158.      */
  159.     function DB_sqlite()
  160.     {
  161.         $this->DB_common();
  162.     }
  163.  
  164.     // }}}
  165.     // {{{ connect()
  166.  
  167.     /**
  168.      * Connect to the database server, log in and open the database
  169.      *
  170.      * Don't call this method directly.  Use DB::connect() instead.
  171.      *
  172.      * PEAR DB's sqlite driver supports the following extra DSN options:
  173.      *   + mode  The permissions for the database file, in four digit
  174.      *            chmod octal format (eg "0600").
  175.      *
  176.      * Example of connecting to a database in read-only mode:
  177.      * <code>
  178.      * require_once 'DB.php';
  179.      * 
  180.      * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
  181.      * $options = array(
  182.      *     'portability' => DB_PORTABILITY_ALL,
  183.      * );
  184.      * 
  185.      * $db = DB::connect($dsn, $options);
  186.      * if (PEAR::isError($db)) {
  187.      *     die($db->getMessage());
  188.      * }
  189.      * </code>
  190.      *
  191.      * @param array $dsn         the data source name
  192.      * @param bool  $persistent  should the connection be persistent?
  193.      *
  194.      * @return int  DB_OK on success. A DB_Error object on failure.
  195.      */
  196.     function connect($dsn$persistent = false)
  197.     {
  198.         if (!PEAR::loadExtension('sqlite')) {
  199.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  200.         }
  201.  
  202.         $this->dsn = $dsn;
  203.         if ($dsn['dbsyntax']{
  204.             $this->dbsyntax = $dsn['dbsyntax'];
  205.         }
  206.  
  207.         if (!$dsn['database']{
  208.             return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  209.         }
  210.  
  211.         if ($dsn['database'!== ':memory:'{
  212.             if (!file_exists($dsn['database'])) {
  213.                 if (!touch($dsn['database'])) {
  214.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  215.                 }
  216.                 if (!isset($dsn['mode']||
  217.                     !is_numeric($dsn['mode']))
  218.                 {
  219.                     $mode = 0644;
  220.                 else {
  221.                     $mode octdec($dsn['mode']);
  222.                 }
  223.                 if (!chmod($dsn['database']$mode)) {
  224.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  225.                 }
  226.                 if (!file_exists($dsn['database'])) {
  227.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  228.                 }
  229.             }
  230.             if (!is_file($dsn['database'])) {
  231.                 return $this->sqliteRaiseError(DB_ERROR_INVALID);
  232.             }
  233.             if (!is_readable($dsn['database'])) {
  234.                 return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  235.             }
  236.         }
  237.  
  238.         $connect_function $persistent 'sqlite_popen' 'sqlite_open';
  239.  
  240.         // track_errors must remain on for simpleQuery()
  241.         @ini_set('track_errors'1);
  242.         $php_errormsg '';
  243.  
  244.         if (!$this->connection = @$connect_function($dsn['database'])) {
  245.             return $this->raiseError(DB_ERROR_NODBSELECTED,
  246.                                      nullnullnull,
  247.                                      $php_errormsg);
  248.         }
  249.         return DB_OK;
  250.     }
  251.  
  252.     // }}}
  253.     // {{{ disconnect()
  254.  
  255.     /**
  256.      * Disconnects from the database server
  257.      *
  258.      * @return bool  TRUE on success, FALSE on failure
  259.      */
  260.     function disconnect()
  261.     {
  262.         $ret @sqlite_close($this->connection);
  263.         $this->connection = null;
  264.         return $ret;
  265.     }
  266.  
  267.     // }}}
  268.     // {{{ simpleQuery()
  269.  
  270.     /**
  271.      * Sends a query to the database server
  272.      *
  273.      * NOTICE:  This method needs PHP's track_errors ini setting to be on.
  274.      * It is automatically turned on when connecting to the database.
  275.      * Make sure your scripts don't turn it off.
  276.      *
  277.      * @param string  the SQL query string
  278.      *
  279.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  280.      *                 + the DB_OK constant for other successful queries
  281.      *                 + a DB_Error object on failure
  282.      */
  283.     function simpleQuery($query)
  284.     {
  285.         $ismanip $this->_checkManip($query);
  286.         $this->last_query = $query;
  287.         $query $this->modifyQuery($query);
  288.  
  289.         $php_errormsg '';
  290.  
  291.         $result @sqlite_query($query$this->connection);
  292.         $this->_lasterror $php_errormsg $php_errormsg '';
  293.  
  294.         $this->result $result;
  295.         if (!$this->result{
  296.             return $this->sqliteRaiseError(null);
  297.         }
  298.  
  299.         // sqlite_query() seems to allways return a resource
  300.         // so cant use that. Using $ismanip instead
  301.         if (!$ismanip{
  302.             $numRows $this->numRows($result);
  303.             if (is_object($numRows)) {
  304.                 // we've got PEAR_Error
  305.                 return $numRows;
  306.             }
  307.             return $result;
  308.         }
  309.         return DB_OK;
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ nextResult()
  314.  
  315.     /**
  316.      * Move the internal sqlite result pointer to the next available result
  317.      *
  318.      * @param resource $result  the valid sqlite result resource
  319.      *
  320.      * @return bool  true if a result is available otherwise return false
  321.      */
  322.     function nextResult($result)
  323.     {
  324.         return false;
  325.     }
  326.  
  327.     // }}}
  328.     // {{{ fetchInto()
  329.  
  330.     /**
  331.      * Places a row from the result set into the given array
  332.      *
  333.      * Formating of the array and the data therein are configurable.
  334.      * See DB_result::fetchInto() for more information.
  335.      *
  336.      * This method is not meant to be called directly.  Use
  337.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  338.      * because DB_result is a separate object.
  339.      *
  340.      * @param resource $result    the query result resource
  341.      * @param array    $arr       the referenced array to put the data in
  342.      * @param int      $fetchmode how the resulting array should be indexed
  343.      * @param int      $rownum    the row number to fetch (0 = first row)
  344.      *
  345.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  346.      *                  reached or on failure
  347.      *
  348.      * @see DB_result::fetchInto()
  349.      */
  350.     function fetchInto($result&$arr$fetchmode$rownum = null)
  351.     {
  352.         if ($rownum !== null{
  353.             if (!@sqlite_seek($this->result$rownum)) {
  354.                 return null;
  355.             }
  356.         }
  357.         if ($fetchmode DB_FETCHMODE_ASSOC{
  358.             $arr @sqlite_fetch_array($resultSQLITE_ASSOC);
  359.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  360.                 $arr array_change_key_case($arrCASE_LOWER);
  361.             }
  362.  
  363.             /* Remove extraneous " characters from the fields in the result.
  364.              * Fixes bug #11716. */
  365.             if (is_array($arr&& count($arr> 0{
  366.                 $strippedArr = array();
  367.                 foreach ($arr as $field => $value{
  368.                     $strippedArr[trim($field'"')$value;
  369.                 }
  370.                 $arr $strippedArr;
  371.             }
  372.         else {
  373.             $arr @sqlite_fetch_array($resultSQLITE_NUM);
  374.         }
  375.         if (!$arr{
  376.             return null;
  377.         }
  378.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  379.             /*
  380.              * Even though this DBMS already trims output, we do this because
  381.              * a field might have intentional whitespace at the end that
  382.              * gets removed by DB_PORTABILITY_RTRIM under another driver.
  383.              */
  384.             $this->_rtrimArrayValues($arr);
  385.         }
  386.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  387.             $this->_convertNullArrayValuesToEmpty($arr);
  388.         }
  389.         return DB_OK;
  390.     }
  391.  
  392.     // }}}
  393.     // {{{ freeResult()
  394.  
  395.     /**
  396.      * Deletes the result set and frees the memory occupied by the result set
  397.      *
  398.      * This method is not meant to be called directly.  Use
  399.      * DB_result::free() instead.  It can't be declared "protected"
  400.      * because DB_result is a separate object.
  401.      *
  402.      * @param resource $result  PHP's query result resource
  403.      *
  404.      * @return bool  TRUE on success, FALSE if $result is invalid
  405.      *
  406.      * @see DB_result::free()
  407.      */
  408.     function freeResult(&$result)
  409.     {
  410.         // XXX No native free?
  411.         if (!is_resource($result)) {
  412.             return false;
  413.         }
  414.         $result = null;
  415.         return true;
  416.     }
  417.  
  418.     // }}}
  419.     // {{{ numCols()
  420.  
  421.     /**
  422.      * Gets the number of columns in a result set
  423.      *
  424.      * This method is not meant to be called directly.  Use
  425.      * DB_result::numCols() instead.  It can't be declared "protected"
  426.      * because DB_result is a separate object.
  427.      *
  428.      * @param resource $result  PHP's query result resource
  429.      *
  430.      * @return int  the number of columns.  A DB_Error object on failure.
  431.      *
  432.      * @see DB_result::numCols()
  433.      */
  434.     function numCols($result)
  435.     {
  436.         $cols @sqlite_num_fields($result);
  437.         if (!$cols{
  438.             return $this->sqliteRaiseError();
  439.         }
  440.         return $cols;
  441.     }
  442.  
  443.     // }}}
  444.     // {{{ numRows()
  445.  
  446.     /**
  447.      * Gets the number of rows in a result set
  448.      *
  449.      * This method is not meant to be called directly.  Use
  450.      * DB_result::numRows() instead.  It can't be declared "protected"
  451.      * because DB_result is a separate object.
  452.      *
  453.      * @param resource $result  PHP's query result resource
  454.      *
  455.      * @return int  the number of rows.  A DB_Error object on failure.
  456.      *
  457.      * @see DB_result::numRows()
  458.      */
  459.     function numRows($result)
  460.     {
  461.         $rows @sqlite_num_rows($result);
  462.         if ($rows === null{
  463.             return $this->sqliteRaiseError();
  464.         }
  465.         return $rows;
  466.     }
  467.  
  468.     // }}}
  469.     // {{{ affected()
  470.  
  471.     /**
  472.      * Determines the number of rows affected by a data maniuplation query
  473.      *
  474.      * 0 is returned for queries that don't manipulate data.
  475.      *
  476.      * @return int  the number of rows.  A DB_Error object on failure.
  477.      */
  478.     function affectedRows()
  479.     {
  480.         return @sqlite_changes($this->connection);
  481.     }
  482.  
  483.     // }}}
  484.     // {{{ dropSequence()
  485.  
  486.     /**
  487.      * Deletes a sequence
  488.      *
  489.      * @param string $seq_name  name of the sequence to be deleted
  490.      *
  491.      * @return int  DB_OK on success.  A DB_Error object on failure.
  492.      *
  493.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  494.      *       DB_sqlite::nextID(), DB_sqlite::createSequence()
  495.      */
  496.     function dropSequence($seq_name)
  497.     {
  498.         return $this->query('DROP TABLE ' $this->getSequenceName($seq_name));
  499.     }
  500.  
  501.     /**
  502.      * Creates a new sequence
  503.      *
  504.      * @param string $seq_name  name of the new sequence
  505.      *
  506.      * @return int  DB_OK on success.  A DB_Error object on failure.
  507.      *
  508.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  509.      *       DB_sqlite::nextID(), DB_sqlite::dropSequence()
  510.      */
  511.     function createSequence($seq_name)
  512.     {
  513.         $seqname $this->getSequenceName($seq_name);
  514.         $query   'CREATE TABLE ' $seqname .
  515.                    ' (id INTEGER UNSIGNED PRIMARY KEY) ';
  516.         $result  $this->query($query);
  517.         if (DB::isError($result)) {
  518.             return($result);
  519.         }
  520.         $query   = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
  521.                     BEGIN
  522.                         DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
  523.                     END ";
  524.         $result  $this->query($query);
  525.         if (DB::isError($result)) {
  526.             return($result);
  527.         }
  528.     }
  529.  
  530.     // }}}
  531.     // {{{ nextId()
  532.  
  533.     /**
  534.      * Returns the next free id in a sequence
  535.      *
  536.      * @param string  $seq_name  name of the sequence
  537.      * @param boolean $ondemand  when true, the seqence is automatically
  538.      *                             created if it does not exist
  539.      *
  540.      * @return int  the next id number in the sequence.
  541.      *                A DB_Error object on failure.
  542.      *
  543.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  544.      *       DB_sqlite::createSequence(), DB_sqlite::dropSequence()
  545.      */
  546.     function nextId($seq_name$ondemand = true)
  547.     {
  548.         $seqname $this->getSequenceName($seq_name);
  549.  
  550.         do {
  551.             $repeat = 0;
  552.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  553.             $result $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
  554.             $this->popErrorHandling();
  555.             if ($result === DB_OK{
  556.                 $id @sqlite_last_insert_rowid($this->connection);
  557.                 if ($id != 0{
  558.                     return $id;
  559.                 }
  560.             elseif ($ondemand && DB::isError($result&&
  561.                       $result->getCode(== DB_ERROR_NOSUCHTABLE)
  562.             {
  563.                 $result $this->createSequence($seq_name);
  564.                 if (DB::isError($result)) {
  565.                     return $this->raiseError($result);
  566.                 else {
  567.                     $repeat = 1;
  568.                 }
  569.             }
  570.         while ($repeat);
  571.  
  572.         return $this->raiseError($result);
  573.     }
  574.  
  575.     // }}}
  576.     // {{{ getDbFileStats()
  577.  
  578.     /**
  579.      * Get the file stats for the current database
  580.      *
  581.      * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
  582.      * atime, mtime, ctime, blksize, blocks or a numeric key between
  583.      * 0 and 12.
  584.      *
  585.      * @param string $arg  the array key for stats()
  586.      *
  587.      * @return mixed  an array on an unspecified key, integer on a passed
  588.      *                 arg and false at a stats error
  589.      */
  590.     function getDbFileStats($arg '')
  591.     {
  592.         $stats stat($this->dsn['database']);
  593.         if ($stats == false{
  594.             return false;
  595.         }
  596.         if (is_array($stats)) {
  597.             if (is_numeric($arg)) {
  598.                 if (((int)$arg <= 12((int)$arg >= 0)) {
  599.                     return false;
  600.                 }
  601.                 return $stats[$arg ];
  602.             }
  603.             if (array_key_exists(trim($arg)$stats)) {
  604.                 return $stats[$arg ];
  605.             }
  606.         }
  607.         return $stats;
  608.     }
  609.  
  610.     // }}}
  611.     // {{{ escapeSimple()
  612.  
  613.     /**
  614.      * Escapes a string according to the current DBMS's standards
  615.      *
  616.      * In SQLite, this makes things safe for inserts/updates, but may
  617.      * cause problems when performing text comparisons against columns
  618.      * containing binary data. See the
  619.      * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
  620.      *
  621.      * @param string $str  the string to be escaped
  622.      *
  623.      * @return string  the escaped string
  624.      *
  625.      * @since Method available since Release 1.6.1
  626.      * @see DB_common::escapeSimple()
  627.      */
  628.     function escapeSimple($str)
  629.     {
  630.         return @sqlite_escape_string($str);
  631.     }
  632.  
  633.     // }}}
  634.     // {{{ modifyLimitQuery()
  635.  
  636.     /**
  637.      * Adds LIMIT clauses to a query string according to current DBMS standards
  638.      *
  639.      * @param string $query   the query to modify
  640.      * @param int    $from    the row to start to fetching (0 = the first row)
  641.      * @param int    $count   the numbers of rows to fetch
  642.      * @param mixed  $params  array, string or numeric data to be used in
  643.      *                          execution of the statement.  Quantity of items
  644.      *                          passed must match quantity of placeholders in
  645.      *                          query:  meaning 1 placeholder for non-array
  646.      *                          parameters or 1 placeholder per array element.
  647.      *
  648.      * @return string  the query string with LIMIT clauses added
  649.      *
  650.      * @access protected
  651.      */
  652.     function modifyLimitQuery($query$from$count$params = array())
  653.     {
  654.         return "$query LIMIT $count OFFSET $from";
  655.     }
  656.  
  657.     // }}}
  658.     // {{{ modifyQuery()
  659.  
  660.     /**
  661.      * Chang