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

Source for file odbc.php

Documentation is available at odbc.php

  1. <?php
  2.  
  3. // vim: set et ts=4 sw=4 fdm=marker:
  4.  
  5.  
  6. // Wrapper
  7. function odbc_query($query$connection{
  8.     //echo "\n".$connection."\n";
  9.     return odbc_do($connection$query);
  10. }
  11.  
  12. function odbc_fetch_row_wrapper($result{
  13.     return @array_values(odbc_fetch_array($result));
  14. }
  15.  
  16. function odbc_fetch_assoc ($result){
  17.     return odbc_fetch_array($result);
  18. }
  19.  
  20. // {{{ Class MDB2_Driver_odbc
  21. /**
  22.  * MDB2 odbc Server driver
  23.  *
  24.  * @package MDB2
  25.  * @category Database
  26.  * @author  Frank M. Kromann <frank@kromann.info> rewritten for ODBC by Philipp Schellhaas (mail@pschellhaas.de)
  27.  */
  28. class MDB2_Driver_odbc extends MDB2_Driver_Common
  29. {
  30.     // {{{ properties
  31.  
  32.     var $string_quoting = array('start' => "'"'end' => "'"'escape' => "'"'escape_pattern' => false);
  33.  
  34.     var $identifier_quoting = array('start' => '[''end' => ']''escape' => ']');
  35.  
  36.     // }}}
  37.     // {{{ constructor
  38.  
  39.     /**
  40.      * Constructor
  41.      */
  42.     function __construct()
  43.     {
  44.         parent::__construct();
  45.  
  46.         $this->phptype 'odbc';
  47.         $this->dbsyntax 'odbc';
  48.  
  49.         $this->supported['sequences''emulated';
  50.         $this->supported['indexes'= true;
  51.         $this->supported['affected_rows'= false;
  52.         $this->supported['transactions'= false;
  53.         $this->supported['savepoints'= false;
  54.         $this->supported['summary_functions'= true;
  55.         $this->supported['order_by_text'= true;
  56.         $this->supported['current_id''emulated';
  57.         $this->supported['limit_queries''emulated';
  58.         $this->supported['LOBs'= true;
  59.         $this->supported['replace''emulated';
  60.         $this->supported['sub_selects'= true;
  61.         $this->supported['triggers'= true;
  62.         $this->supported['auto_increment'= true;
  63.         $this->supported['primary_key'= true;
  64.         $this->supported['result_introspection'= false;
  65.         $this->supported['prepared_statements''emulated';
  66.         $this->supported['pattern_escaping'= true;
  67.         $this->supported['new_link'= true;
  68.  
  69.         $this->options['DBA_username'= false;
  70.         $this->options['DBA_password'= false;
  71.         $this->options['database_device'= false;
  72.         $this->options['database_size'= false;
  73.         $this->options['max_identifiers_length'= 128; // MS Access: 64
  74.     }
  75.  
  76.     // }}}
  77.     // {{{ errorInfo()
  78.  
  79.     /**
  80.      * This method is used to collect information about an error
  81.      *
  82.      * @param integer $error 
  83.      * @return array 
  84.      * @access public
  85.      */
  86.     function errorInfo($error = null$connection = null)
  87.     {
  88.         if (is_null($connection)) {
  89.             $connection $this->connection;
  90.         }
  91.  
  92.         $native_code = null;
  93.         if ($connection{
  94.             $result @odbc_query('select @@ERROR as ErrorCode'$connection);
  95.             if ($result{
  96.                 $native_code @odbc_result($result00);
  97.                 @odbc_free_result($result);
  98.             }
  99.         }
  100.         $native_msg @odbc_errormsg();
  101.         if (is_null($error)) {
  102.             static $ecode_map;
  103.             if (empty($ecode_map)) {
  104.                 $ecode_map = array(
  105.                     102   => MDB2_ERROR_SYNTAX,
  106.                     110   => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  107.                     155   => MDB2_ERROR_NOSUCHFIELD,
  108.                     156   => MDB2_ERROR_SYNTAX,
  109.                     170   => MDB2_ERROR_SYNTAX,
  110.                     207   => MDB2_ERROR_NOSUCHFIELD,
  111.                     208   => MDB2_ERROR_NOSUCHTABLE,
  112.                     245   => MDB2_ERROR_INVALID_NUMBER,
  113.                     319   => MDB2_ERROR_SYNTAX,
  114.                     321   => MDB2_ERROR_NOSUCHFIELD,
  115.                     325   => MDB2_ERROR_SYNTAX,
  116.                     336   => MDB2_ERROR_SYNTAX,
  117.                     515   => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  118.                     547   => MDB2_ERROR_CONSTRAINT,
  119.                     911   => MDB2_ERROR_NOT_FOUND,
  120.                     1018  => MDB2_ERROR_SYNTAX,
  121.                     1035  => MDB2_ERROR_SYNTAX,
  122.                     1801  => MDB2_ERROR_ALREADY_EXISTS,
  123.                     1913  => MDB2_ERROR_ALREADY_EXISTS,
  124.                     2209  => MDB2_ERROR_SYNTAX,
  125.                     2223  => MDB2_ERROR_SYNTAX,
  126.                     2248  => MDB2_ERROR_SYNTAX,
  127.                     2256  => MDB2_ERROR_SYNTAX,
  128.                     2257  => MDB2_ERROR_SYNTAX,
  129.                     2627  => MDB2_ERROR_CONSTRAINT,
  130.                     2714  => MDB2_ERROR_ALREADY_EXISTS,
  131.                     3607  => MDB2_ERROR_DIVZERO,
  132.                     3701  => MDB2_ERROR_NOSUCHTABLE,
  133.                     7630  => MDB2_ERROR_SYNTAX,
  134.                     8134  => MDB2_ERROR_DIVZERO,
  135.                     9303  => MDB2_ERROR_SYNTAX,
  136.                     9317  => MDB2_ERROR_SYNTAX,
  137.                     9318  => MDB2_ERROR_SYNTAX,
  138.                     9331  => MDB2_ERROR_SYNTAX,
  139.                     9332  => MDB2_ERROR_SYNTAX,
  140.                     15253 => MDB2_ERROR_SYNTAX,
  141.                 );
  142.             }
  143.             if (isset($ecode_map[$native_code])) {
  144.                 if ($native_code == 3701
  145.                     && preg_match('/Cannot drop the index/i'$native_msg)
  146.                 {
  147.                    $error = MDB2_ERROR_NOT_FOUND;
  148.                 else {
  149.                     $error $ecode_map[$native_code];
  150.                 }
  151.             }
  152.         }
  153.         return array($error$native_code$native_msg);
  154.     }
  155.  
  156.     // }}}
  157.     // {{{ function escapePattern($text)
  158.  
  159.     /**
  160.      * Quotes pattern (% and _) characters in a string)
  161.      *
  162.      * @param   string  the input string to quote
  163.      *
  164.      * @return  string  quoted string
  165.      *
  166.      * @access  public
  167.      */
  168.     function escapePattern($text)
  169.     {
  170.         $text str_replace("[""[ [ ]"$text);
  171.         foreach ($this->wildcards as $wildcard{
  172.             $text str_replace($wildcard'[' $wildcard ']'$text);
  173.         }
  174.         return $text;
  175.     }
  176.  
  177.     // }}}
  178.     // {{{ beginTransaction()
  179.  
  180.     /**
  181.      * Start a transaction or set a savepoint.
  182.      *
  183.      * @param   string  name of a savepoint to set
  184.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  185.      *
  186.      * @access  public
  187.      */
  188.     function beginTransaction($savepoint = null)
  189.     {
  190.         $this->debug('Starting transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  191.         if (!is_null($savepoint)) {
  192.             if (!$this->in_transaction{
  193.                 return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  194.                     'savepoint cannot be released when changes are auto committed'__FUNCTION__);
  195.             }
  196.             $query 'SAVE TRANSACTION '.$savepoint;
  197.             return $this->_doQuery($querytrue);
  198.         elseif ($this->in_transaction{
  199.             return MDB2_OK;  //nothing to do
  200.         }
  201.         if (!$this->destructor_registered && $this->opened_persistent{
  202.             $this->destructor_registered = true;
  203.             register_shutdown_function('MDB2_closeOpenTransactions');
  204.         }
  205.         $result =$this->_doQuery('BEGIN TRANSACTION'true);
  206.         if (MDB2::isError($result)) {
  207.             return $result;
  208.         }
  209.         $this->in_transaction = true;
  210.         return MDB2_OK;
  211.     }
  212.  
  213.     // }}}
  214.     // {{{ commit()
  215.  
  216.     /**
  217.      * Commit the database changes done during a transaction that is in
  218.      * progress or release a savepoint. This function may only be called when
  219.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  220.      * transaction is implicitly started after committing the pending changes.
  221.      *
  222.      * @param   string  name of a savepoint to release
  223.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  224.      *
  225.      * @access  public
  226.      */
  227.     function commit($savepoint = null)
  228.     {
  229.         $this->debug('Committing transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  230.         if (!$this->in_transaction{
  231.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  232.                 'commit/release savepoint cannot be done changes are auto committed'__FUNCTION__);
  233.         }
  234.         if (!is_null($savepoint)) {
  235.             return MDB2_OK;
  236.         }
  237.  
  238.         $result =$this->_doQuery('COMMIT TRANSACTION'true);
  239.         if (MDB2::isError($result)) {
  240.             return $result;
  241.         }
  242.         $this->in_transaction = false;
  243.         return MDB2_OK;
  244.     }
  245.  
  246.     // }}}
  247.     // {{{ rollback()
  248.  
  249.     /**
  250.      * Cancel any database changes done during a transaction or since a specific
  251.      * savepoint that is in progress. This function may only be called when
  252.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  253.      * transaction is implicitly started after canceling the pending changes.
  254.      *
  255.      * @param   string  name of a savepoint to rollback to
  256.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  257.      *
  258.      * @access  public
  259.      */
  260.     function rollback($savepoint = null)
  261.     {
  262.         $this->debug('Rolling back transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  263.         if (!$this->in_transaction{
  264.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  265.                 'rollback cannot be done changes are auto committed'__FUNCTION__);
  266.         }
  267.         if (!is_null($savepoint)) {
  268.             $query 'ROLLBACK TRANSACTION '.$savepoint;
  269.             return $this->_doQuery($querytrue);
  270.         }
  271.  
  272.         $result =$this->_doQuery('ROLLBACK TRANSACTION'true);
  273.         if (MDB2::isError($result)) {
  274.             return $result;
  275.         }
  276.         $this->in_transaction = false;
  277.         return MDB2_OK;
  278.     }
  279.  
  280.     // }}}
  281.     // {{{ _doConnect()
  282.  
  283.     /**
  284.      * do the grunt work of the connect
  285.      *
  286.      * @return connection on success or MDB2 Error Object on failure
  287.      * @access protected
  288.      */
  289.     function _doConnect($username$password$persistent = false)
  290.     {
  291.         if (!extension_loaded($this->phptype)) {
  292.             return $this->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  293.                 'extension '.$this->phptype.' is not compiled into PHP'__FUNCTION__);
  294.         }
  295.  
  296.         $params = array(
  297.             $this->dsn['hostspec'$this->dsn['hostspec''localhost',
  298.             $username $username : null,
  299.             $password $password : null,
  300.         );
  301.         if ($this->dsn['port']{
  302.             $params[0].= ((substr(PHP_OS03== 'WIN'',' ':').$this->dsn['port'];
  303.         }
  304.         if (!$persistent{
  305.             if ($this->_isNewLinkSet()) {
  306.                 $params[= true;
  307.             else {
  308.                 $params[= false;
  309.             }
  310.         }
  311.  
  312.  
  313.         $connect_function $persistent 'odbc_pconnect' 'odbc_connect';
  314.  
  315.  
  316.     $params = array($this->database_name,$this->dsn[username],$this->dsn[password]);
  317.         $connection @call_user_func_array($connect_function$params);
  318.  
  319.         if ($connection <= 0{
  320.  
  321.             return $this->raiseError(MDB2_ERROR_CONNECT_FAILEDnullnull,
  322.                 'unable to establish a connection'__FUNCTION____FUNCTION__);
  323.         }
  324.  
  325.         //odbc_query('SET ANSI_NULL_DFLT_ON ON', $connection);
  326.  
  327.         /*
  328.         if (!empty($this->dsn['charset'])) {
  329.             $result = $this->setCharset($this->dsn['charset'], $connection);
  330.             if (MDB2::isError($result)) {
  331.                 return $result;
  332.             }
  333.         }
  334.         */
  335.  
  336.        if ((bool)ini_get('odbc.datetimeconvert')) {
  337.            @ini_set('odbc.datetimeconvert''0');
  338.        }
  339.  
  340.        /*
  341.        if (empty($this->dsn['disable_iso_date'])) {
  342.            @odbc_query('SET DATEFORMAT ymd', $connection);
  343.        }
  344.        */
  345.  
  346.        return $connection;
  347.     }
  348.  
  349.     // }}}
  350.     // {{{ connect()
  351.  
  352.     /**
  353.      * Connect to the database
  354.      *
  355.      * @return true on success, MDB2 Error Object on failure
  356.      */
  357.     function connect()
  358.     {
  359.         if (is_resource($this->connection)) {
  360.             //if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
  361.             if (MDB2::areEquals($this->connected_dsn$this->dsn)
  362.                 && $this->opened_persistent == $this->options['persistent']
  363.             {
  364.                 return MDB2_OK;
  365.             }
  366.             $this->disconnect(false);
  367.         }
  368.  
  369.         $connection $this->_doConnect(
  370.             $this->dsn['username'],
  371.             $this->dsn['password'],
  372.             $this->options['persistent']
  373.         );
  374.         if (MDB2::isError($connection)) {
  375.             return $connection;
  376.         }
  377.  
  378.         $this->connection $connection;
  379.         $this->connected_dsn $this->dsn;
  380.         $this->connected_database_name '';
  381.         $this->opened_persistent $this->options['persistent'];
  382.         $this->dbsyntax $this->dsn['dbsyntax'$this->dsn['dbsyntax'$this->phptype;
  383.  
  384.         if ($this->database_name{
  385.             if ($this->database_name != $this->connected_database_name{
  386.                 /*
  387.                 if (!odbc_select_db($this->database_name, $connection)) {
  388.                     $err = $this->raiseError(null, null, null,
  389.                         'Could not select the database: '.$this->database_name, __FUNCTION__);
  390.                     return $err;
  391.                 }
  392.                 */
  393.                 $this->connected_database_name $this->database_name;
  394.             }
  395.         }
  396.  
  397.         return MDB2_OK;
  398.     }
  399.  
  400.     // }}}
  401.     // {{{ databaseExists()
  402.  
  403.     /**
  404.      * check if given database name is exists?
  405.      *
  406.      * @param string $name    name of the database that should be checked
  407.      *
  408.      * @return mixed true/false on success, a MDB2 error on failure
  409.      * @access public
  410.      */
  411.     function databaseExists($name)
  412.     {
  413.         $connection $this->_doConnect($this->dsn['username'],
  414.                                         $this->dsn['password'],
  415.                                         $this->options['persistent']);
  416.         if (MDB2::isError($connection)) {
  417.             return $connection;
  418.         }
  419.  
  420.         $result = odbc_select_db($name$connection);
  421.         $errorInfo $this->errorInfo(null$connection);
  422.         odbc_close($connection);
  423.         if (!$result{
  424.             if ($errorInfo[0!= MDB2_ERROR_NOT_FOUND{
  425.             exit;
  426.                 $result $this->raiseError($errorInfo[0]nullnull$errorInfo[2]__FUNCTION__);
  427.                 return $result;
  428.             }
  429.             $result = false;
  430.         }
  431.  
  432.         return $result;
  433.     }
  434.  
  435.     // }}}
  436.     // {{{ disconnect()
  437.  
  438.     /**
  439.      * Log out and disconnect from the database.
  440.      *
  441.      * @param  boolean $force if the disconnect should be forced even if the
  442.      *                         connection is opened persistently
  443.      * @return mixed true on success, false if not connected and error
  444.      *                 object on error
  445.      * @access public
  446.      */
  447.     function disconnect($force = true)
  448.     {
  449.         if (is_resource($this->connection)) {
  450.             if ($this->in_transaction{
  451.                 $dsn $this->dsn;
  452.                 $database_name $this->database_name;
  453.                 $persistent $this->options['persistent'];
  454.                 $this->dsn $this->connected_dsn;
  455.                 $this->database_name $this->connected_database_name;
  456.                 $this->options['persistent'$this->opened_persistent;
  457.                 $this->rollback();
  458.                 $this->dsn $dsn;
  459.                 $this->database_name $database_name;
  460.                 $this->options['persistent'$persistent;
  461.             }
  462.  
  463.             if (!$this->opened_persistent || $force{
  464.                 $ok = odbc_close($this->connection);
  465.                 if (!$ok{
  466.                     return $this->raiseError(MDB2_ERROR_DISCONNECT_FAILED,
  467.                            nullnullnull__FUNCTION__);
  468.                 }
  469.             }
  470.         else {
  471.             return false;
  472.         }
  473.         return parent::disconnect($force);
  474.     }
  475.  
  476.     // }}}
  477.     // {{{ standaloneQuery()
  478.  
  479.    /**
  480.      * execute a query as DBA
  481.      *
  482.      * @param string $query the SQL query
  483.      * @param mixed   $types  array that contains the types of the columns in
  484.      *                         the result set
  485.      * @param boolean $is_manip  if the query is a manipulation query
  486.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  487.      * @access public
  488.      */
  489.     function &standaloneQuery($query$types = null$is_manip = false)
  490.     {
  491.         $user $this->options['DBA_username']$this->options['DBA_username'$this->dsn['username'];
  492.         $pass $this->options['DBA_password']$this->options['DBA_password'$this->dsn['password'];
  493.         $connection $this->_doConnect($user$pass$this->options['persistent']);
  494.         if (MDB2::isError($connection)) {
  495.             return $connection;
  496.         }
  497.  
  498.         $offset $this->offset;
  499.         $limit $this->limit;
  500.         $this->offset $this->limit = 0;
  501.         $query $this->_modifyQuery($query$is_manip$limit$offset);
  502.  
  503.         $result =$this->_doQuery($query$is_manip$connection$this->database_name);
  504.         if (!MDB2::isError($result)) {
  505.             $result $this->_affectedRows($connection$result);
  506.         }
  507.  
  508.         odbc_close($connection);
  509.         return $result;
  510.     }
  511.  
  512.     // }}}
  513.     // {{{ _doQuery()
  514.  
  515.     /**
  516.      * Execute a query
  517.      * @param string $query  query
  518.      * @param boolean $is_manip  if the query is a manipulation query
  519.      * @param resource $connection 
  520.      * @param string $database_name 
  521.      * @return result or error object
  522.      * @access protected
  523.      */
  524.     function &_doQuery($query$is_manip = false$connection = null$database_name = null)
  525.     {
  526.          // echo "<hr>".$query."<br>\n";
  527.         $this->last_query $query;
  528.         $result $this->debug($query'query'array('is_manip' => $is_manip'when' => 'pre'));
  529.         if ($result{
  530.             if (MDB2::isError($result)) {
  531.                 return $result;
  532.             }
  533.             $query $result;
  534.         }
  535.         if ($this->options['disable_query']{
  536.             $result $is_manip ? 0 : null;
  537.             return $result;
  538.         }
  539.  
  540.         if (is_null($connection)) {
  541.             $connection $this->getConnection();
  542.             if (MDB2::isError($connection)) {
  543.                 return $connection;
  544.             }
  545.         }
  546.         if (is_null($database_name)) {
  547.             $database_name $this->database_name;
  548.         }
  549.  
  550.         if ($database_name{
  551.             if ($database_name != $this->connected_database_name{
  552.                 /*
  553.                 if (!odbc_select_db($database_name, $connection)) {
  554.                     $err = $this->raiseError(null, null, null,
  555.                         'Could not select the database: '.$database_name, __FUNCTION__);
  556.                     return $err;
  557.                 }
  558.                 */
  559.  
  560.                 $this->connected_database_name $database_name;
  561.             }
  562.         }
  563.  
  564.         $result odbc_query($query$connection);
  565.         if (!$result{
  566.             $err =$this->raiseError(nullnullnull,
  567.                 'Could not execute statement'__FUNCTION__);
  568.             return $err;
  569.         }
  570.  
  571.         $this->debug($query'query'array('is_manip' => $is_manip'when' => 'post''result' => $result));
  572.         //print_r(odbc_fetch_array($result));
  573.         return $result;
  574.     }
  575.  
  576.     // }}}
  577.     // {{{ _affectedRows()
  578.  
  579.     /**
  580.      * Returns the number of rows affected
  581.      *
  582.      * @param resource $result 
  583.      * @param resource $connection 
  584.      * @return mixed MDB2 Error Object or the number of rows affected
  585.      * @access private
  586.      */
  587.     function _affectedRows($connection$result = null)
  588.     {
  589.         if (is_null($connection)) {
  590.             $connection $this->getConnection();
  591.             if (MDB2::isError($connection)) {
  592.                 return $connection;
  593.             }
  594.         }
  595.         return odbc_rows_affected($connection);
  596.     }
  597.  
  598.     // }}}
  599.     // {{{ _modifyQuery()
  600.  
  601.     /**
  602.      * Changes a query string for various DBMS specific reasons
  603.      *
  604.      * @param string $query  query to modify
  605.      * @param boolean $is_manip  if it is a DML query
  606.      * @param integer $limit  limit the number of rows
  607.      * @param integer $offset  start reading from given offset
  608.      * @return string modified query
  609.      * @access protected
  610.      */
  611.     function _modifyQuery($query$is_manip$limit$offset)
  612.     {
  613.         if ($limit > 0{
  614.             $fetch $offset $limit;
  615.             if (!$is_manip{
  616.                 return preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',
  617.                     "\\1SELECT\\2 TOP $fetch"$query);
  618.             }
  619.         }
  620.         return $query;
  621.     }
  622.  
  623.     // }}}
  624.     // {{{ getServerVersion()
  625.  
  626.     /**
  627.      * return version information about the server
  628.      *
  629.      * @param bool   $native  determines if the raw version string should be returned
  630.      * @return mixed array/string with version information or MDB2 error object
  631.      * @access public
  632.      */
  633.     function getServerVersion($native = false)
  634.     {
  635.         if ($this->connected_server_info{
  636.             $server_info $this->connected_server_info;
  637.         else {
  638.             $query 'SELECT @@VERSION';
  639.             $server_info $this->queryOne($query'text');
  640.             if (MDB2::isError($server_info)) {
  641.                 return $server_info;
  642.             }
  643.         }
  644.         // cache server_info
  645.         $this->connected_server_info $server_info;
  646.         if (!$native && !MDB2::isError($server_info)) {
  647.             if (preg_match('/(\d+)\.(\d+)\.(\d+)/'$server_info$tmp)) {
  648.                 $server_info = array(
  649.                     'major' => $tmp[1],
  650.                     'minor' => $tmp[2],
  651.                     'patch' => $tmp[3],
  652.                     'extra' => null,
  653.                     'native' => $server_info,
  654.                 );
  655.             else {
  656.                 $server_info = array(
  657.                     'major' => null,
  658.                     'minor' => null,
  659.                     'patch' => null,
  660.                     'extra' => null,
  661.                     'native' => $server_info,
  662.                 );
  663.             }
  664.         }
  665.         return $server_info;
  666.     }
  667.  
  668.     // }}}
  669.     // {{{ _checkSequence
  670.  
  671.     /**
  672.      * Checks if there's a sequence that exists.
  673.      *
  674.      * @param  string $seq_name    The sequence name to verify.
  675.      * @return bool   $tableExists The value if the table exists or not
  676.      * @access private
  677.      */
  678.     function _checkSequence($seq_name)
  679.     {
  680.         $query = "SELECT * FROM $seq_name";
  681.         $tableExists =$this->_doQuery($querytrue);
  682.         if (MDB2::isError($tableExists)) {
  683.             if ($tableExists->getCode(== MDB2_ERROR_NOSUCHTABLE{
  684.                 return false;
  685.             }
  686.             //return $tableExists;
  687.             return false;
  688.         }
  689.         return odbc_result($tableExists00);
  690.     }
  691.  
  692.     // }}}
  693.     // {{{ nextID()
  694.  
  695.     /**
  696.      * Returns the next free id of a sequence
  697.      *
  698.      * @param string $seq_name name of the sequence
  699.      * @param boolean $ondemand when true the sequence is
  700.      *                           automatic created, if it
  701.      *                           not exists
  702.      *
  703.      * @return mixed MDB2 Error Object or id
  704.      * @access public
  705.      */
  706.     function nextID($seq_name$ondemand = true)
  707.     {
  708.         $sequence_name $this->quoteIdentifier($this->getSequenceName($seq_name)true);
  709.         $seqcol_name $this->quoteIdentifier($this->options['seqcol_name']true);
  710.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  711.         $this->expectError(MDB2_ERROR_NOSUCHTABLE);
  712.  
  713.         $seq_val $this->_checkSequence($sequence_name);
  714.  
  715.         if ($seq_val{
  716.             $query = "SET IDENTITY_INSERT $sequence_name OFF ".
  717.                      "INSERT INTO $sequence_name DEFAULT VALUES";
  718.         else {
  719.             $query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (0)";
  720.         }
  721.         $result =$this->_doQuery($querytrue);
  722.         $this->popExpect();
  723.         $this->popErrorHandling();
  724.         if (MDB2::isError($result)) {
  725.             if ($ondemand && !$this->_checkSequence($sequence_name)) {
  726.                 $this->loadModule('Manager'nulltrue);
  727.                 $result $this->manager->createSequence($seq_name);
  728.                 if (MDB2::isError($result)) {
  729.                     return $this->raiseError($resultnullnull,
  730.                         'on demand sequence '.$seq_name.' could not be created'__FUNCTION__);
  731.                 else {
  732.                     /**
  733.                      * Little off-by-one problem with the sequence emulation
  734.                      * here being fixed, that instead of re-calling nextID
  735.                      * and forcing an increment by one, we simply check if it
  736.                      * exists, then we get the last inserted id if it does.
  737.                      *
  738.                      * In theory, $seq_name should be created otherwise there would
  739.                      * have been an error thrown somewhere up there..
  740.                      *
  741.                      * @todo confirm
  742.                      */
  743.                     if ($this->_checkSequence($seq_name)) {
  744.                         return $this->lastInsertID($seq_name);
  745.                     }
  746.  
  747.                     return $this->nextID($seq_namefalse);
  748.                 }
  749.             }
  750.             return $result;
  751.         }
  752.         $value $this->lastInsertID($sequence_name);
  753.         if (is_numeric($value)) {
  754.             $query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
  755.             $result =$this->_doQuery($querytrue);
  756.             if (MDB2::isError($result)) {
  757.                 $this->warnings['nextID: could not delete previous sequence table values from '.$seq_name;
  758.             }
  759.         }
  760.         return $value;
  761.     }
  762.  
  763.     // }}}
  764.     // {{{ lastInsertID()
  765.  
  766.     /**
  767.      * Returns the autoincrement ID if supported or $id or fetches the current
  768.      * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
  769.      *
  770.      * @param string $table name of the table into which a new row was inserted
  771.      * @param string $field name of the field into which a new row was inserted
  772.      *
  773.      * @return mixed MDB2 Error Object or id
  774.      * @access public
  775.      */
  776.     function lastInsertID($table = null$field = null)
  777.     {
  778.         $server_info $this->getServerVersion();
  779.         if (is_array($server_info&& !is_null($server_info['major'])
  780.            && $server_info['major'>= 8
  781.         {
  782.             $query = "SELECT IDENT_CURRENT('$table')";
  783.         else {
  784.             $query "SELECT @@IDENTITY";
  785.             if (!is_null($table)) {
  786.                 $query .= ' FROM '.$this->quoteIdentifier($tabletrue);
  787.             }
  788.         }
  789.  
  790.         return $this->queryOne($query'integer');
  791.     }
  792.  
  793.     // }}}
  794. }
  795.  
  796. // }}}
  797. // {{{ Class MDB2_Result_odbc
  798.  
  799. /**
  800.  * MDB2 odbc Server result driver
  801.  *
  802.  * @package MDB2
  803.  * @category Database
  804.  * @author  Frank M. Kromann <frank@kromann.info>
  805.  */
  806. class MDB2_Result_odbc extends MDB2_Result_Common
  807. {
  808.     // {{{ _skipLimitOffset()
  809.  
  810.     /**
  811.      * Skip the first row of a result set.
  812.      *
  813.      * @param resource $result 
  814.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  815.      * @access protected
  816.      */
  817.     function _skipLimitOffset()
  818.     {
  819.         if ($this->limit{
  820.             if ($this->rownum >= $this->limit{
  821.                 return false;
  822.             }
  823.         }
  824.         if ($this->offset{
  825.             while ($this->offset_count $this->offset{
  826.                 ++$this->offset_count;
  827.                 if (!is_array(odbc_fetch_row_wrapper($this->result))) {
  828.                     $this->offset_count $this->limit;
  829.                     return false;
  830.                 }
  831.             }
  832.         }
  833.         return MDB2_OK;
  834.     }
  835.  
  836.     // }}}
  837.     // {{{ fetchRow()
  838.  
  839.     /**
  840.      * Fetch a row and insert the data into an existing array.
  841.      *
  842.      * @param int       $fetchmode  how the array data should be indexed
  843.      * @param int    $rownum    number of the row where the data can be found
  844.      * @return int data array on success, a MDB2 error on failure
  845.      * @access public
  846.      */
  847.     function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT$rownum = null)
  848.     {
  849.  
  850.         if (!$this->_skipLimitOffset()) {
  851.             $null = null;
  852.             return $null;
  853.         }
  854.         if (!is_null($rownum)) {
  855.             $seek $this->seek($rownum);
  856.             if (MDB2::isError($seek)) {
  857.                 return $seek;
  858.             }
  859.         }
  860.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  861.             $fetchmode $this->db->fetchmode;
  862.         }
  863.         if (   $fetchmode == MDB2_FETCHMODE_ASSOC
  864.             || $fetchmode == MDB2_FETCHMODE_OBJECT
  865.         {
  866.             $row odbc_fetch_assoc($this->result);
  867.  
  868.             if (is_array($row)
  869.                 && $this->db->options['portability'MDB2_PORTABILITY_FIX_CASE
  870.             {
  871.                 $row array_change_key_case($row$this->db->options['field_case']);
  872.             }
  873.         else {
  874.             $row odbc_fetch_row_wrapper($this->result);
  875.  
  876.  
  877.         }
  878.         if (!$row{
  879.             if ($this->result === false{
  880.                 $err =$this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  881.                     'resultset has already been freed'__FUNCTION__);
  882.                 return $err;
  883.             }
  884.             $null = null;
  885.             return $null;
  886.         }
  887.         $mode $this->db->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL;
  888.         $rtrim = false;
  889.         if ($this->db->options['portability'MDB2_PORTABILITY_RTRIM{
  890.             if (empty($this->types)) {
  891.                 $mode += MDB2_PORTABILITY_RTRIM;
  892.             else {
  893.                 $rtrim = true;
  894.             }
  895.         }
  896.         if ($mode{
  897.             $this->db->_fixResultArrayValues($row$mode);
  898.         }
  899.         if (   (   $fetchmode != MDB2_FETCHMODE_ASSOC
  900.                 && $fetchmode != MDB2_FETCHMODE_OBJECT)
  901.             && !empty($this->types)
  902.         {
  903.             $row $this->db->datatype->convertResultRow($this->types$row$rtrim);
  904.         elseif (($fetchmode == MDB2_FETCHMODE_ASSOC
  905.                 || $fetchmode == MDB2_FETCHMODE_OBJECT)
  906.             && !empty($this->types_assoc)
  907.         {
  908.             $row $this->db->datatype->convertResultRow($this->types_assoc$row$rtrim);
  909.         }
  910.         if (!empty($this->values)) {
  911.             $this->_assignBindColumns($row);
  912.         }
  913.         if ($fetchmode === MDB2_FETCHMODE_OBJECT{
  914.             $object_class $this->db->options['fetch_class'];
  915.             if ($object_class == 'stdClass'{
  916.                 $row = (object) $row;
  917.             else {
  918.                 $row = new $object_class($row);
  919.             }
  920.         }
  921.         ++$this->rownum;
  922.         return $row;
  923.     }
  924.  
  925.     // }}}
  926.     // {{{ _getColumnNames()
  927.  
  928.     /**
  929.      * Retrieve the names of columns returned by the DBMS in a query result.
  930.      *
  931.      * @return  mixed   Array variable that holds the names of columns as keys
  932.      *                   or an MDB2 error on failure.
  933.      *                   Some DBMS may not return any columns when the result set
  934.      *                   does not contain any rows.
  935.      * @access private
  936.      */
  937.     function _getColumnNames()
  938.     {
  939.         $columns = array();
  940.         $numcols $this->numCols();
  941.         if (MDB2::isError($numcols)) {
  942.             return $numcols;
  943.         }
  944.         for ($column = 0; $column $numcols$column++{
  945.             $column_name = odbc_field_name($this->result$column);
  946.             $columns[$column_name$column;
  947.         }
  948.         if ($this->db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  949.             $columns array_change_key_case($columns$this->db->options['field_case']);
  950.         }
  951.         return $columns;
  952.     }
  953.  
  954.     // }}}
  955.     // {{{ numCols()
  956.  
  957.     /**
  958.      * Count the number of columns returned by the DBMS in a query result.
  959.      *
  960.      * @return mixed integer value with the number of columns, a MDB2 error
  961.      *       on failure
  962.      * @access public
  963.      */
  964.     function numCols()
  965.     {
  966.         $cols = odbc_num_fields($this->result);
  967.         if (is_null($cols)) {
  968.             if ($this->result === false{
  969.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  970.                     'resultset has already been freed'__FUNCTION__);
  971.             elseif (is_null($this->result)) {
  972.                 return count($this->types);
  973.             }
  974.             return $this->db->raiseError(nullnullnull,
  975.                 'Could not get column count'__FUNCTION__);
  976.         }
  977.         return $cols;
  978.     }
  979.  
  980.     // }}}
  981.     // {{{ nextResult()
  982.  
  983.     /**
  984.      * Move the internal result pointer to the next available result
  985.      *
  986.      * @return true on success, false if there is no more result set or an error object on failure
  987.      * @access public
  988.      */
  989.     function nextResult()
  990.     {
  991.         if ($this->result === false{
  992.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  993.                 'resultset has already been freed'__FUNCTION__);
  994.         elseif (is_null($this->result)) {
  995.             return false;
  996.         }
  997.         return odbc_next_result($this->result);
  998.     }
  999.  
  1000.     // }}}
  1001.     // {{{ free()
  1002.  
  1003.     /**
  1004.      * Free the internal resources associated with $result.
  1005.      *
  1006.      * @return boolean true on success, false if $result is invalid
  1007.      * @access public
  1008.      */
  1009.     function free()
  1010.     {
  1011.         if (is_resource($this->result&& $this->db->connection{
  1012.             $free = odbc_free_result($this->result);
  1013.             if ($free === false{
  1014.                 return $this->db->raiseError(nullnullnull,
  1015.                     'Could not free result'__FUNCTION__);
  1016.             }
  1017.         }
  1018.         $this->result = false;
  1019.         return MDB2_OK;
  1020.     }
  1021.  
  1022.     // }}}
  1023. }
  1024.  
  1025. // }}}
  1026. // {{{ class MDB2_BufferedResult_odbc
  1027.  
  1028. /**
  1029.  * MDB2 odbc Server buffered result driver
  1030.  *
  1031.  * @package MDB2
  1032.  * @category Database
  1033.  * @author  Frank M. Kromann <frank@kromann.info>
  1034.  */
  1035. {
  1036.     // {{{ seek()
  1037.  
  1038.     /**
  1039.      * Seek to a specific row in a result set
  1040.      *
  1041.      * @param int    $rownum    number of the row where the data can be found
  1042.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1043.      * @access public
  1044.      */
  1045.     function seek($rownum = 0)
  1046.     {
  1047.         if ($this->rownum != ($rownum - 1&& !odbc_data_seek($this->result$rownum)) {
  1048.             if ($this->result === false{
  1049.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1050.                     'resultset has already been freed'__FUNCTION__);
  1051.             elseif (is_null($this->result)) {
  1052.                 return MDB2_OK;
  1053.             }
  1054.             return $this->db->raiseError(MDB2_ERROR_INVALIDnullnull,
  1055.                 'tried to seek to an invalid row number ('.$rownum.')'__FUNCTION__);
  1056.         }
  1057.         $this->rownum $rownum - 1;
  1058.         return MDB2_OK;
  1059.     }
  1060.  
  1061.     // }}}
  1062.     // {{{ valid()
  1063.  
  1064.     /**
  1065.      * Check if the end of the result set has been reached
  1066.      *
  1067.      * @return mixed true or false on sucess, a MDB2 error on failure
  1068.      * @access public
  1069.      */
  1070.     function valid()
  1071.     {
  1072.         $numrows $this->numRows();
  1073.         if (MDB2::isError($numrows)) {
  1074.             return $numrows;
  1075.         }
  1076.         return $this->rownum ($numrows - 1);
  1077.     }
  1078.  
  1079.     // }}}
  1080.     // {{{ numRows()
  1081.  
  1082.     /**
  1083.      * Returns the number of rows in a result object
  1084.      *
  1085.      * @return mixed MDB2 Error Object or the number of rows
  1086.      * @access public
  1087.      */
  1088.     function numRows()
  1089.     {
  1090.         $rows = odbc_num_rows($this->result);
  1091.  
  1092.         // Hack the Planet
  1093.         $count = 0;
  1094.         while ($row = odbc_fetch_row($this->result)) {
  1095.             $count++;
  1096.         }
  1097.         @odbc_fetch_row($this->result0);
  1098.         if($count >= 0{
  1099.             $rows $count;
  1100.         }
  1101.  
  1102.         if (is_null($rows)) {
  1103.             if ($this->result === false{
  1104.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1105.                     'resultset has already been freed'__FUNCTION__);
  1106.             elseif (is_null($this->result)) {
  1107.                 return 0;
  1108.             }
  1109.             return $this->db->raiseError(nullnullnull,
  1110.                 'Could not get row count'__FUNCTION__);
  1111.         }
  1112.         if ($this->limit{
  1113.             $rows -= $this->offset;
  1114.             if ($rows $this->limit{
  1115.                 $rows $this->limit;
  1116.             }
  1117.             if ($rows < 0{
  1118.                 $rows = 0;
  1119.             }
  1120.         }
  1121.         return $rows;
  1122.     }
  1123. }
  1124.  
  1125. // }}}
  1126. // {{{ MDB2_Statement_odbc
  1127.  
  1128. /**
  1129.  * MDB2 odbc Server statement driver
  1130.  *
  1131.  * @package MDB2
  1132.  * @category Database
  1133.  * @author  Frank M. Kromann <frank@kromann.info>
  1134.  */
  1135. class MDB2_Statement_odbc extends MDB2_Statement_Common
  1136. {
  1137.  
  1138. }
  1139.  
  1140. // }}}
  1141. ?>

Documentation generated on Mon, 11 Mar 2019 15:51:21 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.