home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2001 August
/
PCWorld_2001-08_cd.bin
/
Komunikace
/
phptriad
/
phptriadsetup2-11.exe
/
php
/
pear
/
DB
/
common.php
next >
Wrap
PHP Script
|
2001-03-12
|
24KB
|
871 lines
<?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);
}
// }}}
}
?>