Spaces:
Sleeping
Sleeping
| /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ | |
| // +----------------------------------------------------------------------+ | |
| // | PHP Version 4 | | |
| // +----------------------------------------------------------------------+ | |
| // | Copyright (c) 1997-2004 The PHP Group | | |
| // +----------------------------------------------------------------------+ | |
| // | This source file is subject to version 2.02 of the PHP license, | | |
| // | that is bundled with this package in the file LICENSE, and is | | |
| // | available at through the world-wide-web at | | |
| // | http://www.php.net/license/2_02.txt. | | |
| // | If you did not receive a copy of the PHP license and are unable to | | |
| // | obtain it through the world-wide-web, please send a note to | | |
| // | license@php.net so we can mail you a copy immediately. | | |
| // +----------------------------------------------------------------------+ | |
| // | Author: Stig Bakken <ssb@php.net> | | |
| // | Tomas V.V.Cox <cox@idecnet.com> | | |
| // | Maintainer: Daniel Convissor <danielc@php.net> | | |
| // +----------------------------------------------------------------------+ | |
| // | |
| // $Id: common.php 3355 2005-06-11 22:14:40Z nbm $ | |
| require_once 'PEAR.php'; | |
| /** | |
| * DB_common is a base class for DB implementations, and must be | |
| * inherited by all such | |
| * | |
| * @package DB | |
| * @version $Id: common.php 3355 2005-06-11 22:14:40Z nbm $ | |
| * @category Database | |
| * @author Stig Bakken <ssb@php.net> | |
| * @author Tomas V.V.Cox <cox@idecnet.com> | |
| */ | |
| class DB_common extends PEAR | |
| { | |
| // {{{ properties | |
| /** | |
| * assoc of capabilities for this DB implementation | |
| * $features['limit'] => 'emulate' => emulate with fetch row by number | |
| * 'alter' => alter the query | |
| * false => skip rows | |
| * @var array | |
| */ | |
| var $features = array(); | |
| /** | |
| * assoc mapping native error codes to DB ones | |
| * @var array | |
| */ | |
| var $errorcode_map = array(); | |
| /** | |
| * DB type (mysql, oci8, odbc etc.) | |
| * @var string | |
| */ | |
| var $phptype; | |
| /** | |
| * @var string | |
| */ | |
| var $prepare_tokens; | |
| /** | |
| * @var string | |
| */ | |
| var $prepare_types; | |
| /** | |
| * @var string | |
| */ | |
| var $prepared_queries; | |
| /** | |
| * @var integer | |
| */ | |
| var $prepare_maxstmt = 0; | |
| /** | |
| * @var string | |
| */ | |
| var $last_query = ''; | |
| /** | |
| * @var integer | |
| */ | |
| var $fetchmode = DB_FETCHMODE_ORDERED; | |
| /** | |
| * @var string | |
| */ | |
| var $fetchmode_object_class = 'stdClass'; | |
| /** | |
| * Run-time configuration options. | |
| * | |
| * The 'optimize' option has been deprecated. Use the 'portability' | |
| * option instead. | |
| * | |
| * @see DB_common::setOption() | |
| * @var array | |
| */ | |
| var $options = array( | |
| 'persistent' => false, | |
| 'ssl' => false, | |
| 'debug' => 0, | |
| 'seqname_format' => '%s_seq', | |
| 'autofree' => false, | |
| 'portability' => DB_PORTABILITY_NONE, | |
| 'optimize' => 'performance', // Deprecated. Use 'portability'. | |
| ); | |
| /** | |
| * DB handle | |
| * @var resource | |
| */ | |
| var $dbh; | |
| // }}} | |
| // {{{ toString() | |
| /** | |
| * String conversation | |
| * | |
| * @return string | |
| * @access private | |
| */ | |
| function toString() | |
| { | |
| $info = strtolower(get_class($this)); | |
| $info .= ': (phptype=' . $this->phptype . | |
| ', dbsyntax=' . $this->dbsyntax . | |
| ')'; | |
| if ($this->connection) { | |
| $info .= ' [connected]'; | |
| } | |
| return $info; | |
| } | |
| // }}} | |
| // {{{ constructor | |
| /** | |
| * Constructor | |
| */ | |
| function DB_common() | |
| { | |
| $this->PEAR('DB_Error'); | |
| } | |
| // }}} | |
| // {{{ quoteString() | |
| /** | |
| * DEPRECATED: Quotes a string so it can be safely used within string | |
| * delimiters in a query | |
| * | |
| * @return string quoted string | |
| * | |
| * @see DB_common::quoteSmart(), DB_common::escapeSimple() | |
| * @deprecated Deprecated in release 1.2 or lower | |
| * @internal | |
| */ | |
| function quoteString($string) | |
| { | |
| $string = $this->quote($string); | |
| if ($string{0} == "'") { | |
| return substr($string, 1, -1); | |
| } | |
| return $string; | |
| } | |
| // }}} | |
| // {{{ quote() | |
| /** | |
| * DEPRECATED: Quotes a string so it can be safely used in a query | |
| * | |
| * @param string $string the input string to quote | |
| * | |
| * @return string The NULL string or the string quotes | |
| * in magic_quote_sybase style | |
| * | |
| * @see DB_common::quoteSmart(), DB_common::escapeSimple() | |
| * @deprecated Deprecated in release 1.6.0 | |
| * @internal | |
| */ | |
| function quote($string = null) | |
| { | |
| return ($string === null) ? 'NULL' : "'".str_replace("'", "''", $string)."'"; | |
| } | |
| // }}} | |
| // {{{ quoteIdentifier() | |
| /** | |
| * Quote a string so it can be safely used as a table or column name | |
| * | |
| * Delimiting style depends on which database driver is being used. | |
| * | |
| * NOTE: just because you CAN use delimited identifiers doesn't mean | |
| * you SHOULD use them. In general, they end up causing way more | |
| * problems than they solve. | |
| * | |
| * Portability is broken by using the following characters inside | |
| * delimited identifiers: | |
| * + backtick (<kbd>`</kbd>) -- due to MySQL | |
| * + double quote (<kbd>"</kbd>) -- due to Oracle | |
| * + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access | |
| * | |
| * Delimited identifiers are known to generally work correctly under | |
| * the following drivers: | |
| * + mssql | |
| * + mysql | |
| * + mysqli | |
| * + oci8 | |
| * + odbc(access) | |
| * + odbc(db2) | |
| * + pgsql | |
| * + sqlite | |
| * + sybase | |
| * | |
| * InterBase doesn't seem to be able to use delimited identifiers | |
| * via PHP 4. They work fine under PHP 5. | |
| * | |
| * @param string $str identifier name to be quoted | |
| * | |
| * @return string quoted identifier string | |
| * | |
| * @since 1.6.0 | |
| * @access public | |
| */ | |
| function quoteIdentifier($str) | |
| { | |
| return '"' . str_replace('"', '""', $str) . '"'; | |
| } | |
| // }}} | |
| // {{{ quoteSmart() | |
| /** | |
| * Format input so it can be safely used in a query | |
| * | |
| * The output depends on the PHP data type of input and the database | |
| * type being used. | |
| * | |
| * @param mixed $in data to be quoted | |
| * | |
| * @return mixed the format of the results depends on the input's | |
| * PHP type: | |
| * | |
| * <ul> | |
| * <li> | |
| * <kbd>input</kbd> -> <samp>returns</samp> | |
| * </li> | |
| * <li> | |
| * <kbd>null</kbd> -> the string <samp>NULL</samp> | |
| * </li> | |
| * <li> | |
| * <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number | |
| * </li> | |
| * <li> | |
| * &type.bool; -> output depends on the driver in use | |
| * Most drivers return integers: <samp>1</samp> if | |
| * <kbd>true</kbd> or <samp>0</samp> if | |
| * <kbd>false</kbd>. | |
| * Some return strings: <samp>TRUE</samp> if | |
| * <kbd>true</kbd> or <samp>FALSE</samp> if | |
| * <kbd>false</kbd>. | |
| * Finally one returns strings: <samp>T</samp> if | |
| * <kbd>true</kbd> or <samp>F</samp> if | |
| * <kbd>false</kbd>. Here is a list of each DBMS, | |
| * the values returned and the suggested column type: | |
| * <ul> | |
| * <li> | |
| * <kbd>dbase</kbd> -> <samp>T/F</samp> | |
| * (<kbd>Logical</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp> | |
| * (<kbd>BOOLEAN</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>ibase</kbd> -> <samp>1/0</samp> | |
| * (<kbd>SMALLINT</kbd>) [1] | |
| * </li> | |
| * <li> | |
| * <kbd>ifx</kbd> -> <samp>1/0</samp> | |
| * (<kbd>SMALLINT</kbd>) [1] | |
| * </li> | |
| * <li> | |
| * <kbd>msql</kbd> -> <samp>1/0</samp> | |
| * (<kbd>INTEGER</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>mssql</kbd> -> <samp>1/0</samp> | |
| * (<kbd>BIT</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>mysql</kbd> -> <samp>1/0</samp> | |
| * (<kbd>TINYINT(1)</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>mysqli</kbd> -> <samp>1/0</samp> | |
| * (<kbd>TINYINT(1)</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>oci8</kbd> -> <samp>1/0</samp> | |
| * (<kbd>NUMBER(1)</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>odbc</kbd> -> <samp>1/0</samp> | |
| * (<kbd>SMALLINT</kbd>) [1] | |
| * </li> | |
| * <li> | |
| * <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp> | |
| * (<kbd>BOOLEAN</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>sqlite</kbd> -> <samp>1/0</samp> | |
| * (<kbd>INTEGER</kbd>) | |
| * </li> | |
| * <li> | |
| * <kbd>sybase</kbd> -> <samp>1/0</samp> | |
| * (<kbd>TINYINT(1)</kbd>) | |
| * </li> | |
| * </ul> | |
| * [1] Accommodate the lowest common denominator because not all | |
| * versions of have <kbd>BOOLEAN</kbd>. | |
| * </li> | |
| * <li> | |
| * other (including strings and numeric strings) -> | |
| * the data with single quotes escaped by preceeding | |
| * single quotes, backslashes are escaped by preceeding | |
| * backslashes, then the whole string is encapsulated | |
| * between single quotes | |
| * </li> | |
| * </ul> | |
| * | |
| * @since 1.6.0 | |
| * @see DB_common::escapeSimple() | |
| * @access public | |
| */ | |
| function quoteSmart($in) | |
| { | |
| if (is_int($in) || is_double($in)) { | |
| return $in; | |
| } elseif (is_bool($in)) { | |
| return $in ? 1 : 0; | |
| } elseif (is_null($in)) { | |
| return 'NULL'; | |
| } else { | |
| return "'" . $this->escapeSimple($in) . "'"; | |
| } | |
| } | |
| // }}} | |
| // {{{ escapeSimple() | |
| /** | |
| * Escape a string according to the current DBMS's standards | |
| * | |
| * In SQLite, this makes things safe for inserts/updates, but may | |
| * cause problems when performing text comparisons against columns | |
| * containing binary data. See the | |
| * {@link http://php.net/sqlite_escape_string PHP manual} for more info. | |
| * | |
| * @param string $str the string to be escaped | |
| * | |
| * @return string the escaped string | |
| * | |
| * @since 1.6.0 | |
| * @see DB_common::quoteSmart() | |
| * @access public | |
| */ | |
| function escapeSimple($str) { | |
| return str_replace("'", "''", $str); | |
| } | |
| // }}} | |
| // {{{ provides() | |
| /** | |
| * Tell whether a DB implementation or its backend extension | |
| * supports a given feature | |
| * | |
| * @param array $feature name of the feature (see the DB class doc) | |
| * @return bool whether this DB implementation supports $feature | |
| * @access public | |
| */ | |
| function provides($feature) | |
| { | |
| return $this->features[$feature]; | |
| } | |
| // }}} | |
| // {{{ errorCode() | |
| /** | |
| * Map native error codes to DB's portable ones | |
| * | |
| * Requires that the DB implementation's constructor fills | |
| * in the <var>$errorcode_map</var> property. | |
| * | |
| * @param mixed $nativecode the native error code, as returned by the | |
| * backend database extension (string or integer) | |
| * | |
| * @return int a portable DB error code, or DB_ERROR if this DB | |
| * implementation has no mapping for the given error code. | |
| * | |
| * @access public | |
| */ | |
| function errorCode($nativecode) | |
| { | |
| if (isset($this->errorcode_map[$nativecode])) { | |
| return $this->errorcode_map[$nativecode]; | |
| } | |
| // Fall back to DB_ERROR if there was no mapping. | |
| return DB_ERROR; | |
| } | |
| // }}} | |
| // {{{ errorMessage() | |
| /** | |
| * Map a DB error code to a textual message. This is actually | |
| * just a wrapper for DB::errorMessage() | |
| * | |
| * @param integer $dbcode the DB error code | |
| * | |
| * @return string the corresponding error message, of false | |
| * if the error code was unknown | |
| * | |
| * @access public | |
| */ | |
| function errorMessage($dbcode) | |
| { | |
| return DB::errorMessage($this->errorcode_map[$dbcode]); | |
| } | |
| // }}} | |
| // {{{ raiseError() | |
| /** | |
| * Communicate an error and invoke error callbacks, etc | |
| * | |
| * Basically a wrapper for PEAR::raiseError without the message string. | |
| * | |
| * @param mixed integer error code, or a PEAR error object (all | |
| * other parameters are ignored if this parameter is | |
| * an object | |
| * | |
| * @param int error mode, see PEAR_Error docs | |
| * | |
| * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the | |
| * error level (E_USER_NOTICE etc). If error mode is | |
| * PEAR_ERROR_CALLBACK, this is the callback function, | |
| * either as a function name, or as an array of an | |
| * object and method name. For other error modes this | |
| * parameter is ignored. | |
| * | |
| * @param string Extra debug information. Defaults to the last | |
| * query and native error code. | |
| * | |
| * @param mixed Native error code, integer or string depending the | |
| * backend. | |
| * | |
| * @return object a PEAR error object | |
| * | |
| * @access public | |
| * @see PEAR_Error | |
| */ | |
| function &raiseError($code = DB_ERROR, $mode = null, $options = null, | |
| $userinfo = null, $nativecode = null) | |
| { | |
| // The error is yet a DB error object | |
| if (is_object($code)) { | |
| // because we the static PEAR::raiseError, our global | |
| // handler should be used if it is set | |
| if ($mode === null && !empty($this->_default_error_mode)) { | |
| $mode = $this->_default_error_mode; | |
| $options = $this->_default_error_options; | |
| } | |
| $tmp = PEAR::raiseError($code, null, $mode, $options, null, null, true); | |
| return $tmp; | |
| } | |
| if ($userinfo === null) { | |
| $userinfo = $this->last_query; | |
| } | |
| if ($nativecode) { | |
| $userinfo .= ' [nativecode=' . trim($nativecode) . ']'; | |
| } | |
| $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, | |
| 'DB_Error', true); | |
| return $tmp; | |
| } | |
| // }}} | |
| // {{{ setFetchMode() | |
| /** | |
| * Sets which fetch mode should be used by default on queries | |
| * on this connection | |
| * | |
| * @param integer $fetchmode DB_FETCHMODE_ORDERED or | |
| * DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with | |
| * DB_FETCHMODE_FLIPPED. | |
| * | |
| * @param string $object_class The class of the object | |
| * to be returned by the fetch methods when | |
| * the DB_FETCHMODE_OBJECT mode is selected. | |
| * If no class is specified by default a cast | |
| * to object from the assoc array row will be done. | |
| * There is also the posibility to use and extend the | |
| * 'DB_row' class. | |
| * | |
| * @see DB_FETCHMODE_ORDERED | |
| * @see DB_FETCHMODE_ASSOC | |
| * @see DB_FETCHMODE_FLIPPED | |
| * @see DB_FETCHMODE_OBJECT | |
| * @see DB_row::DB_row() | |
| * @access public | |
| */ | |
| function setFetchMode($fetchmode, $object_class = 'stdClass') | |
| { | |
| switch ($fetchmode) { | |
| case DB_FETCHMODE_OBJECT: | |
| $this->fetchmode_object_class = $object_class; | |
| case DB_FETCHMODE_ORDERED: | |
| case DB_FETCHMODE_ASSOC: | |
| $this->fetchmode = $fetchmode; | |
| break; | |
| default: | |
| return $this->raiseError('invalid fetchmode mode'); | |
| } | |
| } | |
| // }}} | |
| // {{{ setOption() | |
| /** | |
| * Set run-time configuration options for PEAR DB | |
| * | |
| * Options, their data types, default values and description: | |
| * <ul> | |
| * <li> | |
| * <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp> | |
| * <br />should results be freed automatically when there are no | |
| * more rows? | |
| * </li><li> | |
| * <var>debug</var> <kbd>integer</kbd> = <samp>0</samp> | |
| * <br />debug level | |
| * </li><li> | |
| * <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp> | |
| * <br />should the connection be persistent? | |
| * </li><li> | |
| * <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp> | |
| * <br />portability mode constant (see below) | |
| * </li><li> | |
| * <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp> | |
| * <br />the sprintf() format string used on sequence names. This | |
| * format is applied to sequence names passed to | |
| * createSequence(), nextID() and dropSequence(). | |
| * </li><li> | |
| * <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp> | |
| * <br />use ssl to connect? | |
| * </li> | |
| * </ul> | |
| * | |
| * ----------------------------------------- | |
| * | |
| * PORTABILITY MODES | |
| * | |
| * These modes are bitwised, so they can be combined using <kbd>|</kbd> | |
| * and removed using <kbd>^</kbd>. See the examples section below on how | |
| * to do this. | |
| * | |
| * <samp>DB_PORTABILITY_NONE</samp> | |
| * turn off all portability features | |
| * | |
| * This mode gets automatically turned on if the deprecated | |
| * <var>optimize</var> option gets set to <samp>performance</samp>. | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_LOWERCASE</samp> | |
| * convert names of tables and fields to lower case when using | |
| * <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd> | |
| * | |
| * This mode gets automatically turned on in the following databases | |
| * if the deprecated option <var>optimize</var> gets set to | |
| * <samp>portability</samp>: | |
| * + oci8 | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_RTRIM</samp> | |
| * right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd> | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_DELETE_COUNT</samp> | |
| * force reporting the number of rows deleted | |
| * | |
| * Some DBMS's don't count the number of rows deleted when performing | |
| * simple <kbd>DELETE FROM tablename</kbd> queries. This portability | |
| * mode tricks such DBMS's into telling the count by adding | |
| * <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries. | |
| * | |
| * This mode gets automatically turned on in the following databases | |
| * if the deprecated option <var>optimize</var> gets set to | |
| * <samp>portability</samp>: | |
| * + fbsql | |
| * + mysql | |
| * + mysqli | |
| * + sqlite | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_NUMROWS</samp> | |
| * enable hack that makes <kbd>numRows()</kbd> work in Oracle | |
| * | |
| * This mode gets automatically turned on in the following databases | |
| * if the deprecated option <var>optimize</var> gets set to | |
| * <samp>portability</samp>: | |
| * + oci8 | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_ERRORS</samp> | |
| * makes certain error messages in certain drivers compatible | |
| * with those from other DBMS's | |
| * | |
| * + mysql, mysqli: change unique/primary key constraints | |
| * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT | |
| * | |
| * + odbc(access): MS's ODBC driver reports 'no such field' as code | |
| * 07001, which means 'too few parameters.' When this option is on | |
| * that code gets mapped to DB_ERROR_NOSUCHFIELD. | |
| * DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp> | |
| * convert null values to empty strings in data output by get*() and | |
| * fetch*(). Needed because Oracle considers empty strings to be null, | |
| * while most other DBMS's know the difference between empty and null. | |
| * | |
| * | |
| * <samp>DB_PORTABILITY_ALL</samp> | |
| * turn on all portability features | |
| * | |
| * ----------------------------------------- | |
| * | |
| * Example 1. Simple setOption() example | |
| * <code> <?php | |
| * $dbh->setOption('autofree', true); | |
| * ?></code> | |
| * | |
| * Example 2. Portability for lowercasing and trimming | |
| * <code> <?php | |
| * $dbh->setOption('portability', | |
| * DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM); | |
| * ?></code> | |
| * | |
| * Example 3. All portability options except trimming | |
| * <code> <?php | |
| * $dbh->setOption('portability', | |
| * DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM); | |
| * ?></code> | |
| * | |
| * @param string $option option name | |
| * @param mixed $value value for the option | |
| * | |
| * @return int DB_OK on success. DB_Error object on failure. | |
| * | |
| * @see DB_common::$options | |
| */ | |
| function setOption($option, $value) | |
| { | |
| if (isset($this->options[$option])) { | |
| $this->options[$option] = $value; | |
| /* | |
| * Backwards compatibility check for the deprecated 'optimize' | |
| * option. Done here in case settings change after connecting. | |
| */ | |
| if ($option == 'optimize') { | |
| if ($value == 'portability') { | |
| switch ($this->phptype) { | |
| case 'oci8': | |
| $this->options['portability'] = | |
| DB_PORTABILITY_LOWERCASE | | |
| DB_PORTABILITY_NUMROWS; | |
| break; | |
| case 'fbsql': | |
| case 'mysql': | |
| case 'mysqli': | |
| case 'sqlite': | |
| $this->options['portability'] = | |
| DB_PORTABILITY_DELETE_COUNT; | |
| break; | |
| } | |
| } else { | |
| $this->options['portability'] = DB_PORTABILITY_NONE; | |
| } | |
| } | |
| return DB_OK; | |
| } | |
| return $this->raiseError("unknown option $option"); | |
| } | |
| // }}} | |
| // {{{ getOption() | |
| /** | |
| * Returns the value of an option | |
| * | |
| * @param string $option option name | |
| * | |
| * @return mixed the option value | |
| */ | |
| function getOption($option) | |
| { | |
| if (isset($this->options[$option])) { | |
| return $this->options[$option]; | |
| } | |
| return $this->raiseError("unknown option $option"); | |
| } | |
| // }}} | |
| // {{{ prepare() | |
| /** | |
| * Prepares a query for multiple execution with execute() | |
| * | |
| * Creates a query that can be run multiple times. Each time it is run, | |
| * the placeholders, if any, will be replaced by the contents of | |
| * execute()'s $data argument. | |
| * | |
| * Three types of placeholders can be used: | |
| * + <kbd>?</kbd> scalar value (i.e. strings, integers). The system | |
| * will automatically quote and escape the data. | |
| * + <kbd>!</kbd> value is inserted 'as is' | |
| * + <kbd>&</kbd> requires a file name. The file's contents get | |
| * inserted into the query (i.e. saving binary | |
| * data in a db) | |
| * | |
| * Example 1. | |
| * <code> <?php | |
| * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); | |
| * $data = array( | |
| * "John's text", | |
| * "'it''s good'", | |
| * 'filename.txt' | |
| * ); | |
| * $res = $dbh->execute($sth, $data); | |
| * ?></code> | |
| * | |
| * Use backslashes to escape placeholder characters if you don't want | |
| * them to be interpreted as placeholders: | |
| * <pre> | |
| * "UPDATE foo SET col=? WHERE col='over \& under'" | |
| * </pre> | |
| * | |
| * With some database backends, this is emulated. | |
| * | |
| * {@internal ibase and oci8 have their own prepare() methods.}} | |
| * | |
| * @param string $query query to be prepared | |
| * | |
| * @return mixed DB statement resource on success. DB_Error on failure. | |
| * | |
| * @see DB_common::execute() | |
| * @access public | |
| */ | |
| function prepare($query) | |
| { | |
| $tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, | |
| PREG_SPLIT_DELIM_CAPTURE); | |
| $token = 0; | |
| $types = array(); | |
| $newtokens = array(); | |
| foreach ($tokens as $val) { | |
| switch ($val) { | |
| case '?': | |
| $types[$token++] = DB_PARAM_SCALAR; | |
| break; | |
| case '&': | |
| $types[$token++] = DB_PARAM_OPAQUE; | |
| break; | |
| case '!': | |
| $types[$token++] = DB_PARAM_MISC; | |
| break; | |
| default: | |
| $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val); | |
| } | |
| } | |
| $this->prepare_tokens[] = &$newtokens; | |
| end($this->prepare_tokens); | |
| $k = key($this->prepare_tokens); | |
| $this->prepare_types[$k] = $types; | |
| $this->prepared_queries[$k] = implode(' ', $newtokens); | |
| return $k; | |
| } | |
| // }}} | |
| // {{{ autoPrepare() | |
| /** | |
| * Automaticaly generate an insert or update query and pass it to prepare() | |
| * | |
| * @param string $table name of the table | |
| * @param array $table_fields ordered array containing the fields names | |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) | |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement | |
| * @return resource handle for the query | |
| * @see DB_common::prepare(), DB_common::buildManipSQL() | |
| * @access public | |
| */ | |
| function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, $where = false) | |
| { | |
| $query = $this->buildManipSQL($table, $table_fields, $mode, $where); | |
| return $this->prepare($query); | |
| } | |
| // }}} | |
| // {{{ autoExecute() | |
| /** | |
| * Automaticaly generate an insert or update query and call prepare() | |
| * and execute() with it | |
| * | |
| * @param string $table name of the table | |
| * @param array $fields_values assoc ($key=>$value) where $key is a field name and $value its value | |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) | |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement | |
| * @return mixed a new DB_Result or a DB_Error when fail | |
| * @see DB_common::autoPrepare(), DB_common::buildManipSQL() | |
| * @access public | |
| */ | |
| function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, $where = false) | |
| { | |
| $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, $where); | |
| $ret =& $this->execute($sth, array_values($fields_values)); | |
| $this->freePrepared($sth); | |
| return $ret; | |
| } | |
| // }}} | |
| // {{{ buildManipSQL() | |
| /** | |
| * Make automaticaly an sql query for prepare() | |
| * | |
| * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), DB_AUTOQUERY_INSERT) | |
| * will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) | |
| * NB : - This belongs more to a SQL Builder class, but this is a simple facility | |
| * - Be carefull ! If you don't give a $where param with an UPDATE query, all | |
| * the records of the table will be updated ! | |
| * | |
| * @param string $table name of the table | |
| * @param array $table_fields ordered array containing the fields names | |
| * @param int $mode type of query to make (DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE) | |
| * @param string $where in case of update queries, this string will be put after the sql WHERE statement | |
| * @return string sql query for prepare() | |
| * @access public | |
| */ | |
| function buildManipSQL($table, $table_fields, $mode, $where = false) | |
| { | |
| if (count($table_fields) == 0) { | |
| $this->raiseError(DB_ERROR_NEED_MORE_DATA); | |
| } | |
| $first = true; | |
| switch ($mode) { | |
| case DB_AUTOQUERY_INSERT: | |
| $values = ''; | |
| $names = ''; | |
| foreach ($table_fields as $value) { | |
| if ($first) { | |
| $first = false; | |
| } else { | |
| $names .= ','; | |
| $values .= ','; | |
| } | |
| $names .= $value; | |
| $values .= '?'; | |
| } | |
| return "INSERT INTO $table ($names) VALUES ($values)"; | |
| case DB_AUTOQUERY_UPDATE: | |
| $set = ''; | |
| foreach ($table_fields as $value) { | |
| if ($first) { | |
| $first = false; | |
| } else { | |
| $set .= ','; | |
| } | |
| $set .= "$value = ?"; | |
| } | |
| $sql = "UPDATE $table SET $set"; | |
| if ($where) { | |
| $sql .= " WHERE $where"; | |
| } | |
| return $sql; | |
| default: | |
| $this->raiseError(DB_ERROR_SYNTAX); | |
| } | |
| } | |
| // }}} | |
| // {{{ execute() | |
| /** | |
| * Executes a DB statement prepared with prepare() | |
| * | |
| * Example 1. | |
| * <code> <?php | |
| * $sth = $dbh->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); | |
| * $data = array( | |
| * "John's text", | |
| * "'it''s good'", | |
| * 'filename.txt' | |
| * ); | |
| * $res =& $dbh->execute($sth, $data); | |
| * ?></code> | |
| * | |
| * @param resource $stmt a DB statement resource returned from prepare() | |
| * @param mixed $data array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return object a new DB_Result or a DB_Error when fail | |
| * | |
| * {@internal ibase and oci8 have their own execute() methods.}} | |
| * | |
| * @see DB_common::prepare() | |
| * @access public | |
| */ | |
| function &execute($stmt, $data = array()) | |
| { | |
| $realquery = $this->executeEmulateQuery($stmt, $data); | |
| if (DB::isError($realquery)) { | |
| return $realquery; | |
| } | |
| $result = $this->simpleQuery($realquery); | |
| if (DB::isError($result) || $result === DB_OK) { | |
| return $result; | |
| } else { | |
| $tmp =& new DB_result($this, $result); | |
| return $tmp; | |
| } | |
| } | |
| // }}} | |
| // {{{ executeEmulateQuery() | |
| /** | |
| * Emulates the execute statement, when not supported | |
| * | |
| * @param resource $stmt a DB statement resource returned from execute() | |
| * @param mixed $data array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return mixed a string containing the real query run when emulating | |
| * prepare/execute. A DB error code is returned on failure. | |
| * | |
| * @see DB_common::execute() | |
| * @access private | |
| */ | |
| function executeEmulateQuery($stmt, $data = array()) | |
| { | |
| $stmt = (int)$stmt; | |
| if (!is_array($data)) { | |
| $data = array($data); | |
| } | |
| if (count($this->prepare_types[$stmt]) != count($data)) { | |
| $this->last_query = $this->prepared_queries[$stmt]; | |
| return $this->raiseError(DB_ERROR_MISMATCH); | |
| } | |
| $realquery = $this->prepare_tokens[$stmt][0]; | |
| $i = 0; | |
| foreach ($data as $value) { | |
| if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { | |
| $realquery .= $this->quoteSmart($value); | |
| } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { | |
| $fp = @fopen($value, 'rb'); | |
| if (!$fp) { | |
| return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); | |
| } | |
| $realquery .= $this->quoteSmart(fread($fp, filesize($value))); | |
| fclose($fp); | |
| } else { | |
| $realquery .= $value; | |
| } | |
| $realquery .= $this->prepare_tokens[$stmt][++$i]; | |
| } | |
| return $realquery; | |
| } | |
| // }}} | |
| // {{{ executeMultiple() | |
| /** | |
| * This function does several execute() calls on the same | |
| * statement handle | |
| * | |
| * $data must be an array indexed numerically | |
| * from 0, one execute call is done for every "row" in the array. | |
| * | |
| * If an error occurs during execute(), executeMultiple() does not | |
| * execute the unfinished rows, but rather returns that error. | |
| * | |
| * @param resource $stmt query handle from prepare() | |
| * @param array $data numeric array containing the | |
| * data to insert into the query | |
| * | |
| * @return mixed DB_OK or DB_Error | |
| * | |
| * @see DB_common::prepare(), DB_common::execute() | |
| * @access public | |
| */ | |
| function executeMultiple($stmt, $data) | |
| { | |
| foreach ($data as $value) { | |
| $res =& $this->execute($stmt, $value); | |
| if (DB::isError($res)) { | |
| return $res; | |
| } | |
| } | |
| return DB_OK; | |
| } | |
| // }}} | |
| // {{{ freePrepared() | |
| /** | |
| * Free the resource used in a prepared query | |
| * | |
| * @param $stmt The resurce returned by the prepare() function | |
| * @see DB_common::prepare() | |
| */ | |
| function freePrepared($stmt) | |
| { | |
| $stmt = (int)$stmt; | |
| // Free the internal prepared vars | |
| if (isset($this->prepare_tokens[$stmt])) { | |
| unset($this->prepare_tokens[$stmt]); | |
| unset($this->prepare_types[$stmt]); | |
| unset($this->prepared_queries[$stmt]); | |
| return true; | |
| } | |
| return false; | |
| } | |
| // }}} | |
| // {{{ modifyQuery() | |
| /** | |
| * This method is used by backends to alter queries for various | |
| * reasons | |
| * | |
| * It is defined here to assure that all implementations | |
| * have this method defined. | |
| * | |
| * @param string $query query to modify | |
| * | |
| * @return the new (modified) query | |
| * | |
| * @access private | |
| */ | |
| function modifyQuery($query) { | |
| return $query; | |
| } | |
| // }}} | |
| // {{{ modifyLimitQuery() | |
| /** | |
| * This method is used by backends to alter limited queries | |
| * | |
| * @param string $query query to modify | |
| * @param integer $from the row to start to fetching | |
| * @param integer $count the numbers of rows to fetch | |
| * | |
| * @return the new (modified) query | |
| * | |
| * @access private | |
| */ | |
| function modifyLimitQuery($query, $from, $count, $params = array()) | |
| { | |
| return $query; | |
| } | |
| // }}} | |
| // {{{ query() | |
| /** | |
| * Send a query to the database and return any results with a | |
| * DB_result object | |
| * | |
| * The query string can be either a normal statement to be sent directly | |
| * to the server OR if <var>$params</var> are passed the query can have | |
| * placeholders and it will be passed through prepare() and execute(). | |
| * | |
| * @param string $query the SQL query or the statement to prepare | |
| * @param mixed $params array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return mixed a DB_result object or DB_OK on success, a DB | |
| * error on failure | |
| * | |
| * @see DB_result, DB_common::prepare(), DB_common::execute() | |
| * @access public | |
| */ | |
| function &query($query, $params = array()) | |
| { | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $ret =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| return $ret; | |
| } else { | |
| $result = $this->simpleQuery($query); | |
| if (DB::isError($result) || $result === DB_OK) { | |
| return $result; | |
| } else { | |
| $tmp =& new DB_result($this, $result); | |
| return $tmp; | |
| } | |
| } | |
| } | |
| // }}} | |
| // {{{ limitQuery() | |
| /** | |
| * Generates a limited query | |
| * | |
| * @param string $query query | |
| * @param integer $from the row to start to fetching | |
| * @param integer $count the numbers of rows to fetch | |
| * @param mixed $params array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return mixed a DB_Result object, DB_OK or a DB_Error | |
| * | |
| * @access public | |
| */ | |
| function &limitQuery($query, $from, $count, $params = array()) | |
| { | |
| $query = $this->modifyLimitQuery($query, $from, $count, $params); | |
| if (DB::isError($query)){ | |
| return $query; | |
| } | |
| $result =& $this->query($query, $params); | |
| if (is_a($result, 'DB_result')) { | |
| $result->setOption('limit_from', $from); | |
| $result->setOption('limit_count', $count); | |
| } | |
| return $result; | |
| } | |
| // }}} | |
| // {{{ getOne() | |
| /** | |
| * Fetch the first column of the first row of data returned from | |
| * a query | |
| * | |
| * Takes care of doing the query and freeing the results when finished. | |
| * | |
| * @param string $query the SQL query | |
| * @param mixed $params array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return mixed the returned value of the query. DB_Error on failure. | |
| * | |
| * @access public | |
| */ | |
| function &getOne($query, $params = array()) | |
| { | |
| settype($params, 'array'); | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $res =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| } else { | |
| $res =& $this->query($query); | |
| } | |
| if (DB::isError($res)) { | |
| return $res; | |
| } | |
| $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); | |
| $res->free(); | |
| if ($err !== DB_OK) { | |
| return $err; | |
| } | |
| return $row[0]; | |
| } | |
| // }}} | |
| // {{{ getRow() | |
| /** | |
| * Fetch the first row of data returned from a query | |
| * | |
| * Takes care of doing the query and freeing the results when finished. | |
| * | |
| * @param string $query the SQL query | |
| * @param array $params array to be used in execution of the statement. | |
| * Quantity of array elements must match quantity | |
| * of placeholders in query. This function does | |
| * NOT support scalars. | |
| * @param int $fetchmode the fetch mode to use | |
| * | |
| * @return array the first row of results as an array indexed from | |
| * 0, or a DB error code. | |
| * | |
| * @access public | |
| */ | |
| function &getRow($query, | |
| $params = array(), | |
| $fetchmode = DB_FETCHMODE_DEFAULT) | |
| { | |
| // compat check, the params and fetchmode parameters used to | |
| // have the opposite order | |
| if (!is_array($params)) { | |
| if (is_array($fetchmode)) { | |
| if ($params === null) { | |
| $tmp = DB_FETCHMODE_DEFAULT; | |
| } else { | |
| $tmp = $params; | |
| } | |
| $params = $fetchmode; | |
| $fetchmode = $tmp; | |
| } elseif ($params !== null) { | |
| $fetchmode = $params; | |
| $params = array(); | |
| } | |
| } | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $res =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| } else { | |
| $res =& $this->query($query); | |
| } | |
| if (DB::isError($res)) { | |
| return $res; | |
| } | |
| $err = $res->fetchInto($row, $fetchmode); | |
| $res->free(); | |
| if ($err !== DB_OK) { | |
| return $err; | |
| } | |
| return $row; | |
| } | |
| // }}} | |
| // {{{ getCol() | |
| /** | |
| * Fetch a single column from a result set and return it as an | |
| * indexed array | |
| * | |
| * @param string $query the SQL query | |
| * @param mixed $col which column to return (integer [column number, | |
| * starting at 0] or string [column name]) | |
| * @param mixed $params array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * | |
| * @return array an indexed array with the data from the first | |
| * row at index 0, or a DB error code | |
| * | |
| * @see DB_common::query() | |
| * @access public | |
| */ | |
| function &getCol($query, $col = 0, $params = array()) | |
| { | |
| settype($params, 'array'); | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $res =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| } else { | |
| $res =& $this->query($query); | |
| } | |
| if (DB::isError($res)) { | |
| return $res; | |
| } | |
| $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; | |
| if (!is_array($row = $res->fetchRow($fetchmode))) { | |
| $ret = array(); | |
| } else { | |
| if (!array_key_exists($col, $row)) { | |
| $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); | |
| } else { | |
| $ret = array($row[$col]); | |
| while (is_array($row = $res->fetchRow($fetchmode))) { | |
| $ret[] = $row[$col]; | |
| } | |
| } | |
| } | |
| $res->free(); | |
| if (DB::isError($row)) { | |
| $ret = $row; | |
| } | |
| return $ret; | |
| } | |
| // }}} | |
| // {{{ getAssoc() | |
| /** | |
| * Fetch the entire result set of a query and return it as an | |
| * associative array using the first column as the key | |
| * | |
| * If the result set contains more than two columns, the value | |
| * will be an array of the values from column 2-n. If the result | |
| * set contains only two columns, the returned value will be a | |
| * scalar with the value of the second column (unless forced to an | |
| * array with the $force_array parameter). A DB error code is | |
| * returned on errors. If the result set contains fewer than two | |
| * columns, a DB_ERROR_TRUNCATED error is returned. | |
| * | |
| * For example, if the table "mytable" contains: | |
| * | |
| * <pre> | |
| * ID TEXT DATE | |
| * -------------------------------- | |
| * 1 'one' 944679408 | |
| * 2 'two' 944679408 | |
| * 3 'three' 944679408 | |
| * </pre> | |
| * | |
| * Then the call getAssoc('SELECT id,text FROM mytable') returns: | |
| * <pre> | |
| * array( | |
| * '1' => 'one', | |
| * '2' => 'two', | |
| * '3' => 'three', | |
| * ) | |
| * </pre> | |
| * | |
| * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: | |
| * <pre> | |
| * array( | |
| * '1' => array('one', '944679408'), | |
| * '2' => array('two', '944679408'), | |
| * '3' => array('three', '944679408') | |
| * ) | |
| * </pre> | |
| * | |
| * If the more than one row occurs with the same value in the | |
| * first column, the last row overwrites all previous ones by | |
| * default. Use the $group parameter if you don't want to | |
| * overwrite like this. Example: | |
| * | |
| * <pre> | |
| * getAssoc('SELECT category,id,name FROM mytable', false, null, | |
| * DB_FETCHMODE_ASSOC, true) returns: | |
| * | |
| * array( | |
| * '1' => array(array('id' => '4', 'name' => 'number four'), | |
| * array('id' => '6', 'name' => 'number six') | |
| * ), | |
| * '9' => array(array('id' => '4', 'name' => 'number four'), | |
| * array('id' => '6', 'name' => 'number six') | |
| * ) | |
| * ) | |
| * </pre> | |
| * | |
| * Keep in mind that database functions in PHP usually return string | |
| * values for results regardless of the database's internal type. | |
| * | |
| * @param string $query the SQL query | |
| * @param boolean $force_array used only when the query returns | |
| * exactly two columns. If true, the values | |
| * of the returned array will be one-element | |
| * arrays instead of scalars. | |
| * @param mixed $params array, string or numeric data to be used in | |
| * execution of the statement. Quantity of items | |
| * passed must match quantity of placeholders in | |
| * query: meaning 1 placeholder for non-array | |
| * parameters or 1 placeholder per array element. | |
| * @param int $fetchmode the fetch mode to use | |
| * @param boolean $group if true, the values of the returned array | |
| * is wrapped in another array. If the same | |
| * key value (in the first column) repeats | |
| * itself, the values will be appended to | |
| * this array instead of overwriting the | |
| * existing values. | |
| * | |
| * @return array associative array with results from the query. | |
| * DB Error on failure. | |
| * | |
| * @access public | |
| */ | |
| function &getAssoc($query, $force_array = false, $params = array(), | |
| $fetchmode = DB_FETCHMODE_DEFAULT, $group = false) | |
| { | |
| settype($params, 'array'); | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $res =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| } else { | |
| $res =& $this->query($query); | |
| } | |
| if (DB::isError($res)) { | |
| return $res; | |
| } | |
| if ($fetchmode == DB_FETCHMODE_DEFAULT) { | |
| $fetchmode = $this->fetchmode; | |
| } | |
| $cols = $res->numCols(); | |
| if ($cols < 2) { | |
| $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); | |
| return $tmp; | |
| } | |
| $results = array(); | |
| if ($cols > 2 || $force_array) { | |
| // return array values | |
| // XXX this part can be optimized | |
| if ($fetchmode == DB_FETCHMODE_ASSOC) { | |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { | |
| reset($row); | |
| $key = current($row); | |
| unset($row[key($row)]); | |
| if ($group) { | |
| $results[$key][] = $row; | |
| } else { | |
| $results[$key] = $row; | |
| } | |
| } | |
| } elseif ($fetchmode == DB_FETCHMODE_OBJECT) { | |
| while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { | |
| $arr = get_object_vars($row); | |
| $key = current($arr); | |
| if ($group) { | |
| $results[$key][] = $row; | |
| } else { | |
| $results[$key] = $row; | |
| } | |
| } | |
| } else { | |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { | |
| // we shift away the first element to get | |
| // indices running from 0 again | |
| $key = array_shift($row); | |
| if ($group) { | |
| $results[$key][] = $row; | |
| } else { | |
| $results[$key] = $row; | |
| } | |
| } | |
| } | |
| if (DB::isError($row)) { | |
| $results = $row; | |
| } | |
| } else { | |
| // return scalar values | |
| while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { | |
| if ($group) { | |
| $results[$row[0]][] = $row[1]; | |
| } else { | |
| $results[$row[0]] = $row[1]; | |
| } | |
| } | |
| if (DB::isError($row)) { | |
| $results = $row; | |
| } | |
| } | |
| $res->free(); | |
| return $results; | |
| } | |
| // }}} | |
| // {{{ getAll() | |
| /** | |
| * Fetch all the rows returned from a query | |
| * | |
| * @param string $query the SQL query | |
| * @param array $params array to be used in execution of the statement. | |
| * Quantity of array elements must match quantity | |
| * of placeholders in query. This function does | |
| * NOT support scalars. | |
| * @param int $fetchmode the fetch mode to use | |
| * | |
| * @return array an nested array. DB error on failure. | |
| * | |
| * @access public | |
| */ | |
| function &getAll($query, | |
| $params = array(), | |
| $fetchmode = DB_FETCHMODE_DEFAULT) | |
| { | |
| // compat check, the params and fetchmode parameters used to | |
| // have the opposite order | |
| if (!is_array($params)) { | |
| if (is_array($fetchmode)) { | |
| if ($params === null) { | |
| $tmp = DB_FETCHMODE_DEFAULT; | |
| } else { | |
| $tmp = $params; | |
| } | |
| $params = $fetchmode; | |
| $fetchmode = $tmp; | |
| } elseif ($params !== null) { | |
| $fetchmode = $params; | |
| $params = array(); | |
| } | |
| } | |
| if (sizeof($params) > 0) { | |
| $sth = $this->prepare($query); | |
| if (DB::isError($sth)) { | |
| return $sth; | |
| } | |
| $res =& $this->execute($sth, $params); | |
| $this->freePrepared($sth); | |
| } else { | |
| $res =& $this->query($query); | |
| } | |
| if (DB::isError($res) || $res === DB_OK) { | |
| return $res; | |
| } | |
| $results = array(); | |
| while (DB_OK === $res->fetchInto($row, $fetchmode)) { | |
| if ($fetchmode & DB_FETCHMODE_FLIPPED) { | |
| foreach ($row as $key => $val) { | |
| $results[$key][] = $val; | |
| } | |
| } else { | |
| $results[] = $row; | |
| } | |
| } | |
| $res->free(); | |
| if (DB::isError($row)) { | |
| $tmp =& $this->raiseError($row); | |
| return $tmp; | |
| } | |
| return $results; | |
| } | |
| // }}} | |
| // {{{ autoCommit() | |
| /** | |
| * enable automatic Commit | |
| * | |
| * @param boolean $onoff | |
| * @return mixed DB_Error | |
| * | |
| * @access public | |
| */ | |
| function autoCommit($onoff=false) | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ commit() | |
| /** | |
| * starts a Commit | |
| * | |
| * @return mixed DB_Error | |
| * | |
| * @access public | |
| */ | |
| function commit() | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ rollback() | |
| /** | |
| * starts a rollback | |
| * | |
| * @return mixed DB_Error | |
| * | |
| * @access public | |
| */ | |
| function rollback() | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ numRows() | |
| /** | |
| * Returns the number of rows in a result object | |
| * | |
| * @param object DB_Result the result object to check | |
| * | |
| * @return mixed DB_Error or the number of rows | |
| * | |
| * @access public | |
| */ | |
| function numRows($result) | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ affectedRows() | |
| /** | |
| * Returns the affected rows of a query | |
| * | |
| * @return mixed DB_Error or number of rows | |
| * | |
| * @access public | |
| */ | |
| function affectedRows() | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ errorNative() | |
| /** | |
| * Returns an errormessage, provides by the database | |
| * | |
| * @return mixed DB_Error or message | |
| * | |
| * @access public | |
| */ | |
| function errorNative() | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ getSequenceName() | |
| /** | |
| * Generate the name used inside the database for a sequence | |
| * | |
| * The createSequence() docblock contains notes about storing sequence | |
| * names. | |
| * | |
| * @param string $sqn the sequence's public name | |
| * | |
| * @return string the sequence's name in the backend | |
| * | |
| * @see DB_common::createSequence(), DB_common::dropSequence(), | |
| * DB_common::nextID(), DB_common::setOption() | |
| * @access private | |
| */ | |
| function getSequenceName($sqn) | |
| { | |
| return sprintf($this->getOption('seqname_format'), | |
| preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); | |
| } | |
| // }}} | |
| // {{{ nextId() | |
| /** | |
| * Returns the next free id in a sequence | |
| * | |
| * @param string $seq_name name of the sequence | |
| * @param boolean $ondemand when true, the seqence is automatically | |
| * created if it does not exist | |
| * | |
| * @return int the next id number in the sequence. DB_Error if problem. | |
| * | |
| * @see DB_common::createSequence(), DB_common::dropSequence(), | |
| * DB_common::getSequenceName() | |
| * @access public | |
| */ | |
| function nextId($seq_name, $ondemand = true) | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ createSequence() | |
| /** | |
| * Creates a new sequence | |
| * | |
| * The name of a given sequence is determined by passing the string | |
| * provided in the <var>$seq_name</var> argument through PHP's sprintf() | |
| * function using the value from the <var>seqname_format</var> option as | |
| * the sprintf()'s format argument. | |
| * | |
| * <var>seqname_format</var> is set via setOption(). | |
| * | |
| * @param string $seq_name name of the new sequence | |
| * | |
| * @return int DB_OK on success. A DB_Error object is returned if | |
| * problems arise. | |
| * | |
| * @see DB_common::dropSequence(), DB_common::getSequenceName(), | |
| * DB_common::nextID() | |
| * @access public | |
| */ | |
| function createSequence($seq_name) | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ dropSequence() | |
| /** | |
| * Deletes a sequence | |
| * | |
| * @param string $seq_name name of the sequence to be deleted | |
| * | |
| * @return int DB_OK on success. DB_Error if problems. | |
| * | |
| * @see DB_common::createSequence(), DB_common::getSequenceName(), | |
| * DB_common::nextID() | |
| * @access public | |
| */ | |
| function dropSequence($seq_name) | |
| { | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ tableInfo() | |
| /** | |
| * Returns information about a table or a result set | |
| * | |
| * The format of the resulting array depends on which <var>$mode</var> | |
| * you select. The sample output below is based on this query: | |
| * <pre> | |
| * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId | |
| * FROM tblFoo | |
| * JOIN tblBar ON tblFoo.fldId = tblBar.fldId | |
| * </pre> | |
| * | |
| * <ul> | |
| * <li> | |
| * | |
| * <kbd>null</kbd> (default) | |
| * <pre> | |
| * [0] => Array ( | |
| * [table] => tblFoo | |
| * [name] => fldId | |
| * [type] => int | |
| * [len] => 11 | |
| * [flags] => primary_key not_null | |
| * ) | |
| * [1] => Array ( | |
| * [table] => tblFoo | |
| * [name] => fldPhone | |
| * [type] => string | |
| * [len] => 20 | |
| * [flags] => | |
| * ) | |
| * [2] => Array ( | |
| * [table] => tblBar | |
| * [name] => fldId | |
| * [type] => int | |
| * [len] => 11 | |
| * [flags] => primary_key not_null | |
| * ) | |
| * </pre> | |
| * | |
| * </li><li> | |
| * | |
| * <kbd>DB_TABLEINFO_ORDER</kbd> | |
| * | |
| * <p>In addition to the information found in the default output, | |
| * a notation of the number of columns is provided by the | |
| * <samp>num_fields</samp> element while the <samp>order</samp> | |
| * element provides an array with the column names as the keys and | |
| * their location index number (corresponding to the keys in the | |
| * the default output) as the values.</p> | |
| * | |
| * <p>If a result set has identical field names, the last one is | |
| * used.</p> | |
| * | |
| * <pre> | |
| * [num_fields] => 3 | |
| * [order] => Array ( | |
| * [fldId] => 2 | |
| * [fldTrans] => 1 | |
| * ) | |
| * </pre> | |
| * | |
| * </li><li> | |
| * | |
| * <kbd>DB_TABLEINFO_ORDERTABLE</kbd> | |
| * | |
| * <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more | |
| * dimensions to the array in which the table names are keys and | |
| * the field names are sub-keys. This is helpful for queries that | |
| * join tables which have identical field names.</p> | |
| * | |
| * <pre> | |
| * [num_fields] => 3 | |
| * [ordertable] => Array ( | |
| * [tblFoo] => Array ( | |
| * [fldId] => 0 | |
| * [fldPhone] => 1 | |
| * ) | |
| * [tblBar] => Array ( | |
| * [fldId] => 2 | |
| * ) | |
| * ) | |
| * </pre> | |
| * | |
| * </li> | |
| * </ul> | |
| * | |
| * The <samp>flags</samp> element contains a space separated list | |
| * of extra information about the field. This data is inconsistent | |
| * between DBMS's due to the way each DBMS works. | |
| * + <samp>primary_key</samp> | |
| * + <samp>unique_key</samp> | |
| * + <samp>multiple_key</samp> | |
| * + <samp>not_null</samp> | |
| * | |
| * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp> | |
| * elements if <var>$result</var> is a table name. The following DBMS's | |
| * provide full information from queries: | |
| * + fbsql | |
| * + mysql | |
| * | |
| * If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp> | |
| * turned on, the names of tables and fields will be lowercased. | |
| * | |
| * @param object|string $result DB_result object from a query or a | |
| * string containing the name of a table. | |
| * While this also accepts a query result | |
| * resource identifier, this behavior is | |
| * deprecated. | |
| * @param int $mode either unused or one of the tableInfo modes: | |
| * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>, | |
| * <kbd>DB_TABLEINFO_ORDER</kbd> or | |
| * <kbd>DB_TABLEINFO_FULL</kbd> (which does both). | |
| * These are bitwise, so the first two can be | |
| * combined using <kbd>|</kbd>. | |
| * @return array an associative array with the information requested. | |
| * If something goes wrong an error object is returned. | |
| * | |
| * @see DB_common::setOption() | |
| * @access public | |
| */ | |
| function tableInfo($result, $mode = null) | |
| { | |
| /* | |
| * If the DB_<driver> class has a tableInfo() method, that one | |
| * overrides this one. But, if the driver doesn't have one, | |
| * this method runs and tells users about that fact. | |
| */ | |
| return $this->raiseError(DB_ERROR_NOT_CAPABLE); | |
| } | |
| // }}} | |
| // {{{ getTables() | |
| /** | |
| * @deprecated Deprecated in release 1.2 or lower | |
| */ | |
| function getTables() | |
| { | |
| return $this->getListOf('tables'); | |
| } | |
| // }}} | |
| // {{{ getListOf() | |
| /** | |
| * list internal DB info | |
| * valid values for $type are db dependent, | |
| * often: databases, users, view, functions | |
| * | |
| * @param string $type type of requested info | |
| * | |
| * @return mixed DB_Error or the requested data | |
| * | |
| * @access public | |
| */ | |
| function getListOf($type) | |
| { | |
| $sql = $this->getSpecialQuery($type); | |
| if ($sql === null) { // No support | |
| return $this->raiseError(DB_ERROR_UNSUPPORTED); | |
| } elseif (is_int($sql) || DB::isError($sql)) { // Previous error | |
| return $this->raiseError($sql); | |
| } elseif (is_array($sql)) { // Already the result | |
| return $sql; | |
| } | |
| return $this->getCol($sql); // Launch this query | |
| } | |
| // }}} | |
| // {{{ getSpecialQuery() | |
| /** | |
| * Returns the query needed to get some backend info | |
| * | |
| * @param string $type What kind of info you want to retrieve | |
| * | |
| * @return string The SQL query string | |
| * | |
| * @access public | |
| */ | |
| function getSpecialQuery($type) | |
| { | |
| return $this->raiseError(DB_ERROR_UNSUPPORTED); | |
| } | |
| // }}} | |
| // {{{ _rtrimArrayValues() | |
| /** | |
| * Right trim all strings in an array | |
| * | |
| * @param array $array the array to be trimmed (passed by reference) | |
| * @return void | |
| * @access private | |
| */ | |
| function _rtrimArrayValues(&$array) | |
| { | |
| foreach ($array as $key => $value) { | |
| if (is_string($value)) { | |
| $array[$key] = rtrim($value); | |
| } | |
| } | |
| } | |
| // }}} | |
| // {{{ _convertNullArrayValuesToEmpty() | |
| /** | |
| * Convert all null values in an array to empty strings | |
| * | |
| * @param array $array the array to be de-nullified (passed by reference) | |
| * @return void | |
| * @access private | |
| */ | |
| function _convertNullArrayValuesToEmpty(&$array) | |
| { | |
| foreach ($array as $key => $value) { | |
| if (is_null($value)) { | |
| $array[$key] = ''; | |
| } | |
| } | |
| } | |
| // }}} | |
| } | |
| /* | |
| * Local variables: | |
| * tab-width: 4 | |
| * c-basic-offset: 4 | |
| * End: | |
| */ | |