Source for file DB.php
Documentation is available at DB.php
* This file has the same name as the file holding the {@link }
* http://pear.php.net/package/DB PEAR DB class}.
* To use the mock DB, put this file in the PHP include path ahead of
* the PEAR library, so that any class which requires DB.php will
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @copyright (c) Walter O. Haas 2006
* @version $Id: DB.php 198 2006-04-20 16:20:30Z haas $
* @author Walt Haas <haas@xmission.com>
require_once 'PHPUnit2/Framework/Assert.php';
* The code returned by many methods upon success
define('DB_ERROR_SYNTAX', - 2);
* Tried to insert a duplicate value into a primary or unique index
define('DB_ERROR_CONSTRAINT', - 3);
* An identifier in the query refers to a non-existant object
define('DB_ERROR_NOT_FOUND', - 4);
* Tried to create a duplicate object
define('DB_ERROR_ALREADY_EXISTS', - 5);
* The current driver does not support the action you attempted
define('DB_ERROR_UNSUPPORTED', - 6);
* The number of parameters does not match the number of placeholders
define('DB_ERROR_MISMATCH', - 7);
* A literal submitted did not match the data type expected
define('DB_ERROR_INVALID', - 8);
* The current DBMS does not support the action you attempted
define('DB_ERROR_NOT_CAPABLE', - 9);
* A literal submitted was too long so the end of it was removed
define('DB_ERROR_TRUNCATED', - 10);
* A literal number submitted did not match the data type expected
define('DB_ERROR_INVALID_NUMBER', - 11);
* A literal date submitted did not match the data type expected
define('DB_ERROR_INVALID_DATE', - 12);
* Attempt to divide something by zero
define('DB_ERROR_DIVZERO', - 13);
* A database needs to be selected
define('DB_ERROR_NODBSELECTED', - 14);
* Could not create the object requested
define('DB_ERROR_CANNOT_CREATE', - 15);
* Could not drop the database requested because it does not exist
define('DB_ERROR_CANNOT_DROP', - 17);
* An identifier in the query refers to a non-existant table
define('DB_ERROR_NOSUCHTABLE', - 18);
* An identifier in the query refers to a non-existant column
define('DB_ERROR_NOSUCHFIELD', - 19);
* The data submitted to the method was inappropriate
define('DB_ERROR_NEED_MORE_DATA', - 20);
* The attempt to lock the table failed
define('DB_ERROR_NOT_LOCKED', - 21);
* The number of columns doesn't match the number of values
define('DB_ERROR_VALUE_COUNT_ON_ROW', - 22);
* The DSN submitted has problems
define('DB_ERROR_INVALID_DSN', - 23);
* Could not connect to the database
define('DB_ERROR_CONNECT_FAILED', - 24);
* The PHP extension needed for this DBMS could not be found
define('DB_ERROR_EXTENSION_NOT_FOUND',- 25);
* The present user has inadequate permissions to perform the task requestd
define('DB_ERROR_ACCESS_VIOLATION', - 26);
* The database requested does not exist
define('DB_ERROR_NOSUCHDB', - 27);
* Tried to insert a null value into a column that doesn't allow nulls
define('DB_ERROR_CONSTRAINT_NOT_NULL',- 29);
* Identifiers for the placeholders used in prepared statements.
* Indicates a scalar (<kbd>?</kbd>) placeholder was used
* Quote and escape the value as necessary.
* Indicates an opaque (<kbd>&</kbd>) placeholder was used
* The value presented is a file name. Extract the contents of that file
* and place them in this column.
* Indicates a misc (<kbd>!</kbd>) placeholder was used
* The value should not be quoted or escaped.
* The different ways of returning binary data from queries.
* Sends the fetched data straight through to output
define('DB_BINMODE_PASSTHRU', 1);
* Lets you return data as usual
define('DB_BINMODE_RETURN', 2);
* Converts the data to hex format before returning it
* For example the string "123" would become "313233".
define('DB_BINMODE_CONVERT', 3);
define('DB_FETCHMODE_DEFAULT', 0);
define('DB_FETCHMODE_ORDERED', 1);
define('DB_FETCHMODE_ASSOC', 2);
define('DB_FETCHMODE_OBJECT', 3);
* For multi-dimensional results, make the column name the first level
* of the array and put the row number in the second level of the array
* This is flipped from the normal behavior, which puts the row numbers
* in the first level of the array and the column names in the second level.
define('DB_FETCHMODE_FLIPPED', 4);
* Old fetch modes. Left here for compatibility.
define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC);
define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED);
* The type of information to return from the tableInfo() method.
* Bitwised constants, so they can be combined using <kbd>|</kbd>
* and removed using <kbd>^</kbd>.
define('DB_TABLEINFO_ORDER', 1);
define('DB_TABLEINFO_ORDERTABLE', 2);
define('DB_TABLEINFO_FULL', 3);
* The type of query to create with the automatic query building methods.
* @see autoPrepare(), autoExecute()
define('DB_AUTOQUERY_INSERT', 1);
define('DB_AUTOQUERY_UPDATE', 2);
* Bitwised constants, so they can be combined using <kbd>|</kbd>
* and removed using <kbd>^</kbd>.
* Turn off all portability features
define('DB_PORTABILITY_NONE', 0);
* Convert names of tables and fields to lower case
* when using the get*(), fetch*() and tableInfo() methods
define('DB_PORTABILITY_LOWERCASE', 1);
* Right trim the data output by get*() and fetch*()
define('DB_PORTABILITY_RTRIM', 2);
* Force reporting the number of rows deleted
define('DB_PORTABILITY_DELETE_COUNT', 4);
* Enable hack that makes numRows() work in Oracle
define('DB_PORTABILITY_NUMROWS', 8);
* 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.
define('DB_PORTABILITY_ERRORS', 16);
* Convert null values to empty strings in data output by
define('DB_PORTABILITY_NULL_TO_EMPTY', 32);
* Turn on all portability features
define('DB_PORTABILITY_ALL', 63);
* Mock DB class for testing
* This class is a mock version of the
* {@link http://pear.php.net/package/DB PEAR DB class}. It is
* intended to provide the same interface as the real DB class, plus
* a small database sufficient to test software.
* Create a new DB object for the specified database type but don't
* connect to the database
* @param string $type the database type (eg "mysql")
* @param array $options an associative array of option names and values
* @return object a new DB object. A DB_Error object on failure.
* @see DB_common::setOption()
* @todo Implement mock DB::factory
public function &factory($type, $options = false)
// if (!is_array($options)) {
// $options = array('persistent' => $options);
// if (isset($options['debug']) && $options['debug'] >= 2) {
// // expose php errors with sufficient debug level
// include_once "DB/{$type}.php";
// @include_once "DB/{$type}.php";
// $classname = "DB_${type}";
// if (!class_exists($classname)) {
// $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null,
// "Unable to include the DB/{$type}.php"
// @$obj =& new $classname;
// foreach ($options as $option => $value) {
// $test = $obj->setOption($option, $value);
// if (DB::isError($test)) {
* Create a new DB object including a connection to the specified database
* @param mixed $dsn the string "data source name" or array in the
* format returned by DB::parseDSN()
* @param array $options an associative array of option names and values
* @return object a new DB object. A DB_Error object on failure.
* @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError()
* @todo Implement mock DB::connect
function &connect($dsn, $options = array())
$type = $dsninfo['phptype'];
// only support MySQL at the moment
PHPUnit2_Framework_Assert::assertEquals($type,'mysql');
foreach ($options as $option => $value) {
$test = $obj->setOption($option, $value);
// $err = $obj->connect($dsninfo, $obj->getOption('persistent'));
// if (DB::isError($err)) {
// $err->addUserInfo($dsn);
* Return the DB API version
* @return string the DB API version number
* Determines if a variable is a DB_Error object
* @param mixed $value the variable to check
* @return bool whether $value is DB_Error object
return is_a($value, 'DB_Error');
* Determines if a value is a DB_<driver> object
* @param mixed $value the value to test
* @return bool whether $value is a DB_<driver> object
* @todo Implement mock DB::isConnection
// return (is_object($value) &&
// is_subclass_of($value, 'db_common') &&
// method_exists($value, 'simpleQuery'));
* Tell whether a query is a data manipulation or data definition query
* @param string $query the query
* @return boolean whether $query is a data manipulation query
$manips = 'INSERT|UPDATE|DELETE|REPLACE|'
. 'LOAD DATA|SELECT .* INTO|COPY|'
if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) {
* Return a textual error message for a DB error code
* @param integer $value the DB error code
* @return string the error message or false if the error code was
* @todo Implement mock DB::errorMessage
if (!isset ($errorMessages)) {
// if (DB::isError($value)) {
// $value = $value->getCode();
// return isset($errorMessages[$value]) ? $errorMessages[$value]
// : $errorMessages[DB_ERROR];
* Parse a data source name
* @param string $dsn Data Source Name to be parsed
* @return array an associative array with the following keys:
* + phptype: Database backend used in PHP (mysql, odbc etc.)
* + dbsyntax: Database used with regards to SQL syntax etc.
* + protocol: Communication protocol to use (tcp, unix etc.)
* + hostspec: Host specification (hostname[:port])
* + database: Database to use on the DBMS server
* + username: User name for login
* + password: Password for login
* @todo Implement mock DB::parseDSN
$dsn['dbsyntax'] = $dsn['phptype'];
// Find phptype and dbsyntax
if (($pos = strpos($dsn, '://')) !== false) {
$dsn = substr($dsn, $pos + 3);
// Get phptype and dbsyntax
// $str => phptype(dbsyntax)
if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
$parsed['phptype'] = $arr[1];
$parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
$parsed['phptype'] = $str;
$parsed['dbsyntax'] = $str;
// Get (if found): username and password
// $dsn => username:password@protocol+hostspec/database
if (($at = strrpos($dsn,'@')) !== false) {
if (($pos = strpos($str, ':')) !== false) {
// Find protocol and hostspec
if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) {
// $dsn => proto(proto_opts)/database
$proto_opts = $match[2] ? $match[2] : false;
// $dsn => protocol+hostspec/database (old format)
if (strpos($dsn, '+') !== false) {
list ($proto, $dsn) = explode('+', $dsn, 2);
if (strpos($dsn, '/') !== false) {
list ($proto_opts, $dsn) = explode('/', $dsn, 2);
// process the different protocol options
$parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp';
if ($parsed['protocol'] == 'tcp') {
if (strpos($proto_opts, ':') !== false) {
list ($parsed['hostspec'],
$parsed['port']) = explode(':', $proto_opts);
$parsed['hostspec'] = $proto_opts;
} elseif ($parsed['protocol'] == 'unix') {
$parsed['socket'] = $proto_opts;
if (($pos = strpos($dsn, '?')) === false) {
// /database?param1=value1¶m2=value2
$dsn = substr($dsn, $pos + 1);
if (strpos($dsn, '&') !== false) {
|