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

Source for file odbc.php

Documentation is available at odbc.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Stig Bakken <ssb@php.net>                                    |
  17. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: odbc.php,v 1.47 2004/10/04 17:14:32 danielc Exp $
  21.  
  22.  
  23. // XXX legend:
  24. //  More info on ODBC errors could be found here:
  25. //  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp
  26. //
  27. // XXX ERRORMSG: The error message from the odbc function should
  28. //                 be registered here.
  29.  
  30.  
  31. require_once 'DB/common.php';
  32.  
  33. /**
  34.  * Database independent query interface definition for PHP's ODBC
  35.  * extension.
  36.  *
  37.  * @package  DB
  38.  * @version  $Id: odbc.php,v 1.47 2004/10/04 17:14:32 danielc Exp $
  39.  * @category Database
  40.  * @author   Stig Bakken <ssb@php.net>
  41.  */
  42. class DB_odbc extends DB_common
  43. {
  44.     // {{{ properties
  45.  
  46.     var $connection;
  47.     var $phptype$dbsyntax;
  48.     var $row = array();
  49.  
  50.     // }}}
  51.     // {{{ constructor
  52.  
  53.     function DB_odbc()
  54.     {
  55.         $this->DB_common();
  56.         $this->phptype = 'odbc';
  57.         $this->dbsyntax = 'sql92';
  58.         $this->features = array(
  59.             'prepare' => true,
  60.             'pconnect' => true,
  61.             'transactions' => false,
  62.             'limit' => 'emulate'
  63.         );
  64.         $this->errorcode_map = array(
  65.             '01004' => DB_ERROR_TRUNCATED,
  66.             '07001' => DB_ERROR_MISMATCH,
  67.             '21S01' => DB_ERROR_MISMATCH,
  68.             '21S02' => DB_ERROR_MISMATCH,
  69.             '22003' => DB_ERROR_INVALID_NUMBER,
  70.             '22005' => DB_ERROR_INVALID_NUMBER,
  71.             '22008' => DB_ERROR_INVALID_DATE,
  72.             '22012' => DB_ERROR_DIVZERO,
  73.             '23000' => DB_ERROR_CONSTRAINT,
  74.             '23502' => DB_ERROR_CONSTRAINT_NOT_NULL,
  75.             '23503' => DB_ERROR_CONSTRAINT,
  76.             '23505' => DB_ERROR_CONSTRAINT,
  77.             '24000' => DB_ERROR_INVALID,
  78.             '34000' => DB_ERROR_INVALID,
  79.             '37000' => DB_ERROR_SYNTAX,
  80.             '42000' => DB_ERROR_SYNTAX,
  81.             '42601' => DB_ERROR_SYNTAX,
  82.             'IM001' => DB_ERROR_UNSUPPORTED,
  83.             'S0000' => DB_ERROR_NOSUCHTABLE,
  84.             'S0001' => DB_ERROR_ALREADY_EXISTS,
  85.             'S0002' => DB_ERROR_NOSUCHTABLE,
  86.             'S0011' => DB_ERROR_ALREADY_EXISTS,
  87.             'S0012' => DB_ERROR_NOT_FOUND,
  88.             'S0021' => DB_ERROR_ALREADY_EXISTS,
  89.             'S0022' => DB_ERROR_NOSUCHFIELD,
  90.             'S1000' => DB_ERROR_CONSTRAINT_NOT_NULL,
  91.             'S1009' => DB_ERROR_INVALID,
  92.             'S1090' => DB_ERROR_INVALID,
  93.             'S1C00' => DB_ERROR_NOT_CAPABLE
  94.         );
  95.     }
  96.  
  97.     // }}}
  98.     // {{{ connect()
  99.  
  100.     /**
  101.      * Connect to a database and log in as the specified user.
  102.      *
  103.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  104.      * @param $persistent (optional) whether the connection should
  105.      *         be persistent
  106.      *
  107.      * @return int DB_OK on success, a DB error code on failure
  108.      */
  109.     function connect($dsninfo$persistent = false)
  110.     {
  111.         if (!DB::assertExtension('odbc')) {
  112.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  113.         }
  114.  
  115.         $this->dsn $dsninfo;
  116.         if ($dsninfo['dbsyntax']{
  117.             $this->dbsyntax = $dsninfo['dbsyntax'];
  118.         }
  119.         switch ($this->dbsyntax{
  120.             case 'solid':
  121.                 $this->features = array(
  122.                     'prepare' => true,
  123.                     'pconnect' => true,
  124.                     'transactions' => true
  125.                 );
  126.                 break;
  127.             case 'navision':
  128.                 // the Navision driver doesn't support fetch row by number
  129.                 $this->features['limit'= false;
  130.         }
  131.  
  132.         /*
  133.          * This is hear for backwards compatibility.
  134.          * Should have been using 'database' all along, but used hostspec.
  135.          */
  136.         if ($dsninfo['database']{
  137.             $odbcdsn $dsninfo['database'];
  138.         elseif ($dsninfo['hostspec']{
  139.             $odbcdsn $dsninfo['hostspec'];
  140.         else {
  141.             $odbcdsn 'localhost';
  142.         }
  143.  
  144.         if ($this->provides('pconnect')) {
  145.             $connect_function $persistent 'odbc_pconnect' 'odbc_connect';
  146.         else {
  147.             $connect_function 'odbc_connect';
  148.         }
  149.  
  150.         if (empty($dsninfo['cursor'])) {
  151.             $conn @$connect_function($odbcdsn$dsninfo['username'],
  152.                                        $dsninfo['password']);
  153.         else {
  154.             $conn @$connect_function($odbcdsn$dsninfo['username'],
  155.                                        $dsninfo['password'],
  156.                                        $dsninfo['cursor']);
  157.         }
  158.  
  159.         if (!is_resource($conn)) {
  160.             return $this->raiseError(DB_ERROR_CONNECT_FAILEDnullnull,
  161.                                          null$this->errorNative());
  162.         }
  163.         $this->connection = $conn;
  164.         return DB_OK;
  165.     }
  166.  
  167.     // }}}
  168.     // {{{ disconnect()
  169.  
  170.     function disconnect()
  171.     {
  172.         $err @odbc_close($this->connection);
  173.         $this->connection = null;
  174.         return $err;
  175.     }
  176.  
  177.     // }}}
  178.     // {{{ simpleQuery()
  179.  
  180.     /**
  181.      * Send a query to ODBC and return the results as a ODBC resource
  182.      * identifier.
  183.      *
  184.      * @param $query the SQL query
  185.      *
  186.      * @return int returns a valid ODBC result for successful SELECT
  187.      *  queries, DB_OK for other successful queries.  A DB error code
  188.      *  is returned on failure.
  189.      */
  190.     function simpleQuery($query)
  191.     {
  192.         $this->last_query = $query;
  193.         $query $this->modifyQuery($query);
  194.         $result @odbc_exec($this->connection$query);
  195.         if (!$result{
  196.             return $this->odbcRaiseError()// XXX ERRORMSG
  197.         }
  198.         // Determine which queries that should return data, and which
  199.         // should return an error code only.
  200.         if (DB::isManip($query)) {
  201.             $this->manip_result $result// For affectedRows()
  202.             return DB_OK;
  203.         }
  204.         $this->row[(int)$result= 0;
  205.         $this->manip_result = 0;
  206.         return $result;
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ nextResult()
  211.  
  212.     /**
  213.      * Move the internal odbc result pointer to the next available result
  214.      *
  215.      * @param valid fbsql result resource
  216.      *
  217.      * @access public
  218.      *
  219.      * @return true if a result is available otherwise return false
  220.      */
  221.     function nextResult($result)
  222.     {
  223.         return @odbc_next_result($result);
  224.     }
  225.  
  226.     // }}}
  227.     // {{{ fetchInto()
  228.  
  229.     /**
  230.      * Fetch a row and insert the data into an existing array.
  231.      *
  232.      * Formating of the array and the data therein are configurable.
  233.      * See DB_result::fetchInto() for more information.
  234.      *
  235.      * @param resource $result    query result identifier
  236.      * @param array    $arr       (reference) array where data from the row
  237.      *                             should be placed
  238.      * @param int      $fetchmode how the resulting array should be indexed
  239.      * @param int      $rownum    the row number to fetch
  240.      *
  241.      * @return mixed DB_OK on success, null when end of result set is
  242.      *                reached or on failure
  243.      *
  244.      * @see DB_result::fetchInto()
  245.      * @access private
  246.      */
  247.     function fetchInto($result&$arr$fetchmode$rownum=null)
  248.     {
  249.         $arr = array();
  250.         if ($rownum !== null{
  251.             $rownum++; // ODBC first row is 1
  252.             if (version_compare(phpversion()'4.2.0''ge')) {
  253.                 $cols @odbc_fetch_into($result$arr$rownum);
  254.             else {
  255.                 $cols @odbc_fetch_into($result$rownum$arr);
  256.             }
  257.         else {
  258.             $cols @odbc_fetch_into($result$arr);
  259.         }
  260.  
  261.         if (!$cols{
  262.             /* XXX FIXME: doesn't work with unixODBC and easysoft
  263.                           (get corrupted $errno values)
  264.             if ($errno = @odbc_error($this->connection)) {
  265.                 return $this->RaiseError($errno);
  266.             }*/
  267.             return null;
  268.         }
  269.         if ($fetchmode !== DB_FETCHMODE_ORDERED{
  270.             for ($i = 0; $i count($arr)$i++{
  271.                 $colName @odbc_field_name($result$i+1);
  272.                 $a[$colName$arr[$i];
  273.             }
  274.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE{
  275.                 $a array_change_key_case($aCASE_LOWER);
  276.             }
  277.             $arr $a;
  278.         }
  279.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  280.             $this->_rtrimArrayValues($arr);
  281.         }
  282.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  283.             $this->_convertNullArrayValuesToEmpty($arr);
  284.         }
  285.         return DB_OK;
  286.     }
  287.  
  288.     // }}}
  289.     // {{{ freeResult()
  290.  
  291.     function freeResult($result)
  292.     {
  293.         unset($this->row[(int)$result]);
  294.         return @odbc_free_result($result);
  295.     }
  296.  
  297.     // }}}
  298.     // {{{ numCols()
  299.  
  300.     function numCols($result)
  301.     {
  302.         $cols @odbc_num_fields($result);
  303.         if (!$cols{
  304.             return $this->odbcRaiseError();
  305.         }
  306.         return $cols;
  307.     }
  308.  
  309.     // }}}
  310.     // {{{ affectedRows()
  311.  
  312.     /**
  313.      * Returns the number of rows affected by a manipulative query
  314.      * (INSERT, DELETE, UPDATE)
  315.      * @return mixed int affected rows, 0 when non manip queries or
  316.      *                DB error on error
  317.      */
  318.     function affectedRows()
  319.     {
  320.         if (empty($this->manip_result)) {  // In case of SELECT stms
  321.             return 0;
  322.         }
  323.         $nrows @odbc_num_rows($this->manip_result);
  324.         if ($nrows == -1{
  325.             return $this->odbcRaiseError();
  326.         }
  327.         return $nrows;
  328.     }
  329.  
  330.     // }}}
  331.     // {{{ numRows()
  332.  
  333.     /**
  334.      * ODBC may or may not support counting rows in the result set of
  335.      * SELECTs.
  336.      *
  337.      * @param $result the odbc result resource
  338.      * @return the number of rows, or 0
  339.      */
  340.     function numRows($result)
  341.     {
  342.         $nrows @odbc_num_rows($result);
  343.         if ($nrows == -1{
  344.             return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED);
  345.         }
  346.         return $nrows;
  347.     }
  348.  
  349.     // }}}
  350.     // {{{ quoteIdentifier()
  351.  
  352.     /**
  353.      * Quote a string so it can be safely used as a table / column name
  354.      *
  355.      * Quoting style depends on which dbsyntax was passed in the DSN.
  356.      *
  357.      * Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
  358.      * "Use ANSI quoted identifiers" when setting up the ODBC data source.
  359.      *
  360.      * @param string $str  identifier name to be quoted
  361.      *
  362.      * @return string  quoted identifier string
  363.      *
  364.      * @since 1.6.0
  365.      * @access public
  366.      */
  367.     function quoteIdentifier($str)
  368.     {
  369.         switch ($this->dsn['dbsyntax']{
  370.             case 'access':
  371.                 return '[' $str ']';
  372.             case 'mssql':
  373.             case 'sybase':
  374.                 return '[' str_replace(']'']]'$str']';
  375.             case 'mysql':
  376.             case 'mysqli':
  377.                 return '`' $str '`';
  378.             default:
  379.                 return '"' str_replace('"''""'$str'"';
  380.         }
  381.     }
  382.  
  383.     // }}}
  384.     // {{{ quote()
  385.  
  386.     /**
  387.      * @deprecated  Deprecated in release 1.6.0
  388.      * @internal
  389.      */
  390.     function quote($str{
  391.         return $this->quoteSmart($str);
  392.     }
  393.  
  394.     // }}}
  395.     // {{{ errorNative()
  396.  
  397.     /**
  398.      * Get the native error code of the last error (if any) that
  399.      * occured on the current connection.
  400.      *
  401.      * @access public
  402.      *
  403.      * @return int ODBC error code
  404.      */
  405.     function errorNative()
  406.     {
  407.         if (!isset($this->connection|| !is_resource($this->connection)) {
  408.             return @odbc_error(' ' @odbc_errormsg();
  409.         }
  410.         return @odbc_error($this->connection' ' @odbc_errormsg($this->connection);
  411.     }
  412.  
  413.     // }}}
  414.     // {{{ nextId()
  415.  
  416.     /**
  417.      * Returns the next free id in a sequence
  418.      *
  419.      * @param string  $seq_name  name of the sequence
  420.      * @param boolean $ondemand  when true, the seqence is automatically
  421.      *                            created if it does not exist
  422.      *
  423.      * @return int  the next id number in the sequence.  DB_Error if problem.
  424.      *
  425.      * @internal
  426.      * @see DB_common::nextID()
  427.      * @access public
  428.      */
  429.     function nextId($seq_name$ondemand = true)
  430.     {
  431.         $seqname $this->getSequenceName($seq_name);
  432.         $repeat = 0;
  433.         do {
  434.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  435.             $result $this->query("update ${seqname} set id = id + 1");
  436.             $this->popErrorHandling();
  437.             if ($ondemand && DB::isError($result&&
  438.                 $result->getCode(== DB_ERROR_NOSUCHTABLE{
  439.                 $repeat = 1;
  440.                 $this->pushErrorHandling(PEAR_ERROR_RETURN);
  441.                 $result $this->createSequence($seq_name);
  442.                 $this->popErrorHandling();
  443.                 if (DB::isError($result)) {
  444.                     return $this->raiseError($result);
  445.                 }
  446.                 $result $this->query("insert into ${seqname} (id) values(0)");
  447.             else {
  448.                 $repeat = 0;
  449.             }
  450.         while ($repeat);
  451.  
  452.         if (DB::isError($result)) {
  453.             return $this->raiseError($result);
  454.         }
  455.  
  456.         $result $this->query("select id from ${seqname}");
  457.         if (DB::isError($result)) {
  458.             return $result;
  459.         }
  460.  
  461.         $row $result->fetchRow(DB_FETCHMODE_ORDERED);
  462.         if (DB::isError($row || !$row)) {
  463.             return $row;
  464.         }
  465.  
  466.         return $row[0];
  467.     }
  468.  
  469.     /**
  470.      * Creates a new sequence
  471.      *
  472.      * @param string $seq_name  name of the new sequence
  473.      *
  474.      * @return int  DB_OK on success.  A DB_Error object is returned if
  475.      *               problems arise.
  476.      *
  477.      * @internal
  478.      * @see DB_common::createSequence()
  479.      * @access public
  480.      */
  481.     function createSequence($seq_name)
  482.     {
  483.         $seqname $this->getSequenceName($seq_name);
  484.         return $this->query("CREATE TABLE ${seqname} ".
  485.                             '(id integer NOT NULL,'.
  486.                             ' PRIMARY KEY(id))');
  487.     }
  488.  
  489.     // }}}
  490.     // {{{ dropSequence()
  491.  
  492.     /**
  493.      * Deletes a sequence
  494.      *
  495.      * @param string $seq_name  name of the sequence to be deleted
  496.      *
  497.      * @return int  DB_OK on success.  DB_Error if problems.
  498.      *
  499.      * @internal
  500.      * @see DB_common::dropSequence()
  501.      * @access public
  502.      */
  503.     function dropSequence($seq_name)
  504.     {
  505.         $seqname $this->getSequenceName($seq_name);
  506.         return $this->query("DROP TABLE ${seqname}");
  507.     }
  508.  
  509.     // }}}
  510.     // {{{ autoCommit()
  511.  
  512.     function autoCommit($onoff = false)
  513.     {
  514.         if (!@odbc_autocommit($this->connection$onoff)) {
  515.             return $this->odbcRaiseError();
  516.         }
  517.         return DB_OK;
  518.     }
  519.  
  520.     // }}}
  521.     // {{{ commit()
  522.  
  523.     function commit()
  524.     {
  525.         if (!@odbc_commit($this->connection)) {
  526.             return $this->odbcRaiseError();
  527.         }
  528.         return DB_OK;
  529.     }
  530.  
  531.     // }}}
  532.     // {{{ rollback()
  533.  
  534.     function rollback()
  535.     {
  536.         if (!@odbc_rollback($this->connection)) {
  537.             return $this->odbcRaiseError();
  538.         }
  539.         return DB_OK;
  540.     }
  541.  
  542.     // }}}
  543.     // {{{ odbcRaiseError()
  544.  
  545.     /**
  546.      * Gather information about an error, then use that info to create a
  547.      * DB error object and finally return that object.
  548.      *
  549.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  550.      *                           manually raising an error
  551.      * @return object  DB error object
  552.      * @see errorNative()
  553.      * @see DB_common::errorCode()
  554.      * @see DB_common::raiseError()
  555.      */
  556.     function odbcRaiseError($errno = null)
  557.     {
  558.         if ($errno === null{
  559.             switch ($this->dbsyntax{
  560.                 case 'access':
  561.                     if ($this->options['portability'DB_PORTABILITY_ERRORS{
  562.                         $this->errorcode_map['07001'DB_ERROR_NOSUCHFIELD;
  563.                     else {
  564.                         // Doing this in case mode changes during runtime.
  565.                         $this->errorcode_map['07001'DB_ERROR_MISMATCH;
  566.                     }
  567.             }
  568.             $errno $this->errorCode(odbc_error($this->connection));
  569.         }
  570.         return $this->raiseError($errnonullnullnull,
  571.                         $this->errorNative());
  572.     }
  573.  
  574.     // }}}
  575.  
  576. }
  577.  
  578. /*
  579.  * Local variables:
  580.  * tab-width: 4
  581.  * c-basic-offset: 4
  582.  * End:
  583.  */
  584.  
  585. ?>

Documentation generated on Mon, 11 Mar 2019 13:56:44 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.