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

Source for file sybase.php

Documentation is available at sybase.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's sybase extension
  7.  * for interacting with Sybase 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     Sterling Hughes <sterling@php.net>
  20.  * @author     Antônio Carlos Venâncio Júnior <floripa@php.net>
  21.  * @author     Daniel Convissor <danielc@php.net>
  22.  * @copyright  1997-2005 The PHP Group
  23.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24.  * @version    CVS: $Id: sybase.php,v 1.85 2007/02/06 07:35:07 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 sybase extension
  35.  * for interacting with Sybase databases
  36.  *
  37.  * These methods overload the ones declared in DB_common.
  38.  *
  39.  * WARNING:  This driver may fail with multiple connections under the
  40.  * same user/pass/host and different databases.
  41.  *
  42.  * @category   Database
  43.  * @package    DB
  44.  * @author     Sterling Hughes <sterling@php.net>
  45.  * @author     Antônio Carlos Venâncio Júnior <floripa@php.net>
  46.  * @author     Daniel Convissor <danielc@php.net>
  47.  * @copyright  1997-2005 The PHP Group
  48.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  49.  * @version    Release: 1.7.10
  50.  * @link       http://pear.php.net/package/DB
  51.  */
  52. class DB_sybase extends DB_common
  53. {
  54.     // {{{ properties
  55.  
  56.     
  57.     /**
  58.      * The DB driver type (mysql, oci8, odbc, etc.)
  59.      * @var string 
  60.      */
  61.     var $phptype = 'sybase';
  62.  
  63.     /**
  64.      * The database syntax variant to be used (db2, access, etc.), if any
  65.      * @var string 
  66.      */
  67.     var $dbsyntax = 'sybase';
  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'         => 'emulate',
  84.         'new_link'      => false,
  85.         'numrows'       => true,
  86.         'pconnect'      => true,
  87.         'prepare'       => false,
  88.         'ssl'           => false,
  89.         'transactions'  => true,
  90.     );
  91.  
  92.     /**
  93.      * A mapping of native error codes to DB error codes
  94.      * @var array 
  95.      */
  96.     var $errorcode_map = array(
  97.     );
  98.  
  99.     /**
  100.      * The raw database connection created by PHP
  101.      * @var resource 
  102.      */
  103.     var $connection;
  104.  
  105.     /**
  106.      * The DSN information for connecting to a database
  107.      * @var array 
  108.      */
  109.     var $dsn = array();
  110.  
  111.  
  112.     /**
  113.      * Should data manipulation queries be committed automatically?
  114.      * @var bool 
  115.      * @access private
  116.      */
  117.     var $autocommit = true;
  118.  
  119.     /**
  120.      * The quantity of transactions begun
  121.      *
  122.      * {@internal  While this is private, it can't actually be designated
  123.      * private in PHP 5 because it is directly accessed in the test suite.}}
  124.      *
  125.      * @var integer 
  126.      * @access private
  127.      */
  128.     var $transaction_opcount = 0;
  129.  
  130.     /**
  131.      * The database specified in the DSN
  132.      *
  133.      * It's a fix to allow calls to different databases in the same script.
  134.      *
  135.      * @var string 
  136.      * @access private
  137.      */
  138.     var $_db '';
  139.  
  140.  
  141.     // }}}
  142.     // {{{ constructor
  143.  
  144.     
  145.     /**
  146.      * This constructor calls <kbd>$this->DB_common()</kbd>
  147.      *
  148.      * @return void 
  149.      */
  150.     function DB_sybase()
  151.     {
  152.         $this->DB_common();
  153.     }
  154.  
  155.     // }}}
  156.     // {{{ connect()
  157.  
  158.     
  159.     /**
  160.      * Connect to the database server, log in and open the database
  161.      *
  162.      * Don't call this method directly.  Use DB::connect() instead.
  163.      *
  164.      * PEAR DB's sybase driver supports the following extra DSN options:
  165.      *   + appname       The application name to use on this connection.
  166.      *                   Available since PEAR DB 1.7.0.
  167.      *   + charset       The character set to use on this connection.
  168.      *                   Available since PEAR DB 1.7.0.
  169.      *
  170.      * @param array $dsn         the data source name
  171.      * @param bool  $persistent  should the connection be persistent?
  172.      *
  173.      * @return int  DB_OK on success. A DB_Error object on failure.
  174.      */
  175.     function connect($dsn$persistent = false)
  176.     {
  177.         if (!PEAR::loadExtension('sybase'&&
  178.             !PEAR::loadExtension('sybase_ct'))
  179.         {
  180.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  181.         }
  182.  
  183.         $this->dsn = $dsn;
  184.         if ($dsn['dbsyntax']{
  185.             $this->dbsyntax = $dsn['dbsyntax'];
  186.         }
  187.  
  188.         $dsn['hostspec'$dsn['hostspec'$dsn['hostspec''localhost';
  189.         $dsn['password'!empty($dsn['password']$dsn['password': false;
  190.         $dsn['charset'= isset($dsn['charset']$dsn['charset': false;
  191.         $dsn['appname'= isset($dsn['appname']$dsn['appname': false;
  192.  
  193.         $connect_function $persistent 'sybase_pconnect' 'sybase_connect';
  194.  
  195.         if ($dsn['username']{
  196.             $this->connection = @$connect_function($dsn['hostspec'],
  197.                                                    $dsn['username'],
  198.                                                    $dsn['password'],
  199.                                                    $dsn['charset'],
  200.                                                    $dsn['appname']);
  201.         else {
  202.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  203.                                      nullnullnull,
  204.                                      'The DSN did not contain a username.');
  205.         }
  206.  
  207.         if (!$this->connection{
  208.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  209.                                      nullnullnull,
  210.                                      @sybase_get_last_message());
  211.         }
  212.  
  213.         if ($dsn['database']{
  214.             if (!@sybase_select_db($dsn['database']$this->connection)) {
  215.                 return $this->raiseError(DB_ERROR_NODBSELECTED,
  216.                                          nullnullnull,
  217.                                          @sybase_get_last_message());
  218.             }
  219.             $this->_db $dsn['database'];
  220.         }
  221.  
  222.         return DB_OK;
  223.     }
  224.  
  225.     // }}}
  226.     // {{{ disconnect()
  227.  
  228.     
  229.     /**
  230.      * Disconnects from the database server
  231.      *
  232.      * @return bool  TRUE on success, FALSE on failure
  233.      */
  234.     function disconnect()
  235.     {
  236.         $ret @sybase_close($this->connection);
  237.         $this->connection = null;
  238.         return $ret;
  239.     }
  240.  
  241.     // }}}
  242.     // {{{ simpleQuery()
  243.  
  244.     
  245.     /**
  246.      * Sends a query to the database server
  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 $this->_checkManip($query);
  257.         $this->last_query = $query;
  258.         if ($this->_db && !@sybase_select_db($this->_db$this->connection)) {
  259.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  260.         }
  261.         $query $this->modifyQuery($query);
  262.         if (!$this->autocommit && $ismanip{
  263.             if ($this->transaction_opcount == 0{
  264.                 $result @sybase_query('BEGIN TRANSACTION'$this->connection);
  265.                 if (!$result{
  266.                     return $this->sybaseRaiseError();
  267.                 }
  268.             }
  269.             $this->transaction_opcount++;
  270.         }
  271.         $result @sybase_query($query$this->connection);
  272.         if (!$result{
  273.             return $this->sybaseRaiseError();
  274.         }
  275.         if (is_resource($result)) {
  276.             return $result;
  277.         }
  278.         // Determine which queries that should return data, and which
  279.         // should return an error code only.
  280.         return $ismanip DB_OK : $result;
  281.     }
  282.  
  283.     // }}}
  284.     // {{{ nextResult()
  285.  
  286.     
  287.     /**
  288.      * Move the internal sybase result pointer to the next available result
  289.      *
  290.      * @param valid sybase result resource
  291.      *
  292.      * @access public
  293.      *
  294.      * @return true if a result is available otherwise return false
  295.      */
  296.     function nextResult($result)
  297.     {
  298.         return false;
  299.     }
  300.  
  301.     // }}}
  302.     // {{{ fetchInto()
  303.  
  304.     
  305.     /**
  306.      * Places a row from the result set into the given array
  307.      *
  308.      * Formating of the array and the data therein are configurable.
  309.      * See DB_result::fetchInto() for more information.
  310.      *
  311.      * This method is not meant to be called directly.  Use
  312.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  313.      * because DB_result is a separate object.
  314.      *
  315.      * @param resource $result    the query result resource
  316.      * @param array    $arr       the referenced array to put the data in
  317.      * @param int      $fetchmode how the resulting array should be indexed
  318.      * @param int      $rownum    the row number to fetch (0 = first row)
  319.      *
  320.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  321.      *                  reached or on failure
  322.      *
  323.      * @see DB_result::fetchInto()
  324.      */
  325.     function fetchInto($result&$arr$fetchmode$rownum = null)
  326.     {
  327.         if ($rownum !== null{
  328.             if (!@sybase_data_seek($result$rownum)) {
  329.                 return null;
  330.             }
  331.         }
  332.         if ($fetchmode DB_FETCHMODE_ASSOC{
  333.             if (function_exists('sybase_fetch_assoc')) {
  334.                 $arr @sybase_fetch_assoc($result);
  335.             else {
  336.                 if ($arr @sybase_fetch_array($result)) {
  337.                     foreach ($arr as $key => $value{
  338.                         if (is_int($key)) {
  339.                             unset($arr[$key]);
  340.                         }
  341.                     }
  342.                 }
  343.             }
  344.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  345.                 $arr array_change_key_case($arrCASE_LOWER);
  346.             }
  347.         else {
  348.             $arr @sybase_fetch_row($result);
  349.         }
  350.         if (!$arr{
  351.             return null;
  352.         }
  353.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  354.             $this->_rtrimArrayValues($arr);
  355.         }
  356.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  357.             $this->_convertNullArrayValuesToEmpty($arr);
  358.         }
  359.         return DB_OK;
  360.     }
  361.  
  362.     // }}}
  363.     // {{{ freeResult()
  364.  
  365.     
  366.     /**
  367.      * Deletes the result set and frees the memory occupied by the result set
  368.      *
  369.      * This method is not meant to be called directly.  Use
  370.      * DB_result::free() instead.  It can't be declared "protected"
  371.      * because DB_result is a separate object.
  372.      *
  373.      * @param resource $result  PHP's query result resource
  374.      *
  375.      * @return bool  TRUE on success, FALSE if $result is invalid
  376.      *
  377.      * @see DB_result::free()
  378.      */
  379.     function freeResult($result)
  380.     {
  381.         return is_resource($result? sybase_free_result($result: false;
  382.     }
  383.  
  384.     // }}}
  385.     // {{{ numCols()
  386.  
  387.     
  388.     /**
  389.      * Gets the number of columns in a result set
  390.      *
  391.      * This method is not meant to be called directly.  Use
  392.      * DB_result::numCols() instead.  It can't be declared "protected"
  393.      * because DB_result is a separate object.
  394.      *
  395.      * @param resource $result  PHP's query result resource
  396.      *
  397.      * @return int  the number of columns.  A DB_Error object on failure.
  398.      *
  399.      * @see DB_result::numCols()
  400.      */
  401.     function numCols($result)
  402.     {
  403.         $cols @sybase_num_fields($result);
  404.         if (!$cols{
  405.             return $this->sybaseRaiseError();
  406.         }
  407.         return $cols;
  408.     }
  409.  
  410.     // }}}
  411.     // {{{ numRows()
  412.  
  413.     
  414.     /**
  415.      * Gets the number of rows in a result set
  416.      *
  417.      * This method is not meant to be called directly.  Use
  418.      * DB_result::numRows() instead.  It can't be declared "protected"
  419.      * because DB_result is a separate object.
  420.      *
  421.      * @param resource $result  PHP's query result resource
  422.      *
  423.      * @return int  the number of rows.  A DB_Error object on failure.
  424.      *
  425.      * @see DB_result::numRows()
  426.      */
  427.     function numRows($result)
  428.     {
  429.         $rows @sybase_num_rows($result);
  430.         if ($rows === false{
  431.             return $this->sybaseRaiseError();
  432.         }
  433.         return $rows;
  434.     }
  435.  
  436.     // }}}
  437.     // {{{ affectedRows()
  438.  
  439.     
  440.     /**
  441.      * Determines the number of rows affected by a data maniuplation query
  442.      *
  443.      * 0 is returned for queries that don't manipulate data.
  444.      *
  445.      * @return int  the number of rows.  A DB_Error object on failure.
  446.      */
  447.     function affectedRows()
  448.     {
  449.         if ($this->_last_query_manip{
  450.             $result @sybase_affected_rows($this->connection);
  451.         else {
  452.             $result = 0;
  453.         }
  454.         return $result;
  455.      }
  456.  
  457.     // }}}
  458.     // {{{ nextId()
  459.  
  460.     
  461.     /**
  462.      * Returns the next free id in a sequence
  463.      *
  464.      * @param string  $seq_name  name of the sequence
  465.      * @param boolean $ondemand  when true, the seqence is automatically
  466.      *                             created if it does not exist
  467.      *
  468.      * @return int  the next id number in the sequence.
  469.      *                A DB_Error object on failure.
  470.      *
  471.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  472.      *       DB_sybase::createSequence(), DB_sybase::dropSequence()
  473.      */
  474.     function nextId($seq_name$ondemand = true)
  475.     {
  476.         $seqname $this->getSequenceName($seq_name);
  477.         if ($this->_db && !@sybase_select_db($this->_db$this->connection)) {
  478.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  479.         }
  480.         $repeat = 0;
  481.         do {
  482.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  483.             $result $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
  484.             $this->popErrorHandling();
  485.             if ($ondemand && DB::isError($result&&
  486.                 ($result->getCode(== DB_ERROR || $result->getCode(== DB_ERROR_NOSUCHTABLE))
  487.             {
  488.                 $repeat = 1;
  489.                 $result $this->createSequence($seq_name);
  490.                 if (DB::isError($result)) {
  491.                     return $this->raiseError($result);
  492.                 }
  493.             elseif (!DB::isError($result)) {
  494.                 $result =$this->query("SELECT @@IDENTITY FROM $seqname");
  495.                 $repeat = 0;
  496.             else {
  497.                 $repeat = false;
  498.             }
  499.         while ($repeat);
  500.         if (DB::isError($result)) {
  501.             return $this->raiseError($result);
  502.         }
  503.         $result $result->fetchRow(DB_FETCHMODE_ORDERED);
  504.         return $result[0];
  505.     }
  506.  
  507.     /**
  508.      * Creates a new sequence
  509.      *
  510.      * @param string $seq_name  name of the new sequence
  511.      *
  512.      * @return int  DB_OK on success.  A DB_Error object on failure.
  513.      *
  514.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  515.      *       DB_sybase::nextID(), DB_sybase::dropSequence()
  516.      */
  517.     function createSequence($seq_name)
  518.     {
  519.         return $this->query('CREATE TABLE '
  520.                             . $this->getSequenceName($seq_name)
  521.                             . ' (id numeric(10, 0) IDENTITY NOT NULL,'
  522.                             . ' vapor int NULL)');
  523.     }
  524.  
  525.     // }}}
  526.     // {{{ dropSequence()
  527.  
  528.     
  529.     /**
  530.      * Deletes a sequence
  531.      *
  532.      * @param string $seq_name  name of the sequence to be deleted
  533.      *
  534.      * @return int  DB_OK on success.  A DB_Error object on failure.
  535.      *
  536.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  537.      *       DB_sybase::nextID(), DB_sybase::createSequence()
  538.      */
  539.     function dropSequence($seq_name)
  540.     {
  541.         return $this->query('DROP TABLE ' $this->getSequenceName($seq_name));
  542.     }
  543.  
  544.     // }}}
  545.     // {{{ quoteFloat()
  546.  
  547.     
  548.     /**
  549.      * Formats a float value for use within a query in a locale-independent
  550.      * manner.
  551.      *
  552.      * @param float the float value to be quoted.
  553.      * @return string the quoted string.
  554.      * @see DB_common::quoteSmart()
  555.      * @since Method available since release 1.7.8.
  556.      */
  557.     function quoteFloat($float{
  558.         return $this->escapeSimple(str_replace(',''.'strval(floatval($float))));
  559.     }
  560.      
  561.     // }}}
  562.     // {{{ autoCommit()
  563.  
  564.     
  565.     /**
  566.      * Enables or disables automatic commits
  567.      *
  568.      * @param bool $onoff  true turns it on, false turns it off
  569.      *
  570.      * @return int  DB_OK on success.  A DB_Error object if the driver
  571.      *                doesn't support auto-committing transactions.
  572.      */
  573.     function autoCommit($onoff = false)
  574.     {
  575.         // XXX if $this->transaction_opcount > 0, we should probably
  576.         // issue a warning here.
  577.         $this->autocommit $onoff ? true : false;
  578.         return DB_OK;
  579.     }
  580.  
  581.     // }}}
  582.     // {{{ commit()
  583.  
  584.     
  585.     /**
  586.      * Commits the current transaction
  587.      *
  588.      * @return int  DB_OK on success.  A DB_Error object on failure.
  589.      */
  590.     function commit()
  591.     {
  592.         if ($this->transaction_opcount > 0{
  593.             if ($this->_db && !@sybase_select_db($this->_db$this->connection)) {
  594.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  595.             }
  596.             $result @sybase_query('COMMIT'$this->connection);
  597.             $this->transaction_opcount = 0;
  598.             if (!$result{
  599.                 return $this->sybaseRaiseError();
  600.             }
  601.         }
  602.         return DB_OK;
  603.     }
  604.  
  605.     // }}}
  606.     // {{{ rollback()
  607.  
  608.     
  609.     /**
  610.      * Reverts the current transaction
  611.      *
  612.      * @return int  DB_OK on success.  A DB_Error object on failure.
  613.      */
  614.     function rollback()
  615.     {
  616.         if ($this->transaction_opcount > 0{
  617.             if ($this->_db && !@sybase_select_db($this->_db$this->connection)) {
  618.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  619.             }
  620.             $result @sybase_query('ROLLBACK'$this->connection);
  621.             $this->transaction_opcount = 0;
  622.             if (!$result{
  623.                 return $this->sybaseRaiseError();
  624.             }
  625.         }
  626.         return DB_OK;
  627.     }
  628.  
  629.     // }}}
  630.     // {{{ sybaseRaiseError()
  631.  
  632.     
  633.     /**
  634.      * Produces a DB_Error object regarding the current problem
  635.      *
  636.      * @param int $errno  if the error is being manually raised pass a
  637.      *                      DB_ERROR* constant here.  If this isn't passed
  638.      *                      the error information gathered from the DBMS.
  639.      *
  640.      * @return object  the DB_Error object
  641.      *
  642.      * @see DB_common::raiseError(),
  643.      *       DB_sybase::errorNative(), DB_sybase::errorCode()
  644.      */
  645.     function sybaseRaiseError($errno = null)
  646.     {
  647.         $native $this->errorNative();
  648.         if ($errno === null{
  649.             $errno $this->errorCode($native);
  650.         }
  651.         return $this->raiseError($errnonullnullnull$native);
  652.     }
  653.  
  654.     // }}}
  655.     // {{{ errorNative()
  656.  
  657.     
  658.     /**
  659.      * Gets the DBMS' native error message produced by the last query
  660.      *
  661.      * @return string  the DBMS' error message
  662.      */
  663.     function errorNative