home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 April / PCWorld_2005-04_cd.bin / akce / web / phptriad / phptriad2-2-1.exe / php / pear / DB.php < prev    next >
PHP Script  |  2001-11-13  |  26KB  |  794 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2001 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. // | Authors: Stig Bakken <ssb@fast.no>                                   |
  17. // |          Tomas V.V.Cox <cox@idecnet.com>                             |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: DB.php,v 1.73.2.2 2001/11/13 01:26:39 ssb Exp $
  21. //
  22. // Database independent query interface.
  23. //
  24.  
  25. require_once "PEAR.php";
  26.  
  27. /*
  28.  * The method mapErrorCode in each DB_dbtype implementation maps
  29.  * native error codes to one of these.
  30.  *
  31.  * If you add an error code here, make sure you also add a textual
  32.  * version of it in DB::errorMessage().
  33.  */
  34.  
  35. define("DB_OK",                         1);
  36. define("DB_ERROR",                     -1);
  37. define("DB_ERROR_SYNTAX",              -2);
  38. define("DB_ERROR_CONSTRAINT",          -3);
  39. define("DB_ERROR_NOT_FOUND",           -4);
  40. define("DB_ERROR_ALREADY_EXISTS",      -5);
  41. define("DB_ERROR_UNSUPPORTED",         -6);
  42. define("DB_ERROR_MISMATCH",            -7);
  43. define("DB_ERROR_INVALID",             -8);
  44. define("DB_ERROR_NOT_CAPABLE",         -9);
  45. define("DB_ERROR_TRUNCATED",          -10);
  46. define("DB_ERROR_INVALID_NUMBER",     -11);
  47. define("DB_ERROR_INVALID_DATE",       -12);
  48. define("DB_ERROR_DIVZERO",            -13);
  49. define("DB_ERROR_NODBSELECTED",       -14);
  50. define("DB_ERROR_CANNOT_CREATE",      -15);
  51. define("DB_ERROR_CANNOT_DELETE",      -16);
  52. define("DB_ERROR_CANNOT_DROP",        -17);
  53. define("DB_ERROR_NOSUCHTABLE",        -18);
  54. define("DB_ERROR_NOSUCHFIELD",        -19);
  55. define("DB_ERROR_NEED_MORE_DATA",     -20);
  56. define("DB_ERROR_NOT_LOCKED",         -21);
  57. define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
  58. define("DB_ERROR_INVALID_DSN",        -23);
  59. define("DB_ERROR_CONNECT_FAILED",     -24);
  60. define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
  61.  
  62. /*
  63.  * Warnings are not detected as errors by DB::isError(), and are not
  64.  * fatal.  You can detect whether an error is in fact a warning with
  65.  * DB::isWarning().
  66.  */
  67.  
  68. define('DB_WARNING',           -1000);
  69. define('DB_WARNING_READ_ONLY', -1001);
  70.  
  71. /*
  72.  * These constants are used when storing information about prepared
  73.  * statements (using the "prepare" method in DB_dbtype).
  74.  *
  75.  * The prepare/execute model in DB is mostly borrowed from the ODBC
  76.  * extension, in a query the "?" character means a scalar parameter.
  77.  * There are two extensions though, a "&" character means an opaque
  78.  * parameter.  An opaque parameter is simply a file name, the real
  79.  * data are in that file (useful for putting uploaded files into your
  80.  * database and such). The "!" char means a parameter that must be
  81.  * left as it is.
  82.  * They modify the quote behavoir:
  83.  * DB_PARAM_SCALAR (?) => 'original string quoted'
  84.  * DB_PARAM_OPAQUE (&) => 'string from file quoted'
  85.  * DB_PARAM_MISC   (!) => original string
  86.  */
  87.  
  88. define('DB_PARAM_SCALAR', 1);
  89. define('DB_PARAM_OPAQUE', 2);
  90. define('DB_PARAM_MISC',   3);
  91.  
  92. /*
  93.  * These constants define different ways of returning binary data
  94.  * from queries.  Again, this model has been borrowed from the ODBC
  95.  * extension.
  96.  *
  97.  * DB_BINMODE_PASSTHRU sends the data directly through to the browser
  98.  * when data is fetched from the database.
  99.  * DB_BINMODE_RETURN lets you return data as usual.
  100.  * DB_BINMODE_CONVERT returns data as well, only it is converted to
  101.  * hex format, for example the string "123" would become "313233".
  102.  */
  103.  
  104. define('DB_BINMODE_PASSTHRU', 1);
  105. define('DB_BINMODE_RETURN',   2);
  106. define('DB_BINMODE_CONVERT',  3);
  107.  
  108. /**
  109.  * This is a special constant that tells DB the user hasn't specified
  110.  * any particular get mode, so the default should be used.
  111.  */
  112.  
  113. define('DB_FETCHMODE_DEFAULT', 0);
  114.  
  115. /**
  116.  * Column data indexed by numbers, ordered from 0 and up
  117.  */
  118.  
  119. define('DB_FETCHMODE_ORDERED', 1);
  120.  
  121. /**
  122.  * Column data indexed by column names
  123.  */
  124.  
  125. define('DB_FETCHMODE_ASSOC', 2);
  126.  
  127. /**
  128. * Column data as object properties
  129. */
  130.  
  131. define('DB_FETCHMODE_OBJECT', 3);
  132.  
  133. /**
  134.  * For multi-dimensional results: normally the first level of arrays
  135.  * is the row number, and the second level indexed by column number or name.
  136.  * DB_FETCHMODE_FLIPPED switches this order, so the first level of arrays
  137.  * is the column name, and the second level the row number.
  138.  */
  139.  
  140. define('DB_FETCHMODE_FLIPPED', 4);
  141.  
  142. /* for compatibility */
  143.  
  144. define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
  145. define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);
  146. define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED);
  147.  
  148. /**
  149.  * these are constants for the tableInfo-function
  150.  * they are bitwised or'ed. so if there are more constants to be defined
  151.  * in the future, adjust DB_TABLEINFO_FULL accordingly
  152.  */
  153.  
  154. define('DB_TABLEINFO_ORDER', 1);
  155. define('DB_TABLEINFO_ORDERTABLE', 2);
  156. define('DB_TABLEINFO_FULL', 3);
  157.  
  158.  
  159. /**
  160.  * The main "DB" class is simply a container class with some static
  161.  * methods for creating DB objects as well as some utility functions
  162.  * common to all parts of DB.
  163.  *
  164.  * The object model of DB is as follows (indentation means inheritance):
  165.  *
  166.  * DB           The main DB class.  This is simply a utility class
  167.  *              with some "static" methods for creating DB objects as
  168.  *              well as common utility functions for other DB classes.
  169.  *
  170.  * DB_common    The base for each DB implementation.  Provides default
  171.  * |            implementations (in OO lingo virtual methods) for
  172.  * |            the actual DB implementations as well as a bunch of
  173.  * |            query utility functions.
  174.  * |
  175.  * +-DB_mysql   The DB implementation for MySQL.  Inherits DB_common.
  176.  *              When calling DB::factory or DB::connect for MySQL
  177.  *              connections, the object returned is an instance of this
  178.  *              class.
  179.  *
  180.  * @package  DB
  181.  * @version  2
  182.  * @author   Stig Bakken <ssb@fast.no>
  183.  * @since    PHP 4.0
  184.  */
  185.  
  186. class DB
  187. {
  188.     /**
  189.      * Create a new DB connection object for the specified database
  190.      * type
  191.      *
  192.      * @param $type string database type, for example "mysql"
  193.      *
  194.      * @return object a newly created DB object, or a DB error code on
  195.      * error
  196.      */
  197.  
  198.     function &factory($type)
  199.     {
  200.         @include_once("DB/${type}.php");
  201.  
  202.         $classname = "DB_${type}";
  203.  
  204.         if (!class_exists($classname)) {
  205.             return PEAR::raiseError(null, DB_ERROR_NOT_FOUND,
  206.                                     null, null, null, 'DB_Error', true);
  207.         }
  208.  
  209.         @$obj =& new $classname;
  210.  
  211.         return $obj;
  212.     }
  213.  
  214.     /**
  215.      * Create a new DB connection object and connect to the specified
  216.      * database
  217.      *
  218.      * @param $dsn mixed "data source name", see the DB::parseDSN
  219.      * method for a description of the dsn format.  Can also be
  220.      * specified as an array of the format returned by DB::parseDSN.
  221.      *
  222.      * @param $options mixed An associative array of option names and
  223.      * their values.  For backwards compatibility, this parameter may
  224.      * also be a boolean that tells whether the connection should be
  225.      * persistent.  See DB_common::setOption for more information on
  226.      * connection options.
  227.      *
  228.      * @return object a newly created DB connection object, or a DB
  229.      * error object on error
  230.      *
  231.      * @see DB::parseDSN
  232.      * @see DB::isError
  233.      * @see DB_common::setOption
  234.      */
  235.     function &connect($dsn, $options = false)
  236.     {
  237.         if (is_array($dsn)) {
  238.             $dsninfo = $dsn;
  239.         } else {
  240.             $dsninfo = DB::parseDSN($dsn);
  241.         }
  242.         $type = $dsninfo["phptype"];
  243.  
  244.         if (is_array($options) && isset($options["debug"]) &&
  245.             $options["debug"] >= 2) {
  246.             // expose php errors with sufficient debug level
  247.             include_once "DB/${type}.php";
  248.         } else {
  249.             @include_once "DB/${type}.php";
  250.         }
  251.  
  252.         $classname = "DB_${type}";
  253.         if (!class_exists($classname)) {
  254.             return PEAR::raiseError(null, DB_ERROR_NOT_FOUND,
  255.                                     null, null, null, 'DB_Error', true);
  256.         }
  257.  
  258.         @$obj =& new $classname;
  259.  
  260.         if (is_array($options)) {
  261.             foreach ($options as $option => $value) {
  262.                 $test = $obj->setOption($option, $value);
  263.                 if (DB::isError($test)) {
  264.                     return $test;
  265.                 }
  266.             }
  267.         } else {
  268.             $obj->setOption('persistent', $options);
  269.         }
  270.         $err = $obj->connect($dsninfo, $obj->getOption('persistent'));
  271.  
  272.         if (DB::isError($err)) {
  273.             $err->addUserInfo($dsn);
  274.             return $err;
  275.         }
  276.  
  277.         return $obj;
  278.     }
  279.  
  280.     /**
  281.      * Return the DB API version
  282.      *
  283.      * @return int the DB API version number
  284.      */
  285.     function apiVersion()
  286.     {
  287.         return 2;
  288.     }
  289.  
  290.     /**
  291.      * Tell whether a result code from a DB method is an error
  292.      *
  293.      * @param $value int result code
  294.      *
  295.      * @return bool whether $value is an error
  296.      */
  297.     function isError($value)
  298.     {
  299.         return (is_object($value) &&
  300.                 (get_class($value) == 'db_error' ||
  301.                  is_subclass_of($value, 'db_error')));
  302.     }
  303.  
  304.     /**
  305.      * Tell whether a query is a data manipulation query (insert,
  306.      * update or delete) or a data definition query (create, drop,
  307.      * alter, grant, revoke).
  308.      *
  309.      * @access public
  310.      *
  311.      * @param string the query
  312.      *
  313.      * @return bool whether $query is a data manipulation query
  314.      */
  315.     function isManip($query)
  316.     {
  317.         $manips = 'INSERT|UPDATE|DELETE|'.'REPLACE|CREATE|DROP|'.
  318.                   'ALTER|GRANT|REVOKE|'.'LOCK|UNLOCK';
  319.         if (preg_match('/^\s*"?('.$manips.')\s+/i', $query)) {
  320.             return true;
  321.         }
  322.         return false;
  323.     }
  324.  
  325.     /**
  326.      * Tell whether a result code from a DB method is a warning.
  327.      * Warnings differ from errors in that they are generated by DB,
  328.      * and are not fatal.
  329.      *
  330.      * @param $value mixed result value
  331.      *
  332.      * @return bool whether $value is a warning
  333.      */
  334.     function isWarning($value)
  335.     {
  336.         return (is_object($value) &&
  337.                 (get_class($value) == "db_warning" ||
  338.                  is_subclass_of($value, "db_warning")));
  339.     }
  340.  
  341.     /**
  342.      * Return a textual error message for a DB error code
  343.      *
  344.      * @param $value int error code
  345.      *
  346.      * @return string error message, or false if the error code was
  347.      * not recognized
  348.      */
  349.     function errorMessage($value)
  350.     {
  351.         static $errorMessages;
  352.         if (!isset($errorMessages)) {
  353.             $errorMessages = array(
  354.                 DB_ERROR                    => 'unknown error',
  355.                 DB_ERROR_ALREADY_EXISTS     => 'already exists',
  356.                 DB_ERROR_CANNOT_CREATE      => 'can not create',
  357.                 DB_ERROR_CANNOT_DELETE      => 'can not delete',
  358.                 DB_ERROR_CANNOT_DROP        => 'can not drop',
  359.                 DB_ERROR_CONSTRAINT         => 'constraint violation',
  360.                 DB_ERROR_DIVZERO            => 'division by zero',
  361.                 DB_ERROR_INVALID            => 'invalid',
  362.                 DB_ERROR_INVALID_DATE       => 'invalid date or time',
  363.                 DB_ERROR_INVALID_NUMBER     => 'invalid number',
  364.                 DB_ERROR_MISMATCH           => 'mismatch',
  365.                 DB_ERROR_NODBSELECTED       => 'no database selected',
  366.                 DB_ERROR_NOSUCHFIELD        => 'no such field',
  367.                 DB_ERROR_NOSUCHTABLE        => 'no such table',
  368.                 DB_ERROR_NOT_CAPABLE        => 'DB backend not capable',
  369.                 DB_ERROR_NOT_FOUND          => 'not found',
  370.                 DB_ERROR_NOT_LOCKED         => 'not locked',
  371.                 DB_ERROR_SYNTAX             => 'syntax error',
  372.                 DB_ERROR_UNSUPPORTED        => 'not supported',
  373.                 DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
  374.                 DB_ERROR_INVALID_DSN        => 'invalid DSN',
  375.                 DB_ERROR_CONNECT_FAILED     => 'connect failed',
  376.                 DB_OK                       => 'no error',
  377.                 DB_WARNING                  => 'unknown warning',
  378.                 DB_WARNING_READ_ONLY        => 'read only',
  379.                 DB_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
  380.                 DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found'
  381.             );
  382.         }
  383.  
  384.         if (DB::isError($value)) {
  385.             $value = $value->getCode();
  386.         }
  387.  
  388.         return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[DB_ERROR];
  389.     }
  390.  
  391.     /**
  392.      * Parse a data source name
  393.      *
  394.      * @param $dsn string Data Source Name to be parsed
  395.      *
  396.      * @return array an associative array with the following keys:
  397.      *
  398.      *  phptype: Database backend used in PHP (mysql, odbc etc.)
  399.      *  dbsyntax: Database used with regards to SQL syntax etc.
  400.      *  protocol: Communication protocol to use (tcp, unix etc.)
  401.      *  hostspec: Host specification (hostname[:port])
  402.      *  database: Database to use on the DBMS server
  403.      *  username: User name for login
  404.      *  password: Password for login
  405.      *
  406.      * The format of the supplied DSN is in its fullest form:
  407.      *
  408.      *  phptype(dbsyntax)://username:password@protocol+hostspec/database
  409.      *
  410.      * Most variations are allowed:
  411.      *
  412.      *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
  413.      *  phptype://username:password@hostspec/database_name
  414.      *  phptype://username:password@hostspec
  415.      *  phptype://username@hostspec
  416.      *  phptype://hostspec/database
  417.      *  phptype://hostspec
  418.      *  phptype(dbsyntax)
  419.      *  phptype
  420.      *
  421.      * @author Tomas V.V.Cox <cox@idecnet.com>
  422.      */
  423.     function parseDSN($dsn)
  424.     {
  425.         if (is_array($dsn)) {
  426.             return $dsn;
  427.         }
  428.  
  429.         $parsed = array(
  430.             'phptype'  => false,
  431.             'dbsyntax' => false,
  432.             'protocol' => false,
  433.             'hostspec' => false,
  434.             'database' => false,
  435.             'username' => false,
  436.             'password' => false
  437.         );
  438.  
  439.         // Find phptype and dbsyntax
  440.         if (($pos = strpos($dsn, '://')) !== false) {
  441.             $str = substr($dsn, 0, $pos);
  442.             $dsn = substr($dsn, $pos + 3);
  443.         } else {
  444.             $str = $dsn;
  445.             $dsn = NULL;
  446.         }
  447.  
  448.         // Get phptype and dbsyntax
  449.         // $str => phptype(dbsyntax)
  450.         if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
  451.             $parsed['phptype'] = $arr[1];
  452.             $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
  453.         } else {
  454.             $parsed['phptype'] = $str;
  455.             $parsed['dbsyntax'] = $str;
  456.         }
  457.  
  458.         if (empty($dsn)) {
  459.             return $parsed;
  460.         }
  461.  
  462.         // Get (if found): username and password
  463.         // $dsn => username:password@protocol+hostspec/database
  464.         if (($at = strrpos($dsn,'@')) !== false) {
  465.             $str = substr($dsn, 0, $at);
  466.             $dsn = substr($dsn, $at + 1);
  467.             if (($pos = strpos($str, ':')) !== false) {
  468.                 $parsed['username'] = urldecode(substr($str, 0, $pos));
  469.                 $parsed['password'] = urldecode(substr($str, $pos + 1));
  470.             } else {
  471.                 $parsed['username'] = urldecode($str);
  472.             }
  473.         }
  474.  
  475.         // Find protocol and hostspec
  476.         // $dsn => protocol+hostspec/database
  477.         if (($pos=strpos($dsn, '/')) !== false) {
  478.             $str = substr($dsn, 0, $pos);
  479.             $dsn = substr($dsn, $pos + 1);
  480.         } else {
  481.             $str = $dsn;
  482.             $dsn = NULL;
  483.         }
  484.  
  485.         // Get protocol + hostspec
  486.         // $str => protocol+hostspec
  487.         if (($pos=strpos($str, '+')) !== false) {
  488.             $parsed['protocol'] = substr($str, 0, $pos);
  489.             $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
  490.         } else {
  491.             $parsed['hostspec'] = urldecode($str);
  492.         }
  493.  
  494.         // Get dabase if any
  495.         // $dsn => database
  496.         if (!empty($dsn)) {
  497.             $parsed['database'] = $dsn;
  498.         }
  499.  
  500.         return $parsed;
  501.     }
  502.  
  503.     /**
  504.      * Load a PHP database extension if it is not loaded already.
  505.      *
  506.      * @access public
  507.      *
  508.      * @param $name the base name of the extension (without the .so or
  509.      * .dll suffix)
  510.      *
  511.      * @return bool true if the extension was already or successfully
  512.      * loaded, false if it could not be loaded
  513.      */
  514.     function assertExtension($name)
  515.     {
  516.         if (!extension_loaded($name)) {
  517.             $dlext = OS_WINDOWS ? '.dll' : '.so';
  518.             @dl($name . $dlext);
  519.         }
  520.         return extension_loaded($name);
  521.     }
  522. }
  523.  
  524. /**
  525.  * DB_Error implements a class for reporting portable database error
  526.  * messages.
  527.  *
  528.  * @package  DB
  529.  * @author Stig Bakken <ssb@fast.no>
  530.  */
  531. class DB_Error extends PEAR_Error
  532. {
  533.     /**
  534.      * DB_Error constructor.
  535.      *
  536.      * @param $code mixed DB error code, or string with error message.
  537.      * @param $mode int what "error mode" to operate in
  538.      * @param $level what error level to use for $mode & PEAR_ERROR_TRIGGER
  539.      * @param $debuginfo additional debug info, such as the last query
  540.      *
  541.      * @access public
  542.      *
  543.      * @see PEAR_Error
  544.      */
  545.  
  546.     function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
  547.               $level = E_USER_NOTICE, $debuginfo = null)
  548.     {
  549.         if (is_int($code)) {
  550.             $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo);
  551.         } else {
  552.             $this->PEAR_Error("DB Error: $code", DB_ERROR, $mode, $level, $debuginfo);
  553.         }
  554.     }
  555. }
  556.  
  557. /**
  558.  * DB_Warning implements a class for reporting portable database
  559.  * warning messages.
  560.  *
  561.  * @package  DB
  562.  * @author Stig Bakken <ssb@fast.no>
  563.  */
  564. class DB_Warning extends PEAR_Error
  565. {
  566.     /**
  567.      * DB_Warning constructor.
  568.      *
  569.      * @param $code mixed DB error code, or string with error message.
  570.      * @param $mode int what "error mode" to operate in
  571.      * @param $level what error level to use for $mode == PEAR_ERROR_TRIGGER
  572.      * @param $debuginfo additional debug info, such as the last query
  573.      *
  574.      * @access public
  575.      *
  576.      * @see PEAR_Error
  577.      */
  578.  
  579.     function DB_Warning($code = DB_WARNING, $mode = PEAR_ERROR_RETURN,
  580.             $level = E_USER_NOTICE, $debuginfo = null)
  581.     {
  582.         if (is_int($code)) {
  583.             $this->PEAR_Error('DB Warning: ' . DB::errorMessage($code), $code, $mode, $level, $debuginfo);
  584.         } else {
  585.             $this->PEAR_Error("DB Warning: $code", 0, $mode, $level, $debuginfo);
  586.         }
  587.     }
  588. }
  589.  
  590. /**
  591.  * This class implements a wrapper for a DB result set.
  592.  * A new instance of this class will be returned by the DB implementation
  593.  * after processing a query that returns data.
  594.  *
  595.  * @package  DB
  596.  * @author Stig Bakken <ssb@fast.no>
  597.  */
  598.  
  599. class DB_result
  600. {
  601.     var $dbh;
  602.     var $result;
  603.     var $row_counter = null;
  604.  
  605.     /**
  606.      * DB_result constructor.
  607.      * @param   $dbh    DB object reference
  608.      * @param   $result result resource id
  609.      */
  610.  
  611.     function DB_result(&$dbh, $result)
  612.     {
  613.         $this->dbh = &$dbh;
  614.         $this->result = $result;
  615.     }
  616.  
  617.     /**
  618.      * Fetch and return a row of data (it uses driver->fetchInto for that)
  619.      * @param int $fetchmode  format of fetched row
  620.      * @param int $rownum     the row number to fetch
  621.      *
  622.      * @return  array a row of data, NULL on no more rows or PEAR_Error on error
  623.      */
  624.     function fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null)
  625.     {
  626.         if ($fetchmode === DB_FETCHMODE_DEFAULT) {
  627.             $fetchmode = $this->dbh->fetchmode;
  628.         }
  629.         if ($fetchmode === DB_FETCHMODE_OBJECT) {
  630.             $fetchmode = DB_FETCHMODE_ASSOC;
  631.             $object_class = $this->dbh->fetchmode_object_class;
  632.         }
  633.         if ($this->dbh->limit_from !== null) {
  634.             if ($this->row_counter === null) {
  635.                 $this->row_counter = $this->dbh->limit_from;
  636.                 // For Interbase
  637.                 if ($this->dbh->features['limit'] == false) {
  638.                     $i = 0;
  639.                     while ($i++ < $this->dbh->limit_from) {
  640.                         $this->dbh->fetchInto($this->result, $arr, $fetchmode);
  641.                     }
  642.                 }
  643.             }
  644.             if ($this->row_counter >= (
  645.                     $this->dbh->limit_from + $this->dbh->limit_count))
  646.             {
  647.                 return null;
  648.             }
  649.             if ($this->dbh->features['limit'] == 'emulate') {
  650.                 $rownum = $this->row_counter;
  651.             }
  652.  
  653.             $this->row_counter++;
  654.         }
  655.         $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
  656.         if ($res !== DB_OK) {
  657.             return $res;
  658.         }
  659.         if (isset($object_class)) {
  660.             // default mode specified in DB_common::fetchmode_object_class property
  661.             if ($object_class == 'stdClass') {
  662.                 $ret = (object) $arr;
  663.             } else {
  664.                 $ret =& new $object_class($arr);
  665.             }
  666.             return $ret;
  667.         }
  668.         return $arr;
  669.     }
  670.  
  671.     /**
  672.      * Fetch a row of data into an existing variable.
  673.      *
  674.      * @param  mixed $arr        reference to data containing the row
  675.      * @param  int   $fetchmode  format of fetched row
  676.      * @param  int   $rownum     the row number to fetch
  677.      *
  678.      * @return  mixed  DB_OK on success, NULL on no more rows or
  679.      *                 a DB_Error object on error
  680.      */
  681.     function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null)
  682.     {
  683.         if ($fetchmode === DB_FETCHMODE_DEFAULT) {
  684.             $fetchmode = $this->dbh->fetchmode;
  685.         }
  686.         if ($fetchmode === DB_FETCHMODE_OBJECT) {
  687.             $fetchmode = DB_FETCHMODE_ASSOC;
  688.             $object_class = $this->dbh->fetchmode_object_class;
  689.         }
  690.         if ($this->dbh->limit_from !== null) {
  691.             if ($this->row_counter === null) {
  692.                 $this->row_counter = $this->dbh->limit_from;
  693.                 // For Interbase
  694.                 if ($this->dbh->features['limit'] == false) {
  695.                     $i = 0;
  696.                     while ($i++ < $this->dbh->limit_from) {
  697.                         $this->dbh->fetchInto($this->result, $arr, $fetchmode);
  698.                     }
  699.                 }
  700.             }
  701.             if ($this->row_counter >= (
  702.                     $this->dbh->limit_from + $this->dbh->limit_count))
  703.             {
  704.                 return null;
  705.             }
  706.             if ($this->dbh->features['limit'] == 'emulate') {
  707.                 $rownum = $this->row_counter;
  708.             }
  709.  
  710.             $this->row_counter++;
  711.         }
  712.         $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum);
  713.         if (($res === DB_OK) && isset($object_class)) {
  714.             // default mode specified in DB_common::fetchmode_object_class property
  715.             if ($object_class == 'stdClass') {
  716.                 $arr = (object) $arr;
  717.             } else {
  718.                 $arr = new $object_class($arr);
  719.             }
  720.         }
  721.         return $res;
  722.     }
  723.  
  724.     /**
  725.      * Get the the number of columns in a result set.
  726.      *
  727.      * @return int the number of columns, or a DB error
  728.      */
  729.     function numCols()
  730.     {
  731.         return $this->dbh->numCols($this->result);
  732.     }
  733.  
  734.     /**
  735.      * Get the number of rows in a result set.
  736.      *
  737.      * @return int the number of rows, or a DB error
  738.      */
  739.     function numRows()
  740.     {
  741.         return $this->dbh->numRows($this->result);
  742.     }
  743.  
  744.     /**
  745.      * Get the next result if a batch of queries was executed.
  746.      *
  747.      * @return bool true if a new result is available or false if not.
  748.      */
  749.     function nextResult()
  750.     {
  751.         return $this->dbh->nextResult($this->result);
  752.     }
  753.  
  754.     /**
  755.      * Frees the resources allocated for this result set.
  756.      * @return  int     error code
  757.      */
  758.     function free()
  759.     {
  760.         $err = $this->dbh->freeResult($this->result);
  761.         if(DB::isError($err)) {
  762.             return $err;
  763.         }
  764.         $this->result = false;
  765.         return true;
  766.     }
  767.  
  768.     function tableInfo($mode = null)
  769.     {
  770.         return $this->dbh->tableInfo($this->result, $mode);
  771.     }
  772.  
  773.     function getRowCounter()
  774.     {
  775.         return $this->row_counter;
  776.     }
  777. }
  778.  
  779. /**
  780. * Pear DB Row Object
  781. * @see DB_common::setFetchMode()
  782. */
  783. class DB_row
  784. {
  785.     function DB_row(&$arr)
  786.     {
  787.         for (reset($arr); $key = key($arr); next($arr)) {
  788.             $this->$key = &$arr[$key];
  789.         }
  790.     }
  791. }
  792.  
  793. ?>
  794.