home *** CD-ROM | disk | FTP | other *** search
- <?php
- //
- // +----------------------------------------------------------------------+
- // | PHP version 4.0 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1997-2001 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. |
- // +----------------------------------------------------------------------+
- // | Authors: Stig Bakken <ssb@fast.no> |
- // | |
- // +----------------------------------------------------------------------+
- //
- // Base class for DB implementations.
- //
-
- /**
- * DB_common is a base class for DB implementations, and must be
- * inherited by all such.
- */
-
- class DB_common
- {
- // {{{ properties
-
- var $features; // assoc of capabilities for this DB implementation
- var $errorcode_map; // assoc mapping native error codes to DB ones
- var $type; // DB type (mysql, oci8, odbc etc.)
- var $prepare_tokens;
- var $prepare_types;
- var $prepare_maxstmt;
- var $error_mode = PEAR_ERROR_RETURN;
- var $error_level = E_USER_NOTICE;
- var $error_callback;
- var $last_query = '';
- var $fetchmode = DB_FETCHMODE_ORDERED;
- var $options = array(
- 'persistent' => false, // persistent connection?
- 'optimize' => 'performance', // 'performance' or 'portability'
- );
- var $dbh;
-
- // }}}
- // {{{ toString()
-
- function toString()
- {
- $info = get_class($this);
-
- $info .= ": (phptype=" . $this->phptype .
- ", dbsyntax=" . $this->dbsyntax .
- ")";
-
- if ($this->connection) {
- $info .= " [connected]";
- }
-
- return $info;
- }
-
- // }}}
- // {{{ constructor
-
- function DB_common()
- {
- $this->features = array();
- $this->errorcode_map = array();
- $this->fetchmode = DB_FETCHMODE_ORDERED;
- }
-
- // }}}
- // {{{ quoteString()
-
- /**
- * Quotes a string so it can be safely used within string delimiters
- * in a query.
- *
- * @param $string the input string to quote
- *
- * @return string the quoted string
- */
-
- function quoteString($string)
- {
- return str_replace("'", "\'", $string);
- }
-
- // }}}
- // {{{ provides()
-
- /**
- * Tell whether a DB implementation or its backend extension
- * supports a given feature.
- *
- * @param $feature name of the feature (see the DB class doc)
- *
- * @return bool whether this DB implementation supports $feature
- */
-
- 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 $errorcode_map
- * property.
- *
- * @param $nativecode the native error code, as returned by the backend
- * database extension (string or integer)
- *
- * @return int a portable DB error code, or FALSE if this DB
- * implementation has no mapping for the given error code.
- */
-
- function errorCode($nativecode)
- {
- if ($this->errorcode_map[$nativecode]) {
- return $this->errorcode_map[$nativecode];
- }
-
- //php_error(E_WARNING, get_class($this)."::errorCode: no mapping for $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 $dbcode the DB error code
- *
- * @return string the corresponding error message, of FALSE
- * if the error code was unknown
- */
-
- function errorMessage($dbcode)
- {
- return DB::errorMessage($this->errorcode_map[$dbcode]);
- }
-
- // }}}
- // {{{ raiseError()
-
- /**
- * This method is called by DB to generate an error.
- *
- */
-
- function &raiseError($code = DB_ERROR, $mode = false, $level = false,
- $debuginfo = false, $nativecode = false)
- {
- if (!$mode) {
- $mode = $this->error_mode;
- }
-
- if ($mode == PEAR_ERROR_CALLBACK) {
- if (!is_string($level) &&
- !(is_array($level) && sizeof($level) == 2 &&
- is_object($level[0]) && is_string($level[1]))) {
- $level = $this->error_callback;
- }
- } else {
- if (!$level) {
- $level = $this->error_level;
- }
- }
-
- if (!$debuginfo) {
- $debuginfo = $this->last_query;
- }
-
- if ($nativecode) {
- $debuginfo .= " [nativecode=$nativecode]";
- }
-
- return new DB_Error($code, $mode, $level, $debuginfo);
- }
-
- // }}}
- // {{{ setErrorHandling()
-
- /**
- * Sets how errors generated by this DB object should be handled.
- *
- * @param $mode int
- * one of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
- * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE or
- * PEAR_ERROR_CALLBACK.
- *
- * @param $options mixed
- * Ignored unless $mode is PEAR_ERROR_TRIGGER or
- * PEAR_ERROR_CALLBACK. When $mode is PEAR_ERROR_TRIGGER,
- * this parameter is expected to be an integer among
- * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR. When
- * $mode is PEAR_ERROR_CALLBACK, this parameter is expected
- * to be the callback function or method. A callback
- * function is a string with the name of the function, a
- * callback method is an array of two elements: the element
- * at index 0 is an object, and the element at index 1 is
- * the name of the method to call in the object.
- *
- * @see PEAR_ERROR_RETURN
- * @see PEAR_ERROR_PRINT
- * @see PEAR_ERROR_TRIGGER
- * @see PEAR_ERROR_DIE
- * @see PEAR_ERROR_CALLBACK
- */
-
- function setErrorHandling($mode, $options = false)
- {
- switch ($mode) {
- case PEAR_ERROR_RETURN:
- case PEAR_ERROR_PRINT:
- case PEAR_ERROR_TRIGGER:
- case PEAR_ERROR_DIE:
- $this->error_mode = $mode;
-
- if (!$options) {
- $this->error_level = E_USER_NOTICE;
- } else {
- $this->error_level = $options;
- }
- break;
-
- case PEAR_ERROR_CALLBACK:
- $this->error_mode = $mode;
- if (is_string($options) ||
- (is_array($options) && sizeof($options) == 2 &&
- is_object($options[0]) && is_string($options[1]))) {
- $this->error_callback = $options;
- } else {
- trigger_error("invalid error callback", E_USER_WARNING);
- }
- $this->error_level = PEAR_ERROR_RETURN;
- break;
-
- default:
- trigger_error("invalid error mode", E_USER_WARNING);
- break;
- }
- }
-
- // }}}
- // {{{ setFetchMode()
-
- /**
- * Sets which fetch mode should be used by default on queries
- * on this connection.
- *
- * @param $fetchmode int DB_FETCHMODE_ORDERED or
- * DB_FETCHMODE_ASSOC, possibly bit-wise OR'ed with
- * DB_FETCHMODE_FLIPPED.
- *
- * @see DB_FETCHMODE_ORDERED
- * @see DB_FETCHMODE_ASSOC
- * @see DB_FETCHMODE_FLIPPED
- */
-
- function setFetchMode($fetchmode)
- {
- switch ($fetchmode) {
- case DB_FETCHMODE_ORDERED:
- case DB_FETCHMODE_ASSOC:
- $this->fetchmode = $fetchmode;
- break;
- default:
- return $this->raiseError("invalid get mode");
- }
- }
-
- // }}}
- // {{{ setOption()
-
- function setOption($option, $value)
- {
- if (isset($this->options[$option])) {
- $this->options[$option] = $value;
- return DB_OK;
- }
- return $this->raiseError("unknown option $option");
- }
-
- // }}}
- // {{{ getOption()
-
- 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(). With
- * some database backends, this is emulated.
- */
-
- function prepare($query)
- {
- $tokens = split("[\&\?]", $query);
- $token = 0;
- $types = array();
-
- for ($i = 0; $i < strlen($query); $i++) {
- switch ($query[$i]) {
- case "?":
- $types[$token++] = DB_PARAM_SCALAR;
- break;
- case "&":
- $types[$token++] = DB_PARAM_OPAQUE;
- break;
- }
- }
-
- $this->prepare_tokens[] = &$tokens;
- end($this->prepare_tokens);
-
- $k = key($this->prepare_tokens);
- $this->prepare_types[$k] = $types;
-
- return $k;
- }
-
- // }}}
- // {{{ execute()
-
- function execute($stmt, $data = false)
- {
- $realquery = $this->executeEmulateQuery($stmt, $data);
- $result = $this->simpleQuery($realquery);
- if (DB::isError($result) || $result === DB_OK) {
- return $result;
- } else {
- return new DB_result($this, $result);
- }
- }
-
- // }}}
- // {{{ executeEmulateQuery()
-
- /**
- * @return a string containing the real query run when emulating
- * prepare/execute. A DB error code is returned on failure.
- */
-
- function executeEmulateQuery($stmt, $data = false)
- {
- $p = &$this->prepare_tokens;
- $stmt = (int)$this->prepare_maxstmt++;
-
- if (!isset($this->prepare_tokens[$stmt]) ||
- !is_array($this->prepare_tokens[$stmt]) ||
- !sizeof($this->prepare_tokens[$stmt])) {
- return $this->raiseError(DB_ERROR_INVALID);
- }
-
- $qq = &$this->prepare_tokens[$stmt];
- $qp = sizeof($qq) - 1;
-
- if ((!$data && $qp > 0) ||
- (!is_array($data) && $qp > 1) ||
- (is_array($data) && $qp > sizeof($data))) {
- return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
- }
-
- $realquery = $qq[0];
-
- for ($i = 0; $i < $qp; $i++) {
- if ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) {
- if (is_array($data)) {
- $fp = fopen($data[$i], "r");
- } else {
- $fp = fopen($data, "r");
- }
-
- $pdata = "";
-
- if ($fp) {
- while (($buf = fread($fp, 4096)) != false) {
- $pdata .= $buf;
- }
- }
- } else {
- if (is_array($data)) {
- $pdata = &$data[$i];
- } else {
- $pdata = &$data;
- }
- }
-
- $realquery .= "'" . $this->quoteString($pdata) . "'";
- $realquery .= $qq[$i + 1];
- }
-
- 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.
- */
-
- function executeMultiple( $stmt, &$data )
- {
- for($i = 0; $i < sizeof( $data ); $i++) {
- $res = $this->execute($stmt, $data[$i]);
- if (DB::isError($res)) {
- return $res;
- }
- }
- return DB_OK;
- }
-
- // }}}
- // {{{ 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.
- *
- * @access private
- *
- * @param query to modify
- *
- * @return the new (modified) query
- */
- function modifyQuery($query) {
- return $query;
- }
-
- // }}}
- // {{{ query()
-
- /**
- * Send a query to the database and return any results with a
- * DB_result object.
- *
- * @access public
- *
- * @param the SQL query
- *
- * @return object a DB_result object or DB_OK on success, a DB
- * error on failure
- *
- * @see DB::isError
- */
- function &query($query) {
- $result = $this->simpleQuery($query);
- if (DB::isError($result) || $result === DB_OK) {
- return $result;
- } else {
- return new DB_result($this, $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 $query the SQL query
- * @param $params if supplied, prepare/execute will be used
- * with this array as execute parameters
- * @access public
- */
-
- function &getOne($query, $params = array())
- {
- if (sizeof($params) > 0) {
- $sth = $this->prepare($query);
-
- if (DB::isError($sth)) {
- return $sth;
- }
- $res = $this->execute($sth, $params);
- } else {
- $res = $this->simpleQuery($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $row = $this->fetchRow($res, DB_FETCHMODE_ORDERED);
-
- if (DB::isError($row)) {
- return $row;
- }
-
- $ret = &$row[0];
- $this->freeResult($res);
-
- if (isset($sth)) {
- $this->freeResult($sth);
- }
-
- return $ret;
- }
-
- // }}}
- // {{{ getRow()
-
- /**
- * Fetch the first row of data returned from a query. Takes care
- * of doing the query and freeing the results when finished.
- *
- * @param $query the SQL query
- * @access public
- * @return array the first row of results as an array indexed from
- * 0, or a DB error code.
- */
-
- function &getRow($query, $fetchmode = DB_FETCHMODE_DEFAULT,
- $params = array())
- {
- if ($fetchmode == DB_FETCHMODE_DEFAULT) {
- $fetchmode = $this->fetchmode;
- }
-
- if (sizeof($params) > 0) {
- $sth = $this->prepare( $query );
- if (DB::isError($sth)) {
- return $sth;
- }
- $res = $this->execute($sth, $params);
- } else {
- $res = $this->simpleQuery($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $row = $this->fetchRow($res, $fetchmode);
-
- if (DB::isError($row)) {
- return $row;
- }
-
- $this->freeResult($res);
-
- if (isset($sth)) {
- $this->freeResult($sth);
- }
-
- return $row;
- }
-
- // }}}
- // {{{ getCol()
-
- /**
- * Fetch a single column from a result set and return it as an
- * indexed array.
- *
- * @param $query the SQL query
- *
- * @param $col which column to return (integer [column number,
- * starting at 0] or string [column name])
- *
- * @access public
- *
- * @return array an indexed array with the data from the first
- * row at index 0, or a DB error code.
- */
-
- function &getCol($query, $col = 0, $params = array())
- {
- if (sizeof($params) > 0) {
- $sth = $this->prepare($query);
-
- if (DB::isError($sth)) {
- return $sth;
- }
-
- $res = $this->execute($sth, $params);
- } else {
- $res = $this->simpleQuery($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC;
- $ret = array();
-
- while ($row = $this->fetchRow($res, $fetchmode)) {
- if (DB::isError($row)) {
- $ret = $row;
- break;
- }
-
- $ret[] = $row[$col];
- }
-
- $this->freeResult($res);
-
- if (isset($sth)) {
- $this->freeResult($sth);
- }
-
- 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.
- *
- * @param $query the SQL query
- *
- * @param $force_array (optional) 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.
- *
- * @access public
- *
- * @return array associative array with results from the query.
- * 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:
- *
- * ID TEXT DATE
- * --------------------------------
- * 1 'one' 944679408
- * 2 'two' 944679408
- * 3 'three' 944679408
- *
- * Then the call getAssoc('SELECT id,text FROM mytable') returns:
- * array(
- * '1' => 'one',
- * '2' => 'two',
- * '3' => 'three',
- * )
- *
- * ...while the call getAssoc('SELECT id,text,date FROM mydate') returns:
- * array(
- * '1' => array('one', '944679408'),
- * '2' => array('two', '944679408'),
- * '3' => array('three', '944679408')
- * )
- *
- * Keep in mind that database functions in PHP usually return string
- * values for results regardless of the database's internal type.
- */
-
- function &getAssoc($query, $force_array = false, $params = array())
- {
- if (sizeof($params) > 0) {
- $sth = $this->prepare($query);
-
- if (DB::isError($sth)) {
- return $sth;
- }
-
- $res = $this->execute($sth, $params);
- } else {
- $res = $this->simpleQuery($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $cols = $this->numCols($res);
-
- if ($cols < 2) {
- return $this->raiseError(DB_ERROR_TRUNCATED);
- }
-
- $results = array();
-
- if ($cols > 2 || $force_array) {
- // return array values
- // XXX this part can be optimized
- while (($row = $this->fetchRow($res, DB_FETCHMODE_ORDERED)) &&
- !DB::isError($row)) {
- reset($row);
- // we copy the row of data into a new array
- // to get indices running from 0 again
- $results[$row[0]] = array_slice($row, 1);
- }
- } else {
- // return scalar values
- while (($row = $this->fetchRow($res, DB_FETCHMODE_ORDERED)) &&
- !DB::isError($row)) {
- $results[$row[0]] = $row[1];
- }
- }
-
- $this->freeResult($res);
-
- if (isset($sth)) {
- $this->freeResult($sth);
- }
-
- return $results;
- }
-
- // }}}
- // {{{ getAll()
-
- /**
- * Fetch all the rows returned from a query.
- *
- * @param $query the SQL query
- * @access public
- * @return array an nested array, or a DB error
- */
-
- function &getAll($query, $fetchmode = DB_FETCHMODE_DEFAULT,
- $params = array())
- {
- if ($fetchmode == DB_FETCHMODE_DEFAULT) {
- $fetchmode = $this->fetchmode;
- }
-
- if (sizeof($params) > 0) {
- $sth = $this->prepare($query);
-
- if (DB::isError($sth)) {
- return $sth;
- }
-
- $res = $this->execute($sth, $params);
- } else {
- $res = $this->simpleQuery($query);
- }
-
- if (DB::isError($res)) {
- return $res;
- }
-
- $results = array();
-
- while (($row = $this->fetchRow($res, $fetchmode)) &&
- !DB::isError($row)) {
- if ($fetchmode & DB_FETCHMODE_FLIPPED) {
- foreach ($row as $key => $val) {
- $results[$key][] = $val;
- }
- } else {
- $results[] = $row;
- }
- }
-
- $this->freeResult($res);
-
- if (isset($sth)) {
- $this->freeResult($sth);
- }
-
- return $results;
- }
-
- // }}}
- // {{{ autoCommit()
-
- function autoCommit($onoff=false)
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ commit()
-
- function commit()
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ rollback()
-
- function rollback()
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ numRows()
-
- function numRows($result)
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ affectedRows()
-
- function affectedRows()
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ errorNative()
-
- function errorNative()
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ nextId()
-
- function nextId($seq_name, $ondemand = true)
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ createSequence()
-
- function createSequence($seq_name)
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- // {{{ dropSequence()
-
- function dropSequence($seq_name)
- {
- return $this->raiseError(DB_ERROR_NOT_CAPABLE);
- }
-
- // }}}
- }
-
- ?>
-