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.117 2007/09/21 14:23:28 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_PEAR_PATH.'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.13
  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($arr0{
  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.      * Changes a query string for various DBMS specific reasons
  662.      *
  663.      * This little hack lets you know how many rows were deleted
  664.      * when running a "DELETE FROM table" query.  Only implemented
  665.      * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
  666.      *
  667.      * @param string $query  the query string to modify
  668.      *
  669.      * @return string  the modified query string
  670.      *
  671.      * @access protected
  672.      * @see DB_common::setOption()
  673.      */
  674.     function modifyQuery($query)
  675.     {
  676.         if ($this->options['portability'DB_PORTABILITY_DELETE_COUNT{
  677.             if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i'$query)) {
  678.                 $query preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  679.                                       'DELETE FROM \1 WHERE 1=1'$query);
  680.             }
  681.         }
  682.         return $query;
  683.     }
  684.  
  685.     // }}}
  686.     // {{{ sqliteRaiseError()
  687.  
  688.     /**
  689.      * Produces a DB_Error object regarding the current problem
  690.      *
  691.      * @param int $errno  if the error is being manually raised pass a
  692.      *                      DB_ERROR* constant here.  If this isn't passed
  693.      *                      the error information gathered from the DBMS.
  694.      *
  695.      * @return object  the DB_Error object
  696.      *
  697.      * @see DB_common::raiseError(),
  698.      *       DB_sqlite::errorNative(), DB_sqlite::errorCode()
  699.      */
  700.     function sqliteRaiseError($errno null)
  701.     {
  702.         $native $this->errorNative();
  703.         if ($errno === null{
  704.             $errno $this->errorCode($native);
  705.         }
  706.  
  707.         $errorcode @sqlite_last_error($this->connection);
  708.         $userinfo "$errorcode ** $this->last_query";
  709.  
  710.         return $this->raiseError($errnonullnull$userinfo$native);
  711.     }
  712.  
  713.     // }}}
  714.     // {{{ errorNative()
  715.  
  716.     /**
  717.      * Gets the DBMS' native error message produced by the last query
  718.      *
  719.      * {@internal This is used to retrieve more meaningfull error messages
  720.      * because sqlite_last_error() does not provide adequate info.}}}
  721.      *
  722.      * @return string  the DBMS' error message
  723.      */
  724.     function errorNative()
  725.     {
  726.         return $this->_lasterror;
  727.     }
  728.  
  729.     // }}}
  730.     // {{{ errorCode()
  731.  
  732.     /**
  733.      * Determines PEAR::DB error code from the database's text error message
  734.      *
  735.      * @param string $errormsg  the error message returned from the database
  736.      *
  737.      * @return integer  the DB error number
  738.      */
  739.     function errorCode($errormsg)
  740.     {
  741.         static $error_regexps;
  742.         
  743.         // PHP 5.2+ prepends the function name to $php_errormsg, so we need
  744.         // this hack to work around it, per bug #9599.
  745.         $errormsg preg_replace('/^sqlite[a-z_]+\(\): /'''$errormsg);
  746.         
  747.         if (!isset($error_regexps)) {
  748.             $error_regexps array(
  749.                 '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
  750.                 '/^no such index:/' => DB_ERROR_NOT_FOUND,
  751.                 '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
  752.                 '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
  753.                 '/is not unique/' => DB_ERROR_CONSTRAINT,
  754.                 '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
  755.                 '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
  756.                 '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
  757.                 '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
  758.                 '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
  759.                 '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
  760.                 '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
  761.             );
  762.         }
  763.         foreach ($error_regexps as $regexp => $code{
  764.             if (preg_match($regexp$errormsg)) {
  765.                 return $code;
  766.             }
  767.         }
  768.         // Fall back to DB_ERROR if there was no mapping.
  769.         return DB_ERROR;
  770.     }
  771.  
  772.     // }}}
  773.     // {{{ tableInfo()
  774.  
  775.     /**
  776.      * Returns information about a table
  777.      *
  778.      * @param string         $result  a string containing the name of a table
  779.      * @param int            $mode    a valid tableInfo mode
  780.      *
  781.      * @return array  an associative array with the information requested.
  782.      *                  A DB_Error object on failure.
  783.      *
  784.      * @see DB_common::tableInfo()
  785.      * @since Method available since Release 1.7.0
  786.      */
  787.     function tableInfo($result$mode null)
  788.     {
  789.         if (is_string($result)) {
  790.             /*
  791.              * Probably received a table name.
  792.              * Create a result resource identifier.
  793.              */
  794.             $id @sqlite_array_query($this->connection,
  795.                                       "PRAGMA table_info('$result');",
  796.                                       SQLITE_ASSOC);
  797.             $got_string true;
  798.         else {
  799.             $this->last_query = '';
  800.             return $this->raiseError(DB_ERROR_NOT_CAPABLEnullnullnull,
  801.                                      'This DBMS can not obtain tableInfo' .
  802.                                      ' from result sets');
  803.         }
  804.  
  805.         if ($this->options['portability'DB_PORTABILITY_LOWERCASE{
  806.             $case_func 'strtolower';
  807.         else {
  808.             $case_func 'strval';
  809.         }
  810.  
  811.         $count count($id);
  812.         $res   array();
  813.  
  814.         if ($mode{
  815.             $res['num_fields'$count;
  816.         }
  817.  
  818.         for ($i 0$i $count$i++{
  819.             if (strpos($id[$i]['type']'('!== false{
  820.                 $bits explode('('$id[$i]['type']);
  821.                 $type $bits[0];
  822.                 $len  rtrim($bits[1],')');
  823.             else {
  824.                 $type $id[$i]['type'];
  825.                 $len  0;
  826.             }
  827.  
  828.             $flags '';
  829.             if ($id[$i]['pk']{
  830.                 $flags .= 'primary_key ';
  831.             }
  832.             if ($id[$i]['notnull']{
  833.                 $flags .= 'not_null ';
  834.             }
  835.             if ($id[$i]['dflt_value'!== null{
  836.                 $flags .= 'default_' rawurlencode($id[$i]['dflt_value']);
  837.             }
  838.             $flags trim($flags);
  839.  
  840.             $res[$iarray(
  841.                 'table' => $case_func($result),
  842.                 'name'  => $case_func($id[$i]['name']),
  843.                 'type'  => $type,
  844.                 'len'   => $len,
  845.                 'flags' => $flags,
  846.             );
  847.  
  848.             if ($mode DB_TABLEINFO_ORDER{
  849.                 $res['order'][$res[$i]['name']] $i;
  850.             }
  851.             if ($mode DB_TABLEINFO_ORDERTABLE{
  852.                 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  853.             }
  854.         }
  855.  
  856.         return $res;
  857.     }
  858.  
  859.     // }}}
  860.     // {{{ getSpecialQuery()
  861.  
  862.     /**
  863.      * Obtains the query string needed for listing a given type of objects
  864.      *
  865.      * @param string $type  the kind of objects you want to retrieve
  866.      * @param array  $args  SQLITE DRIVER ONLY: a private array of arguments
  867.      *                        used by the getSpecialQuery().  Do not use
  868.      *                        this directly.
  869.      *
  870.      * @return string  the SQL query string or null if the driver doesn't
  871.      *                   support the object type requested
  872.      *
  873.      * @access protected
  874.      * @see DB_common::getListOf()
  875.      */
  876.     function getSpecialQuery($type$args array())
  877.     {
  878.         if (!is_array($args)) {
  879.             return $this->raiseError('no key specified'nullnullnull,
  880.                                      'Argument has to be an array.');
  881.         }
  882.  
  883.         switch ($type{
  884.             case 'master':
  885.                 return 'SELECT * FROM sqlite_master;';
  886.             case 'tables':
  887.                 return "SELECT name FROM sqlite_master WHERE type='table' "
  888.                        . 'UNION ALL SELECT name FROM sqlite_temp_master '
  889.                        . "WHERE type='table' ORDER BY name;";
  890.             case 'schema':
  891.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  892.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  893.                        . "WHERE type!='meta' "
  894.                        . 'ORDER BY tbl_name, type DESC, name;';
  895.             case 'schemax':
  896.             case 'schema_x':
  897.                 /*
  898.                  * Use like:
  899.                  * $res = $db->query($db->getSpecialQuery('schema_x',
  900.                  *                   array('table' => 'table3')));
  901.                  */
  902.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  903.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  904.                        . "WHERE tbl_name LIKE '{$args['table']}"
  905.                        . "AND type!='meta' "
  906.                        . 'ORDER BY type DESC, name;';
  907.             case 'alter':
  908.                 /*
  909.                  * SQLite does not support ALTER TABLE; this is a helper query
  910.                  * to handle this. 'table' represents the table name, 'rows'
  911.                  * the news rows to create, 'save' the row(s) to keep _with_
  912.                  * the data.
  913.                  *
  914.                  * Use like:
  915.                  * $args = array(
  916.                  *     'table' => $table,
  917.                  *     'rows'  => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
  918.                  *     'save'  => "NULL, titel, content, datetime"
  919.                  * );
  920.                  * $res = $db->query( $db->getSpecialQuery('alter', $args));
  921.                  */
  922.                 $rows strtr($args['rows']$this->keywords);
  923.  
  924.                 $q array(
  925.                     'BEGIN TRANSACTION',
  926.                     "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
  927.                     "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
  928.                     "DROP TABLE {$args['table']}",
  929.                     "CREATE TABLE {$args['table']} ({$args['rows']})",
  930.                     "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
  931.                     "DROP TABLE {$args['table']}_backup",
  932.                     'COMMIT',
  933.                 );
  934.  
  935.                 /*
  936.                  * This is a dirty hack, since the above query will not get
  937.                  * executed with a single query call so here the query method
  938.                  * will be called directly and return a select instead.
  939.                  */
  940.                 foreach ($q as $query{
  941.                     $this->query($query);
  942.                 }
  943.                 return "SELECT * FROM {$args['table']};";
  944.             default:
  945.                 return null;
  946.         }
  947.     }
  948.  
  949.     // }}}
  950. }
  951.  
  952. /*
  953.  * Local variables:
  954.  * tab-width: 4
  955.  * c-basic-offset: 4
  956.  * End:
  957.  */
  958.  
  959. ?>

Documentation generated on Wed, 09 Feb 2011 09:04:41 +0700 by phpDocumentor 1.4.2