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

Source for file fbsql.php

Documentation is available at fbsql.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's fbsql extension
  7.  * for interacting with FrontBase 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     Frank M. Kromann <frank@frontbase.com>
  20.  * @author     Daniel Convissor <danielc@php.net>
  21.  * @copyright  1997-2005 The PHP Group
  22.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23.  * @version    CVS: $Id: fbsql.php,v 1.86 2007/01/12 03:11:17 aharvey Exp $
  24.  * @link       http://pear.php.net/package/DB
  25.  */
  26.  
  27. /**
  28.  * Obtain the DB_common class so it can be extended from
  29.  */
  30. require_once 'DB/common.php';
  31.  
  32. /**
  33.  * The methods PEAR DB uses to interact with PHP's fbsql extension
  34.  * for interacting with FrontBase databases
  35.  *
  36.  * These methods overload the ones declared in DB_common.
  37.  *
  38.  * @category   Database
  39.  * @package    DB
  40.  * @author     Frank M. Kromann <frank@frontbase.com>
  41.  * @author     Daniel Convissor <danielc@php.net>
  42.  * @copyright  1997-2005 The PHP Group
  43.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  44.  * @version    Release: 1.7.10
  45.  * @link       http://pear.php.net/package/DB
  46.  * @since      Class functional since Release 1.7.0
  47.  */
  48. class DB_fbsql extends DB_common
  49. {
  50.     // {{{ properties
  51.  
  52.     
  53.     /**
  54.      * The DB driver type (mysql, oci8, odbc, etc.)
  55.      * @var string 
  56.      */
  57.     var $phptype = 'fbsql';
  58.  
  59.     /**
  60.      * The database syntax variant to be used (db2, access, etc.), if any
  61.      * @var string 
  62.      */
  63.     var $dbsyntax = 'fbsql';
  64.  
  65.     /**
  66.      * The capabilities of this DB implementation
  67.      *
  68.      * The 'new_link' element contains the PHP version that first provided
  69.      * new_link support for this DBMS.  Contains false if it's unsupported.
  70.      *
  71.      * Meaning of the 'limit' element:
  72.      *   + 'emulate' = emulate with fetch row by number
  73.      *   + 'alter'   = alter the query
  74.      *   + false     = skip rows
  75.      *
  76.      * @var array 
  77.      */
  78.     var $features = array(
  79.         'limit'         => 'alter',
  80.         'new_link'      => false,
  81.         'numrows'       => true,
  82.         'pconnect'      => true,
  83.         'prepare'       => false,
  84.         'ssl'           => false,
  85.         'transactions'  => true,
  86.     );
  87.  
  88.     /**
  89.      * A mapping of native error codes to DB error codes
  90.      * @var array 
  91.      */
  92.     var $errorcode_map = array(
  93.          22 => DB_ERROR_SYNTAX,
  94.          85 => DB_ERROR_ALREADY_EXISTS,
  95.         108 => DB_ERROR_SYNTAX,
  96.         116 => DB_ERROR_NOSUCHTABLE,
  97.         124 => DB_ERROR_VALUE_COUNT_ON_ROW,
  98.         215 => DB_ERROR_NOSUCHFIELD,
  99.         217 => DB_ERROR_INVALID_NUMBER,
  100.         226 => DB_ERROR_NOSUCHFIELD,
  101.         231 => DB_ERROR_INVALID,
  102.         239 => DB_ERROR_TRUNCATED,
  103.         251 => DB_ERROR_SYNTAX,
  104.         266 => DB_ERROR_NOT_FOUND,
  105.         357 => DB_ERROR_CONSTRAINT_NOT_NULL,
  106.         358 => DB_ERROR_CONSTRAINT,
  107.         360 => DB_ERROR_CONSTRAINT,
  108.         361 => DB_ERROR_CONSTRAINT,
  109.     );
  110.  
  111.     /**
  112.      * The raw database connection created by PHP
  113.      * @var resource 
  114.      */
  115.     var $connection;
  116.  
  117.     /**
  118.      * The DSN information for connecting to a database
  119.      * @var array 
  120.      */
  121.     var $dsn = array();
  122.  
  123.  
  124.     // }}}
  125.     // {{{ constructor
  126.  
  127.     
  128.     /**
  129.      * This constructor calls <kbd>$this->DB_common()</kbd>
  130.      *
  131.      * @return void 
  132.      */
  133.     function DB_fbsql()
  134.     {
  135.         $this->DB_common();
  136.     }
  137.  
  138.     // }}}
  139.     // {{{ connect()
  140.  
  141.     
  142.     /**
  143.      * Connect to the database server, log in and open the database
  144.      *
  145.      * Don't call this method directly.  Use DB::connect() instead.
  146.      *
  147.      * @param array $dsn         the data source name
  148.      * @param bool  $persistent  should the connection be persistent?
  149.      *
  150.      * @return int  DB_OK on success. A DB_Error object on failure.
  151.      */
  152.     function connect($dsn$persistent = false)
  153.     {
  154.         if (!PEAR::loadExtension('fbsql')) {
  155.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  156.         }
  157.  
  158.         $this->dsn = $dsn;
  159.         if ($dsn['dbsyntax']{
  160.             $this->dbsyntax = $dsn['dbsyntax'];
  161.         }
  162.  
  163.         $params = array(
  164.             $dsn['hostspec'$dsn['hostspec''localhost',
  165.             $dsn['username'$dsn['username': null,
  166.             $dsn['password'$dsn['password': null,
  167.         );
  168.  
  169.         $connect_function $persistent 'fbsql_pconnect' 'fbsql_connect';
  170.  
  171.         $ini ini_get('track_errors');
  172.         $php_errormsg '';
  173.         if ($ini{
  174.             $this->connection = @call_user_func_array($connect_function,
  175.                                                       $params);
  176.         else {
  177.             @ini_set('track_errors'1);
  178.             $this->connection = @call_user_func_array($connect_function,
  179.                                                       $params);
  180.             @ini_set('track_errors'$ini);
  181.         }
  182.  
  183.         if (!$this->connection{
  184.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  185.                                      nullnullnull,
  186.                                      $php_errormsg);
  187.         }
  188.  
  189.         if ($dsn['database']{
  190.             if (!@fbsql_select_db($dsn['database']$this->connection)) {
  191.                 return $this->fbsqlRaiseError();
  192.             }
  193.         }
  194.  
  195.         return DB_OK;
  196.     }
  197.  
  198.     // }}}
  199.     // {{{ disconnect()
  200.  
  201.     
  202.     /**
  203.      * Disconnects from the database server
  204.      *
  205.      * @return bool  TRUE on success, FALSE on failure
  206.      */
  207.     function disconnect()
  208.     {
  209.         $ret @fbsql_close($this->connection);
  210.         $this->connection = null;
  211.         return $ret;
  212.     }
  213.  
  214.     // }}}
  215.     // {{{ simpleQuery()
  216.  
  217.     
  218.     /**
  219.      * Sends a query to the database server
  220.      *
  221.      * @param string  the SQL query string
  222.      *
  223.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  224.      *                 + the DB_OK constant for other successful queries
  225.      *                 + a DB_Error object on failure
  226.      */
  227.     function simpleQuery($query)
  228.     {
  229.         $this->last_query = $query;
  230.         $query $this->modifyQuery($query);
  231.         $result @fbsql_query("$query;"$this->connection);
  232.         if (!$result{
  233.             return $this->fbsqlRaiseError();
  234.         }
  235.         // Determine which queries that should return data, and which
  236.         // should return an error code only.
  237.         if ($this->_checkManip($query)) {
  238.             return DB_OK;
  239.         }
  240.         return $result;
  241.     }
  242.  
  243.     // }}}
  244.     // {{{ nextResult()
  245.  
  246.     
  247.     /**
  248.      * Move the internal fbsql result pointer to the next available result
  249.      *
  250.      * @param valid fbsql result resource
  251.      *
  252.      * @access public
  253.      *
  254.      * @return true if a result is available otherwise return false
  255.      */
  256.     function nextResult($result)
  257.     {
  258.         return @fbsql_next_result($result);
  259.     }
  260.  
  261.     // }}}
  262.     // {{{ fetchInto()
  263.  
  264.     
  265.     /**
  266.      * Places a row from the result set into the given array
  267.      *
  268.      * Formating of the array and the data therein are configurable.
  269.      * See DB_result::fetchInto() for more information.
  270.      *
  271.      * This method is not meant to be called directly.  Use
  272.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  273.      * because DB_result is a separate object.
  274.      *
  275.      * @param resource $result    the query result resource
  276.      * @param array    $arr       the referenced array to put the data in
  277.      * @param int      $fetchmode how the resulting array should be indexed
  278.      * @param int      $rownum    the row number to fetch (0 = first row)
  279.      *
  280.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  281.      *                  reached or on failure
  282.      *
  283.      * @see DB_result::fetchInto()
  284.      */
  285.     function fetchInto($result&$arr$fetchmode$rownum = null)
  286.     {
  287.         if ($rownum !== null{
  288.             if (!@fbsql_data_seek($result$rownum)) {
  289.                 return null;
  290.             }
  291.         }
  292.         if ($fetchmode DB_FETCHMODE_ASSOC{
  293.             $arr @fbsql_fetch_array($resultFBSQL_ASSOC);
  294.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  295.                 $arr array_change_key_case($arrCASE_LOWER);
  296.             }
  297.         else {
  298.             $arr @fbsql_fetch_row($result);
  299.         }
  300.         if (!$arr{
  301.             return null;
  302.         }
  303.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  304.             $this->_rtrimArrayValues($arr);
  305.         }
  306.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  307.             $this->_convertNullArrayValuesToEmpty($arr);
  308.         }
  309.         return DB_OK;
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ freeResult()
  314.  
  315.     
  316.     /**
  317.      * Deletes the result set and frees the memory occupied by the result set
  318.      *
  319.      * This method is not meant to be called directly.  Use
  320.      * DB_result::free() instead.  It can't be declared "protected"
  321.      * because DB_result is a separate object.
  322.      *
  323.      * @param resource $result  PHP's query result resource
  324.      *
  325.      * @return bool  TRUE on success, FALSE if $result is invalid
  326.      *
  327.      * @see DB_result::free()
  328.      */
  329.     function freeResult($result)
  330.     {
  331.         return is_resource($result? fbsql_free_result($result: false;
  332.     }
  333.  
  334.     // }}}
  335.     // {{{ autoCommit()
  336.  
  337.     
  338.     /**
  339.      * Enables or disables automatic commits
  340.      *
  341.      * @param bool $onoff  true turns it on, false turns it off
  342.      *
  343.      * @return int  DB_OK on success.  A DB_Error object if the driver
  344.      *                doesn't support auto-committing transactions.
  345.      */
  346.     function autoCommit($onoff=false)
  347.     {
  348.         if ($onoff{
  349.             $this->query("SET COMMIT TRUE");
  350.         else {
  351.             $this->query("SET COMMIT FALSE");
  352.         }
  353.     }
  354.  
  355.     // }}}
  356.     // {{{ commit()
  357.  
  358.     
  359.     /**
  360.      * Commits the current transaction
  361.      *
  362.      * @return int  DB_OK on success.  A DB_Error object on failure.
  363.      */
  364.     function commit()
  365.     {
  366.         @fbsql_commit();
  367.     }
  368.  
  369.     // }}}
  370.     // {{{ rollback()
  371.  
  372.     
  373.     /**
  374.      * Reverts the current transaction
  375.      *
  376.      * @return int  DB_OK on success.  A DB_Error object on failure.
  377.      */
  378.     function rollback()
  379.     {
  380.         @fbsql_rollback();
  381.     }
  382.  
  383.     // }}}
  384.     // {{{ numCols()
  385.  
  386.     
  387.     /**
  388.      * Gets the number of columns in a result set
  389.      *
  390.      * This method is not meant to be called directly.  Use
  391.      * DB_result::numCols() instead.  It can't be declared "protected"
  392.      * because DB_result is a separate object.
  393.      *
  394.      * @param resource $result  PHP's query result resource
  395.      *
  396.      * @return int  the number of columns.  A DB_Error object on failure.
  397.      *
  398.      * @see DB_result::numCols()
  399.      */
  400.     function numCols($result)
  401.     {
  402.         $cols @fbsql_num_fields($result);
  403.         if (!$cols{
  404.             return $this->fbsqlRaiseError();
  405.         }
  406.         return $cols;
  407.     }
  408.  
  409.     // }}}
  410.     // {{{ numRows()
  411.  
  412.     
  413.     /**
  414.      * Gets the number of rows in a result set
  415.      *
  416.      * This method is not meant to be called directly.  Use
  417.      * DB_result::numRows() instead.  It can't be declared "protected"
  418.      * because DB_result is a separate object.
  419.      *
  420.      * @param resource $result  PHP's query result resource
  421.      *
  422.      * @return int  the number of rows.  A DB_Error object on failure.
  423.      *
  424.      * @see DB_result::numRows()
  425.      */
  426.     function numRows($result)
  427.     {
  428.         $rows @fbsql_num_rows($result);
  429.         if ($rows === null{
  430.             return $this->fbsqlRaiseError();
  431.         }
  432.         return $rows;
  433.     }
  434.  
  435.     // }}}
  436.     // {{{ affectedRows()
  437.  
  438.     
  439.     /**
  440.      * Determines the number of rows affected by a data maniuplation query
  441.      *
  442.      * 0 is returned for queries that don't manipulate data.
  443.      *
  444.      * @return int  the number of rows.  A DB_Error object on failure.
  445.      */
  446.     function affectedRows()
  447.     {
  448.         if ($this->_last_query_manip{
  449.             $result @fbsql_affected_rows($this->connection);
  450.         else {
  451.             $result = 0;
  452.         }
  453.         return $result;
  454.      }
  455.  
  456.     // }}}
  457.     // {{{ nextId()
  458.  
  459.     
  460.     /**
  461.      * Returns the next free id in a sequence
  462.      *
  463.      * @param string  $seq_name  name of the sequence
  464.      * @param boolean $ondemand  when true, the seqence is automatically
  465.      *                             created if it does not exist
  466.      *
  467.      * @return int  the next id number in the sequence.
  468.      *                A DB_Error object on failure.
  469.      *
  470.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  471.      *       DB_fbsql::createSequence(), DB_fbsql::dropSequence()
  472.      */
  473.     function nextId($seq_name$ondemand = true)
  474.     {
  475.         $seqname $this->getSequenceName($seq_name);
  476.         do {
  477.             $repeat = 0;
  478.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  479.             $result $this->query('SELECT UNIQUE FROM ' $seqname);
  480.             $this->popErrorHandling();
  481.             if ($ondemand && DB::isError($result&&
  482.                 $result->getCode(== DB_ERROR_NOSUCHTABLE{
  483.                 $repeat = 1;
  484.                 $result $this->createSequence($seq_name);
  485.                 if (DB::isError($result)) {
  486.                     return $result;
  487.                 }
  488.             else {
  489.                 $repeat = 0;
  490.             }
  491.         while ($repeat);
  492.         if (DB::isError($result)) {
  493.             return $this->fbsqlRaiseError();
  494.         }
  495.         $result->fetchInto($tmpDB_FETCHMODE_ORDERED);
  496.         return $tmp[0];
  497.     }
  498.  
  499.     /**
  500.      * Creates a new sequence
  501.      *
  502.      * @param string $seq_name  name of the new sequence
  503.      *
  504.      * @return int  DB_OK on success.  A DB_Error object on failure.
  505.      *
  506.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  507.      *       DB_fbsql::nextID(), DB_fbsql::dropSequence()
  508.      */
  509.     function createSequence($seq_name)
  510.     {
  511.         $seqname $this->getSequenceName($seq_name);
  512.         $res $this->query('CREATE TABLE ' $seqname
  513.                             . ' (id INTEGER NOT NULL,'
  514.                             . ' PRIMARY KEY(id))');
  515.         if ($res{
  516.             $res $this->query('SET UNIQUE = 0 FOR ' $seqname);
  517.         }
  518.         return $res;
  519.     }
  520.  
  521.     // }}}
  522.     // {{{ dropSequence()
  523.  
  524.     
  525.     /**
  526.      * Deletes a sequence
  527.      *
  528.      * @param string $seq_name  name of the sequence to be deleted
  529.      *
  530.      * @return int  DB_OK on success.  A DB_Error object on failure.
  531.      *
  532.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  533.      *       DB_fbsql::nextID(), DB_fbsql::createSequence()
  534.      */
  535.     function dropSequence($seq_name)
  536.     {
  537.         return $this->query('DROP TABLE ' $this->getSequenceName($seq_name)
  538.                             . ' RESTRICT');
  539.     }
  540.  
  541.     // }}}
  542.     // {{{ modifyLimitQuery()
  543.  
  544.     
  545.     /**
  546.      * Adds LIMIT clauses to a query string according to current DBMS standards
  547.      *
  548.      * @param string $query   the query to modify
  549.      * @param int    $from    the row to start to fetching (0 = the first row)
  550.      * @param int    $count   the numbers of rows to fetch
  551.      * @param mixed  $params  array, string or numeric data to be used in
  552.      *                          execution of the statement.  Quantity of items
  553.      *                          passed must match quantity of placeholders in
  554.      *                          query:  meaning 1 placeholder for non-array
  555.      *                          parameters or 1 placeholder per array element.
  556.      *
  557.      * @return string  the query string with LIMIT clauses added
  558.      *
  559.      * @access protected
  560.      */
  561.     function modifyLimitQuery($query$from$count$params = array())
  562.     {
  563.         if (DB::isManip($query|| $this->_next_query_manip{
  564.             return preg_replace('/^([\s(])*SELECT/i',
  565.                                 "\\1SELECT TOP($count)"$query);
  566.         else {
  567.             return preg_replace('/([\s(])*SELECT/i',
  568.                                 "\\1SELECT TOP($from$count)"$query);
  569.         }
  570.     }
  571.  
  572.     // }}}
  573.     // {{{ quoteBoolean()
  574.  
  575.     
  576.     /**
  577.      * Formats a boolean value for use within a query in a locale-independent
  578.      * manner.
  579.      *
  580.      * @param boolean the boolean value to be quoted.
  581.      * @return string the quoted string.
  582.      * @see DB_common::quoteSmart()
  583.      * @since Method available since release 1.7.8.
  584.      */
  585.     function quoteBoolean($boolean{
  586.         return $boolean 'TRUE' 'FALSE';
  587.     }
  588.      
  589.     // }}}
  590.     // {{{ quoteFloat()
  591.  
  592.     
  593.     /**
  594.      * Formats a float value for use within a query in a locale-independent
  595.      * manner.
  596.      *
  597.      * @param float the float value to be quoted.
  598.      * @return string the quoted string.
  599.      * @see DB_common::quoteSmart()
  600.      * @since Method available since release 1.7.8.
  601.      */
  602.     function quoteFloat($float{
  603.         return $this->escapeSimple(str_replace(',''.'strval(floatval($float))));
  604.     }
  605.      
  606.     // }}}
  607.     // {{{ fbsqlRaiseError()
  608.  
  609.     
  610.     /**
  611.      * Produces a DB_Error object regarding the current problem
  612.      *
  613.      * @param int $errno  if the error is being manually raised pass a
  614.      *                      DB_ERROR* constant here.  If this isn't passed
  615.      *                      the error information gathered from the DBMS.
  616.      *
  617.      * @return object  the DB_Error object
  618.      *
  619.      * @see DB_common::raiseError(),
  620.      *       DB_fbsql::errorNative(), DB_common::errorCode()
  621.      */
  622.     function fbsqlRaiseError($errno = null)
  623.     {
  624.         if ($errno === null{
  625.             $errno $this->errorCode(fbsql_errno($this->connection));
  626.         }
  627.         return $this->raiseError($errnonullnullnull,
  628.                                  @fbsql_error($this->connection));
  629.     }
  630.  
  631.     // }}}
  632.     // {{{ errorNative()
  633.  
  634.     
  635.     /**
  636.      * Gets the DBMS' native error code produced by the last query
  637.      *
  638.      * @return int  the DBMS' error code
  639.      */
  640.     function errorNative()
  641.     {
  642.         return @fbsql_errno($this->connection);
  643.     }
  644.  
  645.     // }}}
  646.     // {{{ tableInfo()
  647.  
  648.     
  649.     /**
  650.      * Returns information about a table or a result set
  651.      *
  652.      * @param object|string $result  DB_result object from a query or a
  653.      *                                  string containing the name of a table.
  654.      *                                  While this also accepts a query result
  655.      *                                  resource identifier, this behavior is
  656.      *                                  deprecated.
  657.      * @param int            $mode    a valid tableInfo mode
  658.      *
  659.      * @return array  an associative array with the information requested.
  660.      *                  A DB_Error object on failure.
  661.      *
  662.      * @see DB_common::tableInfo()
  663.      */
  664.     function tableInfo($result$mode = null)
  665.     {
  666.         if (is_string($result)) {
  667.             /*
  668.              * Probably received a table name.
  669.              * Create a result resource identifier.
  670.              */
  671.             $id @fbsql_list_fields($this->dsn['database'],
  672.                                      $result$this->connection);
  673.             $got_string = true;
  674.         elseif (isset($result->result)) {
  675.             /*
  676.              * Probably received a result object.
  677.              * Extract the result resource identifier.
  678.              */
  679.             $id $result->result;
  680.             $got_string = false;
  681.         else {
  682.             /*
  683.              * Probably received a result resource identifier.
  684.              * Copy it.
  685.              * Deprecated.  Here for compatibility only.
  686.              */
  687.     &nbs